prebuilt-common.sh revision 1c60afab0086a6ad50d375723610c16688e9ae7c
1# Common functions for all prebuilt-related scripts
2# This is included/sourced by other scripts
3#
4
5. `dirname $0`/../core/ndk-common.sh
6
7#====================================================
8#
9#  UTILITY FUNCTIONS
10#
11#====================================================
12
13# Return the maximum length of a series of strings
14#
15# Usage:  len=`max_length <string1> <string2> ...`
16#
17max_length ()
18{
19    echo "$@" | tr ' ' '\n' | awk 'BEGIN {max=0} {len=length($1); if (len > max) max=len} END {print max}'
20}
21
22# Translate dashes to underscores
23# Usage:  str=`dashes_to_underscores <values>`
24dashes_to_underscores ()
25{
26    echo $@ | tr '-' '_'
27}
28
29# Translate underscores to dashes
30# Usage: str=`underscores_to_dashes <values>`
31underscores_to_dashes ()
32{
33    echo $@ | tr '_' '-'
34}
35
36# Translate commas to spaces
37# Usage: str=`commas_to_spaces <list>`
38commas_to_spaces ()
39{
40    echo $@ | tr ',' ' '
41}
42
43# Translate spaces to commas
44# Usage: list=`spaces_to_commas <string>`
45spaces_to_commas ()
46{
47    echo $@ | tr ' ' ','
48}
49
50# Predicate: true iff a space-separated list contains a given item regex pattern
51# $1: item regex pattern
52# $2+: list
53list_contains ()
54{
55    local KEY="$1"
56    shift
57    echo $@ | tr ' ' '\n' | grep -q -F -e "$KEY"
58}
59
60#====================================================
61#
62#  OPTION PROCESSING
63#
64#====================================================
65
66# We recognize the following option formats:
67#
68#  -f
69#  --flag
70#
71#  -s<value>
72#  --setting=<value>
73#
74
75# NOTE: We translate '-' into '_' when storing the options in global variables
76#
77
78OPTIONS=""
79OPTION_FLAGS=""
80OPTION_SETTINGS=""
81
82# Set a given option attribute
83# $1: option name
84# $2: option attribute
85# $3: attribute value
86#
87option_set_attr ()
88{
89    eval OPTIONS_$1_$2=\"$3\"
90}
91
92# Get a given option attribute
93# $1: option name
94# $2: option attribute
95#
96option_get_attr ()
97{
98    echo `var_value OPTIONS_$1_$2`
99}
100
101# Register a new option
102# $1: option
103# $2: small abstract for the option
104# $3: optional. default value
105#
106register_option_internal ()
107{
108    optlabel=
109    optname=
110    optvalue=
111    opttype=
112    while [ -n "1" ] ; do
113        # Check for something like --setting=<value>
114        echo "$1" | grep -q -E -e '^--[^=]+=<.+>$'
115        if [ $? = 0 ] ; then
116            optlabel=`expr -- "$1" : '\(--[^=]*\)=.*'`
117            optvalue=`expr -- "$1" : '--[^=]*=\(<.*>\)'`
118            opttype="long_setting"
119            break
120        fi
121
122        # Check for something like --flag
123        echo "$1" | grep -q -E -e '^--[^=]+$'
124        if [ $? = 0 ] ; then
125            optlabel="$1"
126            opttype="long_flag"
127            break
128        fi
129
130        # Check for something like -f<value>
131        echo "$1" | grep -q -E -e '^-[A-Za-z0-9]<.+>$'
132        if [ $? = 0 ] ; then
133            optlabel=`expr -- "$1" : '\(-.\).*'`
134            optvalue=`expr -- "$1" : '-.\(<.+>\)'`
135            opttype="short_setting"
136            break
137        fi
138
139        # Check for something like -f
140        echo "$1" | grep -q -E -e '^-.$'
141        if [ $? = 0 ] ; then
142            optlabel="$1"
143            opttype="short_flag"
144            break
145        fi
146
147        echo "ERROR: Invalid option format: $1"
148        echo "       Check register_option call"
149        exit 1
150    done
151
152    log "new option: type='$opttype' name='$optlabel' value='$optvalue'"
153
154    optname=`dashes_to_underscores $optlabel`
155    OPTIONS="$OPTIONS $optname"
156    OPTIONS_TEXT="$OPTIONS_TEXT $1"
157    option_set_attr $optname label "$optlabel"
158    option_set_attr $optname otype "$opttype"
159    option_set_attr $optname value "$optvalue"
160    option_set_attr $optname text "$1"
161    option_set_attr $optname abstract "$2"
162    option_set_attr $optname default "$3"
163}
164
165# Register a new option with a function callback.
166#
167# $1: option
168# $2: name of function that will be called when the option is parsed
169# $3: small abstract for the option
170# $4: optional. default value
171#
172register_option ()
173{
174    local optname optvalue opttype optlabel
175    register_option_internal "$1" "$3" "$4"
176    option_set_attr $optname funcname "$2"
177}
178
179# Register a new option with a variable store
180#
181# $1: option
182# $2: name of variable that will be set by this option
183# $3: small abstract for the option
184#
185# NOTE: The current value of $2 is used as the default
186#
187register_var_option ()
188{
189    local optname optvalue opttype optlabel
190    register_option_internal "$1" "$3" "`var_value $2`"
191    option_set_attr $optname varname "$2"
192}
193
194
195MINGW=no
196do_mingw_option () { MINGW=yes; }
197
198register_mingw_option ()
199{
200    if [ "$HOST_OS" = "linux" ] ; then
201        register_option "--mingw" do_mingw_option "Generate windows binaries on Linux."
202    fi
203}
204
205TRY64=no
206do_try64_option () { TRY64=yes; }
207
208register_try64_option ()
209{
210    register_option "--try-64" do_try64_option "Generate 64-bit binaries."
211}
212
213# Print the help, including a list of registered options for this program
214# Note: Assumes PROGRAM_PARAMETERS and PROGRAM_DESCRIPTION exist and
215#       correspond to the parameters list and the program description
216#
217print_help ()
218{
219    local opt text abstract default
220
221    echo "Usage: $PROGNAME [options] $PROGRAM_PARAMETERS"
222    echo ""
223    if [ -n "$PROGRAM_DESCRIPTION" ] ; then
224        echo "$PROGRAM_DESCRIPTION"
225        echo ""
226    fi
227    echo "Valid options (defaults are in brackets):"
228    echo ""
229
230    maxw=`max_length "$OPTIONS_TEXT"`
231    AWK_SCRIPT=`echo "{ printf \"%-${maxw}s\", \\$1 }"`
232    for opt in $OPTIONS; do
233        text=`option_get_attr $opt text | awk "$AWK_SCRIPT"`
234        abstract=`option_get_attr $opt abstract`
235        default=`option_get_attr $opt default`
236        if [ -n "$default" ] ; then
237            echo "  $text     $abstract [$default]"
238        else
239            echo "  $text     $abstract"
240        fi
241    done
242    echo ""
243}
244
245option_panic_no_args ()
246{
247    echo "ERROR: Option '$1' does not take arguments. See --help for usage."
248    exit 1
249}
250
251option_panic_missing_arg ()
252{
253    echo "ERROR: Option '$1' requires an argument. See --help for usage."
254    exit 1
255}
256
257extract_parameters ()
258{
259    local opt optname otype value name fin funcname
260    PARAMETERS=""
261    while [ -n "$1" ] ; do
262        # If the parameter does not begin with a dash
263        # it is not an option.
264        param=`expr -- "$1" : '^\([^\-].*\)$'`
265        if [ -n "$param" ] ; then
266            if [ -z "$PARAMETERS" ] ; then
267                PARAMETERS="$1"
268            else
269                PARAMETERS="$PARAMETERS $1"
270            fi
271            shift
272            continue
273        fi
274
275        while [ -n "1" ] ; do
276            # Try to match a long setting, i.e. --option=value
277            opt=`expr -- "$1" : '^\(--[^=]*\)=.*$'`
278            if [ -n "$opt" ] ; then
279                otype="long_setting"
280                value=`expr -- "$1" : '^--[^=]*=\(.*\)$'`
281                break
282            fi
283
284            # Try to match a long flag, i.e. --option
285            opt=`expr -- "$1" : '^\(--.*\)$'`
286            if [ -n "$opt" ] ; then
287                otype="long_flag"
288                value="yes"
289                break
290            fi
291
292            # Try to match a short setting, i.e. -o<value>
293            opt=`expr -- "$1" : '^\(-[A-Za-z0-9]\)..*$'`
294            if [ -n "$opt" ] ; then
295                otype="short_setting"
296                value=`expr -- "$1" : '^-.\(.*\)$'`
297                break
298            fi
299
300            # Try to match a short flag, i.e. -o
301            opt=`expr -- "$1" : '^\(-.\)$'`
302            if [ -n "$opt" ] ; then
303                otype="short_flag"
304                value="yes"
305                break
306            fi
307
308            echo "ERROR: Unknown option '$1'. Use --help for list of valid values."
309            exit 1
310        done
311
312        #echo "Found opt='$opt' otype='$otype' value='$value'"
313
314        name=`dashes_to_underscores $opt`
315        found=0
316        for xopt in $OPTIONS; do
317            if [ "$name" != "$xopt" ] ; then
318                continue
319            fi
320            # Check that the type is correct here
321            #
322            # This also allows us to handle -o <value> as -o<value>
323            #
324            xotype=`option_get_attr $name otype`
325            if [ "$otype" != "$xotype" ] ; then
326                case "$xotype" in
327                "short_flag")
328                    option_panic_no_args $opt
329                    ;;
330                "short_setting")
331                    if [ -z "$2" ] ; then
332                        option_panic_missing_arg $opt
333                    fi
334                    value="$2"
335                    shift
336                    ;;
337                "long_flag")
338                    option_panic_no_args $opt
339                    ;;
340                "long_setting")
341                    option_panic_missing_arg $opt
342                    ;;
343                esac
344            fi
345            found=1
346            break
347            break
348        done
349        if [ "$found" = "0" ] ; then
350            echo "ERROR: Unknown option '$opt'. See --help for usage."
351            exit 1
352        fi
353        # Set variable or launch option-specific function.
354        varname=`option_get_attr $name varname`
355        if [ -n "$varname" ] ; then
356            eval ${varname}=\"$value\"
357        else
358            eval `option_get_attr $name funcname` \"$value\"
359        fi
360        shift
361    done
362}
363
364do_option_help ()
365{
366    print_help
367    exit 0
368}
369
370VERBOSE=no
371VERBOSE2=no
372do_option_verbose ()
373{
374    if [ $VERBOSE = "yes" ] ; then
375        VERBOSE2=yes
376    else
377        VERBOSE=yes
378    fi
379}
380
381register_option "--help"          do_option_help     "Print this help."
382register_option "--verbose"       do_option_verbose  "Enable verbose mode."
383
384#====================================================
385#
386#  TOOLCHAIN AND ABI PROCESSING
387#
388#====================================================
389
390# Determine optional variable value
391# $1: final variable name
392# $2: option variable name
393# $3: small description for the option
394fix_option ()
395{
396    if [ -n "$2" ] ; then
397        eval $1="$2"
398        log "Using specific $3: $2"
399    else
400        log "Using default $3: `var_value $1`"
401    fi
402}
403
404
405# If SYSROOT is empty, check that $1/$2 contains a sysroot
406# and set the variable to it.
407#
408# $1: sysroot path
409# $2: platform/arch suffix
410check_sysroot ()
411{
412    if [ -z "$SYSROOT" ] ; then
413        log "Probing directory for sysroot: $1/$2"
414        if [ -d $1/$2 ] ; then
415            SYSROOT=$1/$2
416        fi
417    fi
418}
419
420# Determine sysroot
421# $1: Option value (or empty)
422#
423fix_sysroot ()
424{
425    if [ -n "$1" ] ; then
426        eval SYSROOT="$1"
427        log "Using specified sysroot: $1"
428    else
429        SYSROOT_SUFFIX=$PLATFORM/arch-$ARCH
430        SYSROOT=
431        check_sysroot $NDK_DIR/platforms $SYSROOT_SUFFIX
432        check_sysroot $ANDROID_NDK_ROOT/platforms $SYSROOT_SUFFIX
433        check_sysroot `dirname $ANDROID_NDK_ROOT`/development/ndk/platforms $SYSROOT_SUFFIX
434
435        if [ -z "$SYSROOT" ] ; then
436            echo "ERROR: Could not find NDK sysroot path for $SYSROOT_SUFFIX."
437            echo "       Use --sysroot=<path> to specify one."
438            exit 1
439        fi
440    fi
441
442    if [ ! -f $SYSROOT/usr/include/stdlib.h ] ; then
443        echo "ERROR: Invalid sysroot path: $SYSROOT"
444        echo "       Use --sysroot=<path> to indicate a valid one."
445        exit 1
446    fi
447}
448
449# Use the check for the availability of a compatibility SDK in Darwin
450# this can be used to generate binaries compatible with either Tiger or
451# Leopard.
452#
453# $1: SDK root path
454# $2: MacOS X minimum version (e.g. 10.4)
455check_darwin_sdk ()
456{
457    if [ -d "$1" ] ; then
458        HOST_CFLAGS="-isysroot $1 -mmacosx-version-min=$2 -DMAXOSX_DEPLOYEMENT_TARGET=$2"
459        HOST_LDFLAGS="-Wl,-syslibroot,$sdk -mmacosx-version-min=$2"
460        return 0  # success
461    fi
462    return 1
463}
464
465
466prepare_host_flags ()
467{
468    # detect build tag
469    case $HOST_TAG in
470        linux-x86)
471            ABI_CONFIGURE_BUILD=i386-linux-gnu
472            ;;
473        linux-x86_64)
474            ABI_CONFIGURE_BUILD=x86_64-linux-gnu
475            ;;
476        darwin-x86)
477            ABI_CONFIGURE_BUILD=i686-apple-darwin
478            ;;
479        darwin-x86_64)
480            ABI_CONFIGURE_BUILD=x86_64-apple-darwin
481            ;;
482        windows)
483            ABI_CONFIGURE_BUILD=i686-pc-cygwin
484            ;;
485        *)
486            echo "ERROR: Unsupported HOST_TAG: $HOST_TAG"
487            echo "Please update 'prepare_host_flags' in build/tools/prebuilt-common.sh"
488            ;;
489    esac
490
491    # By default, assume host == build
492    ABI_CONFIGURE_HOST="$ABI_CONFIGURE_BUILD"
493
494    # On Linux, detect our legacy-compatible toolchain when in the Android
495    # source tree, and use it to force the generation of glibc-2.7 compatible
496    # binaries.
497    #
498    # We only do this if the CC variable is not defined to a given value
499    # and the --mingw or --try-64 options are not used.
500    #
501    if [ "$HOST_OS" = "linux" -a -z "$CC" -a "$MINGW" != "yes" -a "$TRY64" != "yes" ]; then
502        LEGACY_TOOLCHAIN_DIR="$ANDROID_NDK_ROOT/../prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3"
503        if [ -d "$LEGACY_TOOLCHAIN_DIR" ] ; then
504            dump "Forcing generation of Linux binaries with legacy toolchain"
505            CC="$LEGACY_TOOLCHAIN_DIR/bin/i686-linux-gcc"
506            CXX="$LEGACY_TOOLCHAIN_DIR/bin/i686-linux-g++"
507        fi
508    fi
509
510    # Force generation of 32-bit binaries on 64-bit systems
511    CC=${CC:-gcc}
512    CXX=${CXX:-g++}
513    case $HOST_TAG in
514        darwin-*)
515            # Try to build with Tiger SDK if available
516            if check_darwin_sdk /Developer/SDKs/MacOSX10.4.sdku 10.4; then
517                log "Generating Tiger-compatible binaries!"
518            # Otherwise with Leopard SDK
519            elif check_darwin_sdk /Developer/SDKs/MacOSX10.5.sdk 10.5; then
520                log "Generating Leopard-compatible binaries!"
521            else
522                local version=`sw_vers -productVersion`
523                log "Generating $version-compatible binaries!"
524            fi
525            ;;
526    esac
527
528    # Force generation of 32-bit binaries on 64-bit systems.
529    # We used to test the value of $HOST_TAG for *-x86_64, but this is
530    # not sufficient on certain systems.
531    #
532    # For example, Snow Leopard can be booted with a 32-bit kernel, running
533    # a 64-bit userland, with a compiler that generates 64-bit binaries by
534    # default *even* though "gcc -v" will report --target=i686-apple-darwin10!
535    #
536    # So know, simply probe for the size of void* by performing a small runtime
537    # compilation test.
538    #
539    cat > $TMPC <<EOF
540    /* this test should fail if the compiler generates 64-bit machine code */
541    int test_array[1-2*(sizeof(void*) != 4)];
542EOF
543    echo -n "Checking whether the compiler generates 32-bit binaries..."
544    HOST_GMP_ABI=32
545    log $CC $HOST_CFLAGS -c -o $TMPO $TMPC
546    $CC $HOST_CFLAGS -c -o $TMPO $TMPC >$TMPL 2>&1
547    if [ $? != 0 ] ; then
548        echo "no"
549        if [ "$TRY64" != "yes" ]; then
550            # NOTE: We need to modify the definitions of CC and CXX directly
551            #        here. Just changing the value of CFLAGS / HOST_CFLAGS
552            #        will not work well with the GCC toolchain scripts.
553            CC="$CC -m32"
554            CXX="$CXX -m32"
555        else
556            HOST_GMP_ABI=64
557        fi
558    else
559        echo "yes"
560    fi
561
562    # For now, we only support building 32-bit binaries anyway
563    if [ "$TRY64" != "yes" ]; then
564        force_32bit_binaries  # to modify HOST_TAG and others
565        HOST_GMP_ABI="32"
566    fi
567
568    # Now handle the --mingw flag
569    if [ "$MINGW" = "yes" ] ; then
570        case $HOST_TAG in
571            linux-*)
572                ;;
573            *)
574                echo "ERROR: Can only enable mingw on Linux platforms !"
575                exit 1
576                ;;
577        esac
578        if [ "$TRY64" = "yes" ]; then
579            ABI_CONFIGURE_HOST=amd64-mingw32msvc
580        else
581            ABI_CONFIGURE_HOST=i586-mingw32msvc
582        fi
583        HOST_OS=windows
584        HOST_TAG=windows
585        HOST_EXE=.exe
586        # It turns out that we need to undefine this to be able to
587        # perform a canadian-cross build with mingw. Otherwise, the
588        # GMP configure scripts will not be called with the right options
589        HOST_GMP_ABI=
590    fi
591}
592
593parse_toolchain_name ()
594{
595    if [ -z "$TOOLCHAIN" ] ; then
596        echo "ERROR: Missing toolchain name!"
597        exit 1
598    fi
599
600    ABI_CFLAGS_FOR_TARGET=
601    ABI_CXXFLAGS_FOR_TARGET=
602
603    # Determine ABI based on toolchain name
604    #
605    case "$TOOLCHAIN" in
606    arm-eabi-*)
607        ARCH="arm"
608        ABI_CONFIGURE_TARGET="arm-eabi"
609        ABI_CONFIGURE_EXTRA_FLAGS="--with-binutils-version=2.19 --with-mpfr-version=2.3.0 --with-gmp-version=4.2.2"
610        ;;
611    arm-linux-androideabi-*)
612        ARCH="arm"
613        ABI_CONFIGURE_TARGET="arm-linux-androideabi"
614        ABI_CONFIGURE_EXTRA_FLAGS="--with-arch=armv5te"
615        # Disable ARM Gold linker for now, it doesn't build on Windows, it
616        # crashes with SIGBUS on Darwin, and produces weird executables on
617        # linux that strip complains about... Sigh.
618        #ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-gold=both/gold"
619
620        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
621        # You can't really build these separately at the moment.
622        ABI_CFLAGS_FOR_TARGET="-fexceptions"
623        ABI_CXXFLAGS_FOR_TARGET="-frtti"
624        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-libstdc__-v3"
625        # Stick to 6.6 for now. 7.1.x doesn't seem to work right now.
626        #GDB_VERSION=7.1.x
627        ;;
628    x86-*)
629        ARCH="x86"
630        ABI_INSTALL_NAME="x86"
631        ABI_CONFIGURE_TARGET="i686-android-linux"
632        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
633        # You can't really build these separately at the moment.
634        ABI_CFLAGS_FOR_TARGET="-fexceptions -fPIC"
635        ABI_CXXFLAGS_FOR_TARGET="-frtti"
636        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-libstdc__-v3"
637        ;;
638    * )
639        echo "Invalid toolchain specified. Expected (arm-eabi-*|x86-*)"
640        echo ""
641        print_help
642        exit 1
643        ;;
644    esac
645
646    log "Targetting CPU: $ARCH"
647
648    GCC_VERSION=`expr -- "$TOOLCHAIN" : '.*-\([0-9x\.]*\)'`
649    log "Using GCC version: $GCC_VERSION"
650
651    # Determine --host value when building gdbserver
652    case "$TOOLCHAIN" in
653    arm-*)
654        GDBSERVER_HOST=arm-eabi-linux
655        GDBSERVER_CFLAGS="-fno-short-enums"
656        ;;
657    x86-*)
658        GDBSERVER_HOST=i686-android-linux-gnu
659        GDBSERVER_CFLAGS=
660        ;;
661    esac
662
663}
664
665# Return the host/build specific path for prebuilt toolchain binaries
666# relative to $1.
667#
668# $1: target root NDK directory
669#
670get_toolchain_install ()
671{
672    echo "$1/toolchains/$TOOLCHAIN/prebuilt/$HOST_TAG"
673}
674
675
676# Set the toolchain target NDK location.
677# this sets TOOLCHAIN_PATH and TOOLCHAIN_PREFIX
678# $1: target NDK path
679set_toolchain_ndk ()
680{
681    TOOLCHAIN_PATH=`get_toolchain_install $1`
682    log "Using toolchain path: $TOOLCHAIN_PATH"
683
684    TOOLCHAIN_PREFIX=$TOOLCHAIN_PATH/bin/$ABI_CONFIGURE_TARGET
685    log "Using toolchain prefix: $TOOLCHAIN_PREFIX"
686}
687
688# Check that a toolchain is properly installed at a target NDK location
689#
690# $1: target root NDK directory
691#
692check_toolchain_install ()
693{
694    TOOLCHAIN_PATH=`get_toolchain_install $1`
695    if [ ! -d "$TOOLCHAIN_PATH" ] ; then
696        echo "ERROR: Toolchain '$TOOLCHAIN' not installed in '$NDK_DIR'!"
697        echo "       Ensure that the toolchain has been installed there before."
698        exit 1
699    fi
700
701    set_toolchain_ndk $1
702}
703
704
705random_temp_directory ()
706{
707    mkdir -p /tmp/ndk-toolchain
708    mktemp -d /tmp/ndk-toolchain/build-XXXXXX
709}
710
711#
712# Common definitions
713#
714
715# Current list of platform levels we support
716#
717# Note: levels 6 and 7 are omitted since they have the same native
718# APIs as level 5.
719#
720API_LEVELS="3 4 5 8 9"
721
722# Location of the STLport sources, relative to the NDK root directory
723STLPORT_SUBDIR=sources/cxx-stl/stlport
724
725# Default ABIs for the prebuilt STLport binaries
726STLPORT_ABIS="armeabi armeabi-v7a"
727
728# Location of the GNU libstdc++ headers and libraries, relative to the NDK
729# root directory.
730GNUSTL_SUBDIR=sources/cxx-stl/gnu-libstdc++
731
732# The date to use when downloading toolchain sources from android.git.kernel.org
733# Leave it empty for tip of tree.
734TOOLCHAIN_GIT_DATE=2011-02-23
735