aboutsummaryrefslogtreecommitdiff
path: root/build/tools/gen-platforms.sh
blob: 49d4fd8ba2cbf1d8798d0d77d0b0979f3389727b (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
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
#!/bin/sh
#
# Copyright (C) 2011 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.
#
# gen-platforms.sh
#
# This tool is used when packaging a new release, or when developing
# the NDK itself. It will populate DST ($NDK/platforms by default)
# with the content of SRC ($NDK/../development/ndk/platforms/ by default).
#
# The idea is that the content of $SRC/android-N/ only contains stuff
# that is relevant to API level N, and not contain anything that is already
# provided by API level N-1, N-2, etc..
#
# More precisely, for each architecture A:
#  $SRC/android-N/include        --> $DST/android-N/arch-A/usr/include
#  $SRC/android-N/arch-A/include --> $DST/android-N/arch-A/usr/include
#  $SRC/android-N/arch-A/lib     --> $DST/android-N/arch-A/usr/lib
#
# Also, we generate on-the-fly shared dynamic libraries from list of symbols:
#
#  $SRC/android-N/arch-A/symbols --> $DST/android-N/arch-A/usr/lib
#
# Repeat after that for N+1, N+2, etc..
#

PROGDIR=$(dirname "$0")
. "$PROGDIR/prebuilt-common.sh"

# Return the list of platform supported from $1/platforms
# as a single space-separated sorted list of levels. (e.g. "3 4 5 8 9 14")
# $1: source directory
extract_platforms_from ()
{
    if [ -d "$1" ] ; then
        (cd "$1/platforms" && ls -d android-*) | sed -e "s!android-!!" | sort -g | tr '\n' ' '
    else
        echo ""
    fi
}

# Override tmp file to be predictable
TMPC=/tmp/ndk-$USER/tmp/tests/tmp-platform.c
TMPO=/tmp/ndk-$USER/tmp/tests/tmp-platform.o
TMPE=/tmp/ndk-$USER/tmp/tests/tmp-platform$EXE
TMPL=/tmp/ndk-$USER/tmp/tests/tmp-platform.log

SRCDIR="../development/ndk"
DSTDIR="$ANDROID_NDK_ROOT"

ARCHS=$(find_ndk_unknown_archs)
ARCHS="$DEFAULT_ARCHS $ARCHS"
PLATFORMS=`extract_platforms_from "$SRCDIR"`
NDK_DIR=$ANDROID_NDK_ROOT

OPTION_HELP=no
OPTION_PLATFORMS=
OPTION_SRCDIR=
OPTION_DSTDIR=
OPTION_SAMPLES=
OPTION_FAST_COPY=
OPTION_MINIMAL=
OPTION_ARCH=
OPTION_ABI=
OPTION_DEBUG_LIBS=
OPTION_OVERLAY=
OPTION_GCC_VERSION="default"
OPTION_LLVM_VERSION=$DEFAULT_LLVM_VERSION
PACKAGE_DIR=

VERBOSE=no
VERBOSE2=no

for opt do
  optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
  case "$opt" in
  --help|-h|-\?) OPTION_HELP=yes
  ;;
  --verbose)
    if [ "$VERBOSE" = "yes" ] ; then
        VERBOSE2=yes
    else
        VERBOSE=yes
    fi
    ;;
  --src-dir=*)
    OPTION_SRCDIR="$optarg"
    ;;
  --dst-dir=*)
    OPTION_DSTDIR="$optarg"
    ;;
  --ndk-dir=*)
    NDK_DIR=$optarg
    ;;
  --platform=*)
    OPTION_PLATFORM=$optarg
    ;;
  --arch=*)
    OPTION_ARCH=$optarg
    ;;
  --abi=*)  # We still support this for backwards-compatibility
    OPTION_ABI=$optarg
    ;;
  --samples)
    OPTION_SAMPLES=yes
    ;;
  --fast-copy)
    OPTION_FAST_COPY=yes
    ;;
  --minimal)
    OPTION_MINIMAL=yes
    ;;
  --package-dir=*)
    PACKAGE_DIR=$optarg
    ;;
  --debug-libs)
    OPTION_DEBUG_LIBS=true
    ;;
  --overlay)
    OPTION_OVERLAY=true
    ;;
  --gcc-version=*)
    OPTION_GCC_VERSION=$optarg
    ;;
  --llvm-version=*)
    OPTION_LLVM_VERSION=$optarg
    ;;
  *)
    echo "unknown option '$opt', use --help"
    exit 1
  esac
done

if [ $OPTION_HELP = "yes" ] ; then
    echo "Collect files from an Android NDK development tree and assemble"
    echo "the platform files appropriately into a final release structure."
    echo ""
    echo "options:"
    echo ""
    echo "  --help                Print this message"
    echo "  --verbose             Enable verbose messages"
    echo "  --src-dir=<path>      Source directory for development platform files [$SRCDIR]"
    echo "  --dst-dir=<path>      Destination directory [$DSTDIR]"
    echo "  --ndk-dir=<path>      Use toolchains from this NDK directory [$NDK_DIR]"
    echo "  --platform=<list>     List of API levels [$PLATFORMS]"
    echo "  --arch=<list>         List of CPU architectures [$ARCHS]"
    echo "  --minimal             Ignore samples, symlinks and generated shared libs."
    echo "  --fast-copy           Don't create symlinks, copy files instead"
    echo "  --samples             Also generate samples directories."
    echo "  --package-dir=<path>  Package platforms archive in specific path."
    echo "  --debug-libs          Also generate C source file for generated libraries."
    echo ""
    echo "Use the --minimal flag if you want to generate minimal sysroot directories"
    echo "that will be used to generate prebuilt toolchains. Otherwise, the script"
    echo "will require these toolchains to be pre-installed and will use them to"
    echo "generate shared system shared libraries from the symbol list files."
    exit 0
fi

if [ -n "$OPTION_SRCDIR" ] ; then
    SRCDIR="$OPTION_SRCDIR";
    if [ ! -d "$SRCDIR" ] ; then
        echo "ERROR: Source directory $SRCDIR does not exist !"
        exit 1
    fi
    if [ ! -d "$SRCDIR/platforms/android-3" ] ; then
        echo "ERROR: Invalid source directory: $SRCDIR"
        echo "Please make sure it contains platforms/android-3 etc..."
        exit 1
    fi
else
    SRCDIR=`dirname $ANDROID_NDK_ROOT`/development/ndk
    log "Using source directory: $SRCDIR"
fi

if [ -n "$OPTION_PLATFORM" ] ; then
    PLATFORMS=$(commas_to_spaces $OPTION_PLATFORM)
else
    # Build the list from the content of SRCDIR
    PLATFORMS=`extract_platforms_from "$SRCDIR"`
    log "Using platforms: $PLATFORMS"
fi

# Remove the android- prefix of any platform name
PLATFORMS=$(echo $PLATFORMS | tr ' ' '\n' | sed -e 's!^android-!!g' | tr '\n' ' ')

if [ -n "$OPTION_DSTDIR" ] ; then
    DSTDIR="$OPTION_DSTDIR"
else
    log "Using destination directory: $DSTDIR"
fi

# Handle architecture list
#
# We support both --arch and --abi for backwards compatibility reasons
# --arch is the new hotness, --abi is deprecated.
#
if [ -n "$OPTION_ARCH" ]; then
    OPTION_ARCH=$(commas_to_spaces $OPTION_ARCH)
fi

if [ -n "$OPTION_ABI" ] ; then
    echo "WARNING: --abi=<names> is deprecated. Use --arch=<names> instead!"
    OPTION_ABI=$(commas_to_spaces $OPTION_ABI)
    if [ -n "$OPTION_ARCH" -a "$OPTION_ARCH" != "$OPTION_ABI" ]; then
        echo "ERROR: You can't use both --abi and --arch with different values!"
        exit 1
    fi
    OPTION_ARCH=$OPTION_ABI
fi

if [ -n "$OPTION_ARCH" ] ; then
    ARCHS="$OPTION_ARCH"
fi
log "Using architectures: $(commas_to_spaces $ARCHS)"

log "Checking source platforms."
for PLATFORM in $PLATFORMS; do
    DIR="$SRCDIR/platforms/android-$PLATFORM"
    if [ ! -d $DIR ] ; then
        echo "ERROR: Directory missing: $DIR"
        echo "Please check your --platform=<list> option and try again."
        exit 2
    else
        log "  $DIR"
    fi
done

log "Checking source platform architectures."
BAD_ARCHS=
for ARCH in $ARCHS; do
    eval CHECK_$ARCH=no
done
for PLATFORM in $PLATFORMS; do
    for ARCH in $ARCHS; do
        DIR="$SRCDIR/platforms/android-$PLATFORM/arch-$ARCH"
        if [ -d $DIR ] ; then
            log "  $DIR"
            eval CHECK_$ARCH=yes
        fi
    done
done

if [ "$OPTION_MINIMAL" ]; then
    OPTION_SAMPLES=
    OPTION_FAST_COPY=yes
fi

BAD_ARCHS=
for ARCH in $ARCHS; do
    CHECK=`var_value CHECK_$ARCH`
    log "  $ARCH check: $CHECK"
    if [ "$CHECK" = no ] ; then
        if [ -z "$BAD_ARCHS" ] ; then
            BAD_ARCHS=$ARCH
        else
            BAD_ARCHS="$BAD_ARCHS $ARCH"
        fi
    fi
done

if [ -n "$BAD_ARCHS" ] ; then
    echo "ERROR: Source directory doesn't support these ARCHs: $BAD_ARCHS"
    exit 3
fi

# $1: source directory (relative to $SRCDIR)
# $2: destination directory (relative to $DSTDIR)
# $3: description of directory contents (e.g. "sysroot" or "samples")
copy_src_directory ()
{
    local SDIR="$SRCDIR/$1"
    local DDIR="$DSTDIR/$2"
    if [ -d "$SDIR" ] ; then
        log "Copying $3 from \$SRC/$1 to \$DST/$2."
        mkdir -p "$DDIR" && (cd "$SDIR" && 2>/dev/null tar chf - *) | (tar xf - -C "$DDIR")
        if [ $? != 0 ] ; then
            echo "ERROR: Could not copy $3 directory $SDIR into $DDIR !"
            exit 5
        fi
    fi
}

# $1: source dir
# $2: destination dir
# $3: reverse path
#
symlink_src_directory_inner ()
{
    local files file subdir rev
    mkdir -p "$DSTDIR/$2"
    rev=$3
    files=$(cd $DSTDIR/$1 && ls -1p)
    for file in $files; do
        if [ "$file" = "${file%%/}" ]; then
            log2 "Link \$DST/$2/$file --> $rev/$1/$file"
            ln -s $rev/$1/$file $DSTDIR/$2/$file
        else
            file=${file%%/}
            symlink_src_directory_inner "$1/$file" "$2/$file" "$rev/.."
        fi
    done
}
# Create a symlink-copy of directory $1 into $2
# This function is recursive.
#
# $1: source directory (relative to $SRCDIR)
# $2: destination directory (relative to $DSTDIR)
symlink_src_directory ()
{
    symlink_src_directory_inner "$1" "$2" "$(reverse_path $1)"
}

# Remove unwanted symbols
# $1: symbol file (one symbol per line)
# $2+: Input symbol list
# Out: Input symbol file, without any unwanted symbol listed by $1
remove_unwanted_symbols_from ()
{
  local SYMBOL_FILE="$1"
  shift
  if [ -f "$SYMBOL_FILE" ]; then
    echo "$@" | tr ' ' '\n' | grep -v -F -x -f $SYMBOL_FILE | tr '\n' ' '
  else
    echo "$@"
  fi
}

# Remove unwanted symbols from a library's functions list.
# $1: Architecture name
# $2: Library name (e.g. libc.so)
# $3+: Input symbol list
# Out: Input symbol list without any unwanted symbols.
remove_unwanted_function_symbols ()
{
  local ARCH LIBRARY SYMBOL_FILE
  ARCH=$1
  LIBRARY=$2
  shift; shift
  SYMBOL_FILE=$PROGDIR/unwanted-symbols/$ARCH/$LIBRARY.functions.txt
  remove_unwanted_symbols_from $SYMBOL_FILE "$@"
}

# Same as remove_unwanted_functions_symbols, but for variable names.
#
remove_unwanted_variable_symbols ()
{
  local ARCH LIBRARY SYMBOL_FILE
  ARCH=$1
  LIBRARY=$2
  shift; shift
  SYMBOL_FILE=$PROGDIR/unwanted-symbols/$ARCH/$LIBRARY.variables.txt
  remove_unwanted_symbols_from $SYMBOL_FILE "$@"
}

# $1: Architecture
# Out: compiler command
get_default_compiler_for_arch()
{
    local ARCH=$1
    local TOOLCHAIN_PREFIX EXTRA_CFLAGS CC GCC_VERSION

    if [ "$ARCH" = "${ARCH%%64*}" -a "$(arch_in_unknown_archs $ARCH)" = "yes" ]; then
        for TAG in $HOST_TAG $HOST_TAG32; do
            TOOLCHAIN_PREFIX="$NDK_DIR/$(get_llvm_toolchain_binprefix $OPTION_LLVM_VERSION $TAG)"
            CC="$TOOLCHAIN_PREFIX/clang"
            if [ -f "$CC" ]; then
                break;
            fi
        done
        EXTRA_CFLAGS=
    else
        if [ "$ARCH" = "mips" ]; then
            # Support for mips32r6 in the new multilib mipsel-* toolchain is only available from 4.9
            GCC_VERSION=4.9
        elif [ -n "$OPTION_GCC_VERSION" -a "$OPTION_GCC_VERSION" != "default" ]; then
            GCC_VERSION=$OPTION_GCC_VERSION
        else
            # By default we want to use the first gcc (currently 4.6) instead of the default (gcc4.8)
            # for best compatibility, at least before gcc4.6 (now deprecated) is removed from NDK package
            GCC_VERSION=$(get_first_gcc_version_for_arch $ARCH) # $(get_default_gcc_version_for_arch $ARCH)
        fi
        for TAG in $HOST_TAG $HOST_TAG32; do
            TOOLCHAIN_PREFIX="$NDK_DIR/$(get_toolchain_binprefix_for_arch $ARCH $GCC_VERSION $TAG)"
            TOOLCHAIN_PREFIX=${TOOLCHAIN_PREFIX%-}
            CC="$TOOLCHAIN_PREFIX-gcc"
            if [ -f "$CC" ]; then
                break;
            fi
        done
        EXTRA_CFLAGS=
    fi

    if [ ! -f "$CC" ]; then
        dump "ERROR: $ARCH toolchain not installed: $CC"
        dump "Important: Use the --minimal flag to use this script without generated system shared libraries."
        dump "This is generally useful when you want to generate the host cross-toolchain programs."
        exit 1
    fi
    echo "$CC $EXTRA_CFLAGS"
}

# $1: library name
# $2: functions list
# $3: variables list
# $4: destination file
# $5: compiler command
gen_shared_lib ()
{
    local LIBRARY=$1
    local FUNCS="$2"
    local VARS="$3"
    local DSTFILE="$4"
    local CC="$5"

    # Now generate a small C source file that contains similarly-named stubs
    echo "/* Auto-generated file, do not edit */" > $TMPC
    local func var
    for func in $FUNCS; do
        echo "void $func(void) {}" >> $TMPC
    done
    for var in $VARS; do
        echo "int $var = 0;" >> $TMPC
    done

    # Build it with our cross-compiler. It will complain about conflicting
    # types for built-in functions, so just shut it up.
    COMMAND="$CC -Wl,-shared,-Bsymbolic -Wl,-soname,$LIBRARY -nostdlib -o $TMPO $TMPC -Wl,--exclude-libs,libgcc.a"
    echo "## COMMAND: $COMMAND" > $TMPL
    $COMMAND 1>>$TMPL 2>&1
    if [ $? != 0 ] ; then
        dump "ERROR: Can't generate shared library for: $LIBNAME"
        dump "See the content of $TMPC and $TMPL for details."
        cat $TMPL | tail -10
        exit 1
    fi

    # Copy to our destination now
    local libdir=$(dirname "$DSTFILE")
    mkdir -p "$libdir" && rm -f "$DSTFILE" && cp -f $TMPO "$DSTFILE"
    if [ $? != 0 ] ; then
        dump "ERROR: Can't copy shared library for: $LIBNAME"
        dump "target location is: $DSTFILE"
        exit 1
    fi

    if [ "$OPTION_DEBUG_LIBS" ]; then
      cp $TMPC $DSTFILE.c
      echo "$FUNCS" | tr ' ' '\n' > $DSTFILE.functions.txt
      echo "$VARS" | tr ' ' '\n' > $DSTFILE.variables.txt
    fi
}

# $1: Architecture
# $2: symbol source directory (relative to $SRCDIR)
# $3: destination directory for generated libs (relative to $DSTDIR)
# $4: compiler flags (optional)
gen_shared_libraries ()
{
    local ARCH=$1
    local SYMDIR="$SRCDIR/$2"
    local DSTDIR="$DSTDIR/$3"
    local FLAGS="$4"
    local CC funcs vars numfuncs numvars

    # Let's locate the toolchain we're going to use
    CC=$(get_default_compiler_for_arch $ARCH)" $FLAGS"
    if [ $? != 0 ]; then
        echo $CC
        exit 1
    fi

    # In certain cases, the symbols directory doesn't exist,
    # e.g. on x86 for PLATFORM < 9
    if [ ! -d "$SYMDIR" ]; then
        return
    fi

    # Let's list the libraries we're going to generate
    LIBS=$( (cd $SYMDIR && 2>/dev/null ls *.functions.txt) | sort -u | sed -e 's!\.functions\.txt$!!g')

    for LIB in $LIBS; do
        funcs=$(cat "$SYMDIR/$LIB.functions.txt" 2>/dev/null)
        vars=$(cat "$SYMDIR/$LIB.variables.txt" 2>/dev/null)
        funcs=$(remove_unwanted_function_symbols $ARCH libgcc.a $funcs)
        funcs=$(remove_unwanted_function_symbols $ARCH $LIB $funcs)
        vars=$(remove_unwanted_variable_symbols $ARCH libgcc.a $vars)
        vars=$(remove_unwanted_variable_symbols $ARCH $LIB $vars)
        numfuncs=$(echo $funcs | wc -w)
        numvars=$(echo $vars | wc -w)
        log "Generating $ARCH shared library for $LIB ($numfuncs functions + $numvars variables)"

        gen_shared_lib $LIB "$funcs" "$vars" "$DSTDIR/$LIB" "$CC"
    done
}

# $1: platform number
# $2: architecture name
# $3: common source directory (for crtbrand.c, etc)
# $4: source directory (for *.S files)
# $5: destination directory
# $6: flags for compiler (optional)
gen_crt_objects ()
{
    local API=$1
    local ARCH=$2
    local COMMON_SRC_DIR="$SRCDIR/$3"
    local SRC_DIR="$SRCDIR/$4"
    local DST_DIR="$DSTDIR/$5"
    local FLAGS="$6"
    local SRC_FILE DST_FILE
    local CC

    if [ ! -d "$SRC_DIR" ]; then
        return
    fi

    # Let's locate the toolchain we're going to use
    CC=$(get_default_compiler_for_arch $ARCH)" $FLAGS"
    if [ $? != 0 ]; then
        echo $CC
        exit 1
    fi

    CRTBRAND_S=$DST_DIR/crtbrand.s
    log "Generating platform $API crtbrand assembly code: $CRTBRAND_S"
    (cd "$COMMON_SRC_DIR" && mkdir -p `dirname $CRTBRAND_S` && $CC -DPLATFORM_SDK_VERSION=$API -fpic -S -o - crtbrand.c | \
        sed -e '/\.note\.ABI-tag/s/progbits/note/' > "$CRTBRAND_S") 1>>$TMPL 2>&1
    if [ $? != 0 ]; then
        dump "ERROR: Could not generate $CRTBRAND_S from $COMMON_SRC_DIR/crtbrand.c"
        dump "Please see the content of $TMPL for details!"
        cat $TMPL | tail -10
        exit 1
    fi

    for SRC_FILE in $(cd "$SRC_DIR" && ls crt*.[cS]); do
        DST_FILE=${SRC_FILE%%.c}
        DST_FILE=${DST_FILE%%.S}.o

        case "$DST_FILE" in
            "crtend.o")
                # Special case: crtend.S must be compiled as crtend_android.o
                # This is for long historical reasons, i.e. to avoid name conflicts
                # in the past with other crtend.o files. This is hard-coded in the
                # Android toolchain configuration, so switch the name here.
                DST_FILE=crtend_android.o
                ;;
            "crtbegin_dynamic.o"|"crtbegin_static.o")
                # Add .note.ABI-tag section
                SRC_FILE=$SRC_FILE" $CRTBRAND_S"
                ;;
            "crtbegin.o")
                # If we have a single source for both crtbegin_static.o and
                # crtbegin_dynamic.o we generate one and make a copy later.
                DST_FILE=crtbegin_dynamic.o
                # Add .note.ABI-tag section
                SRC_FILE=$SRC_FILE" $CRTBRAND_S"
                ;;
        esac

        log "Generating $ARCH C runtime object: $DST_FILE"
        (cd "$SRC_DIR" && $CC \
                 -I$SRCDIR/../../bionic/libc/include \
                 -I$SRCDIR/../../bionic/libc/arch-common/bionic \
                 -I$SRCDIR/../../bionic/libc/arch-$ARCH/include \
                 -DPLATFORM_SDK_VERSION=$API \
                 -O2 -fpic -Wl,-r -nostdlib -o "$DST_DIR/$DST_FILE" $SRC_FILE) 1>>$TMPL 2>&1
        if [ $? != 0 ]; then
            dump "ERROR: Could not generate $DST_FILE from $SRC_DIR/$SRC_FILE"
            dump "Please see the content of $TMPL for details!"
            cat $TMPL | tail -10
            exit 1
        fi
        if [ ! -s "$DST_DIR/crtbegin_static.o" ]; then
            cp "$DST_DIR/crtbegin_dynamic.o" "$DST_DIR/crtbegin_static.o"
        fi
    done
    rm -f "$CRTBRAND_S"
}

# $1: platform number
# $2: architecture
# $3: target NDK directory
generate_api_level ()
{
    local API=$1
    local ARCH=$2
    local HEADER="platforms/android-$API/arch-$ARCH/usr/include/android/api-level.h"
    log "Generating: $HEADER"
    rm -f "$3/$HEADER"  # Remove symlink if any.
    cat > "$3/$HEADER" <<EOF
/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
#ifndef ANDROID_API_LEVEL_H
#define ANDROID_API_LEVEL_H

#define __ANDROID_API__ $API

#endif /* ANDROID_API_LEVEL_H */
EOF
}

# Copy platform sysroot and samples into your destination
#

# if $SRC/android-$PLATFORM/arch-$ARCH exists
#   $SRC/android-$PLATFORM/include --> $DST/android-$PLATFORM/arch-$ARCH/usr/include
#   $SRC/android-$PLATFORM/arch-$ARCH/include --> $DST/android-$PLATFORM/arch-$ARCH/usr/include
#   $SRC/android-$PLATFORM/arch-$ARCH/lib --> $DST/android-$PLATFORM/arch-$ARCH/usr/lib
#
if [ -z "$OPTION_OVERLAY" ]; then
    rm -rf $DSTDIR/platforms && mkdir -p $DSTDIR/platforms
fi
for ARCH in $ARCHS; do
    echo "## Generating arch: $ARCH"
    # Find first platform for this arch
    PREV_SYSROOT_DST=
    PREV_PLATFORM_SRC_ARCH=
    LIBDIR=$(get_default_libdir_for_arch $ARCH)

    for PLATFORM in $PLATFORMS; do
        echo "## Generating platform: $PLATFORM"
        PLATFORM_DST=platforms/android-$PLATFORM   # Relative to $DSTDIR
        PLATFORM_SRC=$PLATFORM_DST                 # Relative to $SRCDIR
        SYSROOT_DST=$PLATFORM_DST/arch-$ARCH/usr
        # Skip over if there is no arch-specific file for this platform
        # and no destination platform directory was created. This is needed
        # because x86 and MIPS don't have files for API levels 3-8.
        if [ -z "$PREV_SYSROOT_DST" -a \
           ! -d "$SRCDIR/$PLATFORM_SRC/arch-$ARCH" ]; then
            log "Skipping: \$SRC/$PLATFORM_SRC/arch-$ARCH"
            continue
        fi

        log "Populating \$DST/platforms/android-$PLATFORM/arch-$ARCH"

        # If this is not the first destination directory, copy over, or
        # symlink the files from the previous one now.
        if [ "$PREV_SYSROOT_DST" ]; then
            if [ "$OPTION_FAST_COPY" ]; then
                log "Copying \$DST/$PREV_SYSROOT_DST to \$DST/$SYSROOT_DST"
                copy_directory "$DSTDIR/$PREV_SYSROOT_DST" "$DSTDIR/$SYSROOT_DST"
            else
                log "Symlink-copying \$DST/$PREV_SYSROOT_DST to \$DST/$SYSROOT_DST"
                symlink_src_directory $PREV_SYSROOT_DST $SYSROOT_DST
            fi
        fi

        # If this is the first destination directory, copy the common
        # files from previous platform directories into this one.
        # This helps copy the common headers from android-3 to android-8
        # into the x86 and mips android-9 directories.
        if [ -z "$PREV_SYSROOT_DST" ]; then
            for OLD_PLATFORM in $PLATFORMS; do
                if [ "$OLD_PLATFORM" = "$PLATFORM" ]; then
                    break
                fi
                copy_src_directory platforms/android-$OLD_PLATFORM/include \
                                   $SYSROOT_DST/include \
                                   "common android-$OLD_PLATFORM headers"
            done
        fi

        # There are two set of bionic headers: the original ones haven't been updated since
        # gingerbread except for bug fixing, and the new ones in android-$FIRST_API64_LEVEL
        # with 64-bit support.  Before the old bionic headers are deprecated/removed, we need
        # to remove stale old headers when createing platform = $FIRST_API64_LEVEL
        if [ "$PLATFORM" = "$FIRST_API64_LEVEL" ]; then
            log "Removing stale bionic headers in \$DST/$SYSROOT_DST/include"
            nonbionic_files="android EGL GLES GLES2 GLES3 KHR media OMXAL SLES jni.h thread_db.h zconf.h zlib.h"
            if [ -d "$DSTDIR/$SYSROOT_DST/include/" ]; then
                files=$(cd "$DSTDIR/$SYSROOT_DST/include/" && ls)
                for file in $files; do
                    if [ "$nonbionic_files" = "${nonbionic_files%%${file}*}" ]; then
                        rm -rf "$DSTDIR/$SYSROOT_DST/include/$file"
                    fi
                done
            fi
        fi

        # Now copy over all non-arch specific include files
        copy_src_directory $PLATFORM_SRC/include $SYSROOT_DST/include "common system headers"
        copy_src_directory $PLATFORM_SRC/arch-$ARCH/include $SYSROOT_DST/include "$ARCH system headers"

        generate_api_level "$PLATFORM" "$ARCH" "$DSTDIR"

        # If --minimal is not used, copy or generate binary files.
        if [ -z "$OPTION_MINIMAL" ]; then
            # Copy the prebuilt static libraries.  We need full set for multilib compiler for some arch
            case "$ARCH" in
                x86_64)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib $SYSROOT_DST/lib "x86 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib64 $SYSROOT_DST/lib64 "x86_64 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/libx32 $SYSROOT_DST/libx32 "x32 sysroot libs"
                    ;;
                mips64)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib $SYSROOT_DST/lib "mips -mabi=32 -mips32 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/libr2 $SYSROOT_DST/libr2 "mips -mabi=32 -mips32r2 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/libr6 $SYSROOT_DST/libr6 "mips -mabi=32 -mips32r6 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib64r2 $SYSROOT_DST/lib64r2 "mips -mabi=64 -mips64r2 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib64 $SYSROOT_DST/lib64 "mips -mabi=64 -mips64r6 sysroot libs"
                    ;;
                mips)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib $SYSROOT_DST/lib "mips -mabi=32 -mips32 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/libr2 $SYSROOT_DST/libr2 "mips -mabi=32 -mips32r2 sysroot libs"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/libr6 $SYSROOT_DST/libr6 "mips -mabi=32 -mips32r6 sysroot libs"
                    ;;
                *)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/$LIBDIR $SYSROOT_DST/$LIBDIR "$ARCH sysroot libs"
                    ;;
            esac

            # Generate C runtime object files when available
            PLATFORM_SRC_ARCH=$PLATFORM_SRC/arch-$ARCH/src
            if [ ! -d "$SRCDIR/$PLATFORM_SRC_ARCH" ]; then
                PLATFORM_SRC_ARCH=$PREV_PLATFORM_SRC_ARCH
            else
                PREV_PLATFORM_SRC_ARCH=$PLATFORM_SRC_ARCH
            fi

            # Genreate crt objects for known archs
            if [ "$(arch_in_unknown_archs $ARCH)" != "yes" ]; then
                case "$ARCH" in
                    x86_64)
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib "-m32"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib64 "-m64"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/libx32 "-mx32"
                        ;;
                    mips64)
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib "-mabi=32 -mips32"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/libr2 "-mabi=32 -mips32r2"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/libr6 "-mabi=32 -mips32r6"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib64r2 "-mabi=64 -mips64r2"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib64 "-mabi=64 -mips64r6"
                        ;;
                    mips)
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/lib "-mabi=32 -mips32"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/libr2 "-mabi=32 -mips32r2"
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/libr6 "-mabi=32 -mips32r6"
                        ;;
                    *)
                        gen_crt_objects $PLATFORM $ARCH platforms/common/src $PLATFORM_SRC_ARCH $SYSROOT_DST/$LIBDIR
                        ;;
               esac
            fi

            # Generate shared libraries from symbol files
            if [ "$(arch_in_unknown_archs $ARCH)" = "yes" ]; then
                gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib "-target le32-none-ndk"
                gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib64 "-target le64-none-ndk"
            else
                case "$ARCH" in
                    x86_64)
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib "-m32"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib64 "-m64"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/libx32 "-mx32"
                        ;;
                    mips64)
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib "-mabi=32 -mips32"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/libr2 "-mabi=32 -mips32r2"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/libr6 "-mabi=32 -mips32r6"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib64r2 "-mabi=64 -mips64r2"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib64 "-mabi=64 -mips64r6"
                        ;;
                    mips)
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/lib "-mabi=32 -mips32"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/libr2 "-mabi=32 -mips32r2"
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/libr6 "-mabi=32 -mips32r6"
                        ;;
                    *)
                        gen_shared_libraries $ARCH $PLATFORM_SRC/arch-$ARCH/symbols $SYSROOT_DST/$LIBDIR
                        ;;
                esac
            fi
        else
            # Copy the prebuilt binaries to bootstrap GCC
            case "$ARCH" in
                x86_64)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib $SYSROOT_DST/lib "x86 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib64 $SYSROOT_DST/lib64 "x86_64 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/libx32 $SYSROOT_DST/libx32 "x32 sysroot libs (boostrap)"
                    ;;
                mips64)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib $SYSROOT_DST/lib "mips -mabi=32 -mips32 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/libr2 $SYSROOT_DST/libr2 "mips -mabi=32 -mips32r2 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/libr6 $SYSROOT_DST/libr6 "mips -mabi=32 -mips32r6 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib64r2 $SYSROOT_DST/lib64r2 "mips -mabi=64 -mips64r2 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib64 $SYSROOT_DST/lib64 "mips -mabi=64 -mips64r6 sysroot libs (boostrap)"
                    ;;
                mips)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/lib $SYSROOT_DST/lib "mips -mabi=32 -mips32 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/libr2 $SYSROOT_DST/libr2 "mips -mabi=32 -mips32r2 sysroot libs (boostrap)"
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap/libr6 $SYSROOT_DST/libr6 "mips -mabi=32 -mips32r6 sysroot libs (boostrap)"
                    ;;
                *)
                    copy_src_directory $PLATFORM_SRC/arch-$ARCH/lib-bootstrap $SYSROOT_DST/$LIBDIR "$ARCH sysroot libs (boostrap)"
                    ;;
            esac
        fi
        PREV_SYSROOT_DST=$SYSROOT_DST
    done
done

#
# $SRC/android-$PLATFORM/samples --> $DST/samples
#
if [ "$OPTION_SAMPLES" ] ; then
    # Copy platform samples and generic samples into your destination
    #
    # $SRC/samples/ --> $DST/samples/
    # $SRC/android-$PLATFORM/samples/ --> $DST/samples
    #
    dump "Copying generic samples"
    if [ -z "$OPTION_OVERLAY" ]; then
        rm -rf $DSTDIR/samples && mkdir -p $DSTDIR/samples
    fi
    copy_src_directory  samples samples samples

    for PLATFORM in $PLATFORMS; do
        dump "Copy android-$PLATFORM samples"
        # $SRC/platform-$PLATFORM/samples --> $DST/samples
        copy_src_directory platforms/android-$PLATFORM/samples samples samples
    done

    # Cleanup generated files in samples
    rm -rf "$DSTDIR/samples/*/obj"
    rm -rf "$DSTDIR/samples/*/libs"
fi

if [ "$PACKAGE_DIR" ]; then
    mkdir -p "$PACKAGE_DIR"
    fail_panic "Could not create package directory: $PACKAGE_DIR"
    ARCHIVE=platforms.tar.bz2
    dump "Packaging $ARCHIVE"
    pack_archive "$PACKAGE_DIR/$ARCHIVE" "$DSTDIR" "platforms"
    fail_panic "Could not package platforms"
    if [ "$OPTION_SAMPLES" ]; then
        ARCHIVE=samples.tar.bz2
        dump "Packaging $ARCHIVE"
        pack_archive "$PACKAGE_DIR/$ARCHIVE" "$DSTDIR" "samples"
        fail_panic "Could not package samples"
    fi
fi

log "Done !"