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