Home | History | Annotate | Download | only in core
      1 # Copyright (C) 2009 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 #
     15 
     16 # A collection of shell function definitions used by various build scripts
     17 # in the Android NDK (Native Development Kit)
     18 #
     19 
     20 # Get current script name into PROGNAME
     21 PROGNAME=`basename $0`
     22 
     23 # Put location of Android NDK into ANDROID_NDK_ROOT and
     24 # perform a tiny amount of sanity check
     25 #
     26 if [ -z "$ANDROID_NDK_ROOT" ] ; then
     27     # Try to auto-detect the NDK root by walking up the directory
     28     # path to the current script.
     29     PROGDIR=`dirname $0`
     30     while [ -n "1" ] ; do
     31         if [ -d $PROGDIR/build/core ] ; then
     32             break
     33         fi
     34         if [ -z $PROGDIR -o $PROGDIR = '.' ] ; then
     35             echo "Please define ANDROID_NDK_ROOT to point to the root of your"
     36             echo "Android NDK installation."
     37             exit 1
     38         fi
     39         PROGDIR=`dirname $PROGDIR`
     40     done
     41     ANDROID_NDK_ROOT=`cd $PROGDIR && pwd`
     42 fi
     43 
     44 echo "$ANDROID_NDK_ROOT" | grep -q -e " "
     45 if [ $? = 0 ] ; then
     46     echo "ERROR: The Android NDK installation path contains a space !"
     47     echo "Please install to a different location."
     48     exit 1
     49 fi
     50 
     51 if [ ! -d $ANDROID_NDK_ROOT ] ; then
     52     echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory."
     53     exit 1
     54 fi
     55 
     56 if [ ! -f $ANDROID_NDK_ROOT/build/core/ndk-common.sh ] ; then
     57     echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory."
     58     exit 1
     59 fi
     60 
     61 ## Logging support
     62 ##
     63 VERBOSE=${VERBOSE-yes}
     64 VERBOSE2=${VERBOSE2-no}
     65 
     66 TMPLOG=
     67 
     68 # Setup a log file where all log() and log2() output will be sent
     69 #
     70 # $1: log file path  (optional)
     71 #
     72 setup_log_file ()
     73 {
     74     if [ -n "$1" ] ; then
     75         TMPLOG="$1"
     76     else
     77         TMPLOG=/tmp/ndk-log-$$.log
     78     fi
     79     rm -f $TMPLOG && touch $TMPLOG
     80     echo "To follow build in another terminal, please use: tail -F $TMPLOG"
     81 }
     82 
     83 dump ()
     84 {
     85     if [ -n "$TMPLOG" ] ; then
     86         echo "$@" >> $TMPLOG
     87     fi
     88     echo "$@"
     89 }
     90 
     91 log ()
     92 {
     93     if [ "$VERBOSE" = "yes" ] ; then
     94         echo "$@"
     95     else
     96         if [ "$TMPLOG" ] ; then
     97             echo "$@" >> $TMPLOG
     98         fi
     99     fi
    100 }
    101 
    102 log2 ()
    103 {
    104     if [ "$VERBOSE2" = "yes" ] ; then
    105         echo "$@"
    106     else
    107         if [ -n "$TMPLOG" ] ; then
    108             echo "$@" >> $TMPLOG
    109         fi
    110     fi
    111 }
    112 
    113 run ()
    114 {
    115     if [ "$VERBOSE" = "yes" ] ; then
    116         echo "##### NEW COMMAND"
    117         echo "$@"
    118         $@ 2>&1
    119     else
    120         if [ -n "$TMPLOG" ] ; then
    121             echo "##### NEW COMMAND" >> $TMPLOG
    122             echo "$@" >> $TMPLOG
    123             $@ >>$TMPLOG 2>&1
    124         else
    125             $@ > /dev/null 2>&1
    126         fi
    127     fi
    128 }
    129 
    130 ## Utilities
    131 ##
    132 
    133 # return the value of a given named variable
    134 # $1: variable name
    135 #
    136 # example:
    137 #    FOO=BAR
    138 #    BAR=ZOO
    139 #    echo `var_value $FOO`
    140 #    will print 'ZOO'
    141 #
    142 var_value ()
    143 {
    144     # find a better way to do that ?
    145     eval echo "$`echo $1`"
    146 }
    147 
    148 # convert to uppercase
    149 # assumes tr is installed on the platform ?
    150 #
    151 to_uppercase ()
    152 {
    153     echo $1 | tr "[:lower:]" "[:upper:]"
    154 }
    155 
    156 ## Normalize OS and CPU
    157 ##
    158 HOST_ARCH=`uname -m`
    159 case "$HOST_ARCH" in
    160     i?86) HOST_ARCH=x86
    161     ;;
    162     amd64) HOST_ARCH=x86_64
    163     ;;
    164     powerpc) HOST_ARCH=ppc
    165     ;;
    166 esac
    167 
    168 log2 "HOST_ARCH=$HOST_ARCH"
    169 
    170 # at this point, the supported values for CPU are:
    171 #   x86
    172 #   x86_64
    173 #   ppc
    174 #
    175 # other values may be possible but haven't been tested
    176 #
    177 HOST_EXE=""
    178 HOST_OS=`uname -s`
    179 case "$HOST_OS" in
    180     Darwin)
    181         HOST_OS=darwin
    182         ;;
    183     Linux)
    184         # note that building  32-bit binaries on x86_64 is handled later
    185         HOST_OS=linux
    186         ;;
    187     FreeBsd)  # note: this is not tested
    188         HOST_OS=freebsd
    189         ;;
    190     CYGWIN*|*_NT-*)
    191         HOST_OS=windows
    192         HOST_EXE=.exe
    193         if [ "x$OSTYPE" = xcygwin ] ; then
    194             HOST_OS=cygwin
    195         fi
    196         ;;
    197 esac
    198 
    199 log2 "HOST_OS=$HOST_OS"
    200 log2 "HOST_EXE=$HOST_EXE"
    201 
    202 # at this point, the value of HOST_OS should be one of the following:
    203 #   linux
    204 #   darwin
    205 #    windows (MSys)
    206 #    cygwin
    207 #
    208 # Note that cygwin is treated as a special case because it behaves very differently
    209 # for a few things. Other values may be possible but have not been tested
    210 #
    211 
    212 # define HOST_TAG as a unique tag used to identify both the host OS and CPU
    213 # supported values are:
    214 #
    215 #   linux-x86
    216 #   linux-x86_64
    217 #   darwin-x86
    218 #   darwin-ppc
    219 #   windows
    220 #
    221 # other values are possible but were not tested.
    222 #
    223 compute_host_tag ()
    224 {
    225     case "$HOST_OS" in
    226         windows|cygwin)
    227             HOST_TAG="windows"
    228             ;;
    229         *)  HOST_TAG="${HOST_OS}-${HOST_ARCH}"
    230     esac
    231     log2 "HOST_TAG=$HOST_TAG"
    232 }
    233 
    234 compute_host_tag
    235 
    236 # Compute the number of host CPU cores an HOST_NUM_CPUS
    237 #
    238 case "$HOST_OS" in
    239     linux)
    240         HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l`
    241         ;;
    242     darwin|freebsd)
    243         HOST_NUM_CPUS=`sysctl -n hw.ncpu`
    244         ;;
    245     windows|cygwin)
    246         HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS
    247         ;;
    248     *)  # let's play safe here
    249         HOST_NUM_CPUS=1
    250 esac
    251 
    252 log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS"
    253 
    254 # If BUILD_NUM_CPUS is not already defined in your environment,
    255 # define it as the double of HOST_NUM_CPUS. This is used to
    256 # run Make commends in parralles, as in 'make -j$BUILD_NUM_CPUS'
    257 #
    258 if [ -z "$BUILD_NUM_CPUS" ] ; then
    259     BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2`
    260 fi
    261 
    262 log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS"
    263 
    264 
    265 ##  HOST TOOLCHAIN SUPPORT
    266 ##
    267 
    268 # force the generation of 32-bit binaries on 64-bit systems
    269 #
    270 FORCE_32BIT=no
    271 force_32bit_binaries ()
    272 {
    273     if [ "$HOST_ARCH" = x86_64 ] ; then
    274         log2 "Forcing generation of 32-bit host binaries on $HOST_ARCH"
    275         FORCE_32BIT=yes
    276         HOST_ARCH=x86
    277         log2 "HOST_ARCH=$HOST_ARCH"
    278         compute_host_tag
    279     fi
    280 }
    281 
    282 # On Windows, cygwin binaries will be generated by default, but
    283 # you can force mingw ones that do not link to cygwin.dll if you
    284 # call this function.
    285 #
    286 disable_cygwin ()
    287 {
    288     if [ $OS = cygwin ] ; then
    289         log2 "Disabling cygwin binaries generation"
    290         CFLAGS="$CFLAGS -mno-cygwin"
    291         LDFLAGS="$LDFLAGS -mno-cygwin"
    292         OS=windows
    293         HOST_OS=windows
    294         compute_host_tag
    295     fi
    296 }
    297 
    298 # Various probes are going to need to run a small C program
    299 TMPC=/tmp/android-$$-test.c
    300 TMPO=/tmp/android-$$-test.o
    301 TMPE=/tmp/android-$$-test$EXE
    302 TMPL=/tmp/android-$$-test.log
    303 
    304 # cleanup temporary files
    305 clean_temp ()
    306 {
    307     rm -f $TMPC $TMPO $TMPL $TMPE
    308 }
    309 
    310 # cleanup temp files then exit with an error
    311 clean_exit ()
    312 {
    313     clean_temp
    314     exit 1
    315 }
    316 
    317 # this function will setup the compiler and linker and check that they work as advertised
    318 # note that you should call 'force_32bit_binaries' before this one if you want it to
    319 # generate 32-bit binaries on 64-bit systems (that support it).
    320 #
    321 setup_toolchain ()
    322 {
    323     if [ -z "$CC" ] ; then
    324         CC=gcc
    325     fi
    326 
    327     log2 "Using '$CC' as the C compiler"
    328 
    329     # check that we can compile a trivial C program with this compiler
    330     cat > $TMPC <<EOF
    331 int main(void) {}
    332 EOF
    333 
    334     if [ "$FORCE_32BIT" = yes ] ; then
    335         CFLAGS="$CFLAGS -m32"
    336         LDFLAGS="$LDFLAGS -m32"
    337         compile
    338         if [ $? != 0 ] ; then
    339             # sometimes, we need to also tell the assembler to generate 32-bit binaries
    340             # this is highly dependent on your GCC installation (and no, we can't set
    341             # this flag all the time)
    342             CFLAGS="$CFLAGS -Wa,--32"
    343             compile
    344         fi
    345     fi
    346 
    347     compile
    348     if [ $? != 0 ] ; then
    349         echo "your C compiler doesn't seem to work:"
    350         cat $TMPL
    351         clean_exit
    352     fi
    353     log "CC         : compiler check ok ($CC)"
    354 
    355     # check that we can link the trivial program into an executable
    356     if [ -z "$LD" ] ; then
    357         LD=$CC
    358     fi
    359     link
    360     if [ $? != 0 ] ; then
    361         OLD_LD=$LD
    362         LD=gcc
    363         compile
    364         link
    365         if [ $? != 0 ] ; then
    366             LD=$OLD_LD
    367             echo "your linker doesn't seem to work:"
    368             cat $TMPL
    369             clean_exit
    370         fi
    371     fi
    372     log2 "Using '$LD' as the linker"
    373     log "LD         : linker check ok ($LD)"
    374 
    375     # check the C++ compiler
    376     if [ -z "$CXX" ] ; then
    377         CXX=g++
    378     fi
    379     if [ -z "$CXXFLAGS" ] ; then
    380         CXXFLAGS=$CFLAGS
    381     fi
    382 
    383     log2 "Using '$CXX' as the C++ compiler"
    384 
    385     cat > $TMPC <<EOF
    386 #include <iostream>
    387 using namespace std;
    388 int main()
    389 {
    390   cout << "Hello World!" << endl;
    391   return 0;
    392 }
    393 EOF
    394 
    395     compile_cpp
    396     if [ $? != 0 ] ; then
    397         echo "your C++ compiler doesn't seem to work"
    398         cat $TMPL
    399         clean_exit
    400     fi
    401 
    402     log "CXX        : C++ compiler check ok ($CXX)"
    403 
    404     # XXX: TODO perform AR checks
    405     AR=ar
    406     ARFLAGS=
    407 }
    408 
    409 # try to compile the current source file in $TMPC into an object
    410 # stores the error log into $TMPL
    411 #
    412 compile ()
    413 {
    414     log2 "Object     : $CC -o $TMPO -c $CFLAGS $TMPC"
    415     $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
    416 }
    417 
    418 compile_cpp ()
    419 {
    420     log2 "Object     : $CXX -o $TMPO -c $CXXFLAGS $TMPC"
    421     $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL
    422 }
    423 
    424 # try to link the recently built file into an executable. error log in $TMPL
    425 #
    426 link()
    427 {
    428     log2 "Link      : $LD -o $TMPE $TMPO $LDFLAGS"
    429     $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL
    430 }
    431 
    432 # run a command
    433 #
    434 execute()
    435 {
    436     log2 "Running: $*"
    437     $*
    438 }
    439 
    440 # perform a simple compile / link / run of the source file in $TMPC
    441 compile_exec_run()
    442 {
    443     log2 "RunExec    : $CC -o $TMPE $CFLAGS $TMPC"
    444     compile
    445     if [ $? != 0 ] ; then
    446         echo "Failure to compile test program"
    447         cat $TMPC
    448         cat $TMPL
    449         clean_exit
    450     fi
    451     link
    452     if [ $? != 0 ] ; then
    453         echo "Failure to link test program"
    454         cat $TMPC
    455         echo "------"
    456         cat $TMPL
    457         clean_exit
    458     fi
    459     $TMPE
    460 }
    461 
    462 pattern_match ()
    463 {
    464     echo "$2" | grep -q -E -e "$1"
    465 }
    466 
    467 # Let's check that we have a working md5sum here
    468 check_md5sum ()
    469 {
    470     A_MD5=`echo "A" | md5sum | cut -d' ' -f1`
    471     if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then
    472         echo "Please install md5sum on this machine"
    473         exit 2
    474     fi
    475 }
    476 
    477 # Find if a given shell program is available.
    478 # We need to take care of the fact that the 'which <foo>' command
    479 # may return either an empty string (Linux) or something like
    480 # "no <foo> in ..." (Darwin). Also, we need to redirect stderr
    481 # to /dev/null for Cygwin
    482 #
    483 # $1: variable name
    484 # $2: program name
    485 #
    486 # Result: set $1 to the full path of the corresponding command
    487 #         or to the empty/undefined string if not available
    488 #
    489 find_program ()
    490 {
    491     local PROG
    492     PROG=`which $2 2>/dev/null`
    493     if [ -n "$PROG" ] ; then
    494         if pattern_match '^no ' "$PROG"; then
    495             PROG=
    496         fi
    497     fi
    498     eval $1="$PROG"
    499 }
    500 
    501 prepare_download ()
    502 {
    503     find_program CMD_WGET wget
    504     find_program CMD_CURL curl
    505     find_program CMD_SCRP scp
    506 }
    507 
    508 # Download a file with either 'curl', 'wget' or 'scp'
    509 #
    510 # $1: source URL (e.g. http://foo.com, ssh://blah, /some/path)
    511 # $2: target file
    512 download_file ()
    513 {
    514     # Is this HTTP, HTTPS or FTP ?
    515     if pattern_match "^(http|https|ftp):.*" "$1"; then
    516         if [ -n "$CMD_WGET" ] ; then
    517             run $CMD_WGET -O $2 $1 
    518         elif [ -n "$CMD_CURL" ] ; then
    519             run $CMD_CURL -o $2 $1
    520         else
    521             echo "Please install wget or curl on this machine"
    522             exit 1
    523         fi
    524         return
    525     fi
    526 
    527     # Is this SSH ?
    528     # Accept both ssh://<path> or <machine>:<path>
    529     #
    530     if pattern_match "^(ssh|[^:]+):.*" "$1"; then
    531         if [ -n "$CMD_SCP" ] ; then
    532             scp_src=`echo $1 | sed -e s%ssh://%%g`
    533             run $CMD_SCP $scp_src $2
    534         else
    535             echo "Please install scp on this machine"
    536             exit 1
    537         fi
    538         return
    539     fi
    540 
    541     # Is this a file copy ?
    542     # Accept both file://<path> or /<path>
    543     #
    544     if pattern_match "^(file://|/).*" "$1"; then
    545         cp_src=`echo $1 | sed -e s%^file://%%g`
    546         run cp -f $cp_src $2
    547         return
    548     fi
    549 }
    550