# 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
}