aboutsummaryrefslogtreecommitdiff
path: root/build.sh
blob: 572280f451c1beccd0c78df76b92318c8b9fb709 (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
#!/bin/sh
#
# Copyright (C) 2016 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.
#
# Rebuild the mingw64 cross-toolchain from scratch
#
# See --help for usage example.

PROGNAME=$(basename $0)
PROGDIR=$(dirname $0)
PROGDIR=$(cd $PROGDIR && pwd)
ANDROID_BUILD_TOP=$(realpath $PROGDIR/../..)
TOOLCHAIN_DIR=$(realpath $ANDROID_BUILD_TOP/toolchain)

HELP=
VERBOSE=2

# This will be reset later.
LOG_FILE=/dev/null

panic ()
{
    1>&2 echo "Error: $@"
    exit 1
}

fail_panic ()
{
    if [ $? != 0 ]; then
        panic "$@"
    fi
}

var_value ()
{
    eval echo \"$1\"
}

var_append ()
{
    local _varname=$1
    local _varval=$(var_value $_varname)
    shift
    if [ -z "$_varval" ]; then
        eval $_varname=\"$*\"
    else
        eval $_varname=\$$_varname\" $*\"
    fi
}

run ()
{
    if [ "$VERBOSE" -gt 0 ]; then
        echo "COMMAND: >>>> $@" >> $LOG_FILE
    fi
    if [ "$VERBOSE" -gt 1 ]; then
        echo "COMMAND: >>>> $@"
    fi
    if [ "$VERBOSE" -gt 1 ]; then
        "$@"
    else
       "$@" > /dev/null 2>&1
    fi
}

log ()
{
    if [ "$LOG_FILE" ]; then
        echo "$@" >> $LOG_FILE
    fi
    if [ "$VERBOSE" -gt 0 ]; then
        echo "$@"
    fi
}

NUM_CORES=$(grep -c -e '^processor' /proc/cpuinfo)
JOBS=$(( $NUM_CORES * 2 ))

GMP_VERSION=5.0.5
MPFR_VERSION=3.1.1
MPC_VERSION=1.0.1
BINUTILS_VERSION=2.27
GCC_VERSION=4.8.3
MINGW_W64_VERSION=v6.x

TARGET_ARCH=x86_64
TARGET_MULTILIBS=true  # not empty to enable multilib
CLEANUP=

OPT_GCC_VERSION=

for opt; do
    optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
    case $opt in
        -h|-?|--help) HELP=true;;
        --verbose) VERBOSE=$(( $VERBOSE + 1 ));;
        --quiet) VERBOSE=$(( $VERBOSE - 1 ));;
        -j*|--jobs=*) JOBS=$optarg;;
        --target-arch=*) TARGET_ARCH=$optarg;;
        --no-multilib) TARGET_MULTILIBS="";;
        --gcc-version=*) OPT_GCC_VERSION=$optarg;;
        --cleanup) CLEANUP=true;;
        -*) panic "Unknown option '$opt', see --help for list of valid ones.";;
        *) panic "This script doesn't take any parameter, see --help for details.";;
    esac
done


if [ "$HELP" ]; then
    cat <<EOF
Usage: $PROGNAME [options]

This program is used to rebuild a mingw64 cross-toolchain from scratch.

All toolchain binaries can generate both Win32 and Win64 executables. Use -m32
or -m64 at compile/link time to select a specific target.

Valid options:
  -h|-?|--help                 Print this message."
  --verbose                    Increase verbosity."
  --quiet                      Decrease verbosity."
  --jobs=<num>                 Run <num> build tasks in parallel [$JOBS]."
  -j<num>                      Same as --jobs=<num>."
  --no-multilib                Disable multilib toolchain build."
  --target-arch=<arch>         Select default target architecture [$TARGET_ARCH]."
  --gcc-version=<version>      Select alternative GCC version [$GCC_VERSION]"
EOF
    exit 0
fi

if [ "$OPT_GCC_VERSION" ]; then
    GCC_VERSION=$OPT_GCC_VERSION
fi

GCC_SRC_DIR=$TOOLCHAIN_DIR/gcc/gcc-$GCC_VERSION
if [ ! -d "$GCC_SRC_DIR" ]; then
    panic "Missing GCC source directory: $GCC_SRC_DIR"
fi

GCC_MAJOR_MINOR=$(echo "$GCC_VERSION" | cut -d. -f1-2)

# Top level out directory.
OUT_DIR=$ANDROID_BUILD_TOP/out

# Name of the directory inside the package.
PACKAGE_DIR=x86_64-w64-mingw32-$GCC_MAJOR_MINOR

# Directory to isolate the install package from any similarly named directories.
OUTER_INSTALL_DIR=$OUT_DIR/install

# Actual install path.
INSTALL_DIR=$OUTER_INSTALL_DIR/$PACKAGE_DIR

# Install directory for build dependencies that are not in the final package
# (gmp and whatnot).
SUPPORT_DIR=$INSTALL_DIR

# For the final artifacts. Will be archived on the build server.
if [ -z "$DIST_DIR" ]; then
  DIST_DIR=$OUT_DIR/dist
fi

BUILD_TAG64=x86_64-linux-gnu
BUILD_TAG32=i686-linux-gnu

# We don't want debug executables
BUILD_CFLAGS="-O2 -fomit-frame-pointer -s"
BUILD_LDFLAGS=""

rm -rf $OUT_DIR
mkdir -p $OUT_DIR
mkdir -p $INSTALL_DIR
mkdir -p $DIST_DIR
mkdir -p $SUPPORT_DIR

LOG_FILE=$OUT_DIR/build.log
rm -f $LOG_FILE && touch $LOG_FILE
if [ "$VERBOSE" -eq 1 ]; then
    echo  "To follow build, use in another terminal: tail -F $LOG_FILE"
fi

case $TARGET_ARCH in
    x86_64) TARGET_BITS=64;;
    i686) TARGET_BITS=32;;
    *) panic "Invalid --target parameter. Valid values are: x86_64 i686";;
esac
TARGET_TAG=$TARGET_ARCH-w64-mingw32
log "Target arch: $TARGET_TAG"
log "Target bits: $TARGET_BITS"

HOST_ARCH=x86_64
HOST_BITS=64

HOST_TAG=$HOST_ARCH-linux-gnu
log "Host arch: $HOST_TAG"

# Copy this script
cp $0 $INSTALL_DIR/ &&
echo "This file has been automatically generated on $(date) with the following command:" > $INSTALL_DIR/README &&
echo "$PROGNAME $@" >> $INSTALL_DIR/README &&
echo "" >> $INSTALL_DIR/README &&
echo "The MD5 hashes for the original sources packages are:" >> $INSTALL_DIR/README
fail_panic "Could not copy script to installation directory."

PREFIX_FOR_TARGET=$INSTALL_DIR/$TARGET_TAG
WITH_WIDL=$INSTALL_DIR/bin
MINGW_W64_SRC=$TOOLCHAIN_DIR/mingw/mingw-w64-$MINGW_W64_VERSION

setup_host_build_env ()
{
    local BINPREFIX=$ANDROID_BUILD_TOP/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/bin/x86_64-linux-

    CC=${BINPREFIX}gcc
    CXX=${BINPREFIX}g++
    LD=${BINPREFIX}ld
    AS=${BINPREFIX}as
    AR=${BINPREFIX}ar
    RANLIB=${BINPREFIX}ranlib
    STRIP=${BINPREFIX}strip
    export CC CXX LD AS AR RANLIB STRIP

    export CFLAGS="$BUILD_CFLAGS"
    export CXXFLAGS="$BUILD_CFLAGS"
    export LDFLAGS="$BUILD_LDFLAGS"
}

setup_mingw_build_env ()
{
    local BINPREFIX=$INSTALL_DIR/bin/x86_64-w64-mingw32-

    CC=${BINPREFIX}gcc
    CXX=${BINPREFIX}g++
    LD=${BINPREFIX}ld
    AS=${BINPREFIX}as
    AR=${BINPREFIX}ar
    RANLIB=${BINPREFIX}ranlib
    RC=${BINPREFIX}windres
    STRIP=${BINPREFIX}strip
    export CC CXX LD AS AR RANLIB RC STRIP

}

setup_install_env ()
{
    export PATH=$INSTALL_DIR/bin:$PATH
}

build_binutils_package ()
{
    local PKGNAME=$1
    shift

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        setup_host_build_env &&
        log "$PKGNAME: Configuring" &&
        run $TOOLCHAIN_DIR/binutils/$PKGNAME/configure "$@"
        fail_panic "Can't configure $PKGNAME !!"

        log "$PKGNAME: Building" &&
        run make -j$JOBS MAKEINFO=true
        fail_panic "Can't build $PKGNAME !!"

        log "$PKGNAME: Installing" &&
        run make install MAKEINFO=true
        fail_panic "Can't install $PKGNAME"
    ) || exit 1
}

# The GCC build in Android is insane and stores gmp and friends as tarballs and
# extracts them as a part of the build step (in the meta-configure of all
# places). No one understands how any of that mess works, so just deal with
# extracting them here...
EXTRACTED_PACKAGES=$OUT_DIR/packages
mkdir -p $EXTRACTED_PACKAGES
fail_panic "Could not create directory for packages."

log "gmp-$GMP_VERSION: Extracting" &&
tar xf $TOOLCHAIN_DIR/gmp/gmp-$GMP_VERSION.tar.bz2 -C $EXTRACTED_PACKAGES
log "mpfr-$MPFR_VERSION: Extracting" &&
tar xf $TOOLCHAIN_DIR/mpfr/mpfr-$MPFR_VERSION.tar.bz2 -C $EXTRACTED_PACKAGES
log "mpc-$MPC_VERSION: Extracting" &&
tar xf $TOOLCHAIN_DIR/mpc/mpc-$MPC_VERSION.tar.gz -C $EXTRACTED_PACKAGES

build_host_package ()
{
    local PKGNAME=$1
    shift

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        setup_host_build_env &&
        log "$PKGNAME: Configuring" &&
        run $EXTRACTED_PACKAGES/$PKGNAME/configure "$@"
        fail_panic "Can't configure $PKGNAME !!"

        log "$PKGNAME: Building" &&
        run make -j$JOBS
        fail_panic "Can't build $PKGNAME !!"

        log "$PKGNAME: Installing" &&
        run make install
        fail_panic "Can't install $PKGNAME"
    ) || exit 1
}

export ABI=$HOST_BITS
SUPPORT_INSTALL=
BASE_HOST_OPTIONS="--prefix=$SUPPORT_DIR --disable-shared"
build_host_package gmp-$GMP_VERSION $BASE_HOST_OPTIONS
var_append BASE_HOST_OPTIONS "--with-gmp=$SUPPORT_DIR"

build_host_package mpfr-$MPFR_VERSION $BASE_HOST_OPTIONS
var_append BASE_HOST_OPTIONS "--with-mpfr=$SUPPORT_DIR"

build_host_package mpc-$MPC_VERSION $BASE_HOST_OPTIONS
var_append BASE_HOST_OPTIONS "--with-mpc=$SUPPORT_DIR"

BINUTILS_CONFIGURE_OPTIONS=$BASE_HOST_OPTIONS
var_append BINUTILS_CONFIGURE_OPTIONS "--target=$TARGET_TAG --disable-nls"
if [ "$TARGET_MULTILIBS" ]; then
    var_append BINUTILS_CONFIGURE_OPTIONS "--enable-targets=x86_64-w64-mingw32,i686-w64-mingw32"
fi

var_append BINUTILS_CONFIGURE_OPTIONS "--with-sysroot=$INSTALL_DIR"
var_append BINUTILS_CONFIGURE_OPTIONS "--enable-lto --enable-plugin --enable-gold"

build_binutils_package binutils-$BINUTILS_VERSION $BINUTILS_CONFIGURE_OPTIONS

build_mingw_tools ()
{
    local PKGNAME=$1

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        log "$PKGNAME: Configuring" &&
        run $MINGW_W64_SRC/mingw-w64-tools/widl/configure --prefix=$INSTALL_DIR --target=$TARGET_TAG --includedir=$OUT_DIR/install/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/
        fail_panic "Can't configure mingw-64-tools"
        log "$PKGNAME: Installing" &&
        run make install -j$JOBS
    ) || exit 1
}

build_mingw_pthreads_lib ()
{
    local PKGNAME=$1
    local CONFIGURE_EXTRA_ARGS=$2

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        setup_mingw_build_env &&
        log "$PKGNAME (32-bit): Configuring" &&
        run $MINGW_W64_SRC/mingw-w64-libraries/winpthreads/configure --prefix=$PREFIX_FOR_TARGET --target=$TARGET_TAG --host=$TARGET_TAG $CONFIGURE_EXTRA_ARGS &&
        fail_panic "Can't configure $PKGNAME"
    ) || exit 1

    # run it once so fakelib/libgcc.a is created and make subsequently fails
    # while looking for libpthread.a.  Copy libgcc.a to libpthread.a and
    # retry.
    cd $OUT_DIR/$PKGNAME && run make install -j$JOBS

    (
        cd $OUT_DIR/$PKGNAME
        cp fakelib/libgcc.a fakelib/libpthread.a &&
        log "$PKGNAME: Installing" &&
        run make install -j$JOBS
    ) || exit 1
}

build_mingw_pthreads ()
{
    local PKGNAME=$1
    local LDFLAGS_COMMON="-Wl,--dynamicbase -Wl,--nxcompat"
    local LDFLAGS_32="$LDFLAGS_COMMON -m32"
    local LDFLAGS_64="$LDFLAGS_COMMON -Wl,--high-entropy-va"

    (
        CFLAGS="$CFLAGS -m32"
        CXXFLAGS="$CXXFLAGS -m32"
        LDFLAGS=$LDFLAGS_32
        RCFLAGS="-F pe-i386"
        export CFLAGS CXXFLAGS LDFLAGS RCFLAGS
        build_mingw_pthreads_lib $PKGNAME-32 "--build=$BUILD_TAG32 --libdir=$PREFIX_FOR_TARGET/lib32"
        (run cp $PREFIX_FOR_TARGET/bin/libwinpthread-1.dll $PREFIX_FOR_TARGET/lib32) || exit 1
    )

    LDFLAGS=$LDFLAGS_64
    export LDFLAGS
    build_mingw_pthreads_lib $PKGNAME-64 "--build=$BUILD_TAG64"
}

# Install the right mingw64 headers into the sysroot
build_mingw_headers ()
{
    local PKGNAME=$1

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        log "$PKGNAME: Configuring" &&
        run $MINGW_W64_SRC/mingw-w64-headers/configure --prefix=$PREFIX_FOR_TARGET --host=$TARGET_TAG \
            --build=$HOST_TAG --enable-sdk=all --enable-secure-api
        fail_panic "Can't configure mingw-64-headers"

        run make
        log "$PKGNAME: Installing" &&
        run make install -j$JOBS &&
        run cd $INSTALL_DIR &&
        run ln -s $TARGET_TAG mingw &&
        run cd $INSTALL_DIR/mingw &&
        run ln -s lib lib$TARGET_BITS
        fail_panic "Can't install mingw-64-headers"
    ) || exit 1
}

# Slightly different from build_host_package because we need to call
# 'make all-gcc' and 'make install-gcc' as a special case.
#
build_core_gcc ()
{
    local PKGNAME=$1
    shift

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        setup_host_build_env &&
        log "core-$PKGNAME: Configuring" &&
        run $TOOLCHAIN_DIR/gcc/$PKGNAME/configure "$@"
        fail_panic "Can't configure $PKGNAME !!"

        log "core-$PKGNAME: Building" &&
        run make -j$JOBS all-gcc
        fail_panic "Can't build $PKGNAME !!"

        log "core-$PKGNAME: Installing" &&
        run make -j$JOBS install-gcc
        fail_panic "Can't install $PKGNAME"
    ) || exit 1
}


# Build and install the C runtime files needed by the toolchain
build_mingw_crt ()
{
    local PKGNAME=$1
    shift

    (
        mkdir -p $OUT_DIR/$PKGNAME &&
        cd $OUT_DIR/$PKGNAME &&
        export PATH=$INSTALL_DIR/bin:$PATH
        log "$PKGNAME: Configuring" &&
        run $MINGW_W64_SRC/mingw-w64-crt/configure "$@"
        fail_panic "Can't configure $PKGNAME !!"

        log "$PKGNAME: Building" &&
        run make -j$JOBS
        fail_panic "Can't build $PKGNAME !!"

        log "$PKGNAME: Installing" &&
        run make -j$JOBS install
        fail_panic "Can't install $PKGNAME"
    ) || exit 1
}


build_libgcc ()
{
    local PKGNAME=$1
    shift

    (
        # No configure step here! We're resuming work that was started
        # in build_core_gcc.
        cd $OUT_DIR/$PKGNAME &&
        setup_host_build_env &&
        log "libgcc-$PKGNAME: Building" &&
        run make -j$JOBS
        fail_panic "Can't build libgcc-$PKGNAME !!"

        log "libgcc-$PKGNAME: Installing" &&
        run make -j$JOBS install
        fail_panic "Can't install libgcc-$PKGNAME"
    ) || exit 1
}

GCC_CONFIGURE_OPTIONS=$BASE_HOST_OPTIONS
var_append GCC_CONFIGURE_OPTIONS "--target=$TARGET_TAG"
if [ "$TARGET_MULTILIBS" ]; then
    var_append GCC_CONFIGURE_OPTIONS "--enable-targets=all"
fi
var_append GCC_CONFIGURE_OPTIONS "--enable-languages=c,c++"
var_append GCC_CONFIGURE_OPTIONS "--with-sysroot=$INSTALL_DIR"
var_append GCC_CONFIGURE_OPTIONS "--enable-threads=posix"
var_append GCC_CONFIGURE_OPTIONS "--enable-shared=libgcc"

build_mingw_tools mingw-w64-tools
build_mingw_headers mingw-w64-headers

build_core_gcc gcc-$GCC_VERSION $GCC_CONFIGURE_OPTIONS

CRT_CONFIGURE_OPTIONS="--host=$TARGET_TAG --with-sysroot=$INSTALL_DIR --prefix=$PREFIX_FOR_TARGET"
if [ "$TARGET_MULTILIBS" ]; then
    var_append CRT_CONFIGURE_OPTIONS "--enable-lib32"
fi

build_mingw_crt mingw-w64-crt $CRT_CONFIGURE_OPTIONS

# Build winpthreads
build_mingw_pthreads mingw-w64-pthreads

build_libgcc gcc-$GCC_VERSION

check_dlls () {
  local objdump=$INSTALL_DIR/bin/x86_64-w64-mingw32-objdump
  local dlls=($INSTALL_DIR/x86_64-w64-mingw32/bin/libwinpthread-1.dll
              $INSTALL_DIR/x86_64-w64-mingw32/lib32/libwinpthread-1.dll
              $INSTALL_DIR/x86_64-w64-mingw32/lib/libgcc_s_seh-1.dll
              $INSTALL_DIR/x86_64-w64-mingw32/lib32/libgcc_s_sjlj-1.dll
              )
  local dllflags=(00000160 00000140 00000160 00000140)

  # Verify that there are 4 dlls in $INSTALL_DIR
  four_dlls_found=`find $INSTALL_DIR -iname *.dll | wc -l | grep "^4$"`
  fail_panic "Number of DLL files in $INSTALL_DIR is not equal to 4"

  # Verify that each DLL has the expected flags for ASLR, DEP set.
  for index in "${!dlls[@]}"
  do
    local dll=${dlls[index]}
    local flag=${dllflags[index]}
    found=`${objdump} -x ${dll} | grep DllCharacteristics | grep ${flag}`
    fail_panic "Expected DllCharacteristics ${flag} not found for ${dll}"
  done
}

check_dlls

# Let's generate the licenses/ directory
LICENSE_DIRS="$SRC_DIR"
var_append LICENSE_DIRS "$TOOLCHAIN_DIR/binutils/binutils-$BINUTILS_VERSION"
var_append LICENSE_DIRS "$GCC_SRC_DIR"
var_append LICENSE_DIRS "$EXTRACTED_PACKAGES"

echo > $INSTALL_DIR/NOTICE
for LICENSE in $(find $LICENSE_DIRS -name "COPYING*"); do
    cat $SRC_DIR/$LICENSE >> $INSTALL_DIR/NOTICE
done

touch $INSTALL_DIR/MODULE_LICENSE_GPL

# The build server generates a repo.prop file that contains the current SHAs of
# each project.
REPO_PROP_PATH=$INSTALL_DIR/repo.prop
if [ -f $DIST_DIR/repo.prop ]; then
    cp $DIST_DIR/repo.prop $REPO_PROP_PATH
else
    # Generate our own if we're building locally.
    # The pushd/popd is to ensure that we're at least somewhere within our
    # source tree. There aren't any assumptions made about our CWD.
    pushd $ANDROID_BUILD_TOP
    repo forall \
        -c 'echo $REPO_PROJECT $(git rev-parse HEAD)' > $REPO_PROP_PATH
    popd
fi

PACKAGE_NAME=$DIST_DIR/$TARGET_TAG-linux-x86_64.tar.bz2
log "Packaging $TARGET_TAG toolchain to $PACKAGE_NAME"
run tar cjf $PACKAGE_NAME -C $OUTER_INSTALL_DIR $PACKAGE_DIR/
fail_panic "Could not package $TARGET_TAG toolchain!"
log "Done. See $DIST_DIR:"
ls -l $PACKAGE_NAME

exit 0