# Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # A collection of shell function definitions used by various build scripts # in the Android NDK (Native Development Kit) # # Get current script name into PROGNAME PROGNAME=`basename $0` # Put location of Android NDK into ANDROID_NDK_ROOT and # perform a tiny amount of sanity check # if [ -z "$ANDROID_NDK_ROOT" ] ; then # Try to auto-detect the NDK root by walking up the directory # path to the current script. PROGDIR=`dirname $0` while [ -n "1" ] ; do if [ -d $PROGDIR/build/core ] ; then break fi if [ -z $PROGDIR -o $PROGDIR = '.' ] ; then echo "Please define ANDROID_NDK_ROOT to point to the root of your" echo "Android NDK installation." exit 1 fi PROGDIR=`dirname $PROGDIR` done ANDROID_NDK_ROOT=`cd $PROGDIR && pwd` fi if [ ! -d $ANDROID_NDK_ROOT ] ; then echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory." exit 1 fi if [ ! -f $ANDROID_NDK_ROOT/build/core/ndk-common.sh ] ; then echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory." exit 1 fi ## Logging support ## VERBOSE=${VERBOSE-yes} VERBOSE2=${VERBOSE2-no} log () { if [ "$VERBOSE" = "yes" ] ; then echo "$1" fi } log2 () { if [ "$VERBOSE2" = "yes" ] ; then echo "$1" fi } ## Utilities ## # return the value of a given named variable # $1: variable name # # example: # FOO=BAR # BAR=ZOO # echo `var_value $FOO` # will print 'ZOO' # var_value () { # find a better way to do that ? eval echo "$`echo $1`" } # convert to uppercase # assumes tr is installed on the platform ? # to_uppercase () { echo $1 | tr "[:lower:]" "[:upper:]" } ## Normalize OS and CPU ## HOST_ARCH=`uname -m` case "$HOST_ARCH" in i?86) HOST_ARCH=x86 ;; amd64) HOST_ARCH=x86_64 ;; powerpc) HOST_ARCH=ppc ;; esac log2 "HOST_ARCH=$HOST_ARCH" # at this point, the supported values for CPU are: # x86 # x86_64 # ppc # # other values may be possible but haven't been tested # HOST_EXE="" HOST_OS=`uname -s` case "$HOST_OS" in Darwin) HOST_OS=darwin ;; Linux) # note that building 32-bit binaries on x86_64 is handled later HOST_OS=linux ;; FreeBsd) # note: this is not tested HOST_OS=freebsd ;; CYGWIN*|*_NT-*) HOST_OS=windows HOST_EXE=.exe if [ "x$OSTYPE" = xcygwin ] ; then HOST_OS=cygwin HOST_CFLAGS="$CFLAGS -mno-cygwin" HOST_LDFLAGS="$LDFLAGS -mno-cygwin" fi ;; esac log2 "HOST_OS=$HOST_OS" log2 "HOST_EXE=$HOST_EXE" # at this point, the value of HOST_OS should be one of the following: # linux # darwin # windows (MSys) # cygwin # # Note that cygwin is treated as a special case because it behaves very differently # for a few things. Other values may be possible but have not been tested # # define HOST_TAG as a unique tag used to identify both the host OS and CPU # supported values are: # # linux-x86 # linux-x86_64 # darwin-x86 # darwin-ppc # windows # # other values are possible but were not tested. # compute_host_tag () { case "$HOST_OS" in windows|cygwin) HOST_TAG="windows" ;; *) HOST_TAG="${HOST_OS}-${HOST_ARCH}" esac log2 "HOST_TAG=$HOST_TAG" } compute_host_tag # Compute the number of host CPU cores an HOST_NUM_CPUS # case "$HOST_OS" in linux) HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l` ;; darwin|freebsd) HOST_NUM_CPUS=`sysctl -n hw.ncpu` ;; windows|cygwin) HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS ;; *) # let's play safe here HOST_NUM_CPUS=1 esac log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS" # If BUILD_NUM_CPUS is not already defined in your environment, # define it as the double of HOST_NUM_CPUS. This is used to # run Make commends in parralles, as in 'make -j$BUILD_NUM_CPUS' # if [ -z "$BUILD_NUM_CPUS" ] ; then BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2` fi log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS" ## HOST TOOLCHAIN SUPPORT ## # force the generation of 32-bit binaries on 64-bit systems # FORCE_32BIT=no force_32bit_binaries () { if [ "$HOST_ARCH" = x86_64 ] ; then log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH" FORCE_32BIT=yes HOST_ARCH=x86 log2 "HOST_ARCH=$HOST_ARCH" compute_host_tag fi } # On Windows, cygwin binaries will be generated by default, but # you can force mingw ones that do not link to cygwin.dll if you # call this function. # disable_cygwin () { if [ $OS = cygwin ] ; then log2 "Disabling cygwin binaries generation" CFLAGS="$CFLAGS -mno-cygwin" LDFLAGS="$LDFLAGS -mno-cygwin" OS=windows HOST_OS=windows compute_host_tag fi } # Various probes are going to need to run a small C program TMPC=/tmp/android-$$-test.c TMPO=/tmp/android-$$-test.o TMPE=/tmp/android-$$-test$EXE TMPL=/tmp/android-$$-test.log # cleanup temporary files clean_temp () { rm -f $TMPC $TMPO $TMPL $TMPE } # cleanup temp files then exit with an error clean_exit () { clean_temp exit 1 } # this function will setup the compiler and linker and check that they work as advertised # note that you should call 'force_32bit_binaries' before this one if you want it to # generate 32-bit binaries on 64-bit systems (that support it). # setup_toolchain () { if [ -z "$CC" ] ; then CC=gcc fi log2 "Using '$CC' as the C compiler" # check that we can compile a trivial C program with this compiler cat > $TMPC <<EOF int main(void) {} EOF if [ "$FORCE_32BIT" = yes ] ; then CFLAGS="$CFLAGS -m32" LDFLAGS="$LDFLAGS -m32" compile if [ $? != 0 ] ; then # sometimes, we need to also tell the assembler to generate 32-bit binaries # this is highly dependent on your GCC installation (and no, we can't set # this flag all the time) CFLAGS="$CFLAGS -Wa,--32" compile fi fi compile if [ $? != 0 ] ; then echo "your C compiler doesn't seem to work:" cat $TMPL clean_exit fi log "CC : compiler check ok ($CC)" # check that we can link the trivial program into an executable if [ -z "$LD" ] ; then LD=$CC fi link if [ $? != 0 ] ; then OLD_LD=$LD LD=gcc compile link if [ $? != 0 ] ; then LD=$OLD_LD echo "your linker doesn't seem to work:" cat $TMPL clean_exit fi fi log2 "Using '$LD' as the linker" log "LD : linker check ok ($LD)" # check the C++ compiler if [ -z "$CXX" ] ; then CXX=g++ fi if [ -z "$CXXFLAGS" ] ; then CXXFLAGS=$CFLAGS fi log2 "Using '$CXX' as the C++ compiler" cat > $TMPC <<EOF #include <iostream> using namespace std; int main() { cout << "Hello World!" << endl; return 0; } EOF compile_cpp if [ $? != 0 ] ; then echo "your C++ compiler doesn't seem to work" cat $TMPL clean_exit fi log "CXX : C++ compiler check ok ($CXX)" # XXX: TODO perform AR checks AR=ar ARFLAGS= } # try to compile the current source file in $TMPC into an object # stores the error log into $TMPL # compile () { log2 "Object : $CC -o $TMPO -c $CFLAGS $TMPC" $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL } compile_cpp () { log2 "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC" $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL } # try to link the recently built file into an executable. error log in $TMPL # link() { log2 "Link : $LD -o $TMPE $TMPO $LDFLAGS" $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL } # run a command # execute() { log2 "Running: $*" $* } # perform a simple compile / link / run of the source file in $TMPC compile_exec_run() { log2 "RunExec : $CC -o $TMPE $CFLAGS $TMPC" compile if [ $? != 0 ] ; then echo "Failure to compile test program" cat $TMPC cat $TMPL clean_exit fi link if [ $? != 0 ] ; then echo "Failure to link test program" cat $TMPC echo "------" cat $TMPL clean_exit fi $TMPE }