Rev 7530 | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### Copyright (c) VIX TECHNOLOGY (AUST) LTD## Module name : androidBuilder.pl# Module type : Makefile system# Compiler(s) : Perl# Environment(s): jats## Description : This program is invoked by the JATS Makefile System# to 'build' an Android project from an AndroidStudio based# Android project. It does this by:# Creating a build.xml file from the Eclispe files# Injecting properties into the build# Create gradle.properties (Must not be version controlled)# Create local.properties (Must not be version controlled)# Insert external dependencies# Jar files# Aar files# JNI Libraries# Invoking 'gradle' to perform the build## This process requires external tool - delivered in packages# These are:# gradle - Provides the core of gradle# androidSdk - From package rather than installed# This provides flexability when a new Sdk# is required## Usage: The utility is invoked in a controlled manner from a Jats# makefile. The call is generated by the Android Toolset# Arguments:# -verbose - Increase debugging# -verbose=n - Increase debugging# -f=manifestFile.xml - project Manifest file# -i=path - Path to the interface directory# -t=[P|D]" - Build Type. Production or Debug# -pn=PackageName - Package Name# -pv=PackageVersion - Package Version# -clean - Will clean the build# -populate - Test Env and Populate 'libs'# -autotest - Run Unit Tests# -hasTests - Build unit tests too# Aguments that can be provided by the user# -Jar=name - Name of a Jar to include# -Aar=name - Name of an Aar to include# -lname - Name of a Jats library to include# -Lname - Name of a 3rd party library to include# -gradleProps=file - Gradle properties that will be appended to the gradle.properties# -AllPackages - Provide metadata for all dependent packages## Note: This function may be provided by several packages,# thus the interface must not change - this include the name of# this file. See the AndroidBuilder package too.###......................................................................#require 5.008_002;use strict;use warnings;use Getopt::Long qw(:config pass_through);use File::Path;use JatsError;use JatsSystem;use JatsEnv;use FileUtils;use JatsProperties;use JatsVersionUtils;use ReadBuildConfig;use JatsCopy;use ArrayHashUtils;## Globals# Command line arguments#my $opt_verbose = $ENV{GBE_VERBOSE};my $opt_buildFile;my $opt_interface;my $opt_gbetype = 'P';my @opt_gbetypes;my $opt_clean;my $opt_pkgname;my $opt_pkgversion;my $opt_platform;my $opt_populate;my $opt_populateDebug;my $opt_populateProd;my $opt_autotest;my $opt_hastests;my @opt_jlibs; # List of Jats Librariesmy @opt_elibs; # List of 3rd party librariesmy @opt_jars; # List of JARsmy @opt_aars; # List of AARsmy $opt_gprops; # Extra gradle props filesmy $opt_allPackages; # Metadata for all packages## Configuration# Map JATS platforms to Shared library targets# The key is a JATS name for the target# The value is the subdir that android will expect to find the files in#my %SharedLibMap = ('ANDROIDARM' => 'armeabi','ANDROIDARMV7' => 'armeabi-v7a','ANDROIDMIPS' => 'mips','ANDROIDX86' => 'x86','ANDROIDARM64' => 'arm64-v8a','ANDROIDMIPS64' => 'mips64','ANDROIDX86_64' => 'x86_64',);our $GBE_HOSTMACH; # Sanity Test of machine typeour $GBE_MAKE_TARGET; # Current build targetmy $androidJars; # Root of injected JARs and AARsmy $androidJniBase; # Root of injected JNI filesmy $androidJniProd; # Root of injected JNI files - Prodmy $androidJniDebug; # Root of injected JNI files - Debugmy $androidBuildSuffix = ''; # Prefix build commands#-------------------------------------------------------------------------------# Function : Main Entry Point## Description : Main entry to this program## Inputs : @ARGV - Array of command line arguments# See file header## Returns : 0 - No Error# 1 - Error encountered#InitFileUtils();ErrorConfig( 'name' => 'ANDROIDBUILDER','verbose' => $opt_verbose);$opt_verbose = $::ScmVerbose; # Get the calculated verbosity level## Install local signal handlers to process GetOptions messages#local $SIG{__WARN__} = sub { ReportError('AndroidBuilder.' . "@_"); };local $SIG{__DIE__} = sub { ReportError('AndroidBuilder.' . "@_"); };my $result = GetOptions ("verbose:+" => \$opt_verbose, # flag"f=s" => \$opt_buildFile, # string"i=s" => \$opt_interface, # Interface directory"t=s" => \@opt_gbetypes, # string"pn=s" => \$opt_pkgname, # string"pv=s" => \$opt_pkgversion, # string"pf=s" => \$opt_platform, # string"clean" => \$opt_clean, # flag"populate" => \$opt_populate, # flag"autotest" => \$opt_autotest, # flag"hastests" => \$opt_hastests, # flag"Jar=s" => \@opt_jars,"Aar=s" => \@opt_aars,"GradleProps=s" => \$opt_gprops,"allPackages" => \$opt_allPackages,);## Restore signal handlers and report parse errors#$SIG{__WARN__} = 'DEFAULT';$SIG{__DIE__} = 'DEFAULT';Error('AndroidBuilder. Invalid call options detected') if (!$result);## Process remaining arguments# Only --Lname and --lname are valid#foreach my $arg (@ARGV) {if ($arg =~ m~^[-]{1,2}l(.*)~) {push @opt_jlibs, $1;} elsif ($arg =~ m~^[-]{1,2}L(.*)~) {push @opt_elibs, $1;} else {ReportError("Invalid option: $arg");}}ErrorDoExit();## Sanity Test#ReportError ("Gradle build file not specified") unless ( defined $opt_buildFile);ReportError ("Gradle build file not found: $opt_buildFile") unless ( -f $opt_buildFile);ReportError ("Interface directory not specified") unless ( defined $opt_interface);ReportError ("Interface directory not found: $opt_interface") unless ( -d $opt_interface);ReportError ("Package Name not specified") unless ( defined $opt_pkgname);ReportError ("Package Version not specified") unless ( defined $opt_pkgversion);ReportError ("Platform not found") unless ( defined $opt_platform );ErrorDoExit();## Now support Android builder under both Linux and Windows - for development# In the build system we only support Android builder under Windows# This is done for backward compatability# Also to ensure reproducability in escrow# Jats will prevent the use of ANDROID on a non-windows build machine# Generate a reminder - only once and only during the 'build' invocation.#if ($opt_populate) {EnvImport('GBE_HOSTMACH');unless ( $::GBE_HOSTMACH eq 'win32' ) {Message ("AndroidStudioBuilder is only supported under $::GBE_HOSTMACH for development only", "The build and escrow system will use a win32 machine" );}}## Basic setup## Handle multiple opt_gbetypes for populate mode# If we are ony building for Prod, then only populate production artifacts# If we are ony building for Debug, then only populate debug artifactsforeach ( @opt_gbetypes) {$opt_gbetype = $_;$opt_populateProd = 1 if ($opt_gbetype eq 'P');$opt_populateDebug = 1 if ($opt_gbetype eq 'D');}$androidBuildSuffix = ($opt_gbetype eq 'P') ? 'Release' : 'Debug';## The user provides the root build.gradle file# There MUST be a settings.gradle in the same directory# This is a JATS assumption - subject to change# There will be some other files there too# Calculate the root of the project#$opt_buildFile = RelPath(AbsPath($opt_buildFile));my $project_root = StripFileExt($opt_buildFile);$project_root = '.' unless $project_root;my $project_settingsFile = catfile($project_root, 'settings.gradle');Message ("Project Base:" . Getcwd());Message ("Project Root:" . $project_root);Verbose ("Project Settings file:" . $project_settingsFile);## Directories to store Jar's, Aar's and JNI shared libarares# are created in the interface directory#$androidJars = catdir($opt_interface, 'jatsLibs');$androidJniBase = catdir($opt_interface, 'jatsJni');$androidJniProd = catdir($androidJniBase, 'Release');$androidJniDebug = catdir($androidJniBase, 'Debug');Verbose ("Interface:" . $opt_interface);Verbose ("Android Jars: $androidJars");Verbose ("Android JNI : $androidJniBase");Error ("Gradle settings file not found: $project_settingsFile") unless ( -f $project_settingsFile);## Essential tool# gradle - setup# GRADLE_USER_HOME# JAVA_HOME#ReadBuildConfig( $opt_interface, $opt_platform, '--NoTest' );my $gradleTool = getToolInfo('gradle', 'JAVA_VERSION', 'GRADLE_BIN');my $gradleBinDir = catdir($gradleTool->{PKGBASE}, $gradleTool->{TOOLROOT}, $gradleTool->{GRADLE_BIN});## Setup a gradle home# Its used to cache stuff - create it within the interface directory#my $gradleHomeTarget = CleanPath(FullPath(catdir($opt_interface, 'gradleUserHome')));mkpath($gradleHomeTarget, 0, 0775)unless ( -d $gradleHomeTarget);$ENV{GRADLE_USER_HOME} = $gradleHomeTarget;Verbose("GRADLE_USER_HOME:", $ENV{GRADLE_USER_HOME});## Setup the required version of Java for the tool# Force JAVA_OPTS to set Min/Max Heap# Use JAVA_OPTS because# _JAVA_OPTIONS causes system to emit a lot of warnings that _JAVA_OPTIONS is being used# Use of org.gradle.jvmargs in gradle.properties causes warnins about forking speed# Fixing the max size will provide consistent builds# Perhaps one day it will be configured#my $javaVersion = $gradleTool->{JAVA_VERSION};ReportError ("$javaVersion not defined.", "Building ANDROID requires $javaVersion be installed and correctly configured.")unless $ENV{$javaVersion};$ENV{JAVA_HOME}=$ENV{$javaVersion};$ENV{JAVA_OPTS} = '-Xms256m -Xmx1024m';## Essential tool# androidSdk - setup path to the android executable#my $androidSdkTool = getToolInfo('androidSdk');my $androidSdk = catdir($androidSdkTool->{PKGBASE}, $androidSdkTool->{TOOLROOT} );Verbose ("Android SDK : $androidSdk");ReportError("Tool Package 'androidSdk' - Invalid SDK Basedir", "Sdk Base: $androidSdk" )unless -d ($androidSdk);# Essential tool# androidGradleRepo - A repo of gradle plugings for android#my $androidGradleRepo = getToolInfo('androidGradleRepo');my $gradleMavenRepo = catdir($androidGradleRepo->{PKGBASE}, $androidGradleRepo->{TOOLROOT});Verbose ("Maven Repo. Gradle support for android : $gradleMavenRepo");ErrorDoExit();## Create a gradle file with JATS provided version information# and paths for use within the gradle build.## Always do this as the 'clean' will need them#createGradleFiles($opt_clean);## Clean out any build artifacts#if ($opt_clean){## Invoke GRADLE on the build script - if present#Message ("Clean the existing build");runGradle ('clean');deleteGeneratedFiles();exit 0;}## If we are only populating the build then we# need to inject dependencies.#if ($opt_populate){deleteInjectedFiles();injectDependencies();Verbose ("Populate complete");exit 0;}## Build the Android project through gradle#my $rv = 0;if ( ! $opt_autotest ){## Build the project - does not run unit tests# assemble all the code# assemble code for unit tests - does not run unit tests#Message ("Build the android project: $androidBuildSuffix");my @tasks;push (@tasks, 'assemble'. $androidBuildSuffix);push (@tasks, 'assemble' . $androidBuildSuffix . 'UnitTest') if $opt_hastests;$rv = runGradle('assemble'. $androidBuildSuffix , 'assemble' . $androidBuildSuffix . 'UnitTest');Error("Cannot build AndroidStudio project") if $rv;}else{## Run unit tests - does not build the project, although it# will build the unit tests, but these have been buitl before## If the gradle run fails, then its because one or more of the unit tests failed# This is not a build failure as we want to process the test results and feed# them up the chain## Post processing MUST detect and report errors#Message ("Run Unit Tests within the android project: $androidBuildSuffix");$rv = runGradle('test'. $androidBuildSuffix);Message ("Unit Test reports: $rv");}exit(0);#-------------------------------------------------------------------------------# Function : runGradle## Description : Run gradle to build the project# Generate a command like:# PathToGradle/gradle --offline -I SomePath/init.gradle <task>## Use an init-script to inject a sanity test into the build# Ensure that the user is using our version numbers.## Inputs : task - Task to run## Returns : Returns the error code of the build#sub runGradle{my (@tasks) = @_;Verbose ("runGradle: @tasks");# The Windows batch file can run in debug mode# Make sure that it doesn't by default$ENV{DEBUG} = "" unless $opt_verbose;my $gradleProg = catdir($gradleBinDir, 'gradle');Verbose ("GradleProg: $gradleProg");## Locate the 'init.gradle' script# Its co-located with this script#my $initScript = catdir(StripFileExt(__FILE__), 'init.gradle');Verbose ("Gradle Init Script: $initScript");## Build up the arg list#my @gradleArgs;push (@gradleArgs, '--offline');push (@gradleArgs, '--no-daemon');# push (@gradleArgs, '--info');# push (@gradleArgs, '--debug');# push (@gradleArgs, '--stacktrace');push (@gradleArgs, '--warning-mode=none') unless ($opt_verbose);push (@gradleArgs, '--info') if $opt_verbose;push (@gradleArgs, '--debug') if ($opt_verbose > 2);push (@gradleArgs, '--stacktrace') if ($opt_verbose > 3);push (@gradleArgs, '-I', $initScript) unless ($tasks[0] =~ m/clean/);push (@gradleArgs, '-p', $project_root);## Address a gradle issue, under LINUX, that appears to be solved by# having STDIN redirected.## Downside is that Control-C can't be used to terminate the compile#my @gradlePrefix = qw( --NoExit );push (@gradlePrefix, '--Show') if $opt_verbose;if ($ENV{'GBE_UNIX'} ) {push (@gradlePrefix, '--Shell', '</dev/null');} else {push (@gradlePrefix, '--NoShell');}my $rv = System(@gradlePrefix, $gradleProg, @gradleArgs, @tasks);return $rv;}#-------------------------------------------------------------------------------# Function : createGradleFiles## Description : Calculate Version information# gradle.properies# local.properties## Inputs : quiet - No output## Returns : Nothing#sub createGradleFiles{my ($quiet) = @_;## Generate Package Versioning information# Need a text string and a number# Generate the 'number' from the version number#my $version_text;my $version_num;$version_text = $opt_pkgversion;my ($major, $minor, $patch, $build )= SplitVersion($opt_pkgversion);foreach my $item ($major, $minor, $patch, $build){Error("Package version has invalid form. It contains non-numeric parts", $item)unless ( $item =~ m~^\d+$~);}$version_num = ($major << 24) + ($minor << 16) + ($patch << 8) + $build;Message ("Project Version Txt:" . $version_text) unless $quiet;Message ("Project Version Num:" . $version_num) unless $quiet;## Create the gradle.properties file# It needs to be in the projects root directory#my $gradleProperies = catfile($project_root,'gradle.properties');Message ("Create gradle.properties file: " . $gradleProperies) unless $quiet;my $data = JatsProperties::New();$data->setProperty('GBE_VERSION_NAME' , $version_text);$data->setProperty('GBE_VERSION_CODE' , $version_num);$data->setProperty('GBE_JARLIBS' , NicePath($androidJars));$data->setProperty('GBE_JNI_RELEASE' , NicePath($androidJniProd));$data->setProperty('GBE_JNI_DEBUG' , NicePath($androidJniDebug));$data->setProperty('GBE_GRADLE_REPO' , NicePath($gradleMavenRepo));## Create properties for JAVA Stores# Name of variable is based on the package name and prject suffix# Forced to uppercase# '-' replaced with '_'# Locate 'jar' dir and save path as GBE_REPO_<pkgName># Locate 'mavenRepository' and save path as GBE_MVN_<pkgName>#foreach my $pkg (getPackageList()){my $base = $pkg->getBase(3);if ($base){if ($opt_allPackages) {$data->setProperty( $pkg->getUnifiedName('GBE_PKG_') , NicePath($base));}my $jarDir = catdir($base, 'jar');if (-d $jarDir ){$data->setProperty( $pkg->getUnifiedName('GBE_REPO_') , NicePath($jarDir));}my $mvnDir = catdir($base, 'mavenRepository');if (-d $mvnDir ) {$data->setProperty( $pkg->getUnifiedName('GBE_MVN_') , NicePath($mvnDir));}}}## Append user specified graadle properties#if ($opt_gprops) {Error("Gradle properties not found: $opt_gprops") unless -f $opt_gprops;$data->load($opt_gprops);}$data->store( $gradleProperies );## Create the local.properties file# It needs to be in the projects root directory## May be able to do without this file - iff we set ANDROID_HOME#my $localProperies = catfile($project_root,'local.properties');Message ("Create local.properties file: " . $localProperies) unless $quiet;$data = JatsProperties::New();$data->setProperty('sdk.dir' , NicePath($androidSdk));$data->store( $localProperies );}#-------------------------------------------------------------------------------# Function : injectDependencies## Description : Inject dependencies## The android build can make use of files in a specific directory# Place Jar and Aar files in a specific directory under the root of the project# Use a directory called jatsLibs# There are two types of files that can be placed in that directory# These appear to be:# 1) .jar files# 2) .aar files## NDK files will be process automatically by the builder, once the build is made# aware of the location. We are not using the AndroidStudio default location# Place them into jatsJni within the project root# 1) Shared libraries provided by NDK components## Need to keep the production and debug JNI files seperate## The gradle dependency processing needs both production and# debug dependencies to be present at all times## Create three areas:# jatsLibs - Prod and Debug Jars and Ars# jatsJniDebug - Debug JNI files# jatsJniProd - Production JNI files## Inputs :## Returns :#sub injectDependencies{my @jlist; # List of JARs from default directoriesmy @jpathlist; # List of JARs from named directoriesmy @alist; # List of AARs from default directoriesmy @apathlist; # List of AARs from named directoriesmy @libListProd; # List of production librariesmy @libListDebug; # List of debug librariesmy @platformParts; # Platforms Partsmy @jarSearch; # Search paths - diagnostic displaymy @aarSearch;my @libSearch;## Only if we need to do something#return unless (@opt_jars || @opt_aars || @opt_elibs || @opt_jlibs);## Determine the list of platformm parts# This is where 'lib' files will be found#@platformParts = getPlatformParts();Verbose("Platform Parts", @platformParts);## Create search entries suitable for the CopyDir# We will delete entries as the files are copied# Allow for:# jar/aar files to have a .jar /.aar suffix (optional)# jar/aar files to have path specified with a package## Split into two lists ( per type ):# Those with a path and those without#foreach my $item ( @opt_jars) {$item =~ s~\.jar~~i;if ($item =~ m~/~) {UniquePush \@jpathlist, $item;} else {UniquePush \@jlist, $item;}}foreach my $item ( @opt_aars) {$item =~ s~\.aar~~i;if ($item =~ m~/~) {UniquePush \@apathlist, $item;} else {UniquePush \@alist, $item;}}# Shared libraries# Create full namesforeach my $item ( @opt_elibs) {UniquePush (\@libListDebug, 'lib' . $item . '.so');UniquePush (\@libListProd, 'lib' . $item . '.so');}foreach my $item ( @opt_jlibs) {UniquePush (\@libListDebug, 'lib' . $item . 'D.so') if $opt_populateDebug;UniquePush (\@libListProd , 'lib' . $item . 'P.so') if $opt_populateProd;}## Where does it go# JARs/AARs - ROOT/jatsLibs# LIBS - ROOT/jatsJni## Scan all external packages, and the interface directory# Transfer in the required file types#my @pkg_paths = getPackagePaths("--Interface=$opt_interface");foreach my $pkg ( @pkg_paths){## Copy in all JAR files found in dependent packages# Need to allow for Jars that have a P/D suffix as well as those that don't#my $jarDir = catdir($pkg,'jar');push @jarSearch, $jarDir;if (-d $jarDir && @jlist){Verbose("Jar Dir Found found", $jarDir);Message ("Copy in: $jarDir");## Create a matchlist from the JAR list# Create a regular expresssion to find a suitable file#my @mlist;foreach ( @jlist) {push @mlist, $_ . '.jar|' . $_ . 'P.jar|'. $_ . 'D.jar';}CopyDir ( $jarDir, $androidJars,'MatchRE' => \@mlist,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,'Examine' => sub{my ($opt) = @_;my $baseName = $opt->{file};$baseName =~ s~\.jar~~;$baseName =~ s~[PD]$~~;ArrayDelete \@jlist, $baseName;return 1;},);}## Copy in JARs specified by a full pathname# Need to allow for Jars that have a P/D suffix as well as those that don't#my @jpathlistBase = @jpathlist;foreach my $file (@jpathlistBase){foreach my $suffix ( '', 'P' ,'D'){my $jarFile = catdir($pkg, $file . $suffix . '.jar');push @jarSearch, $jarFile;if (-f $jarFile){Verbose("Jar File Found found", $jarDir);Message ("Copy in: $jarFile");CopyFile ( $jarFile, $androidJars,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,);ArrayDelete \@jpathlist, $file;}}}## Copy in AAR files found in dependent packages# Need to allow for both AAR files with a -debug/-release suffix# as well as those without#foreach my $part (@platformParts){my $aarDir = catdir($pkg,'lib/' . $part);push @aarSearch, $aarDir;if (-d $aarDir && @alist){Verbose("Library Dir Found found", $aarDir);Message ("Copy in: $aarDir");## Create a matchlist from the AAR list# Create a regular expresssion to find a suitable file#my @mlist;foreach ( @alist) {push @mlist, $_ . '.aar|' . $_ . '-debug.aar|' . $_ . '-release.aar';}CopyDir ( $aarDir, $androidJars,'MatchRE' => \@mlist,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,'Examine' => sub{my ($opt) = @_;my $baseName = $opt->{file};$baseName =~ s~\.aar$~~;$baseName =~ s~-release$~~;$baseName =~ s~-debug$~~;ArrayDelete \@alist, $baseName;return 1;},);}}## Copy in AAR files specified by a full pathname# Need to allow for both AAR files with a -debug/-release suffix# as well as those without#my @apathlistBase = @apathlist;foreach my $file (@apathlistBase){foreach my $suffix ( '', '-release', '-debug'){my $aarFile = catdir($pkg, $file . $suffix . '.aar');push @aarSearch, $aarFile;if (-f $aarFile){Verbose("Aar File Found found", $aarFile);Message ("Copy in: $aarFile");CopyFile ( $aarFile, $androidJars,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,);ArrayDelete \@apathlist, $file;}}}## Build up the Shared Library structure as used by JNI# Note: Only support current JATS format# Copy in .so files and in to process massage the pathname so that# it confirms to that expected by the Android Project#my $libDir = catdir($pkg, 'lib');push @libSearch, $libDir;if (-d $libDir && @libListProd){Verbose("Lib Dir Found found", $libDir);Message ("Copy in: $libDir");CopyDir ( $libDir, $androidJniProd,'Match' => \@libListProd,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,'Examine' => sub{my ($opt) = @_;foreach my $platform ( keys %SharedLibMap ) {my $replace = $SharedLibMap{$platform};if ($opt->{'target'} =~ s~/$platform/~/$replace/~){ArrayDelete \@libListProd, $opt->{file};return 1;}}return 0;},);}if (-d $libDir && @libListDebug){Verbose("Lib Dir Found found", $libDir);Message ("Copy in: $libDir");CopyDir ( $libDir, $androidJniDebug,'Match' => \@libListDebug,'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,'Examine' => sub{my ($opt) = @_;foreach my $platform ( keys %SharedLibMap ) {my $replace = $SharedLibMap{$platform};if ($opt->{'target'} =~ s~/$platform/~/$replace/~){ArrayDelete \@libListDebug, $opt->{file};return 1;}}return 0;},);}}## Report files that could not be located. They were deleted from the lists# as they were processed#if (@jlist || @jpathlist || @alist || @apathlist || @libListProd || @libListDebug ){ReportError("External dependencies not found:", @jlist , @jpathlist , @alist , @apathlist , @libListProd , @libListDebug);if (@jlist || @jpathlist){ReportError("Jar Search Path", @jarSearch);}if (@alist || @apathlist){ReportError("Aar Search Path", @aarSearch);}if ( @libListProd || @libListDebug){ReportError("Lib Search Path", @libSearch);}ErrorDoExit();}}#-------------------------------------------------------------------------------# Function : deleteGeneratedFiles## Description : Delete files that we generate## Inputs :## Returns :#sub deleteGeneratedFiles{## Delete files that we will create#my @deleteList = qw(local.properties gradle.properties);foreach my $file (@deleteList){Verbose ("Deleting $project_root/$file");unlink catfile($project_root, $file);}}#-------------------------------------------------------------------------------# Function : deleteInjectedFiles## Description : Delete files that we inject## Inputs :## Returns :#sub deleteInjectedFiles{## Remove the jatsJars and JatsJni directories# These are created by this tool#Verbose("RmDirTree($androidJars)");RmDirTree($androidJars);Verbose("RmDirTree($androidJniBase)");RmDirTree($androidJniBase);}#-------------------------------------------------------------------------------# Function : NicePath## Description : Process a path and return one that is# An absolute Path# Uses '/'## Inputs : path - Path to process## Returns : A Nice version of path#sub NicePath{my ($path) = @_;$path = FullPath($path);$path =~ s~\\~/~g;$path = CleanPath($path);return $path;}