Rev 4354 | Go to most recent revision | 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 Eclipse based# Android project. It does this by:# Creating a build.xml file from the Eclispe files# Injecting properties into the build# Invoking ANT to perform the build## This process requires external tool - delivered in packages# These are:# ant - Normally more recent than that installed# on the build machines# 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'# Aguments that can be provided by the user# -projectname=ProjectName - Project Name [optional]# -target=number - Project Target##......................................................................#require 5.008_002;use strict;use warnings;use Getopt::Long;use JatsError;use JatsSystem;use FileUtils;use JatsProperties;use JatsVersionUtils;use ReadBuildConfig;use JatsCopy;## Globals# Command line arguments#my $opt_verbose = $ENV{GBE_VERBOSE};my $opt_manifestFile;my $opt_interface;my $opt_gbetype = 'P';my $opt_clean;my $opt_pkgname;my $opt_pkgversion;my $opt_projectname;my $opt_populate;my $opt_target = 1;## Configuration# Map JATS platforms to Shared library targets#my %SharedLibMap = ('ANDROIDARM' => 'armeabi','ANDROIDMIPS' => 'mips','ANDROIDX86' => 'x86',);# Build type in ant format: release or debugmy $ant_target;#-------------------------------------------------------------------------------# 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#ErrorConfig( 'name' => 'ANDROIDBUILDER','verbose' => $opt_verbose);## 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_manifestFile, # string"i=s" => \$opt_interface, # Interface directory"t=s" => \$opt_gbetype, # string"pn=s" => \$opt_pkgname, # string"pv=s" => \$opt_pkgversion, # string"projectname=s" => \$opt_projectname, # string"clean" => \$opt_clean, # flag"populate" => \$opt_populate, # flag"target:i" => \$opt_target, # Number);## Restore signal handlers and report parse errors#$SIG{__WARN__} = undef;$SIG{__DIE__} = undef;Error('AndroidBuilder. Invalid call options detected') if (!$result);ErrorDoExit();## Sanity Test#ReportError ("Manifest file not specified") unless ( defined $opt_manifestFile);ReportError ("Manifest file not found: $opt_manifestFile") unless ( -f $opt_manifestFile);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);ErrorDoExit();## Basic setup#$ant_target = $opt_gbetype eq 'P' ? 'release' : 'debug';## If multiple project are built in the same package it may be best to provide# a project name#$opt_projectname = $opt_pkgnameunless (defined $opt_projectname);## The AndroidManifest.xml file MUST be in the root of the project# There will be some other files there too# Calculate the root of the project#my $project_root = StripFileExt($opt_manifestFile);my $project_buildfile = catfile($project_root, 'build.xml');Message ("Project Root:" . $project_root);Message ("Project Name:" . $opt_projectname);Message ("Project build file:" . $project_buildfile);## Essential tool# ant - setup ANT_HOME for other tools##ReadBuildConfig( $opt_interface, 'ANDROID', '--NoTest' );my $antTool = getToolInfo('ant', 'JAVA_VERSION');$ENV{ANT_HOME} = catdir($antTool->{PKGBASE}, $antTool->{TOOLROOT});## Setup the required version of Java for the tool#my $javaVersion = $antTool->{JAVA_VERSION};ReportError ("$javaVersion not defined.", "Building ANDROID requires $javaVersion be installed and correctly configured.")unless $ENV{$javaVersion};$ENV{JAVA_HOME}=$ENV{$javaVersion};## Essential tool# androidSdk - setup path to the android executable#my $androidSdk = getToolInfo('androidSdk');my $androidPkg = catdir($androidSdk->{PKGBASE}, $androidSdk->{TOOLROOT} );my $ANDROID = catdir($androidPkg,'sdk', 'tools', 'android' );ReportError("Tool Package 'androidSdk' does not provide program 'android'")unless -f ($ANDROID);ErrorDoExit();## Clean out any build artifacts#if ($opt_clean){## Invoke ANT on the build script - if present#Message ("Clean the existing build");JatsCmd('ant', '-buildfile', $project_buildfile, 'clean')if (-f $project_buildfile);deleteGeneratedFiles();exit 0;}## Delete files that we will create and inject# Not sure about project.properties# It appears that it can be written - and info will be lost#deleteGeneratedFiles();## Populate the Android Project 'libs' directory#injectDependencies();## Create the project files# The android tool does not appear to provide an non-zero exit code on error# Detect error via the non-creation of the expected output file#System($ANDROID, $opt_verbose ? '--verbose' : '--silent','update', 'project','--path', $project_root,'--subprojects','--target', $opt_target,'--name', $opt_projectname );unless ( -f catfile($project_root, 'build.xml')){Error("Cannot update android project: $opt_projectname");}## The provided AndroidManifest.xml file contains# android:versionCode and android:versionName# These prevent the ones in ant.properties from being reflected in the output# Rewrite the AndroidManifest.xml file with corrected versions#updateManifest();## If we are only populating the build then we have done all we need to do#if ($opt_populate){Verbose ("Populate complete");exit 0;}## Build the Android project through the ANT package# ANT_HOME - has been set up# JAVA_HOME - has been set up#Message ("Build the android project: $opt_projectname");my $rv = JatsCmd('ant', '-buildfile', $project_buildfile, $ant_target);Error("Cannot build android project: $opt_projectname") if $rv;exit(0);#-------------------------------------------------------------------------------# Function : updateManifest## Description : Calculate Version information# Rewrite the Projects Manifest file and local properties files## Inputs : None## Returns : Nothing#sub updateManifest{## 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);Message ("Project Version Num:" . $version_num);## Rewrite the Manifest File# Delete the Versioning information# It will be picked up from the ant.properties file# Store it in the interface directory#my $jats_androidManifestFile = catfile($opt_interface, $opt_projectname . '_'.'AndroidManifest.xml');Message ("Rewrite Manifest: " . $jats_androidManifestFile);open (AM, '<', $opt_manifestFile) or Error("Cannot open $opt_manifestFile: $!");open (JAM, '>', $jats_androidManifestFile) or Error ("Cannot create $jats_androidManifestFile: $!");while (<AM>){s~(android:versionCode=").*(")~$1$version_num$2~;s~(android:versionName=").*(")~$1$version_text$2~;print JAM $_}close AM;close JAM;## Create the ant.properties file# It needs to be in the same directory as the build.xml#my $antProperies = catfile($project_root,'ant.properties');Message ("Create Properties file: " . $antProperies);my $data = JatsProperties::New();#$data->setProperty('source.dir' , 'src');# Appears to work best when left as default#$data->setProperty('out.dir' , 'bin');# Don't write these to the properties file as it will# create warning messages. The data is in the Manifest File##$data->setProperty('version.code' , $version_num);#$data->setProperty('version.name' , $version_text);$data->setProperty('manifest.file' , $jats_androidManifestFile);$data->setProperty('verbose' , $opt_verbose ? 'true' : 'false');# May be of interest#<property name="jar.libs.dir" value="libs" />#<property name="jar.libs.absolute.dir" location="${jar.libs.dir}" />#<property name="native.libs.absolute.dir" location="libs" />##<property name="out.dir" value="bin" />#<property name="out.absolute.dir" location="${out.dir}" />#<property name="out.classes.absolute.dir" location="${out.dir}/classes" />#<property name="out.res.absolute.dir" location="${out.dir}/res" />#<property name="out.rs.obj.absolute.dir" location="${out.dir}/rsObj" />#<property name="out.rs.libs.absolute.dir" location="${out.dir}/rsLibs" />#<property name="out.aidl.absolute.dir" location="${out.dir}/aidl" />#<property name="out.dexed.absolute.dir" location="${out.dir}/dexedLibs" />#<property name="out.manifest.abs.file" location="${out.dir}/AndroidManifest.xml" />## Insert key information# Only used in the 'release' build# At the moment the signing step MUST be done outside of the build system##$data->setProperty('key.store' , 'vix-pcc.keystore');#$data->setProperty('key.alias' , 'pcc');#$data->setProperty('key.store.password' , 'VixPassword');#$data->setProperty('key.alias.password' , 'VixPassword');$data->store( $antProperies );}#-------------------------------------------------------------------------------# Function : injectDependencies## Description : Populate the 'libs' directory## Inject dependencies# The android build will make use of files in the 'libs' directory# There are two types of files that can be placed in that directory# These appear to be:# 1) .jar files# 2) Shared libraries provided by NDK components## Assume that the user is doing the right thing and not manually placing# external dependencies in the 'libs' directory## Clean out all files and repopulate - depending on the build type# It may be different for debug and production builds## Inputs :## Returns :#sub injectDependencies{my $androidLibs = catdir($project_root, 'libs');Verbose ("Android libs: $androidLibs");my @pkg_paths = getPackagePaths("--Interface=$opt_interface");foreach my $pkg ( @pkg_paths){## Copy in all JAR files found in dependent packages#my $jarDir = catdir($pkg,'jar');if (-d $jarDir){Verbose("Jar Dir Found found", $jarDir);Message ("Copy in: $jarDir");CopyDir ( $jarDir, $androidLibs,'Match' => ['*.jar'],'Log' => $opt_verbose + 1,'SymlinkFiles' => 1,);}## 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');if (-d $libDir){Verbose("Lib Dir Found found", $libDir);Message ("Copy in: $libDir");CopyDir ( $libDir, $androidLibs,'Match' => ['*.so'],'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/~){return 1;}}return 0;},);}}}#-------------------------------------------------------------------------------# Function : deleteGeneratedFiles## Description : Delete files that we generate## Inputs :## Returns :#sub deleteGeneratedFiles{## Delete files that we will create# Not sure about project.properties# It appears that it can be written - and info will be lost#my @deleteList = qw(local.properties build.xml proguard-project.txt);foreach my $file (@deleteList){Verbose ("Deleting $project_root/$file");unlink catfile($project_root, $file);}## Clean out the 'libs' directory# Assume that its populated with 'external' dependencies# Leave the directory - it may have been checked into version control#my $androidLibs = catdir($project_root, 'libs');RmDirTree(glob(catdir($androidLibs, '*')));}