#!/bin/sh # # Copyright (C) 2009 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 shell script is used to rebuild the Android NDK's prebuilt binaries. # # The source tarballs must be located in $ANDROID_NDK_ROOT/build/archive # They will be located in $ANDROID_NDK_ROOT/build/toolchain after compilation # # include common function and variable definitions . `dirname $0`/../core/ndk-common.sh # number of jobs to run in parallel when running make JOBS=$HOST_NUM_CPUS TOOLCHAIN_NAME=arm-eabi-4.2.1 PLATFORM=android-3 ABI=arm GCC_VERSION=4.2.1 GDB_VERSION=6.6 OPTION_HELP=no OPTION_PLATFORM= OPTION_FORCE_32=no OPTION_REBUILD=no OPTION_GCC_VERSION= OPTION_GDB_VERSION= OPTION_TOOLCHAIN_NAME= OPTION_PACKAGE= VERBOSE=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 ;; --gcc-version=*) OPTION_GCC_VERSION=$optarg ;; --gdb-version=*) OPTION_GDB_VERSION=$optarg ;; --toolchain=*) OPTION_TOOLCHAIN_NAME=$optarg ;; --package=*) OPTION_PACKAGE="$optarg" ;; --platform=*) PLATFORM=$optarg ;; --abi=*) ABI=$optarg ;; --force-download) OPTION_FORCE_DOWNLOAD=yes OPTION_FORCE_BUILD=yes ;; --force-build) OPTION_FORCE_BUILD=yes ;; --verbose) VERBOSE=yes ;; *) echo "unknown option '$opt', use --help" exit 1 esac done if [ $OPTION_HELP = "yes" ] ; then echo "Rebuild the prebuilt binaries for the Android NDK toolchain." echo "This script will automatically download the sources from the" echo "Internet, unless you use the --package=<file> option to specify" echo "the exact source package to use." echo "" echo "See build/tools/download-toolchain-sources.sh for a tool that" echo "can create a compatible source package from the current" echo "git repositories." echo "" echo "options (defaults are within brackets):" echo "" echo " --help print this message" echo " --gcc-version=<version> select GCC version [$GCC_VERSION]" echo " --gdb-version=<version> select GDB version [$GDB_VERSION]" echo " --toolchain=<name> toolchain name (default is $TOOLCHAIN_NAME)" echo " --package=<file> specify download source package" echo " --platform=<name> generate toolchain from platform <name> (default is $PLATFORM)" echo " --abi=<name> generate toolchain from abi <name> (default is $ABI)" echo " --build-out=<path> set Android build out directory" echo " --force-download force a download and unpacking of the toolchain sources" echo " --force-build force a rebuild of the sources" echo "" exit 0 fi # Force generation of 32-bit binaries on 64-bit systems case $HOST_TAG in *-x86_64) HOST_CFLAGS="$HOST_CFLAGS -m32" HOST_LDFLAGS="$HOST_LDFLAGS -m32" force_32bit_binaries # to modify HOST_TAG and others ;; esac TMPLOG=/tmp/android-toolchain-build-$$.log rm -rf $TMPLOG if [ $VERBOSE = yes ] ; then run () { echo "##### NEW COMMAND" echo "$@" $@ 2>&1 } log () { echo "LOG: $@" } else echo "To follow build, please use in another terminal: tail -F $TMPLOG" run () { echo "##### NEW COMMAND" >> $TMPLOG echo "$@" >> $TMPLOG $@ >>$TMPLOG 2>&1 } log () { echo "$@" > /dev/null } fi if [ -n "$OPTION_GCC_VERSION" ] ; then GCC_VERSION="$OPTION_GCC_VERSION" log "Using gcc version $GCC_VERSION" else log "Using default gcc version $GCC_VERSION" fi if [ -n "$OPTION_GDB_VERSION" ] ; then GDB_VERSION="$OPTION_GDB_VERSION" log "Using gdb version $GDB_VERSION" else log "Using default gdb version $GDB_VERSION" fi if [ -n "$OPTION_TOOLCHAIN_NAME" ] ; then TOOLCHAIN_NAME="$OPTION_TOOLCHAIN_NAME" log "Using toolchain name '$TOOLCHAIN_NAME'" else TOOLCHAIN_NAME=arm-eabi-$GCC_VERSION log "Using default toolchain name '$TOOLCHAIN_NAME'" fi if [ -n "$OPTION_PACKAGE" ] ; then if [ ! -f "$OPTION_PACKAGE" ] ; then echo "Package is not a file: $OPTION_PACKAGE" exit 1 fi fi ANDROID_NDK_ROOT=`cd $ANDROID_NDK_ROOT && pwd` ANDROID_NDK_ARCHIVE=$ANDROID_NDK_ROOT/build/toolchains/archive ANDROID_PLATFORMS_ROOT=$ANDROID_NDK_ROOT/build/platforms # where all generated files will be placed OUT=$ANDROID_NDK_ROOT/out/$TOOLCHAIN_NAME PACKAGE_OUT=$OUT/packages TIMESTAMP_OUT=$OUT/timestamps # where the sysroot is located ANDROID_SYSROOT=$ANDROID_NDK_ROOT/build/platforms/$PLATFORM/arch-$ABI # where the toolchain binaries will be placed ANDROID_TOOLCHAIN_OUT=$OUT/toolchain ANDROID_TOOLCHAIN_SRC=$ANDROID_TOOLCHAIN_OUT/src ANDROID_TOOLCHAIN_BUILD=$ANDROID_TOOLCHAIN_OUT/build # where the gdbserver binaries will be placed ANDROID_GDBSERVER_OUT=$OUT/gdbserver ANDROID_GDBSERVER_BUILD=$ANDROID_GDBSERVER_OUT/build ANDROID_GDBSERVER_DEST=$ANDROID_SYSROOT/usr/bin # Let's check that we have a working md5sum here A_MD5=`echo "A" | md5sum | cut -d' ' -f1` if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then echo "Please install md5sum on this machine" exit 2 fi # And wget too WGET=`which wget` CURL=`which curl` SCP=`which scp` # download a file with either 'curl', 'wget' or 'scp' # $1: source # $2: target download_file () { # is this HTTP, HTTPS or FTP ? echo $1 | grep -q -e "^\(http\|https\):.*" if [ $? = 0 ] ; then if [ -n "$WGET" ] ; then $WGET -O $2 $1 elif [ -n "$CURL" ] ; then $CURL -o $2 $1 else echo "Please install wget or curl on this machine" exit 1 fi return fi # is this SSH ? echo $1 | grep -q -e "^ssh:.*" if [ $? = 0 ] ; then if [ -n "$SCP" ] ; then scp_src=`echo $1 | sed -e s%ssh://%%g` $SCP $scp_src $2 else echo "Please install scp on this machine" exit 1 fi return fi echo $1 | grep -q -e "^/.*" if [ $? = 0 ] ; then cp -f $1 $2 fi } TOOLCHAIN_SRC=$ANDROID_TOOLCHAIN_SRC TOOLCHAIN_BUILD=$ANDROID_TOOLCHAIN_BUILD TOOLCHAIN_PREFIX=$ANDROID_NDK_ROOT/build/prebuilt/$HOST_TAG/$TOOLCHAIN_NAME TOOLCHAIN_LICENSES=$ANDROID_NDK_ROOT/build/tools/toolchain-licenses GDBSERVER_BUILD=$ANDROID_GDBSERVER_BUILD timestamp_check () { [ -f $TIMESTAMP_OUT/$1/timestamp-$2 ] } timestamp_set () { mkdir -p $TIMESTAMP_OUT/$1 touch $TIMESTAMP_OUT/$1/timestamp-$2 } timestamp_clear () { rm -f $TIMESTAMP_OUT/$1/timestamp-* } timestamp_force () { rm -f $TIMESTAMP_OUT/$1/timestamp-$2 } # this function will be used to download and verify a toolchain # package # $1: directory name under build/archive (e.g. 'android-toolchain') # download_package () { WORKSPACE=$ANDROID_NDK_ARCHIVE/$1 if [ ! -d $WORKSPACE ] ; then echo "No directory named $1 under $ANDROID_NDK_ARCHIVE" exit 2 fi SOURCES=$WORKSPACE/sources.txt if [ ! -f $SOURCES ] ; then echo "Missing sources.txt in $WORKSPACE" exit 2 fi # First line must be file name PKGNAME=`cat $SOURCES | sed 1q` # Second line must be md5sum PKGSUM=`cat $SOURCES | sed 1d | sed 1q` if [ -z "$PKGNAME" -o -z "$PKGSUM" ] ; then echo "Corrupted file: $SOURCES" exit 2 fi # Try to download the package if it is not there # the Third line of sources.txt, and all others behind # must be wget urls or something. PACKAGE_TARBALL=$PACKAGE_OUT/$PKGNAME if [ ! -f $PACKAGE_TARBALL ] ; then cat $SOURCES | sed 1,2d | while read src; do echo $src | grep -q -e "^/.*" if [ $? = 0 ] ; then if [ -f $src ] ; then echo "Copy : $PKGNAME" echo " from `dirname $src`" echo " into $PACKAGE_TARBALL" run cp -f $src $PACKAGE_TARBALL if [ $? = 0 ] ; then break fi echo "Copy : Problem copying from $src" else echo "Copy : Can't find $src (skipping)" fi continue fi echo $src | grep -q -e "^\(http\|https\|ftp\|ssh\):.*" if [ $? = 0 ] ; then echo "Download: $PKGNAME" echo " from $src" echo " into $PACKAGE_TARBALL" download_file $src $PACKAGE_TARBALL if [ $? = 0 ] ; then break fi continue else "Copy : Unknown method in $src" fi done if [ ! -f $PACKAGE_TARBALL ] ; then echo "ERROR: Could not copy or download $PKGNAME !" echo "Your probably need to edit $WORKSPACE/sources.txt" exit 1 fi fi if ! timestamp_check $1 verify ; then SUM=`md5sum $PACKAGE_TARBALL | cut -d " " -f 1` if [ "$SUM" != "$PKGSUM" ] ; then echo "ERROR: Invalid MD5 Sum for $PACKAGE_TARBALL" echo " Expected $PKGSUM" echo " Computed $SUM" echo "You might want to use the --force-download option." exit 2 fi echo "Verified: $PACKAGE_TARBALL" timestamp_set $1 verify timestamp_force $1 unpack fi eval PKG_$1=$PACKAGE_TARBALL } # Unpack a given package in a target location # $1: package name # $2: target directory # unpack_package () { WORKSPACE=$ANDROID_NDK_ARCHIVE/$1 SRCDIR=$2 SRCPKG=`var_value PKG_$1` if ! timestamp_check $1 unpack; then echo "Unpack : $1 sources" echo " from $SRCPKG" echo " into $SRCDIR" run rm -rf $SRCDIR run mkdir -p $SRCDIR TARFLAGS=xjf if [ $VERBOSE2 = yes ]; then TARFLAGS="v$TARFLAGS" fi run tar $TARFLAGS $SRCPKG -C $SRCDIR if [ $? != 0 ] ; then echo "ERROR: Could not unpack $1, See $TMPLOG" exit 1 fi timestamp_set $1 unpack timestamp_force $1 configure fi } if [ $OPTION_FORCE_DOWNLOAD ] ; then rm -rf $PACKAGE_OUT $ANDROID_TOOLCHAIN_SRC timestamp_force toolchain unpack timestamp_force toolchain verify fi if [ $OPTION_FORCE_BUILD ] ; then rm -rf $ANDROID_TOOLCHAIN_BUILD timestamp_clear toolchain timestamp_clear gdbserver fi # checks, we need more checks.. mkdir -p $PACKAGE_OUT if [ $? != 0 ] ; then echo "Can't create download/archive directory for toolchain tarballs" exit 2 fi if [ -n "$OPTION_PACKAGE" ] ; then PKG_toolchain="$OPTION_PACKAGE" else download_package toolchain fi unpack_package toolchain $ANDROID_TOOLCHAIN_SRC # remove all info files from the unpacked toolchain sources # they create countless little problems during the build # if you don't have exactly the configuration expected by # the scripts. # find $ANDROID_TOOLCHAIN_SRC -type f -a -name "*.info" -print0 | xargs -0 rm -f # configure the toolchain if ! timestamp_check toolchain configure; then echo "Configure: toolchain build" BUILD_SRCDIR=$TOOLCHAIN_SRC/build if [ ! -d $BUILD_SRCDIR ] ; then BUILD_SRCDIR=$TOOLCHAIN_SRC fi mkdir -p $TOOLCHAIN_BUILD && cd $TOOLCHAIN_BUILD && export ABI="32" && # needed to build a 32-bit gmp export CFLAGS="$HOST_CFLAGS" && export LDFLAGS="$HOST_LDFLAGS" && run \ $BUILD_SRCDIR/configure --target=arm-eabi \ --disable-nls \ --prefix=$TOOLCHAIN_PREFIX \ --with-sysroot=$ANDROID_SYSROOT \ --with-gcc-version=$GCC_VERSION \ --with-gdb-version=$GDB_VERSION if [ $? != 0 ] ; then echo "Error while trying to configure toolchain build. See $TMPLOG" exit 1 fi timestamp_set toolchain configure timestamp_force toolchain build fi # build the toolchain if ! timestamp_check toolchain build ; then echo "Building : toolchain [this can take a long time]." cd $TOOLCHAIN_BUILD && export CFLAGS="$HOST_CFLAGS" && export LDFLAGS="$HOST_LDFLAGS" && run make -j$JOBS if [ $? != 0 ] ; then echo "Error while building toolchain. See $TMPLOG" exit 1 fi timestamp_set toolchain build timestamp_force toolchain install fi # install the toolchain to its final location if ! timestamp_check toolchain install ; then echo "Install : toolchain binaries." cd $TOOLCHAIN_BUILD && run make install if [ $? != 0 ] ; then echo "Error while installing toolchain. See $TMPLOG" exit 1 fi # don't forget to copy the GPL and LGPL license files cp -f $TOOLCHAIN_LICENSES/COPYING $TOOLCHAIN_LICENSES/COPYING.LIB $TOOLCHAIN_PREFIX # remove some unneeded files rm -f $TOOLCHAIN_PREFIX/bin/*-gccbug rm -rf $TOOLCHAIN_PREFIX/man $TOOLCHAIN_PREFIX/info # strip binaries to reduce final package size strip $TOOLCHAIN_PREFIX/bin/* strip $TOOLCHAIN_PREFIX/arm-eabi/bin/* strip $TOOLCHAIN_PREFIX/libexec/gcc/*/*/cc1 strip $TOOLCHAIN_PREFIX/libexec/gcc/*/*/cc1plus strip $TOOLCHAIN_PREFIX/libexec/gcc/*/*/collect2 timestamp_set toolchain install timestamp_force gdbserver configure fi # configure the gdbserver build now if ! timestamp_check gdbserver configure; then echo "Configure: gdbserver build." if [ -d $TOOLCHAIN_SRC/gdb ] ; then GDB_SRCDIR=$TOOLCHAIN_SRC/gdb/gdb-$GDB_VERSION else GDB_SRCDIR=$TOOLCHAIN_SRC/gdb-$GDB_VERSION fi mkdir -p $GDBSERVER_BUILD cd $GDBSERVER_BUILD && export CC="$TOOLCHAIN_PREFIX/bin/arm-eabi-gcc" && export CFLAGS="-g -O2 -static -mandroid" && export LDFLAGS= && run $GDB_SRCDIR/gdb/gdbserver/configure \ --host=arm-eabi-linux \ --with-sysroot=$ANDROID_SYSROOT if [ $? != 0 ] ; then echo "Could not configure gdbserver build. See $TMPLOG" exit 1 fi timestamp_set gdbserver configure timestamp_force gdbserver build fi # build gdbserver if ! timestamp_check gdbserver build; then echo "Building : gdbserver." cd $GDBSERVER_BUILD && run make -j$JOBS if [ $? != 0 ] ; then echo "Could not build gdbserver. See $TMPLOG" exit 1 fi timestamp_set gdbserver build timestamp_force gdbserver install fi # install gdbserver # # note that we install it in the toolchain bin directory # not in $SYSROOT/usr/bin # if ! timestamp_check gdbserver install; then echo "Install : gdbserver." DEST=$TOOLCHAIN_PREFIX/bin mkdir -p $DEST && $TOOLCHAIN_PREFIX/bin/arm-eabi-strip $GDBSERVER_BUILD/gdbserver && run cp -f $GDBSERVER_BUILD/gdbserver $DEST/gdbserver if [ $? != 0 ] ; then echo "Could not install gdbserver. See $TMPLOG" exit 1 fi timestamp_set gdbserver install timestamp_force package toolchain fi # package the toolchain TOOLCHAIN_TARBALL=/tmp/android-ndk-prebuilt-$TOOLCHAIN_NAME-$HOST_TAG.tar.bz2 if ! timestamp_check package toolchain; then echo "Package : $HOST_ARCH toolchain binaries" echo " into $TOOLCHAIN_TARBALL" cd $ANDROID_NDK_ROOT && TARFLAGS="cjf" if [ $VERBOSE = yes ] ; then TARFLAGS="v$TARFLAGS" fi run tar $TARFLAGS $TOOLCHAIN_TARBALL build/prebuilt/$HOST_TAG/$TOOLCHAIN_NAME if [ $? != 0 ] ; then echo "ERROR: Cannot package prebuilt toolchain binaries. See $TMPLOG" exit 1 fi timestamp_set package toolchain echo "prebuilt toolchain is in $TOOLCHAIN_TARBALL" else echo "prebuilt toolchain is in $TOOLCHAIN_TARBALL" fi echo "Done." rm -f $TMPLOG