this repo has no description
1#!/usr/bin/env perl -w
2
3###########################################################
4#
5# Convenince script to generate CMake projects for Android
6# for each architecture and build them.
7# Copyright (C) PlayControl Software, LLC.
8# Eric Wing <ewing . public @ playcontrol.net>
9#
10# Convention:
11# You have created standalone toolchains and placed them in a directory called standalone under the $ANDROID_NDK_ROOT:
12# $ANDROID_NDK_ROOT/standalone/
13# arm-linux-androideabi-4.6/
14# x86-4.6/
15#
16##########################################################
17
18
19#use strict;
20use warnings;
21
22# Function to help with command line switches
23use Getopt::Long;
24# Allows extra "unknown options" to be specified which I will use to pass directly to the cmake executable.
25Getopt::Long::Configure("pass_through");
26
27# Function to get the basename of a file
28use File::Basename;
29# Used for tilde expansion
30use File::Glob;
31# for make_path (which is mkdir -p)
32use File::Path qw(make_path);
33
34# Provides functions to convert relative paths to absolute paths.
35use Cwd;
36
37use File::Basename;
38
39# Global constants
40
41my $kCMakeBootStrapCacheFile = "InitialCache_Android.cmake";
42
43my %kArchToDirectoryNameMap =
44(
45# mips => "mips",
46 armeabi => "armeabi",
47 "armeabi-v7a" => "armeabi-v7a",
48# "armeabi-v7a with NEON" => "armeabi-v7a",
49# "armeabi-v7a with VFPV3" => "armeabi-v7a",
50# "armeabi-v6 with VFP" => "armeabi",
51 x86 => "x86"
52);
53
54# Global constants
55my %kArchToCompilerNameMap =
56(
57# mips => "mips",
58 armeabi => "arm-linux-androideabi",
59 "armeabi-v7a" => "arm-linux-androideabi",
60# "armeabi-v7a with NEON" => "armeabi",
61# "armeabi-v7a with VFPV3" => "armeabi",
62# "armeabi-v6 with VFP" => "armeabi",
63 x86 => "x86"
64);
65
66
67my @kSupportedArchitectures =
68(
69# "mips",
70 "armeabi",
71 "armeabi-v7a",
72# "armeabi-v7a with NEON",
73# "armeabi-v7a with VFPV3",
74# "armeabi-v6 with VFP",
75 "x86",
76);
77
78
79# Function prototypes
80
81# main routine
82sub main();
83# call main
84
85sub main()
86{
87
88 my ($blurrr_sdk_root,
89 $blurrr_sdk_path,
90 $cmake_source_dir,
91 $cmake_binary_dir,
92 $libsdir,
93 $android_sdk_root,
94 $standalone_toolchain_root,
95 $targetSdkVersion,
96 $minSdkVersion,
97 $compilerversion,
98 $buildtype,
99 $should_build,
100 $cmake_toolchain,
101 $cmake,
102 $architectures,
103 @remaining_options
104 ) = extract_parameters();
105
106 my @architectures_array;
107
108 if(not defined($architectures))
109 {
110 @architectures_array = @kSupportedArchitectures;
111 }
112 else
113 {
114 @architectures_array = split(/[ ,;]/, $architectures);
115 }
116
117
118
119
120 print("blurrr_sdk_root: ", $blurrr_sdk_root, "\n");
121 print("blurrr_sdk_path: ", $blurrr_sdk_path, "\n");
122 print("cmake_source_dir: ", $cmake_source_dir, "\n");
123 print("cmake_binary_dir: ", $cmake_binary_dir, "\n");
124 print("libsdir: ", $libsdir, "\n");
125
126
127 print("android_sdk_root: ", $android_sdk_root, "\n");
128 print("standalone_toolchain_root: ", $standalone_toolchain_root, "\n");
129 print("targetSdkVersion: ", $targetSdkVersion, "\n");
130 print("minSdkVersion: ", $minSdkVersion, "\n");
131# print("compilerversion: ", $compilerversion, "\n");
132 print("buildtype: ", $buildtype, "\n");
133 print("should_build: ", $should_build, "\n");
134 print("cmake_toolchain: ", $cmake_toolchain, "\n");
135 print("cmake: ", $cmake, "\n");
136
137# print("remaining_options: ", @remaining_options, "\n");
138
139
140
141 copy_build_scripts($cmake_source_dir, $cmake_binary_dir);
142
143
144
145# my ($targetdir, $standalone, $compilerversion, $should_build, $cmake, $toolchain, $libsdir, $buildtype, $sourcedir, @remaining_options) = extract_parameters();
146
147 # Save in case we need to return to the original current working directory.
148 my $original_current_working_directory = Cwd::cwd();
149
150 foreach my $arch(@architectures_array)
151 {
152 # First choose the correct compiler.
153 my $found_compiler;
154 my $compiler_base_name = $kArchToCompilerNameMap{$arch};
155
156 opendir(STANDALONEDIR, $standalone_toolchain_root) or die("Could not open standalone_toolchain_root directory: $!\n");
157 while(my $file = readdir(STANDALONEDIR))
158 {
159 my $full_path_and_file = "$standalone_toolchain_root/$file";
160
161 # Go to the next file unless it is a directory
162 next unless(-d "$full_path_and_file");
163
164 # if a version was specified, make sure it matches
165 if(defined($compilerversion))
166 {
167 if($file =~ m/$compiler_base_name-$compilerversion/)
168 {
169 $found_compiler = $full_path_and_file;
170 last;
171 }
172 }
173 # otherwise if no version was specified, just go for any match
174 else
175 {
176 if($file =~ m/$compiler_base_name/)
177 {
178 $found_compiler = $full_path_and_file;
179 last;
180 }
181 }
182 }
183 closedir(STANDALONEDIR);
184
185 if(not defined $found_compiler)
186 {
187 die("Could not find compiler in directory:$standalone_toolchain_root for arch:$arch\n");
188 }
189
190
191
192 chdir($cmake_binary_dir) or die("Could not change directory to $cmake_binary_dir: $!\n");
193 # Let's make an intermediate subdirectory for all the CMake NDK stuff we're going to create
194 my $cmake_ndk_build = "cmake_ndk_build";
195 unless(-e $cmake_ndk_build or mkdir $cmake_ndk_build)
196 {
197 die("Unable to create $cmake_ndk_build: $!\n");
198 }
199 chdir($cmake_ndk_build) or die("Could not change directory to $cmake_ndk_build: $!\n");
200
201 my $arch_dir = $kArchToDirectoryNameMap{$arch};
202 unless(-e $arch_dir or mkdir $arch_dir)
203 {
204 die("Unable to create $arch_dir: $!\n");
205 }
206 chdir($arch_dir) or die("Could not change directory to $arch_dir: $!\n");
207
208 my $android_standalone_toolchain = "$found_compiler";
209 print("Generating $arch\n");
210
211 #my $initial_cache = "$blurrr_sdk_root/$kCMakeBootStrapCacheFile";
212 my $initial_cache = "$cmake_source_dir/AndroidCMake/$kCMakeBootStrapCacheFile";
213 my $suppress_dev_warnings_flags = "-Wno-dev";
214
215 my $blurrr_path_to_use;
216 if(defined $blurrr_sdk_path)
217 {
218 $blurrr_path_to_use = "-DBLURRR_SDK_PATH=$blurrr_sdk_path";
219 }
220 else
221 {
222 $blurrr_path_to_use = "-DBLURRR_ROOT=$blurrr_sdk_root";
223 }
224
225 # There is something screwing up the call when I do comma separated arguments.
226 my $command_string = "$cmake $suppress_dev_warnings_flags -DCMAKE_TOOLCHAIN_FILE=$cmake_toolchain $blurrr_path_to_use -DBLURRR_SDK_PATH=$blurrr_sdk_path -DANDROID_ABI=$arch -DBLURRR_CMAKE_ANDROID_REAL_BINARY_DIR=$cmake_binary_dir -DANDROID_SDK_ROOT=$android_sdk_root -C $initial_cache -DANDROID_STANDALONE_TOOLCHAIN=$android_standalone_toolchain -DANDROID_TARGET_SDK_VERSION=$targetSdkVersion -DANDROID_MIN_SDK_VERSION=$minSdkVersion -DLIBRARY_OUTPUT_PATH_ROOT=$libsdir -DCMAKE_BUILD_TYPE=$buildtype @remaining_options $cmake_source_dir";
227 #print("Executing: $cmake $cmake_toolchain $blurrr_root_flag $arch_flag $initial_cache $android_standalone_toolchain $libsdir $buildtype @remaining_options $cmake_source_dir\n");
228 print("Executing: $command_string\n\n");
229
230#
231# /Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST/CMake/CMake.app/Contents/bin/cmake -DCMAKE_TOOLCHAIN_FILE=/Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST/Templates/C/CMakeModules/android.toolchain.cmake -DBLURRR_ROOT=/Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST -DANDROID_ABI=armeabi -DBLURRR_CMAKE_ANDROID_REAL_BINARY_DIR=/Volumes/DataPartition/Users/ewing/TEMP/GradleCMakeTest -C /Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST/bootstrap/InitialCache_C_Android.cmake -DANDROID_STANDALONE_TOOLCHAIN=/Library/Frameworks/Android/android-ndk-r9b/standalone/arm-linux-androideabi-4.6 -DLIBRARY_OUTPUT_PATH_ROOT=/Volumes/DataPartition/Users/ewing/TEMP/GradleCMakeTestapp/libs -DCMAKE_BUILD_TYPE=Release /Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST/Templates/Cloading initial cache file /Volumes/DataPartition/Users/ewing/Source/Blurrr/Templates/DIST/bootstrap/InitialCache_C_Android.cmake
232 # Spaces in paths can really system() up, so the comma separated version is better because it is able to distinguish the difference between a space vs. multiple arguments.
233 my $error_status = system($cmake,
234 $suppress_dev_warnings_flags,
235 "-DCMAKE_TOOLCHAIN_FILE=$cmake_toolchain",
236 $blurrr_path_to_use,
237 "-DBLURRR_SDK_PATH=$blurrr_sdk_path",
238 "-DANDROID_ABI=$arch",
239 "-DBLURRR_CMAKE_ANDROID_REAL_BINARY_DIR=$cmake_binary_dir",
240 "-DANDROID_SDK_ROOT=$android_sdk_root",
241 "-C", $initial_cache,
242 "-DANDROID_STANDALONE_TOOLCHAIN=$android_standalone_toolchain",
243 "-DANDROID_TARGET_SDK_VERSION=$targetSdkVersion",
244 "-DANDROID_MIN_SDK_VERSION=$minSdkVersion",
245 "-DLIBRARY_OUTPUT_PATH_ROOT=$libsdir",
246 "-DCMAKE_BUILD_TYPE=$buildtype",
247 @remaining_options,
248 $cmake_source_dir
249 );
250# my $error_status = system($command_string);
251 if($error_status != 0)
252 {
253 die "Invoking CMake failed: $?\n";
254 }
255
256 if($should_build)
257 {
258 print("Building $arch\n");
259 $error_status = system("make");
260 if($error_status != 0)
261 {
262 die "Invoking make failed: $?\n";
263 }
264 }
265 }
266
267 return;
268
269}
270
271
272sub helpmenu()
273{
274 my $basename = basename($0);
275 print "Convenience script for generating and building CMake based projects for Android (multiple architectures).\n\n";
276 print "Convention:\n";
277 print "You have created standalone toolchains and placed them in a directory called standalone under the \$ANDROID_NDK_ROOT:\n";
278 print "\$ANDROID_NDK_ROOT/standalone/\n";
279 print "\tarm-linux-androideabi-4.6/\n";
280 print "\tx86-4.6/\n";
281
282 #print "Usage: perl $basename [-h | -help] --sourcedir=<path to source> --targetdir=<path to build dir> --toolchain=<CMake toolchain file> [--standalone=<standalone root directory>] [--cmake=<CMake exectuable>] [--buildtype=<None|Debug|Release*|RelWithDebInfo|MinSizeRel>] [<other flags passed to CMake>] <Project Source Directory>\n";
283 print "Usage: perl $basename [-h | -help] [<other flags passed to CMake>] <Project Source Directory>\n";
284
285 print "Options:\n";
286 print " -h or -help Brings up this help display.\n";
287 print "\n";
288
289 print "Required Options:\n";
290 print "<Project Source Directory> Path to the source code directory (containing the root CMakeLists.txt)\n";
291 print "\n";
292
293 print "Semi-required Options (needed if required environmental variables are not set)\n";
294 print " --androidsdkroot=<path to Android SDK> Path to the Android SDK. The environmental variable ANDROID_SDK_ROOT or ANDROID_HOME is used if not provided.\n";
295 print " --standalonetoolchainroot=<path> Path to the root of the NDK standalone tool chain you are required to generate. The environmental variable BLURRR_ANDROID_STANDALONE_ANDROID_TOOLCHAIN_ROOT is used if not provided.\n";
296 print " --blurrrsdkpath=<path> Path to the SDK to use, e.g. ~/Blurrr/Libraries/Android/SDK/Lua_f32_i32. You may define this in an environmental variable. This acts as an overrride to BLURRR_ROOT.\n";
297 print "\n";
298
299 print "Optional Options:\n";
300 print " --targetsdkversion=<version> Allows you to override the targetSdkVersion. Default detects the latest availabe in the SDK. (Best to use default.)\n";
301 print " --minsdkversion=<version> Allows you to override the minSdkVersion. Default is 14. (Going lower may cause your app to crash on older devices.)\n";
302 print " --architectures=<list;of;arches> Allows you to override which architectures to build. Default is \"armeabi;armeabi-v7a;x86\"\n";
303 print " --projectsourcedir=<path to source> Overrides the <Project Source Directory> if you need a --switch.\n";
304# print " --cmakebinarydir=<path to build dir> Path to where the CMake projects will be generated. Current directory is assumed and is generally better to use than this.\n";
305 print " --cmaketoolchain=<toolchain file> Path to and file of the CMake toolchain to use. Default finds the Android toolchain shipped in the Blurrr SDK.\n";
306# print " --libsdir=<path where libs are copied> Path where the built libs are placed. \n";
307 print " --compilerversion=<version> Allows you to specify the version number (4.6) of the compiler to disambiguate if you have multiple versions.\n";
308 print " --cmake=<CMake executable> Allows you to specify the path and file to the CMake executable. Default tries to find it in the Blurrr SDK or your environment.\n";
309 print " --buildtype=<build type> The CMake Build Type. Default is MinSizeRel. None|Debug|Release|RelWithDebInfo|MinSizeRel\n";
310 print " --[no]build Specifies whether make should be invoked. Default is nobuild.\n";
311 print "\n";
312 print "Example Usage:\n";
313 print "$basename ~/Source/Blurrr/Examples/Oblivion/OblivionC\n";
314
315 return;
316}
317
318sub home_dir()
319{
320 return File::Glob::bsd_glob("~");
321}
322
323sub expand_tilde($)
324{
325 my $path = shift;
326 my $home_dir = home_dir();
327
328 $path =~ s/^~/$home_dir/;
329 return $path;
330}
331
332sub absolute_path($)
333{
334 my $file = shift;
335 return Cwd::abs_path(expand_tilde($file));
336}
337
338sub get_path_of_main_script()
339{
340 my $dirname = dirname(__FILE__);
341 return absolute_path($dirname);
342# return $dirname;
343}
344
345sub copy_build_scripts($$)
346{
347 my $cmake_source_dir = shift;
348 my $cmake_target_dir = shift;
349
350
351 my $copy = "cp";
352# my $flags = "-f";
353# my $exclude_flags = ' --exclude ".in"';
354 my $flags = '-f';
355 my $source_param = $cmake_source_dir . "/AndroidCMake/*_ndk.sh";
356 my $target_param = $cmake_target_dir;
357 my $command = "$copy $flags $source_param $target_param";
358
359 print("Executing: $copy $flags $source_param $target_param\n");
360# my $error_status = system($rsync, $flags, $exclude_flags, $source_param, $target_param);
361 my $error_status = system($command);
362 if($error_status != 0)
363 {
364 die "Invoking copy failed: $?\n";
365 }
366}
367
368sub sort_api_levels
369{
370 # $a and $b will be automatically defined by sort().
371 # Look up the position of the day in the week
372 # using the DAYS hash.
373 my ($api_level_a) = $a =~ /android-(\d+)/;
374 my ($api_level_b) = $b =~ /android-(\d+)/;
375
376 # reverse sort
377 return $api_level_b <=> $api_level_a;
378
379 # Now we can just compare $x and $y. Note, it
380 # would be simpler in this case to use the <=>
381 # operator.
382}
383
384sub detect_highest_android_sdk_api_level($)
385{
386 my $sdk_root = shift;
387 my $sdk_platforms = $sdk_root . "/platforms";
388
389 opendir(DIR, $sdk_platforms);
390 my @files = grep(/^android-\d+$/, readdir(DIR));
391 closedir(DIR);
392
393 # Sort days in order using a sort algorithm
394 # contained in a function.
395 @files = sort sort_api_levels @files;
396
397
398# foreach $file(@files)
399# {
400# print "$file\n";
401# }
402
403 my ($api_level) = $files[0] =~ /android-(\d+)/;
404 return $api_level;
405}
406
407# Subroutine to extract and process command line parameters
408sub extract_parameters()
409{
410 # To follow the convention of the other bootstrap scripts and CMake itself,
411 # the last parameter is always the path to the source directory.
412 my $cmake_source_dir = $ARGV[$#ARGV];
413
414 # Blurrr assumption: This Perl script is located at the root of the Blurrr SDK.
415 my $blurrr_sdk_root = get_path_of_main_script();
416
417 my %params = (
418 h => \(my $hflag = 0),
419 help => \(my $helpflag = 0),
420 blurrrsdkpath => \(my $blurrr_sdk_path), # acts as an override for blurrr_sdk_root
421 projectsourcedir => \(my $projectsourcedir), # this is allowed to override $cmake_source_dir
422 cmakebinarydir => \(my $cmake_binary_dir), #
423 libsdir => \(my $libsdir),
424 androidsdkroot => \(my $android_sdk_root),
425 standalonetoolchainroot => \(my $standalone_toolchain_root),
426 targetsdkversion => \(my $targetSdkVersion),
427 minsdkversion => \(my $minSdkVersion = 14),
428 architectures => \(my $architectures),
429 compilerversion => \(my $compilerversion),
430 buildtype => \(my $buildtype = "MinSizeRel"),
431 build => \(my $should_build = 0),
432 cmaketoolchain => \(my $cmake_toolchain),
433 cmake => \(my $cmake)
434 );
435
436
437 # Call Library function which will extract and remove all switches and
438 # their corresponding values.
439 # These parameters will be removed from @ARGV
440 my $errorval = &GetOptions(\%params, "h", "help",
441 "blurrrsdkpath=s",
442 "projectsourcedir=s",
443 "cmakebinarydir=s",
444 "libsdir=s",
445 "androidsdkroot=s",
446 "standalonetoolchainroot=s",
447 "targetsdkversion=i",
448 "minsdkversion=i",
449 "architectures=s",
450 "compilerversion=s",
451 "buildtype=s",
452 "build!",
453 "cmaketoolchain=s",
454 "cmake=s"
455 );
456 # the exclaimation point allows for the negation
457 # of the switch (i.e. -nobackup/-nobody is a switch)
458
459 # Error value should have returned 1 if nothing went wrong
460 # Otherwise, an unlisted parameter was specified.
461 if($errorval !=1)
462 {
463 # Expecting GetOptions to state error.
464
465 print "Exiting Program...\n";
466 exit 0;
467 }
468
469 if( ($hflag == 1) || ($helpflag == 1) )
470 {
471 helpmenu();
472 exit 0;
473 }
474
475 if(not defined($projectsourcedir))
476 {
477 # $projectsourcedir = $cmake_source_dir;
478 }
479 else
480 {
481 $cmake_source_dir = $projectsourcedir;
482 }
483 # sanitize path
484 $cmake_source_dir = absolute_path($cmake_source_dir);
485
486
487 if(not defined($cmake_binary_dir))
488 {
489 # This is the current working directory following CMake conventions.
490 $cmake_binary_dir = absolute_path(getcwd());
491 }
492 # sanitize path
493 $cmake_binary_dir = absolute_path($cmake_binary_dir);
494
495
496
497 if(not defined($libsdir))
498 {
499 $libsdir = $cmake_binary_dir . "/dist";
500 }
501
502
503 if(not defined($android_sdk_root))
504 {
505 $android_sdk_root = $ENV{"ANDROID_SDK_ROOT"} or $android_sdk_root = $ENV{"ANDROID_HOME"};
506 if(not defined($android_sdk_root))
507 {
508 print("androidsdkroot directory not specified or environmental variable ANDROID_SDK_ROOT not defined\n");
509 helpmenu();
510 exit 1;
511 }
512 }
513 # sanitize path
514 $android_sdk_root = absolute_path($android_sdk_root);
515
516 if(not defined($blurrr_sdk_path))
517 {
518 $blurrr_sdk_path = $ENV{"BLURRR_SDK_PATH"};
519 if(not defined($blurrr_sdk_path))
520 {
521 $blurrr_sdk_path = undef;
522 }
523 }
524 else
525 {
526 $blurrr_sdk_path = absolute_path($blurrr_sdk_path);
527 }
528
529
530 if(not defined($standalone_toolchain_root))
531 {
532 $standalone_toolchain_root = $ENV{"BLURRR_ANDROID_STANDALONE_ANDROID_TOOLCHAIN_ROOT"};
533 if(not defined($standalone_toolchain_root))
534 {
535 print("standalonetoolchainroot root directory not specified or environmental variable BLURRR_ANDROID_STANDALONE_ANDROID_TOOLCHAIN_ROOT not defined\n");
536 helpmenu();
537 exit 2;
538 }
539
540 }
541 # sanitize path
542 $standalone_toolchain_root = absolute_path($standalone_toolchain_root);
543
544
545
546
547
548
549 if(not defined($targetSdkVersion))
550 {
551 $targetSdkVersion = detect_highest_android_sdk_api_level($android_sdk_root);
552 }
553
554 # test $architectures on return because it is too hard to pass multiple arrays back
555
556 if(not defined($cmake_toolchain))
557 {
558 # We keep a copy of the toolchain in the PROJECT_SOURCE_DIR/CMakeModules directory
559 #$cmake_toolchain = $cmake_source_dir . "/CMakeModules/android.toolchain.cmake";
560 $cmake_toolchain = $cmake_source_dir . "/AndroidCMake/android.toolchain.cmake";
561 }
562
563 if(not defined($cmake))
564 {
565 # Grrrr. On Mac & Windows, we ship CMake with the SDK, but on Linux we depend on package management.
566 $cmake = $blurrr_sdk_root . "/CMake/CMake.app/Contents/bin/cmake";
567 if(!(-f $cmake))
568 {
569 $cmake = $blurrr_sdk_root . "/CMake/bin/cmake.exe";
570 if(!(-f $cmake))
571 {
572 # assume it is in the path and Unix-y (no .exe)
573 $cmake = "cmake";
574 }
575 }
576 }
577 else
578 {
579 $cmake = absolute_path($cmake);
580 }
581
582
583 # Convert to absolute paths because we will be changing directories which will break relative paths.
584
585 # We need to create the directory if it doesn't exist before calling absolute_path() on it.
586 unless(-e $libsdir or make_path($libsdir))
587 {
588 die("Unable to create $libsdir: $!\n");
589 }
590
591
592 $cmake_toolchain = absolute_path($cmake_toolchain);
593 $libsdir = absolute_path($libsdir);
594
595
596 # This can be optimized out, but is left for clarity.
597 # We already assumed the last parameter is the source dir and used it, so pop it.
598# pop @ARGV;
599
600 # GetOptions has removed all found options so anything left in @ARGV is "remaining".
601 my @remaining_options = @ARGV;
602 pop @remaining_options;
603 # Remember, can't pass back 2 arrays or in the middle because it shifts everything
604
605 my @sorted_options = (
606 $blurrr_sdk_root,
607 $blurrr_sdk_path,
608 $cmake_source_dir,
609 $cmake_binary_dir,
610 $libsdir,
611 $android_sdk_root,
612 $standalone_toolchain_root,
613 $targetSdkVersion,
614 $minSdkVersion,
615 $compilerversion,
616 $buildtype,
617 $should_build,
618 $cmake_toolchain,
619 $cmake,
620 $architectures,
621 @remaining_options
622 );
623 return @sorted_options;
624}
625
626
627print("calling main\n");
628main();
629
630