1# Copyright (C) 2008 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# This file is included by other shell scripts; do not execute it directly.
16# It contains common definitions.
17#
18PROGNAME=`basename $0`
19
20## Logging support
21##
22VERBOSE=yes
23VERBOSE2=no
24
25log ()
26{
27    if [ "$VERBOSE" = "yes" ] ; then
28        echo "$1"
29    fi
30}
31
32log2 ()
33{
34    if [ "$VERBOSE2" = "yes" ] ; then
35        echo "$1"
36    fi
37}
38
39## Utilities
40##
41
42# return the value of a given named variable
43# $1: variable name
44#
45var_value ()
46{
47    # find a better way to do that ?
48    local result
49    eval result="$`echo $1`"
50    echo $result
51}
52
53# convert to uppercase
54to_uppercase ()
55{
56    echo $1 | tr "[:lower:]" "[:upper:]"
57}
58
59## Normalize OS and CPU
60##
61
62CPU=`uname -m`
63case "$CPU" in
64    i?86) CPU=x86
65    ;;
66    amd64) CPU=x86_64
67    ;;
68    powerpc) CPU=ppc
69    ;;
70esac
71
72log2 "CPU=$CPU"
73
74# at this point, the supported values for CPU are:
75#   x86
76#   x86_64
77#   ppc
78#
79# other values may be possible but haven't been tested
80#
81
82EXE=""
83OS=`uname -s`
84case "$OS" in
85    Darwin)
86        OS=darwin-$CPU
87        ;;
88    Linux)
89        # note that building  32-bit binaries on x86_64 is handled later
90        OS=linux-$CPU
91	;;
92    FreeBSD)
93        OS=freebsd-$CPU
94        ;;
95    CYGWIN*|*_NT-*)
96        OS=windows
97        EXE=.exe
98        if [ "x$OSTYPE" = xcygwin ] ; then
99            OS=cygwin
100            HOST_CFLAGS="$CFLAGS -mno-cygwin"
101            HOST_LDFLAGS="$LDFLAGS -mno-cygwin"
102        fi
103        ;;
104esac
105
106log2 "OS=$OS"
107log2 "EXE=$EXE"
108
109# at this point, the value of OS should be one of the following:
110#   linux-x86
111#   linux-x86_64
112#   darwin-x86
113#   darwin-x86_64
114#   darwin-ppc
115#   windows  (MSys)
116#   cygwin
117#
118# Note that cygwin is treated as a special case because it behaves very differently
119# for a few things
120#
121# other values may be possible but have not been tested
122
123# define HOST_OS as $OS without any cpu-specific suffix
124#
125case $OS in
126    linux-*) HOST_OS=linux
127    ;;
128    darwin-*) HOST_OS=darwin
129    ;;
130    freebsd-*) HOST_OS=freebsd
131    ;;
132    *) HOST_OS=$OS
133esac
134
135# define HOST_ARCH as the $CPU
136HOST_ARCH=$CPU
137
138# define HOST_TAG
139# special case: windows-x86 => windows
140compute_host_tag ()
141{
142    case $HOST_OS-$HOST_ARCH in
143        cygwin-x86|windows-x86)
144            HOST_TAG=windows
145            ;;
146        *)
147            HOST_TAG=$HOST_OS-$HOST_ARCH
148            ;;
149    esac
150}
151compute_host_tag
152
153#### Toolchain support
154####
155
156# Various probes are going to need to run a small C program
157TMPC=/tmp/android-$$-test.c
158TMPO=/tmp/android-$$-test.o
159TMPE=/tmp/android-$$-test$EXE
160TMPL=/tmp/android-$$-test.log
161
162# cleanup temporary files
163clean_temp ()
164{
165    rm -f $TMPC $TMPO $TMPL $TMPE
166}
167
168# cleanup temp files then exit with an error
169clean_exit ()
170{
171    clean_temp
172    exit 1
173}
174
175# this function should be called to enforce the build of 32-bit binaries on 64-bit systems
176# that support it.
177FORCE_32BIT=no
178force_32bit_binaries ()
179{
180    if [ $CPU = x86_64 ] ; then
181        FORCE_32BIT=yes
182        case $OS in
183            linux-x86_64) OS=linux-x86 ;;
184            darwin-x86_64) OS=darwin-x86 ;;
185	    freebsd-x86_64) OS=freebsd-x86 ;;
186        esac
187        HOST_ARCH=x86
188        CPU=x86
189        compute_host_tag
190        log "Check32Bits: Forcing generation of 32-bit binaries (--try-64 to disable)"
191    fi
192}
193
194# Enable linux-mingw32 compilation. This allows you to build
195# windows executables on a Linux machine, which is considerably
196# faster than using Cygwin / MSys to do the same job.
197#
198enable_linux_mingw ()
199{
200    # Are we on Linux ?
201    log "Mingw      : Checking for Linux host"
202    if [ "$HOST_OS" != "linux" ] ; then
203        echo "Sorry, but mingw compilation is only supported on Linux !"
204        exit 1
205    fi
206    # Do we have the binaries installed
207    log "Mingw64    : Checking for mingw64 installation"
208    MINGW64_PREFIX=x86_64-w64-mingw32
209    find_program MINGW64_CC $MINGW64_PREFIX-gcc
210    if [ -n "$MINGW64_CC" ]; then
211        MINGW_CC=$MINGW64_CC
212        MINGW_PREFIX=$MINGW64_PREFIX
213    else
214    log "Mingw      : Checking for mingw32 installation"
215    MINGW32_PREFIX=i586-mingw32msvc
216    find_program MINGW32_CC $MINGW32_PREFIX-gcc
217    if [ -z "$MINGW32_CC" ] ; then
218            echo "ERROR: It looks like neither $MINGW64_PREFIX-cc nor $MINGW32_PREFIX-gcc"
219            echo "are in your path. Please install the mingw32 package !"
220        exit 1
221        fi
222        MINGW_CC=$MINGW32_CC
223        MINGW_PREFIX=$MINGW32_PREFIX
224        FORCE_32BIT=no
225    fi
226    log2 "Mingw      : Found $MINGW32_CC"
227    CC=$MINGW_CC
228    LD=$MINGW_CC
229    AR=$MINGW_PREFIX-ar
230}
231
232# Cygwin is normally not supported, unless you call this function
233#
234enable_cygwin ()
235{
236    if [ $OS = cygwin ] ; then
237        CFLAGS="$CFLAGS -mno-cygwin"
238        LDFLAGS="$LDFLAGS -mno-cygwin"
239        OS=windows
240        HOST_OS=windows
241    fi
242}
243
244# this function will setup the compiler and linker and check that they work as advertized
245# note that you should call 'force_32bit_binaries' before this one if you want it to work
246# as advertized.
247#
248setup_toolchain ()
249{
250    if [ "$OS" = cygwin ] ; then
251        echo "Do not compile this program or library with Cygwin, use MSYS instead !!"
252        echo "As an experimental feature, you can try to --try-cygwin option to override this"
253        exit 2
254    fi
255
256    if [ -z "$CC" ] ; then
257        CC=gcc
258        if [ $CPU = "powerpc" ] ; then
259            CC=gcc-3.3
260        fi
261    fi
262
263    # check that we can compile a trivial C program with this compiler
264    cat > $TMPC <<EOF
265int main(void) {}
266EOF
267
268    if [ $FORCE_32BIT = yes ] ; then
269        CFLAGS="$CFLAGS -m32"
270        LDFLAGS="$LDFLAGS -m32"
271        compile
272        if [ $? != 0 ] ; then
273            # sometimes, we need to also tell the assembler to generate 32-bit binaries
274            # this is highly dependent on your GCC installation (and no, we can't set
275            # this flag all the time)
276            CFLAGS="$CFLAGS -Wa,--32"
277        fi
278    fi
279
280    compile
281    if [ $? != 0 ] ; then
282        echo "your C compiler doesn't seem to work: $CC"
283        cat $TMPL
284        clean_exit
285    fi
286    log "CC         : compiler check ok ($CC)"
287
288    # check that we can link the trivial program into an executable
289    if [ -z "$LD" ] ; then
290        LD=$CC
291    fi
292    link
293    if [ $? != 0 ] ; then
294        echo "your linker doesn't seem to work:"
295        cat $TMPL
296        clean_exit
297    fi
298    log "LD         : linker check ok ($LD)"
299
300    if [ -z "$AR" ]; then
301        AR=ar
302    fi
303    log "AR         : archiver ($AR)"
304    clean_temp
305}
306
307# try to compile the current source file in $TMPC into an object
308# stores the error log into $TMPL
309#
310compile ()
311{
312    log2 "Object     : $CC -o $TMPO -c $CFLAGS $TMPC"
313    $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
314}
315
316# try to link the recently built file into an executable. error log in $TMPL
317#
318link()
319{
320    log2 "Link      : $LD -o $TMPE $TMPO $LDFLAGS"
321    $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL
322}
323
324# run a command
325#
326execute()
327{
328    log2 "Running: $*"
329    $*
330}
331
332# perform a simple compile / link / run of the source file in $TMPC
333compile_exec_run()
334{
335    log2 "RunExec    : $CC -o $TMPE $CFLAGS $TMPC"
336    compile
337    if [ $? != 0 ] ; then
338        echo "Failure to compile test program"
339        cat $TMPC
340        cat $TMPL
341        clean_exit
342    fi
343    link
344    if [ $? != 0 ] ; then
345        echo "Failure to link test program"
346        cat $TMPC
347        echo "------"
348        cat $TMPL
349        clean_exit
350    fi
351    $TMPE
352}
353
354## Feature test support
355##
356
357# Each feature test allows us to check against a single target-specific feature
358# We run the feature checks in a Makefile in order to be able to do them in
359# parallel, and we also have some cached values in our output directory, just
360# in case.
361#
362# check that a given C program in $TMPC can be compiled on the host system
363# $1: variable name which will be set to "yes" or "no" depending on result
364# you can define EXTRA_CFLAGS for extra C compiler flags
365# for convenience, this variable will be unset by the function
366#
367feature_check_compile ()
368{
369    local result_cc=yes
370    local OLD_CFLAGS
371    OLD_CFLAGS="$CFLAGS"
372    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
373    compile
374    if [ $? != 0 ] ; then
375        result_cc=no
376    fi
377    eval $1=$result_cc
378    EXTRA_CFLAGS=
379    CFLAGS=$OLD_CFLAGS
380}
381
382# check that a given C program $TMPC can be linked on the host system
383# $1: variable name which will be set to "yes" or "no" depending on result
384# you can define EXTRA_CFLAGS for extra C compiler flags
385# you can define EXTRA_LDFLAGS for extra linker flags
386# for convenience, these variables will be unset by the function
387#
388feature_check_link ()
389{
390    local result_cl=yes
391    local OLD_CFLAGS OLD_LDFLAGS
392    OLD_CFLAGS=$CFLAGS
393    OLD_LDFLAGS=$LDFLAGS
394    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
395    LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
396    compile
397    if [ $? != 0 ] ; then
398        result_cl=no
399    else
400        link
401        if [ $? != 0 ] ; then
402            result_cl=no
403        fi
404    fi
405    CFLAGS=$OLD_CFLAGS
406    LDFLAGS=$OLD_LDFLAGS
407    eval $1=$result_cl
408    clean_temp
409}
410
411# check that a given C header file exists on the host system
412# $1: variable name which will be set to "yes" or "no" depending on result
413# $2: header name
414#
415# you can define EXTRA_CFLAGS for extra C compiler flags
416# for convenience, this variable will be unset by the function.
417#
418feature_check_header ()
419{
420    local result_ch
421    log "HeaderCheck: $2"
422    echo "#include $2" > $TMPC
423    cat >> $TMPC <<EOF
424        int main(void) { return 0; }
425EOF
426    feature_check_compile result_ch
427    eval $1=$result_ch
428    #eval result=$`echo $1`
429    #log  "Host       : $1=$result_ch"
430    clean_temp
431}
432
433# run the test program that is in $TMPC and set its exit status
434# in the $1 variable.
435# you can define EXTRA_CFLAGS and EXTRA_LDFLAGS
436#
437feature_run_exec ()
438{
439    local run_exec_result
440    local OLD_CFLAGS="$CFLAGS"
441    local OLD_LDFLAGS="$LDFLAGS"
442    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
443    LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
444    compile_exec_run
445    run_exec_result=$?
446    CFLAGS="$OLD_CFLAGS"
447    LDFLAGS="$OLD_LDFLAGS"
448    eval $1=$run_exec_result
449    log "Host       : $1=$run_exec_result"
450    clean_temp
451}
452
453## Android build system auto-detection
454##
455
456# check whether we're running within the Android build system
457# sets the variable IN_ANDROID_BUILD to either "yes" or "no"
458#
459# in case of success, defines ANDROID_TOP to point to the top
460# of the Android source tree.
461#
462check_android_build ()
463{
464    unset ANDROID_TOP
465    IN_ANDROID_BUILD=no
466
467    if [ -z "$ANDROID_BUILD_TOP" ] ; then
468        return ;
469    fi
470
471    ANDROID_TOP=$ANDROID_BUILD_TOP
472    log "ANDROID_TOP found at $ANDROID_TOP"
473    # $ANDROID_TOP/config/envsetup.make is for the old tree layout
474    # $ANDROID_TOP/build/envsetup.sh is for the new one
475    ANDROID_CONFIG_MK=$ANDROID_TOP/build/core/config.mk
476    if [ ! -f $ANDROID_CONFIG_MK ] ; then
477        ANDROID_CONFIG_MK=$ANDROID_TOP/config/envsetup.make
478    fi
479    if [ ! -f $ANDROID_CONFIG_MK ] ; then
480        echo "Weird: Cannot find build system root defaulting to non-Android build"
481        unset ANDROID_TOP
482        return
483    fi
484    # normalize ANDROID_TOP, we don't want a trailing /
485    ANDROID_TOPDIR=`dirname $ANDROID_TOP`
486    if [ "$ANDROID_TOPDIR" != "." ] ; then
487        ANDROID_TOP=$ANDROID_TOPDIR/`basename $ANDROID_TOP`
488    fi
489    IN_ANDROID_BUILD=yes
490}
491
492# Get the value of an Android build variable as an absolute path.
493# you should only call this if IN_ANDROID_BUILD is "yes"
494#
495get_android_abs_build_var ()
496{
497   (cd $ANDROID_TOP && CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f $ANDROID_CONFIG_MK dumpvar-abs-$1)
498}
499
500# Locate the Android prebuilt directory for your os
501# you should only call this if IN_ANDROID_BUILD is "yes"
502#
503# This will set ANDROID_PREBUILT_HOST_TAG, ANDROID_PREBUILT and ANDROID_PREBUILTS
504#
505locate_android_prebuilt ()
506{
507    # locate prebuilt directory
508    ANDROID_PREBUILT_HOST_TAG=$OS
509    ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG  # AOSP still has it
510    ANDROID_PREBUILTS=$ANDROID_TOP/prebuilts/misc/$ANDROID_PREBUILT_HOST_TAG # AOSP does't have it yet
511    if [ ! -d $ANDROID_PREBUILT ] ; then
512        # this can happen when building on x86_64, or in AOSP
513        case $OS in
514            linux-x86_64)
515                ANDROID_PREBUILT_HOST_TAG=linux-x86
516                ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG
517                ;;
518            *)
519        esac
520        if [ ! -d $ANDROID_PREBUILT ] ; then
521            ANDROID_PREBUILT=
522        fi
523    fi
524    if [ ! -d $ANDROID_PREBUILTS ] ; then
525        # this can happen when building on x86_64
526        case $OS in
527            linux-x86_64)
528                ANDROID_PREBUILT_HOST_TAG=linux-x86
529                ANDROID_PREBUILTS=$ANDROID_TOP/prebuilts/misc/$ANDROID_PREBUILT_HOST_TAG
530                ;;
531            *)
532        esac
533        if [ ! -d $ANDROID_PREBUILTS ] ; then
534            ANDROID_PREBUILTS=
535        fi
536    fi
537    log "Prebuilt   : ANDROID_PREBUILT=$ANDROID_PREBUILT"
538    log "Prebuilts  : ANDROID_PREBUILTS=$ANDROID_PREBUILTS"
539}
540
541## Build configuration file support
542## you must define $config_mk before calling this function
543##
544## $1: Optional output directory.
545create_config_mk ()
546{
547    # create the directory if needed
548    local  config_dir
549    local out_dir=${1:-objs}
550    config_mk=${config_mk:-$out_dir/config.make}
551    config_dir=`dirname $config_mk`
552    mkdir -p $config_dir 2> $TMPL
553    if [ $? != 0 ] ; then
554        echo "Can't create directory for build config file: $config_dir"
555        cat $TMPL
556        clean_exit
557    fi
558
559    # re-create the start of the configuration file
560    log "Generate   : $config_mk"
561
562    echo "# This file was autogenerated by $PROGNAME. Do not edit !" > $config_mk
563    echo "OS          := $OS" >> $config_mk
564    echo "HOST_OS     := $HOST_OS" >> $config_mk
565    echo "HOST_ARCH   := $HOST_ARCH" >> $config_mk
566    echo "CC          := $CC" >> $config_mk
567    echo "LD          := $LD" >> $config_mk
568    echo "AR          := $AR" >> $config_mk
569    echo "CFLAGS      := $CFLAGS" >> $config_mk
570    echo "LDFLAGS     := $LDFLAGS" >> $config_mk
571    echo "HOST_CC     := $CC" >> $config_mk
572    echo "HOST_LD     := $LD" >> $config_mk
573    echo "HOST_AR     := $AR" >> $config_mk
574    echo "OBJS_DIR    := $out_dir" >> $config_mk
575}
576
577add_android_config_mk ()
578{
579    echo "" >> $config_mk
580    if [ $TARGET_ARCH = arm ] ; then
581    echo "TARGET_ARCH       := arm" >> $config_mk
582    fi
583    if [ $TARGET_ARCH = x86 ] ; then
584    echo "TARGET_ARCH       := x86" >> $config_mk
585    fi
586    echo "HOST_PREBUILT_TAG := $HOST_TAG" >> $config_mk
587    echo "PREBUILT          := $ANDROID_PREBUILT" >> $config_mk
588    echo "PREBUILTS         := $ANDROID_PREBUILTS" >> $config_mk
589}
590
591# Find pattern $1 in string $2
592# This is to be used in if statements as in:
593#
594#    if pattern_match <pattern> <string>; then
595#       ...
596#    fi
597#
598pattern_match ()
599{
600    echo "$2" | grep -q -E -e "$1"
601}
602
603# Find if a given shell program is available.
604# We need to take care of the fact that the 'which <foo>' command
605# may return either an empty string (Linux) or something like
606# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
607# to /dev/null for Cygwin
608#
609# $1: variable name
610# $2: program name
611#
612# Result: set $1 to the full path of the corresponding command
613#         or to the empty/undefined string if not available
614#
615find_program ()
616{
617    local PROG
618    PROG=`which $2 2>/dev/null`
619    if [ -n "$PROG" ] ; then
620        if pattern_match '^no ' "$PROG"; then
621            PROG=
622        fi
623    fi
624    eval $1="$PROG"
625}
626