aboutsummaryrefslogtreecommitdiffstats
path: root/android/build/common.sh
blob: c7235aea653f0944fe6ea415f8b92a2eb17a69dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This file is included by other shell scripts; do not execute it directly.
# It contains common definitions.
#
PROGNAME=`basename $0`

## Logging support
##
VERBOSE=yes
VERBOSE2=no

log ()
{
    if [ "$VERBOSE" = "yes" ] ; then
        echo "$1"
    fi
}

log2 ()
{
    if [ "$VERBOSE2" = "yes" ] ; then
        echo "$1"
    fi
}

## Utilities
##

# return the value of a given named variable
# $1: variable name
#
var_value ()
{
    # find a better way to do that ?
    local result
    eval result="$`echo $1`"
    echo $result
}

# convert to uppercase
to_uppercase ()
{
    echo $1 | tr "[:lower:]" "[:upper:]"
}

## Normalize OS and CPU
##

CPU=`uname -m`
case "$CPU" in
    i?86) CPU=x86
    ;;
    amd64) CPU=x86_64
    ;;
    powerpc) CPU=ppc
    ;;
esac

log2 "CPU=$CPU"

# at this point, the supported values for CPU are:
#   x86
#   x86_64
#   ppc
#
# other values may be possible but haven't been tested
#

EXE=""
OS=`uname -s`
case "$OS" in
    Darwin)
        OS=darwin-$CPU
        ;;
    Linux)
        # note that building  32-bit binaries on x86_64 is handled later
        OS=linux-$CPU
	;;
    FreeBSD)
        OS=freebsd-$CPU
        ;;
    CYGWIN*|*_NT-*)
        OS=windows
        EXE=.exe
        if [ "x$OSTYPE" = xcygwin ] ; then
            OS=cygwin
            HOST_CFLAGS="$CFLAGS -mno-cygwin"
            HOST_LDFLAGS="$LDFLAGS -mno-cygwin"
        fi
        ;;
esac

log2 "OS=$OS"
log2 "EXE=$EXE"

# at this point, the value of OS should be one of the following:
#   linux-x86
#   linux-x86_64
#   darwin-x86
#   darwin-ppc
#   windows  (MSys)
#   cygwin
#
# Note that cygwin is treated as a special case because it behaves very differently
# for a few things
#
# other values may be possible but have not been tested

# define HOST_OS as $OS without any cpu-specific suffix
#
case $OS in
    linux-*) HOST_OS=linux
    ;;
    darwin-*) HOST_OS=darwin
    ;;
    freebsd-*) HOST_OS=freebsd
    ;;
    *) HOST_OS=$OS
esac

# define HOST_ARCH as the $CPU
HOST_ARCH=$CPU

# define HOST_TAG
# special case: windows-x86 => windows
compute_host_tag ()
{
    case $HOST_OS-$HOST_ARCH in
        cygwin-x86|windows-x86)
            HOST_TAG=windows
            ;;
        *)
            HOST_TAG=$HOST_OS-$HOST_ARCH
            ;;
    esac
}
compute_host_tag

#### Toolchain support
####

# Various probes are going to need to run a small C program
TMPC=/tmp/android-$$-test.c
TMPO=/tmp/android-$$-test.o
TMPE=/tmp/android-$$-test$EXE
TMPL=/tmp/android-$$-test.log

# cleanup temporary files
clean_temp ()
{
    rm -f $TMPC $TMPO $TMPL $TMPE
}

# cleanup temp files then exit with an error
clean_exit ()
{
    clean_temp
    exit 1
}

# this function should be called to enforce the build of 32-bit binaries on 64-bit systems
# that support it.
FORCE_32BIT=no
force_32bit_binaries ()
{
    if [ $CPU = x86_64 ] ; then
        FORCE_32BIT=yes
        case $OS in
            linux-x86_64) OS=linux-x86 ;;
            darwin-x86_64) OS=darwin-x86 ;;
	    freebsd-x86_64) OS=freebsd-x86 ;;
        esac
        HOST_ARCH=x86
        CPU=x86
        compute_host_tag
        log "Check32Bits: Forcing generation of 32-bit binaries (--try-64 to disable)"
    fi
}

# Enable linux-mingw32 compilation. This allows you to build
# windows executables on a Linux machine, which is considerably
# faster than using Cygwin / MSys to do the same job.
#
enable_linux_mingw ()
{
    # Are we on Linux ?
    log "Mingw      : Checking for Linux host"
    if [ "$HOST_OS" != "linux" ] ; then
        echo "Sorry, but mingw compilation is only supported on Linux !"
        exit 1
    fi
    # Do we have the binaries installed
    log "Mingw      : Checking for mingw32 installation"
    MINGW32_PREFIX=i586-mingw32msvc
    find_program MINGW32_CC $MINGW32_PREFIX-gcc
    if [ -z "$MINGW32_CC" ] ; then
        echo "ERROR: It looks like $MINGW32_PREFIX-gcc is not in your path"
        echo "Please install the mingw32 package !"
        exit 1
    fi
    log2 "Mingw      : Found $MINGW32_CC"
    CC=$MINGW32_CC
    LD=$MINGW32_CC
    AR=$MINGW32_PREFIX-ar
    FORCE_32BIT=no
}

# Cygwin is normally not supported, unless you call this function
#
enable_cygwin ()
{
    if [ $OS = cygwin ] ; then
        CFLAGS="$CFLAGS -mno-cygwin"
        LDFLAGS="$LDFLAGS -mno-cygwin"
        OS=windows
        HOST_OS=windows
    fi
}

# this function will setup the compiler and linker and check that they work as advertized
# note that you should call 'force_32bit_binaries' before this one if you want it to work
# as advertized.
#
setup_toolchain ()
{
    if [ "$OS" = cygwin ] ; then
        echo "Do not compile this program or library with Cygwin, use MSYS instead !!"
        echo "As an experimental feature, you can try to --try-cygwin option to override this"
        exit 2
    fi

    if [ -z "$CC" ] ; then
        CC=gcc
        if [ $CPU = "powerpc" ] ; then
            CC=gcc-3.3
        fi
    fi

    # check that we can compile a trivial C program with this compiler
    cat > $TMPC <<EOF
int main(void) {}
EOF

    if [ $FORCE_32BIT = yes ] ; then
        CFLAGS="$CFLAGS -m32"
        LDFLAGS="$LDFLAGS -m32"
        compile
        if [ $? != 0 ] ; then
            # sometimes, we need to also tell the assembler to generate 32-bit binaries
            # this is highly dependent on your GCC installation (and no, we can't set
            # this flag all the time)
            CFLAGS="$CFLAGS -Wa,--32"
            compile
        fi
    fi

    compile
    if [ $? != 0 ] ; then
        echo "your C compiler doesn't seem to work: $CC"
        cat $TMPL
        clean_exit
    fi
    log "CC         : compiler check ok ($CC)"

    # check that we can link the trivial program into an executable
    if [ -z "$LD" ] ; then
        LD=$CC
    fi
    link
    if [ $? != 0 ] ; then
        OLD_LD=$LD
        LD=gcc
        compile
        link
        if [ $? != 0 ] ; then
            LD=$OLD_LD
            echo "your linker doesn't seem to work:"
            cat $TMPL
            clean_exit
        fi
    fi
    log "LD         : linker check ok ($LD)"

    if [ -z "$AR" ]; then
        AR=ar
    fi
    log "AR         : archiver ($AR)"
}

# try to compile the current source file in $TMPC into an object
# stores the error log into $TMPL
#
compile ()
{
    log2 "Object     : $CC -o $TMPO -c $CFLAGS $TMPC"
    $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
}

# try to link the recently built file into an executable. error log in $TMPL
#
link()
{
    log2 "Link      : $LD -o $TMPE $TMPO $LDFLAGS"
    $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL
}

# run a command
#
execute()
{
    log2 "Running: $*"
    $*
}

# perform a simple compile / link / run of the source file in $TMPC
compile_exec_run()
{
    log2 "RunExec    : $CC -o $TMPE $CFLAGS $TMPC"
    compile
    if [ $? != 0 ] ; then
        echo "Failure to compile test program"
        cat $TMPC
        cat $TMPL
        clean_exit
    fi
    link
    if [ $? != 0 ] ; then
        echo "Failure to link test program"
        cat $TMPC
        echo "------"
        cat $TMPL
        clean_exit
    fi
    $TMPE
}

## Feature test support
##

# Each feature test allows us to check against a single target-specific feature
# We run the feature checks in a Makefile in order to be able to do them in
# parallel, and we also have some cached values in our output directory, just
# in case.
#
# check that a given C program in $TMPC can be compiled on the host system
# $1: variable name which will be set to "yes" or "no" depending on result
# you can define EXTRA_CFLAGS for extra C compiler flags
# for convenience, this variable will be unset by the function
#
feature_check_compile ()
{
    local result_cc=yes
    local OLD_CFLAGS
    OLD_CFLAGS="$CFLAGS"
    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
    compile
    if [ $? != 0 ] ; then
        result_cc=no
    fi
    eval $1=$result_cc
    EXTRA_CFLAGS=
    CFLAGS=$OLD_CFLAGS
}

# check that a given C program $TMPC can be linked on the host system
# $1: variable name which will be set to "yes" or "no" depending on result
# you can define EXTRA_CFLAGS for extra C compiler flags
# you can define EXTRA_LDFLAGS for extra linker flags
# for convenience, these variables will be unset by the function
#
feature_check_link ()
{
    local result_cl=yes
    local OLD_CFLAGS OLD_LDFLAGS
    OLD_CFLAGS=$CFLAGS
    OLD_LDFLAGS=$LDFLAGS
    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
    LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
    compile
    if [ $? != 0 ] ; then
        result_cl=no
    else
        link
        if [ $? != 0 ] ; then
            result_cl=no
        fi
    fi
    CFLAGS=$OLD_CFLAGS
    LDFLAGS=$OLD_LDFLAGS
    eval $1=$result_cl
}

# check that a given C header file exists on the host system
# $1: variable name which will be set to "yes" or "no" depending on result
# $2: header name
#
# you can define EXTRA_CFLAGS for extra C compiler flags
# for convenience, this variable will be unset by the function.
#
feature_check_header ()
{
    local result_ch
    log "HeaderCheck: $2"
    echo "#include $2" > $TMPC
    cat >> $TMPC <<EOF
        int main(void) { return 0; }
EOF
    feature_check_compile result_ch
    eval $1=$result_ch
    #eval result=$`echo $1`
    #log  "Host       : $1=$result_ch"
}

# run the test program that is in $TMPC and set its exit status
# in the $1 variable.
# you can define EXTRA_CFLAGS and EXTRA_LDFLAGS
#
feature_run_exec ()
{
    local run_exec_result
    local OLD_CFLAGS="$CFLAGS"
    local OLD_LDFLAGS="$LDFLAGS"
    CFLAGS="$CFLAGS $EXTRA_CFLAGS"
    LDFLAGS="$LDFLAGS $EXTRA_LDFLAGS"
    compile_exec_run
    run_exec_result=$?
    CFLAGS="$OLD_CFLAGS"
    LDFLAGS="$OLD_LDFLAGS"
    eval $1=$run_exec_result
    log "Host       : $1=$run_exec_result"
}

## Android build system auto-detection
##

# check whether we're running within the Android build system
# sets the variable IN_ANDROID_BUILD to either "yes" or "no"
#
# in case of success, defines ANDROID_TOP to point to the top
# of the Android source tree.
#
check_android_build ()
{
    unset ANDROID_TOP
    IN_ANDROID_BUILD=no

    if [ -z "$ANDROID_BUILD_TOP" ] ; then
        return ;
    fi

    ANDROID_TOP=$ANDROID_BUILD_TOP
    log "ANDROID_TOP found at $ANDROID_TOP"
    # $ANDROID_TOP/config/envsetup.make is for the old tree layout
    # $ANDROID_TOP/build/envsetup.sh is for the new one
    ANDROID_CONFIG_MK=$ANDROID_TOP/build/core/config.mk
    if [ ! -f $ANDROID_CONFIG_MK ] ; then
        ANDROID_CONFIG_MK=$ANDROID_TOP/config/envsetup.make
    fi
    if [ ! -f $ANDROID_CONFIG_MK ] ; then
        echo "Weird: Cannot find build system root defaulting to non-Android build"
        unset ANDROID_TOP
        return
    fi
    # normalize ANDROID_TOP, we don't want a trailing /
    ANDROID_TOPDIR=`dirname $ANDROID_TOP`
    if [ "$ANDROID_TOPDIR" != "." ] ; then
        ANDROID_TOP=$ANDROID_TOPDIR/`basename $ANDROID_TOP`
    fi
    IN_ANDROID_BUILD=yes
}

# Get the value of an Android build variable as an absolute path.
# you should only call this if IN_ANDROID_BUILD is "yes"
#
get_android_abs_build_var ()
{
   (cd $ANDROID_TOP && CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core make -f $ANDROID_CONFIG_MK dumpvar-abs-$1)
}

# Locate the Android prebuilt directory for your os
# you should only call this if IN_ANDROID_BUILD is "yes"
#
# This will set ANDROID_PREBUILT_HOST_TAG, ANDROID_PREBUILT and ANDROID_PREBUILTS
#
locate_android_prebuilt ()
{
    # locate prebuilt directory
    ANDROID_PREBUILT_HOST_TAG=$OS
    ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG
    ANDROID_PREBUILTS=$ANDROID_TOP/prebuilts/misc/$ANDROID_PREBUILT_HOST_TAG
    if [ ! -d $ANDROID_PREBUILT ] ; then
        # this can happen when building on x86_64
        case $OS in
            linux-x86_64)
                ANDROID_PREBUILT_HOST_TAG=linux-x86
                ANDROID_PREBUILT=$ANDROID_TOP/prebuilt/$ANDROID_PREBUILT_HOST_TAG
                ;;
            *)
        esac
        if [ ! -d $ANDROID_PREBUILT ] ; then
            echo "Can't find the prebuilt directory $ANDROID_PREBUILT in Android build"
            exit 1
        fi
    fi
    if [ ! -d $ANDROID_PREBUILTS ] ; then
        # this can happen when building on x86_64
        case $OS in
            linux-x86_64)
                ANDROID_PREBUILT_HOST_TAG=linux-x86
                ANDROID_PREBUILTS=$ANDROID_TOP/prebuilts/misc/$ANDROID_PREBUILT_HOST_TAG
                ;;
            *)
        esac
        if [ ! -d $ANDROID_PREBUILTS ] ; then
            echo "Can't find the prebuilts directory $ANDROID_PREBUILTS in Android build"
            exit 1
        fi
    fi
    log "Prebuilt   : ANDROID_PREBUILT=$ANDROID_PREBUILT"
    log "Prebuilts  : ANDROID_PREBUILTS=$ANDROID_PREBUILTS"
}

## Build configuration file support
## you must define $config_mk before calling this function
##
create_config_mk ()
{
    # create the directory if needed
    local  config_dir
    config_mk=${config_mk:-objs/config.make}
    config_dir=`dirname $config_mk`
    mkdir -p $config_dir 2> $TMPL
    if [ $? != 0 ] ; then
        echo "Can't create directory for build config file: $config_dir"
        cat $TMPL
        clean_exit
    fi

    # re-create the start of the configuration file
    log "Generate   : $config_mk"

    echo "# This file was autogenerated by $PROGNAME. Do not edit !" > $config_mk
    echo "OS          := $OS" >> $config_mk
    echo "HOST_OS     := $HOST_OS" >> $config_mk
    echo "HOST_ARCH   := $HOST_ARCH" >> $config_mk
    echo "CC          := $CC" >> $config_mk
    echo "HOST_CC     := $CC" >> $config_mk
    echo "LD          := $LD" >> $config_mk
    echo "AR          := $AR" >> $config_mk
    echo "CFLAGS      := $CFLAGS" >> $config_mk
    echo "LDFLAGS     := $LDFLAGS" >> $config_mk
}

add_android_config_mk ()
{
    echo "" >> $config_mk
    if [ $TARGET_ARCH = arm ] ; then
    echo "TARGET_ARCH       := arm" >> $config_mk
    fi
    if [ $TARGET_ARCH = x86 ] ; then
    echo "TARGET_ARCH       := x86" >> $config_mk
    fi
    echo "HOST_PREBUILT_TAG := $HOST_TAG" >> $config_mk
    echo "PREBUILT          := $ANDROID_PREBUILT" >> $config_mk
    echo "PREBUILTS         := $ANDROID_PREBUILTS" >> $config_mk
}

# Find pattern $1 in string $2
# This is to be used in if statements as in:
#
#    if pattern_match <pattern> <string>; then
#       ...
#    fi
#
pattern_match ()
{
    echo "$2" | grep -q -E -e "$1"
}

# Find if a given shell program is available.
# We need to take care of the fact that the 'which <foo>' command
# may return either an empty string (Linux) or something like
# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
# to /dev/null for Cygwin
#
# $1: variable name
# $2: program name
#
# Result: set $1 to the full path of the corresponding command
#         or to the empty/undefined string if not available
#
find_program ()
{
    local PROG
    PROG=`which $2 2>/dev/null`
    if [ -n "$PROG" ] ; then
        if pattern_match '^no ' "$PROG"; then
            PROG=
        fi
    fi
    eval $1="$PROG"
}