1# Copyright (C) 2012 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15
16# A set of function shared by the 'build-host-xxxx.sh' scripts.
17# They are mostly related to building host libraries.
18#
19# NOTE: This script uses various prefixes:
20#
21#    BH_       Used for public macros
22#    bh_       Use for public functions
23#
24#    _BH_      Used for private macros
25#    _bh_      Used for private functions
26#
27# Callers should only rely on the public macros and functions defined here.
28#
29
30# List of macros defined by the functions here:
31#
32#   defined by 'bh_set_build_tag'
33#
34#   BH_BUILD_CONFIG     Generic GNU config triplet for build system
35#   BH_BUILD_OS         NDK system name
36#   BH_BUILD_ARCH       NDK arch name
37#   BH_BUILD_TAG        NDK system tag ($OS-$ARCH)
38#   BH_BUILD_BITS       build system bitness (32 or 64)
39#
40#   defined by 'bh_set_host_tag'
41#                          7
42#   BH_HOST_CONFIG
43#   BH_HOST_OS
44#   BH_HOST_ARCH
45#   BH_HOST_TAG
46#   BH_HOST_BITS
47#
48#   defined by 'bh_set_target_tag'
49#
50#   BH_TARGET_CONFIG
51#   BH_TARGET_OS
52#   BH_TARGET_ARCH
53#   BH_TARGET_TAG
54#   BH_TARGET_BITS
55#
56#
57
58
59# The values of HOST_OS/ARCH/TAG will be redefined during the build to
60# match those of the system the generated compiler binaries will run on.
61#
62# Save the original ones into BUILD_XXX variants, corresponding to the
63# machine where the build happens.
64#
65BH_BUILD_OS=$HOST_OS
66BH_BUILD_ARCH=$HOST_ARCH
67BH_BUILD_TAG=$HOST_TAG
68
69# Map an NDK system tag to an OS name
70# $1: system tag (e.g. linux-x86)
71# Out: system name (e.g. linux)
72bh_tag_to_os ()
73{
74    local RET
75    case $1 in
76        android-*) RET="android";;
77        linux-*) RET="linux";;
78        darwin-*) RET="darwin";;
79        windows|windows-*) RET="windows";;
80    esac
81    echo $RET
82}
83
84# Map an NDK system tag to an architecture name
85# $1: system tag (e.g. linux-x86)
86# Out: arch name (e.g. x86)
87bh_tag_to_arch ()
88{
89    local RET
90    case $1 in
91        *-arm) RET=arm;;
92        *-mips) RET=mips;;
93        windows|*-x86) RET=x86;;
94        *-x86_64) RET=x86_64;;
95    esac
96    echo $RET
97}
98
99# Map an NDK system tag to a bit number
100# $1: system tag (e.g. linux-x86)
101# Out: bit number (32 or 64)
102bh_tag_to_bits ()
103{
104    local RET
105    case $1 in
106        windows|*-x86|*-arm|*-mips) RET=32;;
107        *-x86_64) RET=64;;
108    esac
109    echo $RET
110}
111
112# Map an NDK system tag to the corresponding GNU configuration triplet.
113# $1: NDK system tag
114# Out: GNU configuration triplet
115bh_tag_to_config_triplet ()
116{
117    local RET
118    case $1 in
119        linux-x86) RET=i686-linux-gnu;;
120        linux-x86_64) RET=x86_64-linux-gnu;;
121        darwin-x86) RET=i686-apple-darwin;;
122        darwin-x86_64) RET=x86_64-apple-darwin;;
123        windows|windows-x86) RET=i586-pc-mingw32msvc;;
124        windows-x86_64) RET=x86_64-w64-mingw32;;
125        android-arm) RET=arm-linux-androideabi;;
126        android-x86) RET=i686-linux-android;;
127        android-mips) RET=mipsel-linux-android;;
128    esac
129    echo "$RET"
130}
131
132
133bh_set_build_tag ()
134{
135  BH_BUILD_OS=$(bh_tag_to_os $1)
136  BH_BUILD_ARCH=$(bh_tag_to_arch $1)
137  BH_BUILD_BITS=$(bh_tag_to_bits $1)
138  BH_BUILD_TAG=$BH_BUILD_OS-$BH_BUILD_ARCH
139  BH_BUILD_CONFIG=$(bh_tag_to_config_triplet $1)
140}
141
142# Set default BH_BUILD macros.
143bh_set_build_tag $HOST_TAG
144
145bh_set_host_tag ()
146{
147  BH_HOST_OS=$(bh_tag_to_os $1)
148  BH_HOST_ARCH=$(bh_tag_to_arch $1)
149  BH_HOST_BITS=$(bh_tag_to_bits $1)
150  BH_HOST_TAG=$BH_HOST_OS-$BH_HOST_ARCH
151  BH_HOST_CONFIG=$(bh_tag_to_config_triplet $1)
152}
153
154bh_set_target_tag ()
155{
156  BH_TARGET_OS=$(bh_tag_to_os $1)
157  BH_TARGET_ARCH=$(bh_tag_to_arch $1)
158  BH_TARGET_BITS=$(bh_tag_to_bits $1)
159  BH_TARGET_TAG=$BH_TARGET_OS-$BH_TARGET_ARCH
160  BH_TARGET_CONFIG=$(bh_tag_to_config_triplet $1)
161}
162
163bh_sort_systems_build_first ()
164{
165  local IN_SYSTEMS="$1"
166  local OUT_SYSTEMS
167  # Pull out the host if there
168  for IN_SYSTEM in $IN_SYSTEMS; do
169    if [ "$IN_SYSTEM" = "$BH_BUILD_TAG" ]; then
170        OUT_SYSTEMS=$IN_SYSTEM
171    fi
172  done
173  # Append the rest
174  for IN_SYSTEM in $IN_SYSTEMS; do
175    if [ ! "$IN_SYSTEM" = "$BH_BUILD_TAG" ]; then
176        OUT_SYSTEMS=$OUT_SYSTEMS" $IN_SYSTEM"
177    fi
178  done
179  echo $OUT_SYSTEMS
180}
181
182# $1 is the string to search for
183# $2... is the list to search in
184# Returns first, yes or no.
185bh_list_contains ()
186{
187  local SEARCH="$1"
188  shift
189  # For dash, this has to be split over 2 lines.
190  # Seems to be a bug with dash itself:
191  # https://bugs.launchpad.net/ubuntu/+source/dash/+bug/141481
192  local LIST
193  LIST=$@
194  local RESULT=first
195  # Pull out the host if there
196  for ELEMENT in $LIST; do
197    if [ "$ELEMENT" = "$SEARCH" ]; then
198      echo $RESULT
199      return 0
200    fi
201    RESULT=yes
202  done
203  echo no
204  return 1
205}
206
207
208# Use this function to enable/disable colored output
209# $1: 'true' or 'false'
210bh_set_color_mode ()
211{
212  local DO_COLOR=
213  case $1 in
214    on|enable|true) DO_COLOR=true
215    ;;
216  esac
217  if [ "$DO_COLOR" ]; then
218    _BH_COLOR_GREEN="\033[32m"
219    _BH_COLOR_PURPLE="\033[35m"
220    _BH_COLOR_CYAN="\033[36m"
221    _BH_COLOR_END="\033[0m"
222  else
223    _BH_COLOR_GREEN=
224    _BH_COLOR_PURPLE=
225    _BH_COLOR_CYAN=
226    _BH_COLOR_END=
227  fi
228}
229
230# By default, enable color mode
231bh_set_color_mode true
232
233# Pretty printing with colors!
234bh_host_text ()
235{
236    printf "[${_BH_COLOR_GREEN}${BH_HOST_TAG}${_BH_COLOR_END}]"
237}
238
239bh_toolchain_text ()
240{
241    printf "[${_BH_COLOR_PURPLE}${BH_TOOLCHAIN}${_BH_COLOR_END}]"
242}
243
244bh_target_text ()
245{
246    printf "[${_BH_COLOR_CYAN}${BH_TARGET_TAG}${_BH_COLOR_END}]"
247}
248
249bh_arch_text ()
250{
251    # Print arch name in cyan
252    printf "[${_BH_COLOR_CYAN}${BH_TARGET_ARCH}${_BH_COLOR_END}]"
253}
254
255_bh_extract_version ()
256{
257    echo $1 | tr '-' '\n' | tail -1
258}
259
260# Given an input string of the form <foo>-<bar>-<version>, where
261# <version> can be <major>.<minor>, extract <major>
262#
263# $1: versioned name (e.g. arm-linux-androideabi-4.4.3)
264# Out: major version (e.g. 4)
265#
266# Examples:  arm-linux-androideabi-4.4.3 -> 4
267#            gmp-0.81 -> 0
268#
269bh_extract_major_version ()
270{
271    local RET=$(_bh_extract_version $1 | cut -d . -f 1)
272    RET=${RET:-0}
273    echo $RET
274}
275
276# Same as extract_major_version, but for the minor version number
277# $1: versioned named
278# Out: minor version
279#
280bh_extract_minor_version ()
281{
282    local RET=$(_bh_extract_version $1 | cut -d . -f 2)
283    RET=${RET:-0}
284    echo $RET
285}
286
287# Compare two version numbers and only succeeds if the first one is
288# greather or equal than the second one.
289#
290# $1: first version (e.g. 4.4.3)
291# $2: second version (e.g. 4.6)
292#
293# Example: version_is_greater_than 4.6 4.4.3 --> success
294#
295bh_version_is_greater_than ()
296{
297    local A_MAJOR A_MINOR B_MAJOR B_MINOR
298    A_MAJOR=$(bh_extract_major_version $1)
299    B_MAJOR=$(bh_extract_major_version $2)
300
301    if [ $A_MAJOR -lt $B_MAJOR ]; then
302        return 1
303    elif [ $A_MAJOR -gt $B_MAJOR ]; then
304        return 0
305    fi
306
307    # We have A_MAJOR == B_MAJOR here
308
309    A_MINOR=$(bh_extract_minor_version $1)
310    B_MINOR=$(bh_extract_minor_version $2)
311
312    if [ $A_MINOR -lt $B_MINOR ]; then
313        return 1
314    else
315        return 0
316    fi
317}
318
319# Check that a given compiler generates code correctly
320#
321# This is to detect bad/broken toolchains, e.g. amd64-mingw32msvc
322# is totally broken on Ubuntu 10.10 and 11.04
323#
324# $1: compiler
325# $2: optional extra flags
326#
327bh_check_compiler ()
328{
329    local CC="$1"
330    local TMPC=/tmp/build-host-$USER-$$.c
331    local TMPE=${TMPC%%.c}
332    local TMPL=$TMPC.log
333    local RET
334    shift
335    cat > $TMPC <<EOF
336int main(void) { return 0; }
337EOF
338    log_n "Checking compiler code generation ($CC)... "
339    $CC -o $TMPE $TMPC "$@" >$TMPL 2>&1
340    RET=$?
341    rm -f $TMPC $TMPE $TMPL
342    if [ "$RET" = 0 ]; then
343        log "yes"
344    else
345        log "no"
346    fi
347    return $RET
348}
349
350
351# $1: toolchain install dir
352# $2: toolchain prefix, no trailing dash (e.g. arm-linux-androideabi)
353# $3: optional -m32 or -m64.
354_bh_try_host_fullprefix ()
355{
356    local PREFIX="$1/bin/$2"
357    shift; shift;
358    if [ -z "$HOST_FULLPREFIX" ]; then
359        local GCC="$PREFIX-gcc"
360        if [ -f "$GCC" ]; then
361            if bh_check_compiler "$GCC" "$@"; then
362                HOST_FULLPREFIX="${GCC%%gcc}"
363                dump "$(bh_host_text) Using host gcc: $GCC $@"
364            else
365                dump "$(bh_host_text) Ignoring broken host gcc: $GCC $@"
366            fi
367        fi
368    fi
369}
370
371# $1: host prefix, no trailing slash (e.g. i686-linux-android)
372# $2: optional compiler args (should be empty, -m32 or -m64)
373_bh_try_host_prefix ()
374{
375    local PREFIX="$1"
376    shift
377    if [ -z "$HOST_FULLPREFIX" ]; then
378        local GCC="$(which $PREFIX-gcc 2>/dev/null)"
379        if [ "$GCC" -a -e "$GCC" ]; then
380            if bh_check_compiler "$GCC" "$@"; then
381                HOST_FULLPREFIX=${GCC%%gcc}
382                dump "$(bh_host_text) Using host gcc: ${HOST_FULLPREFIX}gcc $@"
383            else
384                dump "$(bh_host_text) Ignoring broken host gcc: $GCC $@"
385            fi
386        fi
387    fi
388}
389
390# Used to determine the minimum possible Darwin version that a Darwin SDK
391# can target. This actually depends from the host architecture.
392# $1: Host architecture name
393# out: SDK version number (e.g. 10.4 or 10.5)
394_bh_darwin_arch_to_min_version ()
395{
396  if [ "$1" = "x86" ]; then
397    echo "10.4"
398  else
399    echo "10.5"
400  fi
401}
402
403# Use the check for the availability of a compatibility SDK in Darwin
404# this can be used to generate binaries compatible with either Tiger or
405# Leopard.
406#
407# $1: SDK root path
408# $2: Darwin compatibility minimum version
409_bh_check_darwin_sdk ()
410{
411    if [ -d "$1" -a -z "$HOST_CFLAGS" ] ; then
412        HOST_CFLAGS="-isysroot $1 -mmacosx-version-min=$2 -DMAXOSX_DEPLOYEMENT_TARGET=$2"
413        HOST_CXXFLAGS=$HOST_CFLAGS
414        HOST_LDFLAGS="-syslibroot $1 -mmacosx-version-min=$2"
415        dump "Generating $2-compatible binaries."
416        return 0  # success
417    fi
418    return 1
419}
420
421# Check that a given compiler generates 32 or 64 bit code.
422# $1: compiler full path (.e.g  /path/to/fullprefix-gcc)
423# $2: 32 or 64
424# $3: extract compiler flags
425# Return: success iff the compiler generates $2-bits code
426_bh_check_compiler_bitness ()
427{
428    local CC="$1"
429    local BITS="$2"
430    local TMPC=/tmp/build-host-gcc-bits-$USER-$$.c
431    local TMPL=$TMPC.log
432    local RET
433    shift; shift;
434    cat > $TMPC <<EOF
435/* this program will fail to compile if the compiler doesn't generate BITS-bits code */
436int tab[1-2*(sizeof(void*)*8 != BITS)];
437EOF
438    dump_n "$(bh_host_text) Checking that the compiler generates $BITS-bits code ($@)... "
439    $CC -c -DBITS=$BITS -o /dev/null $TMPC $HOST_CFLAGS "$@" > $TMPL 2>&1
440    RET=$?
441    rm -f $TMPC $TMPL
442    if [ "$RET" = 0 ]; then
443        dump "yes"
444    else
445        dump "no"
446    fi
447    return $RET
448}
449
450# This function probes the system to find the best toolchain or cross-toolchain
451# to build binaries that run on a given host system. After that, it generates
452# a wrapper toolchain under $2 with a prefix of ${BH_HOST_CONFIG}-
453# where $BH_HOST_CONFIG is a GNU configuration name.
454#
455# Important: this script might redefine $BH_HOST_CONFIG to a different value!
456#
457# $1: NDK system tag (e.g. linux-x86)
458#
459# The following can be defined, otherwise they'll be auto-detected and set.
460#
461#  DARWIN_MIN_VERSION   -> Darwmin minimum compatibility version
462#  DARWIN_SDK_VERSION   -> Darwin SDK version
463#
464# The following can be defined for extra features:
465#
466#  DARWIN_TOOLCHAIN     -> Path to Darwin cross-toolchain (cross-compile only).
467#  DARWIN_SYSROOT       -> Path to Darwin SDK sysroot (cross-compile only).
468#  NDK_CCACHE           -> Ccache binary to use to speed up rebuilds.
469#  ANDROID_NDK_ROOT     -> Top-level NDK directory, for automatic probing
470#                          of prebuilt platform toolchains.
471#
472_bh_select_toolchain_for_host ()
473{
474    local HOST_CFLAGS HOST_CXXFLAGS HOST_LDFLAGS HOST_FULLPREFIX DARWIN_ARCH
475    local DARWIN_ARCH DARWIN_SDK_SUBDIR
476
477    # We do all the complex auto-detection magic in the setup phase,
478    # then save the result in host-specific global variables.
479    #
480    # In the build phase, we will simply restore the values into the
481    # global HOST_FULLPREFIX / HOST_BUILD_DIR
482    # variables.
483    #
484
485    # Try to find the best toolchain to do that job, assuming we are in
486    # a full Android platform source checkout, we can look at the prebuilts/
487    # directory.
488    case $1 in
489        linux-x86)
490            # If possible, automatically use our custom toolchain to generate
491            # 32-bit executables that work on Ubuntu 8.04 and higher.
492            _bh_try_host_fullprefix "$(dirname $ANDROID_NDK_ROOT)/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" i686-linux
493            _bh_try_host_fullprefix "$(dirname $ANDROID_NDK_ROOT)/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.4.3" i686-linux
494            _bh_try_host_fullprefix "$(dirname $ANDROID_NDK_ROOT)/prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3" i686-linux
495            _bh_try_host_prefix i686-linux-gnu
496            _bh_try_host_prefix i686-linux
497            _bh_try_host_prefix x86_64-linux-gnu -m32
498            _bh_try_host_prefix x86_64-linux -m32
499            ;;
500
501        linux-x86_64)
502            # If possible, automaticaly use our custom toolchain to generate
503            # 64-bit executables that work on Ubuntu 8.04 and higher.
504            _bh_try_host_fullprefix "$(dirname $ANDROID_NDK_ROOT)/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" x86_64-linux
505            _bh_try_host_prefix x86_64-linux-gnu
506            _bh_try_host_prefix x84_64-linux
507            _bh_try_host_prefix i686-linux-gnu -m64
508            _bh_try_host_prefix i686-linux -m64
509            ;;
510
511        darwin-*)
512            DARWIN_ARCH=$(bh_tag_to_arch $1)
513            if [ -z "$DARWIN_MIN_VERSION" ]; then
514                DARWIN_MIN_VERSION=$(_bh_darwin_arch_to_min_version $DARWIN_ARCH)
515            fi
516            case $BH_BUILD_OS in
517                darwin)
518                    if [ "$DARWIN_SDK_VERSION" ]; then
519                        # Compute SDK subdirectory name
520                        case $DARWIN_SDK_VERSION in
521                            10.4) DARWIN_SDK_SUBDIR=$DARWIN_SDK.sdku;;
522                            *) DARWIN_SDK_SUBDIR=$DARWIN_SDK.sdk;;
523                        esac
524                        # Since xCode moved to the App Store the SDKs have been 'sandboxed' into the Xcode.app folder.
525                        _bh_check_darwin_sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX$DARWIN_SDK_SUBDIR $DARWIN_MIN_VERSION
526                        _bh_check_darwin_sdk /Developer/SDKs/MacOSX$DARWIN_SDK_SUBDIR $DARWIN_MIN_VERSION
527                    else
528                        # Since xCode moved to the App Store the SDKs have been 'sandboxed' into the Xcode.app folder.
529                        _bh_check_darwin_sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk $DARWIN_MIN_VERSION
530                        _bh_check_darwin_sdk /Developer/SDKs/MacOSX10.7.sdk  $DARWIN_MIN_VERSION
531                        _bh_check_darwin_sdk /Developer/SDKs/MacOSX10.6.sdk  $DARWIN_MIN_VERSION
532                        # NOTE: The 10.5.sdk on Lion is buggy and cannot build basic C++ programs
533                        #_bh_check_darwin_sdk /Developer/SDKs/MacOSX10.5.sdk  $DARWIN_ARCH
534                        # NOTE: The 10.4.sdku is not available anymore and could not be tested.
535                        #_bh_check_darwin_sdk /Developer/SDKs/MacOSX10.4.sdku $DARWIN_ARCH
536                    fi
537                    if [ -z "$HOST_CFLAGS" ]; then
538                        local version="$(sw_vers -productVersion)"
539                        log "Generating $version-compatible binaries!"
540                    fi
541                    ;;
542                *)
543                    if [ -z "$DARWIN_TOOLCHAIN" -o -z "$DARWIN_SYSROOT" ]; then
544                        dump "If you want to build Darwin binaries on a non-Darwin machine,"
545                        dump "Please define DARWIN_TOOLCHAIN to name it, and DARWIN_SYSROOT to point"
546                        dump "to the SDK. For example:"
547                        dump ""
548                        dump "   DARWIN_TOOLCHAIN=\"i686-apple-darwin11\""
549                        dump "   DARWIN_SYSROOT=\"~/darwin-cross/MacOSX10.7.sdk\""
550                        dump "   export DARWIN_TOOLCHAIN DARWIN_SYSROOT"
551                        dump ""
552                        exit 1
553                    fi
554                    _bh_check_darwin_sdk $DARWIN_SYSROOT $DARWIN_MIN_VERSION
555                    _bh_try_host_prefix "$DARWIN_TOOLCHAIN" -m$(bh_tag_to_bits $1) --sysroot "$DARWIN_SYSROOT"
556                    if [ -z "$HOST_FULLPREFIX" ]; then
557                        dump "It looks like $DARWIN_TOOLCHAIN-gcc is not in your path, or does not work correctly!"
558                        exit 1
559                    fi
560                    dump "Using darwin cross-toolchain: ${HOST_FULLPREFIX}gcc"
561                    ;;
562            esac
563            ;;
564
565        windows|windows-x86)
566            case $BH_BUILD_OS in
567                linux)
568                    # We favor these because they are more recent, and because
569                    # we have a script to rebuild them from scratch. See
570                    # build-mingw64-toolchain.sh.
571                    _bh_try_host_prefix x86_64-w64-mingw32 -m32
572                    _bh_try_host_prefix i686-w64-mingw32
573                    # Typically provided by the 'mingw32' package on Debian
574                    # and Ubuntu systems.
575                    _bh_try_host_prefix i586-mingw32msvc
576                    # Special note for Fedora: this distribution used
577                    # to have a mingw32-gcc package that provided a 32-bit
578                    # only cross-toolchain named i686-pc-mingw32.
579                    # Later versions of the distro now provide a new package
580                    # named mingw-gcc which provides i686-w64-mingw32 and
581                    # x86_64-w64-mingw32 instead.
582                    _bh_try_host_prefix i686-pc-mingw32
583                    if [ -z "$HOST_FULLPREFIX" ]; then
584                        dump "There is no Windows cross-compiler. Ensure that you"
585                        dump "have one of these installed and in your path:"
586                        dump "   x86_64-w64-mingw32-gcc  (see build-mingw64-toolchain.sh)"
587                        dump "   i686-w64-mingw32-gcc    (see build-mingw64-toolchain.sh)"
588                        dump "   i586-mingw32msvc-gcc    ('mingw32' Debian/Ubuntu package)"
589                        dump "   i686-pc-mingw32         (on Fedora)"
590                        dump ""
591                        exit 1
592                    fi
593                    # Adjust $HOST to match the toolchain to ensure proper builds.
594                    # I.e. chose configuration triplets that are known to work
595                    # with the gmp/mpfr/mpc/binutils/gcc configure scripts.
596                    case $HOST_FULLPREFIX in
597                        *-mingw32msvc-*|i686-pc-mingw32)
598                            BH_HOST_CONFIG=i586-pc-mingw32msvc
599                            ;;
600                        *)
601                            BH_HOST_CONFIG=i686-w64-mingw32msvc
602                            ;;
603                    esac
604                    ;;
605                *) panic "Sorry, this script only supports building windows binaries on Linux."
606                ;;
607            esac
608            HOST_CFLAGS=$HOST_CFLAGS" -D__USE_MINGW_ANSI_STDIO=1"
609            HOST_CXXFLAGS=$HOST_CXXFLAGS" -D__USE_MINGW_ANSI_STDIO=1"
610            ;;
611
612        windows-x86_64)
613            case $BH_BUILD_OS in
614                linux)
615                    # See comments above for windows-x86
616                    _bh_try_host_prefix x86_64-w64-mingw32
617                    _bh_try_host_prefix i686-w64-mingw32 -m64
618                    # Beware that this package is completely broken on many
619                    # versions of no vinegar Ubuntu (i.e. it fails at building trivial
620                    # programs).
621                    _bh_try_host_prefix amd64-mingw32msvc
622                    # There is no x86_64-pc-mingw32 toolchain on Fedora.
623                    if [ -z "$HOST_FULLPREFIX" ]; then
624                        dump "There is no Windows cross-compiler in your path. Ensure you"
625                        dump "have one of these installed and in your path:"
626                        dump "   x86_64-w64-mingw32-gcc  (see build-mingw64-toolchain.sh)"
627                        dump "   i686-w64-mingw32-gcc    (see build-mingw64-toolchain.sh)"
628                        dump "   amd64-mingw32msvc-gcc   (Debian/Ubuntu - broken until Ubuntu 11.10)"
629                        dump ""
630                        exit 1
631                    fi
632                    # See comment above for windows-x86
633                    case $HOST_FULLPREFIX in
634                        *-mingw32msvc*)
635                            # Actually, this has never been tested.
636                            BH_HOST=amd64-pc-mingw32msvc
637                            ;;
638                        *)
639                            BH_HOST=x86_64-w64-mingw32
640                            ;;
641                    esac
642                    ;;
643
644                *) panic "Sorry, this script only supports building windows binaries on Linux."
645                ;;
646            esac
647            HOST_CFLAGS=$HOST_CFLAGS" -D__USE_MINGW_ANSI_STDIO=1"
648            HOST_CXXFLAGS=$HOST_CXXFLAGS" -D__USE_MINGW_ANSI_STDIO=1"
649            ;;
650    esac
651
652    # Determine the default bitness of our compiler. It it doesn't match
653    # HOST_BITS, tries to see if it supports -m32 or -m64 to change it.
654    if ! _bh_check_compiler_bitness ${HOST_FULLPREFIX}gcc $BH_HOST_BITS; then
655        local TRY_CFLAGS
656        case $BH_HOST_BITS in
657            32) TRY_CFLAGS=-m32;;
658            64) TRY_CFLAGS=-m64;;
659        esac
660        if ! _bh_check_compiler_bitness ${HOST_FULLPREFIX}gcc $BH_HOST_BITS $TRY_CFLAGS; then
661            panic "Can't find a way to generate $BH_HOST_BITS binaries with this compiler: ${HOST_FULLPREFIX}gcc"
662        fi
663        HOST_CFLAGS=$HOST_CFLAGS" "$TRY_CFLAGS
664        HOST_CXXFLAGS=$HOST_CXXFLAGS" "$TRY_CFLAGS
665    fi
666
667    # Support for ccache, to speed up rebuilds.
668    DST_PREFIX=$HOST_FULLPREFIX
669    local CCACHE=
670    if [ "$NDK_CCACHE" ]; then
671        CCACHE="--ccache=$NDK_CCACHE"
672    fi
673
674    # We're going to generate a wrapper toolchain with the $HOST prefix
675    # i.e. if $HOST is 'i686-linux-gnu', then we're going to generate a
676    # wrapper toolchain named 'i686-linux-gnu-gcc' that will redirect
677    # to whatever HOST_FULLPREFIX points to, with appropriate modifier
678    # compiler/linker flags.
679    #
680    # This helps tremendously getting stuff to compile with the GCC
681    # configure scripts.
682    #
683    run mkdir -p "$BH_WRAPPERS_DIR" &&
684    run $NDK_BUILDTOOLS_PATH/gen-toolchain-wrapper.sh "$BH_WRAPPERS_DIR" \
685        --src-prefix="$BH_HOST_CONFIG-" \
686        --dst-prefix="$DST_PREFIX" \
687        --cflags="$HOST_CFLAGS" \
688        --cxxflags="$HOST_CXXFLAGS" \
689        --ldflags="$HOST_LDFLAGS" \
690        $CCACHE
691}
692
693
694# Setup the build directory, i.e. a directory where all intermediate
695# files will be placed.
696#
697# $1: Build directory. If empty, a random one will be selected.
698#
699# $2: Either 'preserve' or 'remove'. Indicates what to do of
700#     existing files in the build directory, if any.
701#
702# $3: Either 'release' or 'debug'. Compilation mode.
703#
704bh_setup_build_dir ()
705{
706    BH_BUILD_DIR="$1"
707    if [ -z "$BH_BUILD_DIR" ]; then
708        BH_BUILD_DIR=/tmp/ndk-$USER/buildhost
709    fi
710    mkdir -p "$BH_BUILD_DIR"
711    fail_panic "Could not create build directory: $BH_BUILD_DIR"
712
713    setup_default_log_file $BH_BUILD_DIR/build.log
714
715    if [ "$_BH_OPTION_FORCE" ]; then
716        rm -rf "$BH_BUILD_DIR"/*
717    fi
718
719    if [ "$_BH_OPTION_NO_STRIP" ]; then
720        BH_BUILD_MODE=debug
721    else
722        BH_BUILD_MODE=release
723    fi
724
725    # The directory that will contain our toolchain wrappers
726    BH_WRAPPERS_DIR=$BH_BUILD_DIR/toolchain-wrappers
727    rm -rf "$BH_WRAPPERS_DIR" && mkdir "$BH_WRAPPERS_DIR"
728    fail_panic "Could not create wrappers dir: $BH_WRAPPERS_DIR"
729
730    # The directory that will contain our timestamps
731    BH_STAMPS_DIR=$BH_BUILD_DIR/timestamps
732    mkdir -p "$BH_STAMPS_DIR"
733    fail_panic "Could not create timestamps dir"
734}
735
736# Call this before anything else to setup a few important variables that are
737# used consistently to build any host-specific binaries.
738#
739# $1: Host system name (e.g. linux-x86), this is the name of the host system
740#     where the generated GCC binaries will run, not the current machine's
741#     type (this one is in $ORIGINAL_HOST_TAG instead).
742#
743bh_setup_build_for_host ()
744{
745    local HOST_VARNAME=$(dashes_to_underscores $1)
746    local HOST_VAR=_BH_HOST_${HOST_VARNAME}
747
748    # Determine the host configuration triplet in $HOST
749    bh_set_host_tag $1
750
751    # Note: since _bh_select_toolchain_for_host can change the value of
752    # $BH_HOST_CONFIG, we need to save it in a variable to later get the
753    # correct one when this function is called again.
754    if [ -z "$(var_value ${HOST_VAR}_SETUP)" ]; then
755        _bh_select_toolchain_for_host $1
756        var_assign ${HOST_VAR}_CONFIG $BH_HOST_CONFIG
757        var_assign ${HOST_VAR}_SETUP true
758    else
759        BH_HOST_CONFIG=$(var_value ${HOST_VAR}_CONFIG)
760    fi
761}
762
763# This function is used to setup the build environment whenever we
764# generate host-specific binaries. You should call it before invoking
765# a configure script or make.
766#
767# It assume sthat bh_setup_build_for_host was called with the right
768# host system tag and wrappers directory.
769#
770bh_setup_host_env ()
771{
772    CC=$BH_HOST_CONFIG-gcc
773    CXX=$BH_HOST_CONFIG-g++
774    LD=$BH_HOST_CONFIG-ld
775    AR=$BH_HOST_CONFIG-ar
776    AS=$BH_HOST_CONFIG-as
777    RANLIB=$BH_HOST_CONFIG-ranlib
778    NM=$BH_HOST_CONFIG-nm
779    STRIP=$BH_HOST_CONFIG-strip
780    STRINGS=$BH_HOST_CONFIG-strings
781    export CC CXX LD AR AS RANLIB NM STRIP STRINGS
782
783    CFLAGS=
784    CXXFLAGS=
785    LDFLAGS=
786    case $BH_BUILD_MODE in
787        release)
788            CFLAGS="-O2 -Os -fomit-frame-pointer -s"
789            CXXFLAGS=$CFLAGS
790            ;;
791        debug)
792            CFLAGS="-O0 -g"
793            CXXFLAGS=$CFLAGS
794            ;;
795    esac
796    export CFLAGS CXXFLAGS LDFLAGS
797
798    export PATH=$BH_WRAPPERS_DIR:$PATH
799}
800
801_bh_option_no_color ()
802{
803    bh_set_color_mode off
804}
805
806# This function is used to register a few command-line options that
807# impact the build of host binaries. Call it before invoking
808# extract_parameters to add them automatically.
809#
810bh_register_options ()
811{
812    BH_HOST_SYSTEMS="$BH_BUILD_TAG"
813    register_var_option "--systems=<list>" BH_HOST_SYSTEMS "Build binaries that run on these systems."
814
815    _BH_OPTION_FORCE=
816    register_var_option "--force" _BH_OPTION_FORCE "Force rebuild."
817
818    _BH_OPTION_NO_STRIP=
819    register_var_option "--no-strip" _BH_OPTION_NO_STRIP "Don't strip generated binaries."
820
821    register_option "--no-color" _bh_option_no_color "Don't output colored text."
822
823    if [ "$HOST_OS" = darwin ]; then
824        DARWIN_SDK_VERSION=
825        register_var_option "--darwin-sdk-version=<version>" DARWIN_SDK "Select Darwin SDK version."
826
827        DARWIN_MIN_VERSION=
828        register_var_option "--darwin-min-version=<version>" DARWIN_MIN_VERSION "Select minimum OS X version of generated host toolchains."
829    fi
830}
831
832# Execute a given command if the corresponding timestamp hasn't been touched
833#
834# NOTE: The command is run in its own sub-shell to avoid environment
835#        contamination.
836#
837# $1: timestamps name
838# $2+: command
839bh_stamps_do ()
840{
841    local STAMP_NAME=$1
842    shift
843    if [ ! -f "$BH_STAMPS_DIR/$STAMP_NAME" ]; then
844        ("$@")
845        fail_panic
846        mkdir -p "$BH_STAMPS_DIR" && touch "$BH_STAMPS_DIR/$STAMP_NAME"
847    fi
848}
849
850# Return host tag with only translation that windows-x86 -> windows
851#
852# $1: host system tag
853install_dir_from_host_tag ()
854{
855    case $1 in
856        windows-x86)
857            echo "windows"
858            ;;
859        *)
860            echo "$1"
861            ;;
862    esac
863}
864
865# Return the build install directory of a given Python version
866#
867# $1: host system tag
868# $2: python version
869# The suffix of this has to match python_ndk_install_dir
870#  as I package them from the build folder, substituting
871#  the end part of python_build_install_dir matching
872#  python_ndk_install_dir with nothing.
873python_build_install_dir ()
874{
875    echo "$BH_BUILD_DIR/install/prebuilt/$(install_dir_from_host_tag $1)"
876}
877
878# Same as python_build_install_dir, but for the final NDK installation
879# directory. Relative to $NDK_DIR.
880#
881# $1: host system tag
882python_ndk_install_dir ()
883{
884    echo "prebuilt/$(install_dir_from_host_tag $1)"
885}
886