1# Common functions for all prebuilt-related scripts
2# This is included/sourced by other scripts
3#
4
5# ensure stable sort order
6export LC_ALL=C
7
8# NDK_BUILDTOOLS_PATH should point to the directory containing
9# this script. If it is not defined, assume that this is one of
10# the scripts in the same directory that sourced this file.
11#
12if [ -z "$NDK_BUILDTOOLS_PATH" ]; then
13    NDK_BUILDTOOLS_PATH=$(dirname $0)
14    if [ ! -f "$NDK_BUILDTOOLS_PATH/prebuilt-common.sh" ]; then
15        echo "INTERNAL ERROR: Please define NDK_BUILDTOOLS_PATH to point to $$NDK/build/tools"
16        exit 1
17    fi
18fi
19
20# Warn about /bin/sh ins't bash.
21if [ -z "$BASH_VERSION" ] ; then
22    echo "WARNING: The shell running this script isn't bash.  Although we try to avoid bashism in scripts, things can happen."
23fi
24
25NDK_BUILDTOOLS_ABSPATH=$(cd $NDK_BUILDTOOLS_PATH && pwd)
26
27. $NDK_BUILDTOOLS_PATH/ndk-common.sh
28. $NDK_BUILDTOOLS_PATH/dev-defaults.sh
29
30
31# Given an input string of the form <foo>-<bar>-<version>, where
32# <version> can be <major>.<minor>, extract <major>
33extract_version ()
34{
35    echo $1 | tr '-' '\n' | tail -1
36}
37
38# $1: versioned name (e.g. arm-linux-androideabi-4.8)
39# Out: major version (e.g. 4)
40#
41# Examples:  arm-linux-androideabi-4.4.3 -> 4
42#            gmp-0.81 -> 0
43#
44extract_major_version ()
45{
46    local RET=$(extract_version $1 | cut -d . -f 1)
47    RET=${RET:-0}
48    echo $RET
49}
50
51# Same as extract_major_version, but for the minor version number
52# $1: versioned named
53# Out: minor version
54#
55extract_minor_version ()
56{
57    local RET=$(extract_version $1 | cut -d . -f 2)
58    RET=${RET:-0}
59    echo $RET
60}
61
62# Compare two version numbers and only succeeds if the first one is
63# greather or equal than the second one.
64#
65# $1: first version (e.g. 4.9)
66# $2: second version (e.g. 4.8)
67#
68# Example: version_is_at_least 4.9 4.8 --> success
69#
70version_is_at_least ()
71{
72    local A_MAJOR A_MINOR B_MAJOR B_MINOR
73    A_MAJOR=$(extract_major_version $1)
74    B_MAJOR=$(extract_major_version $2)
75
76    if [ $A_MAJOR -lt $B_MAJOR ]; then
77        return 1
78    elif [ $A_MAJOR -gt $B_MAJOR ]; then
79        return 0
80    fi
81
82    # We have A_MAJOR == B_MAJOR here
83
84    A_MINOR=$(extract_minor_version $1)
85    B_MINOR=$(extract_minor_version $2)
86
87    if [ $A_MINOR -lt $B_MINOR ]; then
88        return 1
89    else
90        return 0
91    fi
92}
93
94#====================================================
95#
96#  UTILITY FUNCTIONS
97#
98#====================================================
99
100# Return the maximum length of a series of strings
101#
102# Usage:  len=`max_length <string1> <string2> ...`
103#
104max_length ()
105{
106    echo "$@" | tr ' ' '\n' | awk 'BEGIN {max=0} {len=length($1); if (len > max) max=len} END {print max}'
107}
108
109# Translate dashes to underscores
110# Usage:  str=`dashes_to_underscores <values>`
111dashes_to_underscores ()
112{
113    echo "$@" | tr '-' '_'
114}
115
116# Translate underscores to dashes
117# Usage: str=`underscores_to_dashes <values>`
118underscores_to_dashes ()
119{
120    echo "$@" | tr '_' '-'
121}
122
123# Translate commas to spaces
124# Usage: str=`commas_to_spaces <list>`
125commas_to_spaces ()
126{
127    echo "$@" | tr ',' ' '
128}
129
130# Translate spaces to commas
131# Usage: list=`spaces_to_commas <string>`
132spaces_to_commas ()
133{
134    echo "$@" | tr ' ' ','
135}
136
137# Remove trailing path of a path
138# $1: path
139remove_trailing_slash () {
140    echo ${1%%/}
141}
142
143# Reverse a file path directory
144# foo -> .
145# foo/bar -> ..
146# foo/bar/zoo -> ../..
147reverse_path ()
148{
149    local path cur item
150    path=${1%%/} # remove trailing slash
151    cur="."
152    if [ "$path" != "." ] ; then
153        for item in $(echo "$path" | tr '/' ' '); do
154            cur="../$cur"
155        done
156    fi
157    echo ${cur%%/.}
158}
159
160# test_reverse_path ()
161# {
162#     rr=`reverse_path $1`
163#     if [ "$rr" != "$2" ] ; then
164#         echo "ERROR: reverse_path '$1' -> '$rr' (expected '$2')"
165#     fi
166# }
167#
168# test_reverse_path . .
169# test_reverse_path ./ .
170# test_reverse_path foo ..
171# test_reverse_path foo/ ..
172# test_reverse_path foo/bar ../..
173# test_reverse_path foo/bar/ ../..
174# test_reverse_path foo/bar/zoo ../../..
175# test_reverse_path foo/bar/zoo/ ../../..
176
177# Sort a space-separated list and remove duplicates
178# $1+: slist
179# Output: new slist
180sort_uniq ()
181{
182    local RET
183    RET=$(echo "$@" | tr ' ' '\n' | sort -u)
184    echo $RET
185}
186
187# Return the list of all regular files under a given directory
188# $1: Directory path
189# Output: list of files, relative to $1
190list_files_under ()
191{
192    if [ -d "$1" ]; then
193        (cd $1 && find . -type f | sed -e "s!./!!" | sort -u)
194    else
195        echo ""
196    fi
197}
198
199# Returns all words in text that do not match any of the pattern
200# $1: pattern
201# $2: text
202filter_out ()
203{
204    local PATTERN="$1"
205    local TEXT="$2"
206    for pat in $PATTERN; do
207        pat=$"${pat//\//\\/}"
208        TEXT=$(echo $TEXT | sed -e 's/'$pat' //g' -e 's/'$pat'$//g')
209    done
210    echo $TEXT
211}
212
213# Assign a value to a variable
214# $1: Variable name
215# $2: Value
216var_assign ()
217{
218    eval $1=\"$2\"
219}
220
221#====================================================
222#
223#  OPTION PROCESSING
224#
225#====================================================
226
227# We recognize the following option formats:
228#
229#  -f
230#  --flag
231#
232#  -s<value>
233#  --setting=<value>
234#
235
236# NOTE: We translate '-' into '_' when storing the options in global variables
237#
238
239OPTIONS=""
240OPTION_FLAGS=""
241OPTION_SETTINGS=""
242
243# Set a given option attribute
244# $1: option name
245# $2: option attribute
246# $3: attribute value
247#
248option_set_attr ()
249{
250    eval OPTIONS_$1_$2=\"$3\"
251}
252
253# Get a given option attribute
254# $1: option name
255# $2: option attribute
256#
257option_get_attr ()
258{
259    echo `var_value OPTIONS_$1_$2`
260}
261
262# Register a new option
263# $1: option
264# $2: small abstract for the option
265# $3: optional. default value
266#
267register_option_internal ()
268{
269    optlabel=
270    optname=
271    optvalue=
272    opttype=
273    while [ -n "1" ] ; do
274        # Check for something like --setting=<value>
275        echo "$1" | grep -q -E -e '^--[^=]+=<.+>$'
276        if [ $? = 0 ] ; then
277            optlabel=`expr -- "$1" : '\(--[^=]*\)=.*'`
278            optvalue=`expr -- "$1" : '--[^=]*=\(<.*>\)'`
279            opttype="long_setting"
280            break
281        fi
282
283        # Check for something like --flag
284        echo "$1" | grep -q -E -e '^--[^=]+$'
285        if [ $? = 0 ] ; then
286            optlabel="$1"
287            opttype="long_flag"
288            break
289        fi
290
291        # Check for something like -f<value>
292        echo "$1" | grep -q -E -e '^-[A-Za-z0-9]<.+>$'
293        if [ $? = 0 ] ; then
294            optlabel=`expr -- "$1" : '\(-.\).*'`
295            optvalue=`expr -- "$1" : '-.\(<.+>\)'`
296            opttype="short_setting"
297            break
298        fi
299
300        # Check for something like -f
301        echo "$1" | grep -q -E -e '^-.$'
302        if [ $? = 0 ] ; then
303            optlabel="$1"
304            opttype="short_flag"
305            break
306        fi
307
308        echo "ERROR: Invalid option format: $1"
309        echo "       Check register_option call"
310        exit 1
311    done
312
313    log "new option: type='$opttype' name='$optlabel' value='$optvalue'"
314
315    optname=`dashes_to_underscores $optlabel`
316    OPTIONS="$OPTIONS $optname"
317    OPTIONS_TEXT="$OPTIONS_TEXT $1"
318    option_set_attr $optname label "$optlabel"
319    option_set_attr $optname otype "$opttype"
320    option_set_attr $optname value "$optvalue"
321    option_set_attr $optname text "$1"
322    option_set_attr $optname abstract "$2"
323    option_set_attr $optname default "$3"
324}
325
326# Register a new option with a function callback.
327#
328# $1: option
329# $2: name of function that will be called when the option is parsed
330# $3: small abstract for the option
331# $4: optional. default value
332#
333register_option ()
334{
335    local optname optvalue opttype optlabel
336    register_option_internal "$1" "$3" "$4"
337    option_set_attr $optname funcname "$2"
338}
339
340# Register a new option with a variable store
341#
342# $1: option
343# $2: name of variable that will be set by this option
344# $3: small abstract for the option
345#
346# NOTE: The current value of $2 is used as the default
347#
348register_var_option ()
349{
350    local optname optvalue opttype optlabel
351    register_option_internal "$1" "$3" "`var_value $2`"
352    option_set_attr $optname varname "$2"
353}
354
355
356MINGW=no
357DARWIN=no
358do_mingw_option ()
359{
360    if [ "$DARWIN" = "yes" ]; then
361        echo "Can not have both --mingw and --darwin"
362        exit 1
363    fi
364    MINGW=yes;
365}
366do_darwin_option ()
367{
368    if [ "$MINGW" = "yes" ]; then
369        echo "Can not have both --mingw and --darwin"
370        exit 1
371    fi
372    DARWIN=yes;
373}
374
375register_canadian_option ()
376{
377    if [ "$HOST_OS" = "linux" ] ; then
378        register_option "--mingw" do_mingw_option "Generate windows binaries on Linux."
379        register_option "--darwin" do_darwin_option "Generate darwin binaries on Linux."
380    fi
381}
382
383TRY64=no
384do_try64_option () { TRY64=yes; }
385
386register_try64_option ()
387{
388    register_option "--try-64" do_try64_option "Generate 64-bit binaries."
389}
390
391
392register_jobs_option ()
393{
394    NUM_JOBS=$BUILD_NUM_CPUS
395    register_var_option "-j<number>" NUM_JOBS "Use <number> parallel build jobs"
396}
397
398# Print the help, including a list of registered options for this program
399# Note: Assumes PROGRAM_PARAMETERS and PROGRAM_DESCRIPTION exist and
400#       correspond to the parameters list and the program description
401#
402print_help ()
403{
404    local opt text abstract default
405
406    echo "Usage: $PROGNAME [options] $PROGRAM_PARAMETERS"
407    echo ""
408    if [ -n "$PROGRAM_DESCRIPTION" ] ; then
409        echo "$PROGRAM_DESCRIPTION"
410        echo ""
411    fi
412    echo "Valid options (defaults are in brackets):"
413    echo ""
414
415    maxw=`max_length "$OPTIONS_TEXT"`
416    AWK_SCRIPT=`echo "{ printf \"%-${maxw}s\", \\$1 }"`
417    for opt in $OPTIONS; do
418        text=`option_get_attr $opt text | awk "$AWK_SCRIPT"`
419        abstract=`option_get_attr $opt abstract`
420        default=`option_get_attr $opt default`
421        if [ -n "$default" ] ; then
422            echo "  $text     $abstract [$default]"
423        else
424            echo "  $text     $abstract"
425        fi
426    done
427    echo ""
428}
429
430option_panic_no_args ()
431{
432    echo "ERROR: Option '$1' does not take arguments. See --help for usage."
433    exit 1
434}
435
436option_panic_missing_arg ()
437{
438    echo "ERROR: Option '$1' requires an argument. See --help for usage."
439    exit 1
440}
441
442extract_parameters ()
443{
444    local opt optname otype value name fin funcname
445    PARAMETERS=""
446    while [ -n "$1" ] ; do
447        # If the parameter does not begin with a dash
448        # it is not an option.
449        param=`expr -- "$1" : '^\([^\-].*\)$'`
450        if [ -n "$param" ] ; then
451            if [ -z "$PARAMETERS" ] ; then
452                PARAMETERS="$1"
453            else
454                PARAMETERS="$PARAMETERS $1"
455            fi
456            shift
457            continue
458        fi
459
460        while [ -n "1" ] ; do
461            # Try to match a long setting, i.e. --option=value
462            opt=`expr -- "$1" : '^\(--[^=]*\)=.*$'`
463            if [ -n "$opt" ] ; then
464                otype="long_setting"
465                value=`expr -- "$1" : '^--[^=]*=\(.*\)$'`
466                break
467            fi
468
469            # Try to match a long flag, i.e. --option
470            opt=`expr -- "$1" : '^\(--.*\)$'`
471            if [ -n "$opt" ] ; then
472                otype="long_flag"
473                value="yes"
474                break
475            fi
476
477            # Try to match a short setting, i.e. -o<value>
478            opt=`expr -- "$1" : '^\(-[A-Za-z0-9]\)..*$'`
479            if [ -n "$opt" ] ; then
480                otype="short_setting"
481                value=`expr -- "$1" : '^-.\(.*\)$'`
482                break
483            fi
484
485            # Try to match a short flag, i.e. -o
486            opt=`expr -- "$1" : '^\(-.\)$'`
487            if [ -n "$opt" ] ; then
488                otype="short_flag"
489                value="yes"
490                break
491            fi
492
493            echo "ERROR: Unknown option '$1'. Use --help for list of valid values."
494            exit 1
495        done
496
497        #echo "Found opt='$opt' otype='$otype' value='$value'"
498
499        name=`dashes_to_underscores $opt`
500        found=0
501        for xopt in $OPTIONS; do
502            if [ "$name" != "$xopt" ] ; then
503                continue
504            fi
505            # Check that the type is correct here
506            #
507            # This also allows us to handle -o <value> as -o<value>
508            #
509            xotype=`option_get_attr $name otype`
510            if [ "$otype" != "$xotype" ] ; then
511                case "$xotype" in
512                "short_flag")
513                    option_panic_no_args $opt
514                    ;;
515                "short_setting")
516                    if [ -z "$2" ] ; then
517                        option_panic_missing_arg $opt
518                    fi
519                    value="$2"
520                    shift
521                    ;;
522                "long_flag")
523                    option_panic_no_args $opt
524                    ;;
525                "long_setting")
526                    option_panic_missing_arg $opt
527                    ;;
528                esac
529            fi
530            found=1
531            break
532            break
533        done
534        if [ "$found" = "0" ] ; then
535            echo "ERROR: Unknown option '$opt'. See --help for usage."
536            exit 1
537        fi
538        # Set variable or launch option-specific function.
539        varname=`option_get_attr $name varname`
540        if [ -n "$varname" ] ; then
541            eval ${varname}=\"$value\"
542        else
543            eval `option_get_attr $name funcname` \"$value\"
544        fi
545        shift
546    done
547}
548
549do_option_help ()
550{
551    print_help
552    exit 0
553}
554
555VERBOSE=no
556VERBOSE2=no
557do_option_verbose ()
558{
559    if [ $VERBOSE = "yes" ] ; then
560        VERBOSE2=yes
561    else
562        VERBOSE=yes
563    fi
564}
565
566DRYRUN=no
567do_option_dryrun ()
568{
569    DRYRUN=yes
570}
571
572register_option "--help"          do_option_help     "Print this help."
573register_option "--verbose"       do_option_verbose  "Enable verbose mode."
574register_option "--dryrun"        do_option_dryrun   "Set to dryrun mode."
575
576#====================================================
577#
578#  TOOLCHAIN AND ABI PROCESSING
579#
580#====================================================
581
582# Determine optional variable value
583# $1: final variable name
584# $2: option variable name
585# $3: small description for the option
586fix_option ()
587{
588    if [ -n "$2" ] ; then
589        eval $1="$2"
590        log "Using specific $3: $2"
591    else
592        log "Using default $3: `var_value $1`"
593    fi
594}
595
596
597# If SYSROOT is empty, check that $1/$2 contains a sysroot
598# and set the variable to it.
599#
600# $1: sysroot path
601# $2: platform/arch suffix
602check_sysroot ()
603{
604    if [ -z "$SYSROOT" ] ; then
605        log "Probing directory for sysroot: $1/$2"
606        if [ -d $1/$2 ] ; then
607            SYSROOT=$1/$2
608        fi
609    fi
610}
611
612# Determine sysroot
613# $1: Option value (or empty)
614#
615fix_sysroot ()
616{
617    if [ -n "$1" ] ; then
618        eval SYSROOT="$1"
619        log "Using specified sysroot: $1"
620    else
621        SYSROOT_SUFFIX=$PLATFORM/arch-$ARCH
622        SYSROOT=
623        check_sysroot $NDK_DIR/platforms $SYSROOT_SUFFIX
624        check_sysroot $ANDROID_NDK_ROOT/platforms $SYSROOT_SUFFIX
625        check_sysroot `dirname $ANDROID_NDK_ROOT`/development/ndk/platforms $SYSROOT_SUFFIX
626
627        if [ -z "$SYSROOT" ] ; then
628            echo "ERROR: Could not find NDK sysroot path for $SYSROOT_SUFFIX."
629            echo "       Use --sysroot=<path> to specify one."
630            exit 1
631        fi
632    fi
633
634    if [ ! -f $SYSROOT/usr/include/stdlib.h ] ; then
635        echo "ERROR: Invalid sysroot path: $SYSROOT"
636        echo "       Use --sysroot=<path> to indicate a valid one."
637        exit 1
638    fi
639}
640
641# Check for the availability of a compatibility SDK in Darwin
642# this can be used to generate binaries compatible with either Tiger or
643# Leopard.
644#
645# $1: SDK root path
646# $2: Optional MacOS X minimum version (e.g. 10.5)
647DARWIN_MINVER=10.6
648check_darwin_sdk ()
649{
650    local MACSDK="$1"
651    local MINVER=$2
652
653    if [ -z "$MINVER" ] ; then
654        # expect SDK root path ended up with either MacOSX##.#.sdk or MacOSX##.#u.sdk
655        MINVER=${MACSDK##*MacOSX}
656        MINVER=${MINVER%%.sdk*}
657        if [ "$MINVER" = "10.4u" ]; then
658            MINVER=10.4
659        fi
660    fi
661    if [ -d "$MACSDK" ] ; then
662        HOST_CFLAGS=$HOST_CFLAGS" -isysroot $MACSDK -mmacosx-version-min=$MINVER -DMAXOSX_DEPLOYEMENT_TARGET=$MINVER"
663        HOST_LDFLAGS=$HOST_LDFLAGS" -Wl,-syslibroot,$MACSDK -mmacosx-version-min=$MINVER"
664        DARWIN_MINVER=$MINVER
665        return 0  # success
666    fi
667    return 1
668}
669
670# Probe Darwin SDK in specified diectory $DARWIN_SYSROOT, or
671# /Developer/SDKs/MacOSX10.6.sdk
672#
673probe_darwin_sdk ()
674{
675    if [ -n "$DARWIN_SYSROOT" ]; then
676        if check_darwin_sdk "$DARWIN_SYSROOT"; then
677            log "Use darwin sysroot $DARWIN_SYSROOT"
678        else
679            echo "darwin sysroot $DARWIN_SYSROOT is not valid"
680            exit 1
681        fi
682    elif check_darwin_sdk /Developer/SDKs/MacOSX10.6.sdk 10.6; then
683        log "Generating Snow Leopard-compatible binaries!"
684    else
685        local version=`sw_vers -productVersion`
686        log "Generating $version-compatible binaries!"
687    fi
688}
689
690handle_canadian_build ()
691{
692    HOST_EXE=
693    if [ "$MINGW" = "yes" -o "$DARWIN" = "yes" ] ; then
694        case $HOST_TAG in
695            linux-*)
696                ;;
697            *)
698                echo "ERROR: Can only enable --mingw or --darwin on Linux platforms !"
699                exit 1
700                ;;
701        esac
702        if [ "$MINGW" = "yes" ] ; then
703            # NOTE: Use x86_64-pc-mingw32msvc or i586-pc-mingw32msvc because wrappers are generated
704            #       using these names
705            if [ "$TRY64" = "yes" ]; then
706                ABI_CONFIGURE_HOST=x86_64-pc-mingw32msvc
707                HOST_TAG=windows-x86_64
708            else
709                ABI_CONFIGURE_HOST=i586-pc-mingw32msvc
710                HOST_TAG=windows
711            fi
712            HOST_OS=windows
713            HOST_EXE=.exe
714        else
715            if [ "$TRY64" = "yes" ]; then
716                ABI_CONFIGURE_HOST=x86_64-apple-darwin
717                HOST_TAG=darwin-x86_64
718            else
719                ABI_CONFIGURE_HOST=i686-apple-darwin
720                HOST_TAG=darwin-x86
721            fi
722            HOST_OS=darwin
723        fi
724    fi
725}
726
727# Find mingw toolchain
728#
729# Set MINGW_GCC to the found mingw toolchain
730#
731find_mingw_toolchain ()
732{
733    if [ "$DEBIAN_NAME" -a "$BINPREFIX" -a "$MINGW_GCC" ]; then
734        return
735    fi
736    # IMPORTANT NOTE: binutils 2.21 requires a cross toolchain named
737    # i585-pc-mingw32msvc-gcc, or it will fail its configure step late
738    # in the toolchain build. Note that binutils 2.19 can build properly
739    # with i585-mingw32mvsc-gcc, which is the name used by the 'mingw32'
740    # toolchain install on Debian/Ubuntu.
741    #
742    # To solve this dilemma, we create a wrapper toolchain named
743    # i586-pc-mingw32msvc-gcc that really calls i586-mingw32msvc-gcc,
744    # this works with all versions of binutils.
745    #
746    # We apply the same logic to the 64-bit Windows cross-toolchain
747    #
748    # Fedora note: On Fedora it's x86_64-w64-mingw32- or i686-w64-mingw32-
749    # On older Fedora it's 32-bit only and called i686-pc-mingw32-
750    # so we just add more prefixes to the list to check.
751    if [ "$HOST_ARCH" = "x86_64" -a "$TRY64" = "yes" ]; then
752        BINPREFIX=x86_64-pc-mingw32msvc-
753        BINPREFIXLST="x86_64-pc-mingw32msvc- x86_64-w64-mingw32- amd64-mingw32msvc-"
754        DEBIAN_NAME=mingw64
755    else
756        # we are trying 32 bit anyway, so forcing it to avoid build issues
757        force_32bit_binaries
758        BINPREFIX=i586-pc-mingw32msvc-
759        BINPREFIXLST="i586-pc-mingw32msvc- i686-pc-mingw32- i586-mingw32msvc- i686-w64-mingw32-"
760        DEBIAN_NAME=mingw32
761    fi
762
763    # Scan $BINPREFIXLST list to find installed mingw toolchain. It will be
764    # wrapped later with $BINPREFIX.
765    for i in $BINPREFIXLST; do
766        find_program MINGW_GCC ${i}gcc
767        if [ -n "$MINGW_GCC" ]; then
768            dump "Found mingw toolchain: $MINGW_GCC"
769            break
770        fi
771    done
772}
773
774# Check there is a working cross-toolchain installed.
775#
776# $1: install directory for mingw/darwin wrapper toolchain
777#
778prepare_canadian_toolchain ()
779{
780    if [ "$MINGW" != "yes" -a "$DARWIN" != "yes" ]; then
781        return
782    fi
783    CROSS_GCC=
784    if [ "$MINGW" = "yes" ]; then
785        find_mingw_toolchain
786        if [ -z "$MINGW_GCC" ]; then
787            echo "ERROR: Could not find in your PATH any of:"
788            for i in $BINPREFIXLST; do echo "   ${i}gcc"; done
789            echo "Please install the corresponding cross-toolchain and re-run this script"
790            echo "TIP: On Debian or Ubuntu, try: sudo apt-get install $DEBIAN_NAME"
791            exit 1
792        fi
793        CROSS_GCC=$MINGW_GCC
794    else
795        if [ -z "$DARWIN_TOOLCHAIN" ]; then
796            echo "Please set DARWIN_TOOLCHAIN to darwin cross-toolchain"
797            exit 1
798        fi
799        if [ ! -f "${DARWIN_TOOLCHAIN}-gcc" ]; then
800            echo "darwin cross-toolchain $DARWIN_TOOLCHAIN-gcc doesn't exist"
801            exit 1
802        fi
803        if [ "$HOST_ARCH" = "x86_64" -a "$TRY64" = "yes" ]; then
804            BINPREFIX=x86_64-apple-darwin-
805            DEBIAN_NAME=darwin64
806            HOST_CFLAGS=$HOST_CFLAGS" -m64"
807        else
808            force_32bit_binaries
809            BINPREFIX=i686-apple-darwin-
810            DEBIAN_NAME=darwin32
811            HOST_CFLAGS=$HOST_CFLAGS" -m32"
812        fi
813        CROSS_GCC=${DARWIN_TOOLCHAIN}-gcc
814        probe_darwin_sdk
815    fi
816
817    # Create a wrapper toolchain, and prepend its dir to our PATH
818    CROSS_WRAP_DIR="$1"/$DEBIAN_NAME-wrapper
819    rm -rf "$CROSS_WRAP_DIR"
820    mkdir -p "$CROSS_WRAP_DIR"
821
822    if [ "$DARWIN" = "yes" ] ; then
823        cat > "$CROSS_WRAP_DIR/sw_vers" <<EOF
824#!/bin/sh
825# Tiny utility for the real sw_vers some Makefiles need
826case \$1 in
827    -productVersion)
828        echo $DARWIN_MINVER
829        ;;
830    *)
831        echo "ERROR: Unknown switch \$1"
832        exit 1
833esac
834EOF
835    chmod 0755 "$CROSS_WRAP_DIR/sw_vers"
836    fi
837
838    DST_PREFIX=${CROSS_GCC%gcc}
839    if [ "$NDK_CCACHE" ]; then
840        DST_PREFIX="$NDK_CCACHE $DST_PREFIX"
841    fi
842    $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh --src-prefix=$BINPREFIX --dst-prefix="$DST_PREFIX" "$CROSS_WRAP_DIR" \
843        --cflags="$HOST_CFLAGS" --cxxflags="$HOST_CFLAGS" --ldflags="$HOST_LDFLAGS"
844    # generate wrappers for BUILD toolchain
845    # this is required for mingw/darwin build to avoid tools canadian cross configuration issues
846    # 32-bit BUILD toolchain
847    LEGACY_TOOLCHAIN_DIR="$ANDROID_NDK_ROOT/../prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8"
848    $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh --src-prefix=i386-linux-gnu- \
849            --cflags="-m32" --cxxflags="-m32" --ldflags="-m elf_i386" --asflags="--32" \
850            --dst-prefix="$LEGACY_TOOLCHAIN_DIR/bin/x86_64-linux-" "$CROSS_WRAP_DIR"
851    $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh --src-prefix=i386-pc-linux-gnu- \
852            --cflags="-m32" --cxxflags="-m32" --ldflags="-m elf_i386" --asflags="--32" \
853            --dst-prefix="$LEGACY_TOOLCHAIN_DIR/bin/x86_64-linux-" "$CROSS_WRAP_DIR"
854    # 64-bit BUILD toolchain.  libbfd is still built in 32-bit.
855    $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh --src-prefix=x86_64-linux-gnu- \
856            --dst-prefix="$LEGACY_TOOLCHAIN_DIR/bin/x86_64-linux-" "$CROSS_WRAP_DIR"
857    $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh --src-prefix=x86_64-pc-linux-gnu- \
858            --dst-prefix="$LEGACY_TOOLCHAIN_DIR/bin/x86_64-linux-" "$CROSS_WRAP_DIR"
859    fail_panic "Could not create $DEBIAN_NAME wrapper toolchain in $CROSS_WRAP_DIR"
860
861    export PATH=$CROSS_WRAP_DIR:$PATH
862    dump "Using $DEBIAN_NAME wrapper: $CROSS_WRAP_DIR/${BINPREFIX}gcc"
863}
864
865handle_host ()
866{
867    if [ "$TRY64" != "yes" ]; then
868        force_32bit_binaries  # to modify HOST_TAG and others
869        HOST_BITS=32
870    fi
871    handle_canadian_build
872}
873
874setup_ccache ()
875{
876    # Support for ccache compilation
877    # We can't use this here when building Windows/darwin binaries on Linux with
878    # binutils 2.21, because defining CC/CXX in the environment makes the
879    # configure script fail later
880    #
881    if [ "$NDK_CCACHE" -a "$MINGW" != "yes" -a "$DARWIN" != "yes" ]; then
882        NDK_CCACHE_CC=$CC
883        NDK_CCACHE_CXX=$CXX
884        # Unfortunately, we can just do CC="$NDK_CCACHE $CC" because some
885        # configure scripts are not capable of dealing with this properly
886        # E.g. the ones used to rebuild the GCC toolchain from scratch.
887        # So instead, use a wrapper script
888        CC=$NDK_BUILDTOOLS_ABSPATH/ndk-ccache-gcc.sh
889        CXX=$NDK_BUILDTOOLS_ABSPATH/ndk-ccache-g++.sh
890        export NDK_CCACHE_CC NDK_CCACHE_CXX
891        log "Using ccache compilation"
892        log "NDK_CCACHE_CC=$NDK_CCACHE_CC"
893        log "NDK_CCACHE_CXX=$NDK_CCACHE_CXX"
894    fi
895}
896
897prepare_common_build ()
898{
899    if [ "$MINGW" = "yes" -o "$DARWIN" = "yes" ]; then
900        if [ "$TRY64" = "yes" ]; then
901            HOST_BITS=64
902        else
903            HOST_BITS=32
904        fi
905        if [ "$MINGW" = "yes" ]; then
906            log "Generating $HOST_BITS-bit Windows binaries"
907        else
908            log "Generating $HOST_BITS-bit Darwin binaries"
909        fi
910        # Do *not* set CC and CXX when building the Windows/Darwin binaries in canadian build.
911        # Otherwise, the GCC configure/build script will mess that Canadian cross
912        # build in weird ways. Instead we rely on the toolchain detected or generated
913        # previously in prepare_canadian_toolchain.
914        unset CC CXX
915        return
916    fi
917
918    # On Linux, detect our legacy-compatible toolchain when in the Android
919    # source tree, and use it to force the generation of glibc-2.7 compatible
920    # binaries.
921    #
922    # We only do this if the CC variable is not defined to a given value
923    if [ -z "$CC" ]; then
924        LEGACY_TOOLCHAIN_DIR=
925        if [ "$HOST_OS" = "linux" ]; then
926            LEGACY_TOOLCHAIN_DIR="$ANDROID_NDK_ROOT/../prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8/bin"
927            LEGACY_TOOLCHAIN_PREFIX="$LEGACY_TOOLCHAIN_DIR/x86_64-linux-"
928        elif [ "$HOST_OS" = "darwin" ]; then
929            LEGACY_TOOLCHAIN_DIR="$ANDROID_NDK_ROOT/../prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1/bin"
930            LEGACY_TOOLCHAIN_PREFIX="$LEGACY_TOOLCHAIN_DIR/i686-apple-darwin10-"
931        fi
932        if [ -d "$LEGACY_TOOLCHAIN_DIR" ] ; then
933            log "Forcing generation of $HOST_OS binaries with legacy toolchain"
934            CC="${LEGACY_TOOLCHAIN_PREFIX}gcc"
935            CXX="${LEGACY_TOOLCHAIN_PREFIX}g++"
936        fi
937    fi
938
939    CC=${CC:-gcc}
940    CXX=${CXX:-g++}
941    STRIP=${STRIP:-strip}
942    case $HOST_TAG in
943        darwin-*)
944            probe_darwin_sdk
945            ;;
946    esac
947
948    # Force generation of 32-bit binaries on 64-bit systems.
949    # We used to test the value of $HOST_TAG for *-x86_64, but this is
950    # not sufficient on certain systems.
951    #
952    # For example, Snow Leopard can be booted with a 32-bit kernel, running
953    # a 64-bit userland, with a compiler that generates 64-bit binaries by
954    # default *even* though "gcc -v" will report --target=i686-apple-darwin10!
955    #
956    # So know, simply probe for the size of void* by performing a small runtime
957    # compilation test.
958    #
959    cat > $TMPC <<EOF
960    /* this test should fail if the compiler generates 64-bit machine code */
961    int test_array[1-2*(sizeof(void*) != 4)];
962EOF
963    log_n "Checking whether the compiler generates 32-bit binaries..."
964    log2 $CC $HOST_CFLAGS -c -o $TMPO $TMPC
965    $NDK_CCACHE $CC $HOST_CFLAGS -c -o $TMPO $TMPC >$TMPL 2>&1
966    if [ $? != 0 ] ; then
967        log "no"
968        if [ "$TRY64" != "yes" ]; then
969            # NOTE: We need to modify the definitions of CC and CXX directly
970            #        here. Just changing the value of CFLAGS / HOST_CFLAGS
971            #        will not work well with the GCC toolchain scripts.
972            CC="$CC -m32"
973            CXX="$CXX -m32"
974        fi
975    else
976        log "yes"
977        if [ "$TRY64" = "yes" ]; then
978            CC="$CC -m64"
979            CXX="$CXX -m64"
980        fi
981    fi
982
983    if [ "$TRY64" = "yes" ]; then
984        HOST_BITS=64
985    else
986        force_32bit_binaries  # to modify HOST_TAG and others
987        HOST_BITS=32
988    fi
989}
990
991prepare_host_build ()
992{
993    prepare_common_build
994
995    # Now deal with mingw or darwin
996    if [ "$MINGW" = "yes" -o "$DARWIN" = "yes" ]; then
997        handle_canadian_build
998        CC=$ABI_CONFIGURE_HOST-gcc
999        CXX=$ABI_CONFIGURE_HOST-g++
1000        CPP=$ABI_CONFIGURE_HOST-cpp
1001        LD=$ABI_CONFIGURE_HOST-ld
1002        AR=$ABI_CONFIGURE_HOST-ar
1003        AS=$ABI_CONFIGURE_HOST-as
1004        RANLIB=$ABI_CONFIGURE_HOST-ranlib
1005        STRIP=$ABI_CONFIGURE_HOST-strip
1006        export CC CXX CPP LD AR AS RANLIB STRIP
1007    fi
1008
1009    setup_ccache
1010}
1011
1012prepare_abi_configure_build ()
1013{
1014    # detect build tag
1015    case $HOST_TAG in
1016        linux-x86)
1017            ABI_CONFIGURE_BUILD=i386-linux-gnu
1018            ;;
1019        linux-x86_64)
1020            ABI_CONFIGURE_BUILD=x86_64-linux-gnu
1021            ;;
1022        darwin-x86)
1023            ABI_CONFIGURE_BUILD=i686-apple-darwin
1024            ;;
1025        darwin-x86_64)
1026            ABI_CONFIGURE_BUILD=x86_64-apple-darwin
1027            ;;
1028        windows)
1029            ABI_CONFIGURE_BUILD=i686-pc-cygwin
1030            ;;
1031        *)
1032            echo "ERROR: Unsupported HOST_TAG: $HOST_TAG"
1033            echo "Please update 'prepare_host_flags' in build/tools/prebuilt-common.sh"
1034            ;;
1035    esac
1036}
1037
1038prepare_target_build ()
1039{
1040    prepare_abi_configure_build
1041
1042    # By default, assume host == build
1043    ABI_CONFIGURE_HOST="$ABI_CONFIGURE_BUILD"
1044
1045    prepare_common_build
1046    HOST_GMP_ABI=$HOST_BITS
1047
1048    # Now handle the --mingw/--darwin flag
1049    if [ "$MINGW" = "yes" -o "$DARWIN" = "yes" ] ; then
1050        handle_canadian_build
1051        STRIP=$ABI_CONFIGURE_HOST-strip
1052        if [ "$MINGW" = "yes" ] ; then
1053            # It turns out that we need to undefine this to be able to
1054            # perform a canadian-cross build with mingw. Otherwise, the
1055            # GMP configure scripts will not be called with the right options
1056            HOST_GMP_ABI=
1057        fi
1058    fi
1059
1060    setup_ccache
1061}
1062
1063# $1: Toolchain name
1064#
1065parse_toolchain_name ()
1066{
1067    TOOLCHAIN=$1
1068    if [ -z "$TOOLCHAIN" ] ; then
1069        echo "ERROR: Missing toolchain name!"
1070        exit 1
1071    fi
1072
1073    ABI_CFLAGS_FOR_TARGET=
1074    ABI_CXXFLAGS_FOR_TARGET=
1075
1076    # Determine ABI based on toolchain name
1077    #
1078    case "$TOOLCHAIN" in
1079    arm-linux-androideabi-*)
1080        ARCH="arm"
1081        ABI="armeabi"
1082        ABI_CONFIGURE_TARGET="arm-linux-androideabi"
1083        ABI_CONFIGURE_EXTRA_FLAGS="--with-arch=armv5te"
1084        ;;
1085    arm-eabi-*)
1086        ARCH="arm"
1087        ABI="armeabi"
1088        ABI_CONFIGURE_TARGET="arm-eabi"
1089        ABI_CONFIGURE_EXTRA_FLAGS="--with-arch=armv5te --disable-gold --disable-libgomp"
1090        ;;
1091    aarch64-linux-android-*)
1092        ARCH="arm64"
1093        ABI="arm64-v8a"
1094        ABI_CONFIGURE_TARGET="aarch64-linux-android"
1095        ;;
1096    x86-*)
1097        ARCH="x86"
1098        ABI=$ARCH
1099        ABI_INSTALL_NAME="x86"
1100        ABI_CONFIGURE_TARGET="i686-linux-android"
1101        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
1102        # You can't really build these separately at the moment.
1103        ABI_CFLAGS_FOR_TARGET="-fPIC"
1104        ;;
1105    x86_64-*)
1106        ARCH="x86_64"
1107        ABI=$ARCH
1108        ABI_INSTALL_NAME="x86_64"
1109        ABI_CONFIGURE_TARGET="x86_64-linux-android"
1110        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
1111        # You can't really build these separately at the moment.
1112        ABI_CFLAGS_FOR_TARGET="-fPIC"
1113        ;;
1114    mipsel*)
1115        ARCH="mips"
1116        ABI=$ARCH
1117        ABI_INSTALL_NAME="mips"
1118        ABI_CONFIGURE_TARGET="mipsel-linux-android"
1119        # Set default to mips32
1120        ABI_CONFIGURE_EXTRA_FLAGS="--with-arch=mips32"
1121        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
1122        # You can't really build these separately at the moment.
1123        # Add -fpic, because MIPS NDK will need to link .a into .so.
1124        ABI_CFLAGS_FOR_TARGET="-fexceptions -fpic"
1125        ABI_CXXFLAGS_FOR_TARGET="-frtti -fpic"
1126        # Add --disable-fixed-point to disable fixed-point support
1127        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --disable-fixed-point"
1128        ;;
1129    mips64el*)
1130        ARCH="mips64"
1131        ABI=$ARCH
1132        ABI_INSTALL_NAME="mips64"
1133        ABI_CONFIGURE_TARGET="mips64el-linux-android"
1134        # Set default to mips64r6
1135        ABI_CONFIGURE_EXTRA_FLAGS="--with-arch=mips64r6"
1136        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
1137        # You can't really build these separately at the moment.
1138        # Add -fpic, because MIPS NDK will need to link .a into .so.
1139        ABI_CFLAGS_FOR_TARGET="-fexceptions -fpic"
1140        ABI_CXXFLAGS_FOR_TARGET="-frtti -fpic"
1141        # Add --disable-fixed-point to disable fixed-point support
1142        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --disable-fixed-point"
1143        ;;
1144    * )
1145        echo "Invalid toolchain specified. Expected (arm-linux-androideabi-*|arm-eabi-*|x86-*|mipsel*|mips64el*)"
1146        echo ""
1147        print_help
1148        exit 1
1149        ;;
1150    esac
1151
1152    log "Targetting CPU: $ARCH"
1153
1154    GCC_VERSION=`expr -- "$TOOLCHAIN" : '.*-\([0-9x\.]*\)'`
1155    log "Using GCC version: $GCC_VERSION"
1156
1157    # Determine --host value when building gdbserver
1158
1159    case "$TOOLCHAIN" in
1160    arm-*)
1161        GDBSERVER_HOST=arm-eabi-linux
1162        GDBSERVER_CFLAGS="-fno-short-enums"
1163        GDBSERVER_LDFLAGS=
1164        ;;
1165    aarch64-*)
1166        GDBSERVER_HOST=aarch64-eabi-linux
1167        GDBSERVER_CFLAGS="-fno-short-enums -DUAPI_HEADERS"
1168        GDBSERVER_LDFLAGS=
1169        ;;
1170    x86-*)
1171        GDBSERVER_HOST=i686-linux-android
1172        GDBSERVER_CFLAGS=
1173        GDBSERVER_LDFLAGS=
1174        ;;
1175    x86_64-*)
1176        GDBSERVER_HOST=x86_64-linux-android
1177        GDBSERVER_CFLAGS=-DUAPI_HEADERS
1178        GDBSERVER_LDFLAGS=
1179        ;;
1180    mipsel-*)
1181        GDBSERVER_HOST=mipsel-linux-android
1182        GDBSERVER_CFLAGS=
1183        GDBSERVER_LDFLAGS=
1184        ;;
1185    mips64el-*)
1186        GDBSERVER_HOST=mips64el-linux-android
1187        GDBSERVER_CFLAGS=-DUAPI_HEADERS
1188        GDBSERVER_LDFLAGS=
1189        ;;
1190    *)
1191        echo "Unknown TOOLCHAIN=$TOOLCHAIN"
1192        exit
1193    esac
1194}
1195
1196# Return the host "tag" used to identify prebuilt host binaries.
1197# NOTE: Handles the case where '$MINGW = true' or '$DARWIN = true'
1198# For now, valid values are: linux-x86, darwin-x86 and windows
1199get_prebuilt_host_tag ()
1200{
1201    local RET=$HOST_TAG
1202    if [ "$MINGW" = "yes" ]; then
1203        if [ "$TRY64" = "no" ]; then
1204            RET=windows
1205        else
1206            RET=windows-x86_64
1207        fi
1208    fi
1209    if [ "$DARWIN" = "yes" ]; then
1210        RET=darwin-x86_64  # let the following handles 32-bit case
1211    fi
1212    case $RET in
1213        linux-x86_64)
1214            if [ "$TRY64" = "no" ]; then
1215                RET=linux-x86
1216            fi
1217            ;;
1218        darwin-x86_64)
1219            if [ "$TRY64" = "no" ]; then
1220                RET=darwin-x86
1221            fi
1222            ;;
1223    esac
1224    echo $RET
1225}
1226
1227# Return the executable suffix corresponding to host executables
1228get_prebuilt_host_exe_ext ()
1229{
1230    if [ "$MINGW" = "yes" ]; then
1231        echo ".exe"
1232    else
1233        echo ""
1234    fi
1235}
1236
1237# Find all archs from $DEV_DIR/platforms or $NDK_DIR/platforms
1238# Return: the list of found arch name
1239find_ndk_archs ()
1240{
1241    local NDK_ROOT_DIR DEVDIR
1242    local RESULT FOUND_ARCHS
1243
1244    if [ ! -z "$NDK_DIR" ]; then
1245        NDK_ROOT_DIR=$NDK_DIR
1246    else
1247        NDK_ROOT_DIR=$ANDROID_NDK_ROOT
1248    fi
1249
1250    DEVDIR="$ANDROID_NDK_ROOT/../development/ndk"
1251
1252    # Check development directory first
1253    if [ -d $DEVDIR/platforms ]; then
1254        RESULT=$(ls $DEVDIR/platforms/android-* | grep "arch-")
1255        for arch in $RESULT; do
1256            arch=$(basename $arch | sed -e 's/^arch-//')
1257            FOUND_ARCHS="$FOUND_ARCHS $arch"
1258        done
1259    fi
1260
1261    # Check ndk directory
1262    if [ -z "$FOUND_ARCHS" ] && [ -d $NDK_ROOT_DIR/platforms ]; then
1263        RESULT=$(ls $NDK_ROOT_DIR/platforms/android-* | grep "arch-")
1264        for arch in $RESULT; do
1265            arch=$(basename $arch | sed -e 's/^arch-//')
1266            FOUND_ARCHS="$FOUND_ARCHS $arch"
1267        done
1268    fi
1269
1270    # If we cannot find any arch, set to default archs
1271    if [ -z "$FOUND_ARCHS" ]; then
1272        FOUND_ARCHS=$DEFAULT_ARCHS
1273    fi
1274
1275    echo "$(sort_uniq $FOUND_ARCHS)"
1276}
1277
1278# Find unknown archs from $NDK_DIR/platforms
1279# Return: arch names not in ndk default archs
1280find_ndk_unknown_archs()
1281{
1282    local FOUND_ARCHS=$(find_ndk_archs)
1283    # TODO: arm64, x86_64 is here just to be found as known arch.
1284    # It can be removed as soon as it is added into $DEFAULT_ARCHS
1285    echo "$(filter_out "$DEFAULT_ARCHS arm64 x86_64 mips64" "$FOUND_ARCHS")"
1286}
1287
1288# Determine whether given arch is in unknown archs list
1289# $1: arch
1290# Return: yes or no
1291arch_in_unknown_archs()
1292{
1293    local UNKNOWN_ARCH=$(find_ndk_unknown_archs | grep $1)
1294    if [ -z "$UNKNOWN_ARCH" ]; then
1295        echo "no"
1296    else
1297        echo "yes"
1298    fi
1299}
1300
1301# Get library suffix for given ABI
1302# $1: ABI
1303# Return: .so or .bc
1304get_lib_suffix_for_abi ()
1305{
1306    local ABI=$1
1307    if [ $(arch_in_unknown_archs $ABI) = "yes" ]; then
1308       echo ".bc"
1309    else
1310       echo ".so"
1311    fi
1312}
1313
1314# Convert an ABI name into an Architecture name
1315# $1: ABI name
1316# Result: Arch name
1317convert_abi_to_arch ()
1318{
1319    local RET
1320    local ABI=$1
1321    case $ABI in
1322        armeabi|armeabi-v7a|armeabi-v7a-hard)
1323            RET=arm
1324            ;;
1325        x86|mips|x86_64|mips64)
1326            RET=$ABI
1327            ;;
1328        mips32r6)
1329            RET=mips
1330            ;;
1331        arm64-v8a)
1332            RET=arm64
1333            ;;
1334        *)
1335            if [ "$(arch_in_unknown_archs $ABI)" = "yes" ]; then
1336                RET=$ABI
1337            else
1338                >&2 echo "ERROR: Unsupported ABI name: $ABI, use one of: armeabi, armeabi-v7a, x86, mips, armeabi-v7a-hard, arm64-v8a, x86_64 or mips64"
1339                exit 1
1340            fi
1341            ;;
1342    esac
1343    echo "$RET"
1344}
1345
1346# Take architecture name as input, and output the list of corresponding ABIs
1347# Inverse for convert_abi_to_arch
1348# $1: ARCH name
1349# Out: ABI names list (comma-separated)
1350convert_arch_to_abi ()
1351{
1352    local RET
1353    local ARCH=$1
1354    case $ARCH in
1355        arm)
1356            RET=armeabi,armeabi-v7a,armeabi-v7a-hard
1357            ;;
1358        x86|x86_64|mips|mips64)
1359            RET=$ARCH
1360            ;;
1361        arm64)
1362            RET=arm64-v8a
1363            ;;
1364        *)
1365            if [ "$(arch_in_unknown_archs $ARCH)" = "yes" ]; then
1366                RET=$ARCH
1367            else
1368                >&2 echo "ERROR: Unsupported ARCH name: $ARCH, use one of: arm, x86, mips"
1369                exit 1
1370            fi
1371            ;;
1372    esac
1373    echo "$RET"
1374}
1375
1376# Take a list of architecture names as input, and output the list of corresponding ABIs
1377# $1: ARCH names list (separated by spaces or commas)
1378# Out: ABI names list (comma-separated)
1379convert_archs_to_abis ()
1380{
1381    local RET
1382    for ARCH in $(commas_to_spaces $@); do
1383       ABI=$(convert_arch_to_abi $ARCH)
1384       if [ -n "$ABI" ]; then
1385          if [ -n "$RET" ]; then
1386             RET=$RET",$ABI"
1387          else
1388             RET=$ABI
1389          fi
1390       else   # Error message is printed by convert_arch_to_abi
1391          exit 1
1392       fi
1393    done
1394    echo "$RET"
1395}
1396
1397# Return the default toolchain binary path prefix for given architecture and gcc version
1398# For example: arm 4.8 -> toolchains/arm-linux-androideabi-4.8/prebuilt/<system>/bin/arm-linux-androideabi-
1399# $1: Architecture name
1400# $2: GCC version
1401# $3: optional, system name, defaults to $HOST_TAG
1402get_toolchain_binprefix_for_arch ()
1403{
1404    local NAME PREFIX DIR BINPREFIX
1405    local SYSTEM=${3:-$(get_prebuilt_host_tag)}
1406    NAME=$(get_toolchain_name_for_arch $1 $2)
1407    PREFIX=$(get_default_toolchain_prefix_for_arch $1)
1408    DIR=$(get_toolchain_install . $NAME $SYSTEM)
1409    BINPREFIX=${DIR#./}/bin/$PREFIX-
1410    echo "$BINPREFIX"
1411}
1412
1413# Return llvm toolchain binary path prefix for given llvm version
1414# $1: llvm version
1415# $2: optional, system name, defaults to $HOST_TAG
1416get_llvm_toolchain_binprefix ()
1417{
1418    local NAME DIR BINPREFIX
1419    local SYSTEM=${2:-$(get_prebuilt_host_tag)}
1420    NAME=llvm-$1
1421    DIR=$(get_toolchain_install . $NAME $SYSTEM)
1422    BINPREFIX=${DIR#./}/bin/
1423    echo "$BINPREFIX"
1424}
1425
1426# Return the default toochain binary path prefix for a given architecture
1427# For example: arm -> toolchains/arm-linux-androideabi-4.8/prebuilt/<system>/bin/arm-linux-androideabi-
1428# $1: Architecture name
1429# $2: optional, system name, defaults to $HOST_TAG
1430get_default_toolchain_binprefix_for_arch ()
1431{
1432    local GCCVER=$(get_default_gcc_version_for_arch $ARCH)
1433    get_toolchain_binprefix_for_arch $1 $GCCVER $2
1434}
1435
1436# Return default API level for a given arch
1437# This is the level used to build the toolchains.
1438#
1439# $1: Architecture name
1440get_default_api_level_for_arch ()
1441{
1442    # For unknown arch, use API level $FIRST_API64_LEVEL
1443    if [ $(arch_in_unknown_archs $1) = "yes" ]; then
1444        echo $FIRST_API64_LEVEL
1445    else
1446        # For now, always build the toolchain against API level 9 for 32-bit arch
1447        # and API level $FIRST_API64_LEVEL for 64-bit arch
1448        case $1 in
1449            *64) echo $FIRST_API64_LEVEL ;;
1450            *) echo 9 ;;
1451        esac
1452    fi
1453}
1454
1455# Return the default platform sysroot corresponding to a given architecture
1456# This is the sysroot used to build the toolchain and other binaries like
1457# the STLport libraries.
1458# $1: Architecture name
1459get_default_platform_sysroot_for_arch ()
1460{
1461    local ARCH=$1
1462    local LEVEL=$(get_default_api_level_for_arch $ARCH)
1463
1464    if [ "$ARCH" != "${ARCH%%64*}" ] ; then
1465        LEVEL=$FIRST_API64_LEVEL
1466    fi
1467    echo "platforms/android-$LEVEL/arch-$ARCH"
1468}
1469
1470# Return the default platform sysroot corresponding to a given abi
1471# $1: ABI
1472get_default_platform_sysroot_for_abi ()
1473{
1474    local ARCH=$(convert_abi_to_arch $1)
1475    $(get_default_platform_sysroot_for_arch $ARCH)
1476}
1477
1478# Return the default libs dir corresponding to a given architecture
1479# $1: Architecture name
1480get_default_libdir_for_arch ()
1481{
1482    case $1 in
1483      x86_64|mips64) echo "lib64" ;;
1484      arm64) echo "lib" ;; # return "lib" until aarch64 is built to look for sysroot/usr/lib64
1485      *) echo "lib" ;;
1486    esac
1487}
1488
1489# Return the default libs dir corresponding to a given abi
1490# $1: ABI
1491get_default_libdir_for_abi ()
1492{
1493    local ARCH
1494
1495    case $1 in
1496      mips32r6) echo "libr6" ;;
1497      *)
1498        local ARCH=$(convert_abi_to_arch $1)
1499        echo "$(get_default_libdir_for_arch $ARCH)"
1500        ;;
1501    esac
1502}
1503
1504# Return the host/build specific path for prebuilt toolchain binaries
1505# relative to $1.
1506#
1507# $1: target root NDK directory
1508# $2: toolchain name
1509# $3: optional, host system name
1510#
1511get_toolchain_install ()
1512{
1513    local NDK="$1"
1514    shift
1515    echo "$NDK/$(get_toolchain_install_subdir "$@")"
1516}
1517
1518# $1: toolchain name
1519# $2: optional, host system name
1520get_toolchain_install_subdir ()
1521{
1522    local SYSTEM=${2:-$(get_prebuilt_host_tag)}
1523    echo "toolchains/$1/prebuilt/$SYSTEM"
1524}
1525
1526# Return the relative install prefix for prebuilt host
1527# executables (relative to the NDK top directory).
1528# NOTE: This deals with MINGW==yes or DARWIN==yes appropriately
1529#
1530# $1: optional, system name
1531# Out: relative path to prebuilt install prefix
1532get_prebuilt_install_prefix ()
1533{
1534    local TAG=${1:-$(get_prebuilt_host_tag)}
1535    echo "prebuilt/$TAG"
1536}
1537
1538# Return the relative path of an installed prebuilt host
1539# executable
1540# NOTE: This deals with MINGW==yes or DARWIN==yes appropriately.
1541#
1542# $1: executable name
1543# $2: optional, host system name
1544# Out: path to prebuilt host executable, relative
1545get_prebuilt_host_exec ()
1546{
1547    local PREFIX EXE
1548    PREFIX=$(get_prebuilt_install_prefix $2)
1549    EXE=$(get_prebuilt_host_exe_ext)
1550    echo "$PREFIX/bin/$1$EXE"
1551}
1552
1553# Return the name of a given host executable
1554# $1: executable base name
1555# Out: executable name, with optional suffix (e.g. .exe for windows)
1556get_host_exec_name ()
1557{
1558    local EXE=$(get_prebuilt_host_exe_ext)
1559    echo "$1$EXE"
1560}
1561
1562# Return the directory where host-specific binaries are installed.
1563# $1: target root NDK directory
1564get_host_install ()
1565{
1566    echo "$1/$(get_prebuilt_install_prefix)"
1567}
1568
1569# Set the toolchain target NDK location.
1570# this sets TOOLCHAIN_PATH and TOOLCHAIN_PREFIX
1571# $1: target NDK path
1572# $2: toolchain name
1573set_toolchain_ndk ()
1574{
1575    TOOLCHAIN_PATH=`get_toolchain_install "$1" $2`
1576    log "Using toolchain path: $TOOLCHAIN_PATH"
1577
1578    TOOLCHAIN_PREFIX=$TOOLCHAIN_PATH/bin/$ABI_CONFIGURE_TARGET
1579    log "Using toolchain prefix: $TOOLCHAIN_PREFIX"
1580}
1581
1582# Check that a toolchain is properly installed at a target NDK location
1583#
1584# $1: target root NDK directory
1585# $2: toolchain name
1586#
1587check_toolchain_install ()
1588{
1589    TOOLCHAIN_PATH=`get_toolchain_install "$1" $2`
1590    if [ ! -d "$TOOLCHAIN_PATH" ] ; then
1591        echo "ERROR: Cannot find directory '$TOOLCHAIN_PATH'!"
1592        echo "       Toolchain '$2' not installed in '$NDK_DIR'!"
1593        echo "       Ensure that the toolchain has been installed there before."
1594        exit 1
1595    fi
1596
1597    set_toolchain_ndk $1 $2
1598}
1599
1600# $1: toolchain source directory
1601check_toolchain_src_dir ()
1602{
1603    local SRC_DIR="$1"
1604    if [ -z "$SRC_DIR" ]; then
1605        echo "ERROR: Please provide the path to the toolchain source tree. See --help"
1606        exit 1
1607    fi
1608
1609    if [ ! -d "$SRC_DIR" ]; then
1610        echo "ERROR: Not a directory: '$SRC_DIR'"
1611        exit 1
1612    fi
1613
1614    if [ ! -f "$SRC_DIR/build/configure" -o ! -d "$SRC_DIR/gcc" ]; then
1615        echo "ERROR: Either the file $SRC_DIR/build/configure or"
1616        echo "       the directory $SRC_DIR/gcc does not exist."
1617        echo "This is not the top of a toolchain tree: $SRC_DIR"
1618        echo "You must give the path to a copy of the toolchain source directories"
1619        echo "created by 'download-toolchain-sources.sh."
1620        exit 1
1621    fi
1622}
1623
1624#
1625# The NDK_TMPDIR variable is used to specify a root temporary directory
1626# when invoking toolchain build scripts. If it is not defined, we will
1627# create one here, and export the value to ensure that any scripts we
1628# call after that use the same one.
1629#
1630if [ -z "$NDK_TMPDIR" ]; then
1631    NDK_TMPDIR=/tmp/ndk-$USER/tmp/build-$$
1632    mkdir -p $NDK_TMPDIR
1633    if [ $? != 0 ]; then
1634        echo "ERROR: Could not create NDK_TMPDIR: $NDK_TMPDIR"
1635        exit 1
1636    fi
1637    export NDK_TMPDIR
1638fi
1639
1640# Define HOST_TAG32, as the 32-bit version of HOST_TAG
1641# We do this by replacing an -x86_64 suffix by -x86
1642HOST_TAG32=$HOST_TAG
1643case $HOST_TAG32 in
1644    *-x86_64)
1645        HOST_TAG32=${HOST_TAG%%_64}
1646        ;;
1647esac
1648