| # Common functions for all prebuilt-related scripts |
| # This is included/sourced by other scripts |
| # |
| |
| . `dirname $0`/../core/ndk-common.sh |
| |
| #==================================================== |
| # |
| # UTILITY FUNCTIONS |
| # |
| #==================================================== |
| |
| # Return the maximum length of a series of strings |
| # |
| # Usage: len=`max_length <string1> <string2> ...` |
| # |
| max_length () |
| { |
| echo "$@" | tr ' ' '\n' | awk 'BEGIN {max=0} {len=length($1); if (len > max) max=len} END {print max}' |
| } |
| |
| # Translate dashes to underscores |
| # Usage: str=`dashes_to_underscores <values>` |
| dashes_to_underscores () |
| { |
| echo $@ | tr '-' '_' |
| } |
| |
| # Translate underscores to dashes |
| # Usage: str=`underscores_to_dashes <values>` |
| underscores_to_dashes () |
| { |
| echo $@ | tr '_' '-' |
| } |
| |
| #==================================================== |
| # |
| # OPTION PROCESSING |
| # |
| #==================================================== |
| |
| # We recognize the following option formats: |
| # |
| # -f |
| # --flag |
| # |
| # -s<value> |
| # --setting=<value> |
| # |
| |
| # NOTE: We translate '-' into '_' when storing the options in global variables |
| # |
| |
| OPTIONS="" |
| OPTION_FLAGS="" |
| OPTION_SETTINGS="" |
| |
| # Set a given option attribute |
| # $1: option name |
| # $2: option attribute |
| # $3: attribute value |
| # |
| option_set_attr () |
| { |
| eval OPTIONS_$1_$2=\"$3\" |
| } |
| |
| # Get a given option attribute |
| # $1: option name |
| # $2: option attribute |
| # |
| option_get_attr () |
| { |
| echo `var_value OPTIONS_$1_$2` |
| } |
| |
| # Register a new option |
| # $1: option |
| # $2: small abstract for the option |
| # $3: optional. default value |
| # |
| register_option_internal () |
| { |
| optlabel= |
| optname= |
| optvalue= |
| opttype= |
| while [ -n "1" ] ; do |
| # Check for something like --setting=<value> |
| echo "$1" | grep -q -E -e '^--[^=]+=<.+>$' |
| if [ $? = 0 ] ; then |
| optlabel=`expr -- "$1" : '\(--[^=]*\)=.*'` |
| optvalue=`expr -- "$1" : '--[^=]*=\(<.*>\)'` |
| opttype="long_setting" |
| break |
| fi |
| |
| # Check for something like --flag |
| echo "$1" | grep -q -E -e '^--[^=]+$' |
| if [ $? = 0 ] ; then |
| optlabel="$1" |
| opttype="long_flag" |
| break |
| fi |
| |
| # Check for something like -f<value> |
| echo "$1" | grep -q -E -e '^-[A-Za-z0-9]<.+>$' |
| if [ $? = 0 ] ; then |
| optlabel=`expr -- "$1" : '\(-.\).*'` |
| optvalue=`expr -- "$1" : '-.\(<.+>\)'` |
| opttype="short_setting" |
| break |
| fi |
| |
| # Check for something like -f |
| echo "$1" | grep -q -E -e '^-.$' |
| if [ $? = 0 ] ; then |
| optlabel="$1" |
| opttype="short_flag" |
| break |
| fi |
| |
| echo "ERROR: Invalid option format: $1" |
| echo " Check register_option call" |
| exit 1 |
| done |
| |
| log "new option: type='$opttype' name='$optlabel' value='$optvalue'" |
| |
| optname=`dashes_to_underscores $optlabel` |
| OPTIONS="$OPTIONS $optname" |
| OPTIONS_TEXT="$OPTIONS_TEXT $1" |
| option_set_attr $optname label "$optlabel" |
| option_set_attr $optname otype "$opttype" |
| option_set_attr $optname value "$optvalue" |
| option_set_attr $optname text "$1" |
| option_set_attr $optname abstract "$2" |
| option_set_attr $optname default "$3" |
| } |
| |
| # Register a new option with a function callback. |
| # |
| # $1: option |
| # $2: name of function that will be called when the option is parsed |
| # $3: small abstract for the option |
| # $4: optional. default value |
| # |
| register_option () |
| { |
| local optname optvalue opttype optlabel |
| register_option_internal "$1" "$3" "$4" |
| option_set_attr $optname funcname "$2" |
| } |
| |
| # Register a new option with a variable store |
| # |
| # $1: option |
| # $2: name of variable that will be set by this option |
| # $3: small abstract for the option |
| # |
| # NOTE: The current value of $2 is used as the default |
| # |
| register_var_option () |
| { |
| local optname optvalue opttype optlabel |
| register_option_internal "$1" "$3" "`var_value $2`" |
| option_set_attr $optname varname "$2" |
| } |
| |
| |
| MINGW=no |
| do_mingw_option () { MINGW=yes; } |
| |
| register_mingw_option () |
| { |
| if [ "$HOST_OS" = "linux" ] ; then |
| register_option "--mingw" do_mingw_option "Generate windows binaries on Linux." |
| fi |
| } |
| |
| # Print the help, including a list of registered options for this program |
| # Note: Assumes PROGRAM_PARAMETERS and PROGRAM_DESCRIPTION exist and |
| # correspond to the parameters list and the program description |
| # |
| print_help () |
| { |
| local opt text abstract default |
| |
| echo "Usage: $PROGNAME [options] $PROGRAM_PARAMETERS" |
| echo "" |
| if [ -n "$PROGRAM_DESCRIPTION" ] ; then |
| echo "$PROGRAM_DESCRIPTION" |
| echo "" |
| fi |
| echo "Valid options (defaults are in brackets):" |
| echo "" |
| |
| maxw=`max_length "$OPTIONS_TEXT"` |
| AWK_SCRIPT=`echo "{ printf \"%-${maxw}s\", \\$1 }"` |
| for opt in $OPTIONS; do |
| text=`option_get_attr $opt text | awk "$AWK_SCRIPT"` |
| abstract=`option_get_attr $opt abstract` |
| default=`option_get_attr $opt default` |
| if [ -n "$default" ] ; then |
| echo " $text $abstract [$default]" |
| else |
| echo " $text $abstract" |
| fi |
| done |
| echo "" |
| } |
| |
| option_panic_no_args () |
| { |
| echo "ERROR: Option '$1' does not take arguments. See --help for usage." |
| exit 1 |
| } |
| |
| option_panic_missing_arg () |
| { |
| echo "ERROR: Option '$1' requires an argument. See --help for usage." |
| exit 1 |
| } |
| |
| extract_parameters () |
| { |
| local opt optname otype value name fin funcname |
| PARAMETERS="" |
| while [ -n "$1" ] ; do |
| # If the parameter does not begin with a dash |
| # it is not an option. |
| param=`expr -- "$1" : '^\([^\-].*\)$'` |
| if [ -n "$param" ] ; then |
| if [ -z "$PARAMETERS" ] ; then |
| PARAMETERS="$1" |
| else |
| PARAMETERS="$PARAMETERS $1" |
| fi |
| shift |
| continue |
| fi |
| |
| while [ -n "1" ] ; do |
| # Try to match a long setting, i.e. --option=value |
| opt=`expr -- "$1" : '^\(--[^=]*\)=.*$'` |
| if [ -n "$opt" ] ; then |
| otype="long_setting" |
| value=`expr -- "$1" : '^--[^=]*=\(.*\)$'` |
| break |
| fi |
| |
| # Try to match a long flag, i.e. --option |
| opt=`expr -- "$1" : '^\(--.*\)$'` |
| if [ -n "$opt" ] ; then |
| otype="long_flag" |
| value="yes" |
| break |
| fi |
| |
| # Try to match a short setting, i.e. -o<value> |
| opt=`expr -- "$1" : '^\(-[A-Za-z0-9]\)..*$'` |
| if [ -n "$opt" ] ; then |
| otype="short_setting" |
| value=`expr -- "$1" : '^-.\(.*\)$'` |
| break |
| fi |
| |
| # Try to match a short flag, i.e. -o |
| opt=`expr -- "$1" : '^\(-.\)$'` |
| if [ -n "$opt" ] ; then |
| otype="short_flag" |
| value="yes" |
| break |
| fi |
| |
| echo "ERROR: Unknown option '$1'. Use --help for list of valid values." |
| exit 1 |
| done |
| |
| #echo "Found opt='$opt' otype='$otype' value='$value'" |
| |
| name=`dashes_to_underscores $opt` |
| found=0 |
| for xopt in $OPTIONS; do |
| if [ "$name" != "$xopt" ] ; then |
| continue |
| fi |
| # Check that the type is correct here |
| # |
| # This also allows us to handle -o <value> as -o<value> |
| # |
| xotype=`option_get_attr $name otype` |
| if [ "$otype" != "$xotype" ] ; then |
| case "$xotype" in |
| "short_flag") |
| option_panic_no_args $opt |
| ;; |
| "short_setting") |
| if [ -z "$2" ] ; then |
| option_panic_missing_arg $opt |
| fi |
| value="$2" |
| shift |
| ;; |
| "long_flag") |
| option_panic_no_args $opt |
| ;; |
| "long_setting") |
| option_panic_missing_arg $opt |
| ;; |
| esac |
| fi |
| found=1 |
| break |
| break |
| done |
| if [ "$found" = "0" ] ; then |
| echo "ERROR: Unknown option '$opt'. See --help for usage." |
| exit 1 |
| fi |
| # Set variable or launch option-specific function. |
| varname=`option_get_attr $name varname` |
| if [ -n "$varname" ] ; then |
| eval ${varname}=\"$value\" |
| else |
| eval `option_get_attr $name funcname` \"$value\" |
| fi |
| shift |
| done |
| } |
| |
| do_option_help () |
| { |
| print_help |
| exit 0 |
| } |
| |
| VERBOSE=no |
| VERBOSE2=no |
| do_option_verbose () |
| { |
| if [ $VERBOSE = "yes" ] ; then |
| VERBOSE2=yes |
| else |
| VERBOSE=yes |
| fi |
| } |
| |
| register_option "--help" do_option_help "Print this help." |
| register_option "--verbose" do_option_verbose "Enable verbose mode." |
| |
| #==================================================== |
| # |
| # TOOLCHAIN AND ABI PROCESSING |
| # |
| #==================================================== |
| |
| # Determine optional variable value |
| # $1: final variable name |
| # $2: option variable name |
| # $3: small description for the option |
| fix_option () |
| { |
| if [ -n "$2" ] ; then |
| eval $1="$2" |
| log "Using specific $3: $2" |
| else |
| log "Using default $3: `var_value $1`" |
| fi |
| } |
| |
| |
| # If SYSROOT is empty, check that $1/$2 contains a sysroot |
| # and set the variable to it. |
| # |
| # $1: sysroot path |
| # $2: platform/arch suffix |
| check_sysroot () |
| { |
| if [ -z "$SYSROOT" ] ; then |
| log "Probing directory for sysroot: $1/$2" |
| if [ -d $1/$2 ] ; then |
| SYSROOT=$1/$2 |
| fi |
| fi |
| } |
| |
| # Determine sysroot |
| # $1: Option value (or empty) |
| # |
| fix_sysroot () |
| { |
| if [ -n "$1" ] ; then |
| eval SYSROOT="$1" |
| log "Using specified sysroot: $1" |
| else |
| SYSROOT_SUFFIX=$PLATFORM/arch-$ARCH |
| SYSROOT= |
| check_sysroot $NDK_DIR/platforms $SYSROOT_SUFFIX |
| check_sysroot $ANDROID_NDK_ROOT/platforms $SYSROOT_SUFFIX |
| check_sysroot `dirname $ANDROID_NDK_ROOT`/development/ndk/platforms $SYSROOT_SUFFIX |
| |
| if [ -z "$SYSROOT" ] ; then |
| echo "ERROR: Could not find NDK sysroot path for $SYSROOT_SUFFIX." |
| echo " Use --sysroot=<path> to specify one." |
| exit 1 |
| fi |
| fi |
| |
| if [ ! -f $SYSROOT/usr/include/stdlib.h ] ; then |
| echo "ERROR: Invalid sysroot path: $SYSROOT" |
| echo " Use --sysroot=<path> to indicate a valid one." |
| exit 1 |
| fi |
| } |
| |
| # Use the check for the availability of a compatibility SDK in Darwin |
| # this can be used to generate binaries compatible with either Tiger or |
| # Leopard. |
| # |
| # $1: SDK root path |
| # $2: MacOS X minimum version (e.g. 10.4) |
| check_darwin_sdk () |
| { |
| if [ -d "$1" ] ; then |
| HOST_CFLAGS="-isysroot $1 -mmacosx-version-min=$2 -DMAXOSX_DEPLOYEMENT_TARGET=$2" |
| HOST_LDFLAGS="-Wl,-syslibroot,$sdk -mmacosx-version-min=$2" |
| return 0 # success |
| fi |
| return 1 |
| } |
| |
| |
| prepare_host_flags () |
| { |
| # detect build tag |
| case $HOST_TAG in |
| linux-x86) |
| ABI_CONFIGURE_BUILD=i386-linux-gnu |
| ;; |
| linux-x86_64) |
| ABI_CONFIGURE_BUILD=x86_64-linux-gnu |
| ;; |
| darwin-x86) |
| ABI_CONFIGURE_BUILD=i686-apple-darwin |
| ;; |
| darwin-x86_64) |
| ABI_CONFIGURE_BUILD=x86_64-apple-darwin |
| ;; |
| windows) |
| ABI_CONFIGURE_BUILD=i686-pc-cygwin |
| ;; |
| *) |
| echo "ERROR: Unsupported HOST_TAG: $HOST_TAG" |
| echo "Please update 'prepare_host_flags' in build/tools/prebuilt-common.sh" |
| ;; |
| esac |
| |
| # By default, assume host == build |
| ABI_CONFIGURE_HOST="$ABI_CONFIGURE_BUILD" |
| |
| # On Linux, detect our legacy-compatible toolchain when in the Android |
| # source tree, and use it to force the generation of glibc-2.7 compatible |
| # binaries. |
| # |
| # We only do this if the CC variable is not defined to a given value |
| # and the --mingw option is not used. |
| # |
| if [ "$HOST_OS" = "linux" -a -z "$CC" -a "$MINGW" != "yes" ]; then |
| LEGACY_TOOLCHAIN_DIR="$ANDROID_NDK_ROOT/../prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3" |
| if [ -d "$LEGACY_TOOLCHAIN_DIR" ] ; then |
| dump "Forcing generation of Linux binaries with legacy toolchain" |
| CC="$LEGACY_TOOLCHAIN_DIR/bin/i686-linux-gcc" |
| CXX="$LEGACY_TOOLCHAIN_DIR/bin/i686-linux-g++" |
| fi |
| fi |
| |
| # Force generation of 32-bit binaries on 64-bit systems |
| CC=${CC:-gcc} |
| CXX=${CXX:-g++} |
| case $HOST_TAG in |
| darwin-*) |
| # Try to build with Tiger SDK if available |
| if check_darwin_sdk /Developer/SDKs/MacOSX10.4.sdku 10.4; then |
| log "Generating Tiger-compatible binaries!" |
| # Otherwise with Leopard SDK |
| elif check_darwin_sdk /Developer/SDKs/MacOSX10.5.sdk 10.5; then |
| log "Generating Leopard-compatible binaries!" |
| else |
| local version=`sw_vers -productVersion` |
| log "Generating $version-compatible binaries!" |
| fi |
| ;; |
| esac |
| |
| # Force generation of 32-bit binaries on 64-bit systems. |
| # We used to test the value of $HOST_TAG for *-x86_64, but this is |
| # not sufficient on certain systems. |
| # |
| # For example, Snow Leopard can be booted with a 32-bit kernel, running |
| # a 64-bit userland, with a compiler that generates 64-bit binaries by |
| # default *even* though "gcc -v" will report --target=i686-apple-darwin10! |
| # |
| # So know, simply probe for the size of void* by performing a small runtime |
| # compilation test. |
| # |
| cat > $TMPC <<EOF |
| /* this test should fail if the compiler generates 64-bit machine code */ |
| int test_array[1-2*(sizeof(void*) != 4)]; |
| EOF |
| echo -n "Checking whether the compiler generates 32-bit binaries..." |
| log $CC $HOST_CFLAGS -c -o $TMPO $TMPC |
| $CC $HOST_CFLAGS -c -o $TMPO $TMPC >$TMPL 2>&1 |
| if [ $? != 0 ] ; then |
| echo "no" |
| # NOTE: We need to modify the definitions of CC and CXX directly |
| # here. Just changing the value of CFLAGS / HOST_CFLAGS |
| # will not work well with the GCC toolchain scripts. |
| CC="$CC -m32" |
| CXX="$CXX -m32" |
| else |
| echo "yes" |
| fi |
| |
| # For now, we only support building 32-bit binaries anyway |
| force_32bit_binaries # to modify HOST_TAG and others |
| HOST_GMP_ABI="32" |
| |
| # Now handle the --mingw flag |
| if [ "$MINGW" = "yes" ] ; then |
| case $HOST_TAG in |
| linux-*) |
| ;; |
| *) |
| echo "ERROR: Can only enable mingw on Linux platforms !" |
| exit 1 |
| ;; |
| esac |
| ABI_CONFIGURE_HOST=i586-mingw32msvc |
| HOST_OS=windows |
| HOST_TAG=windows |
| HOST_EXE=.exe |
| # It turns out that we need to undefine this to be able to |
| # perform a canadian-cross build with mingw. Otherwise, the |
| # GMP configure scripts will not be called with the right options |
| HOST_GMP_ABI= |
| fi |
| } |
| |
| parse_toolchain_name () |
| { |
| if [ -z "$TOOLCHAIN" ] ; then |
| echo "ERROR: Missing toolchain name!" |
| exit 1 |
| fi |
| |
| ABI_CFLAGS_FOR_TARGET= |
| ABI_CXXFLAGS_FOR_TARGET= |
| |
| # Determine ABI based on toolchain name |
| # |
| case "$TOOLCHAIN" in |
| arm-eabi-*) |
| ARCH="arm" |
| ABI_CONFIGURE_TARGET="arm-eabi" |
| ;; |
| arm-linux-androideabi-*) |
| ARCH="arm" |
| ABI_CONFIGURE_TARGET="arm-linux-androideabi" |
| ABI_CONFIGURE_EXTRA_FLAGS="--with-gmp-version=4.2.4 --with-mpfr-version=2.4.1 |
| --with-arch=armv5te" |
| # Disable ARM Gold linker for now, it doesn't build on Windows, it |
| # crashes with SIGBUS on Darwin, and produces weird executables on |
| # linux that strip complains about... Sigh. |
| #ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-gold=both/gold" |
| |
| # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time |
| # You can't really build these separately at the moment. |
| ABI_CFLAGS_FOR_TARGET="-fexceptions" |
| ABI_CXXFLAGS_FOR_TARGET="-frtti" |
| ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-libstdc__-v3" |
| # Stick to 6.6 for now. 7.1.x doesn't seem to work right now. |
| #GDB_VERSION=7.1.x |
| ;; |
| x86-*) |
| ARCH="x86" |
| ABI_INSTALL_NAME="x86" |
| ABI_CONFIGURE_TARGET="i686-android-linux-gnu" |
| PLATFORM=android-5 |
| ;; |
| * ) |
| echo "Invalid toolchain specified. Expected (arm-eabi-*|x86-*)" |
| echo "" |
| print_help |
| exit 1 |
| ;; |
| esac |
| |
| log "Targetting CPU: $ARCH" |
| |
| GCC_VERSION=`expr -- "$TOOLCHAIN" : '.*-\([0-9\.]*\)'` |
| log "Using GCC version: $GCC_VERSION" |
| |
| # Determine --host value when building gdbserver |
| case "$TOOLCHAIN" in |
| arm-*) |
| GDBSERVER_HOST=arm-eabi-linux |
| GDBSERVER_CFLAGS="-fno-short-enums" |
| ;; |
| x86-*) |
| GDBSERVER_HOST=i686-android-linux-gnu |
| GDBSERVER_CFLAGS= |
| ;; |
| esac |
| |
| } |
| |
| # Return the host/build specific path for prebuilt toolchain binaries |
| # relative to $1. |
| # |
| # $1: target root NDK directory |
| # |
| get_toolchain_install () |
| { |
| echo "$1/toolchains/$TOOLCHAIN/prebuilt/$HOST_TAG" |
| } |
| |
| |
| # Set the toolchain target NDK location. |
| # this sets TOOLCHAIN_PATH and TOOLCHAIN_PREFIX |
| # $1: target NDK path |
| set_toolchain_ndk () |
| { |
| TOOLCHAIN_PATH=`get_toolchain_install $1` |
| log "Using toolchain path: $TOOLCHAIN_PATH" |
| |
| TOOLCHAIN_PREFIX=$TOOLCHAIN_PATH/bin/$ABI_CONFIGURE_TARGET |
| log "Using toolchain prefix: $TOOLCHAIN_PREFIX" |
| } |
| |
| # Check that a toolchain is properly installed at a target NDK location |
| # |
| # $1: target root NDK directory |
| # |
| check_toolchain_install () |
| { |
| TOOLCHAIN_PATH=`get_toolchain_install $1` |
| if [ ! -d "$TOOLCHAIN_PATH" ] ; then |
| echo "ERROR: Toolchain '$TOOLCHAIN' not installed in '$NDK_DIR'!" |
| echo " Ensure that the toolchain has been installed there before." |
| exit 1 |
| fi |
| |
| set_toolchain_ndk $1 |
| } |
| |
| |
| random_temp_directory () |
| { |
| mkdir -p /tmp/ndk-toolchain |
| mktemp -d /tmp/ndk-toolchain/build-XXXXXX |
| } |
| |
| # |
| # Common definitions |
| # |
| |
| # Current list of platform levels we support |
| # |
| # Note: levels 6 and 7 are omitted since they have the same native |
| # APIs as level 5. |
| # |
| API_LEVELS="3 4 5 8 9" |
| |
| # Location of the STLport sources, relative to the NDK root directory |
| STLPORT_SUBDIR=sources/cxx-stl/stlport |
| |
| # Default ABIs for the prebuilt STLport binaries |
| STLPORT_ABIS="armeabi armeabi-v7a" |
| |
| # Location of the GNU libstdc++ headers and libraries, relative to the NDK |
| # root directory. |
| GNUSTL_SUBDIR=sources/cxx-stl/gnu-libstdc++ |
| |
| # The date to use when downloading toolchain sources from android.git.kernel.org |
| # Leave it empty for tip of tree. |
| TOOLCHAIN_GIT_DATE=2010-12-13 |