#!/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
source `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
OPTION_HELP=no
OPTION_PLATFORM=
OPTION_FORCE_32=no
OPTION_REBUILD=no
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
;;
--toolchain=*)
TOOLCHAIN_NAME=$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 ""
echo "options:"
echo ""
echo " --help print this message"
echo " --toolchain=<name> toolchain name (default is $TOOLCHAIN_NAME)"
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 | tee $TMPLOG
}
else
echo "To follow build long, please use in another terminal: tail -F $TMPLOG"
run ()
{
echo "##### NEW COMMAND" >> $TMPLOG
echo "$@" >> $TMPLOG
$@ 1>$TMPLOG 2>&1
}
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
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"
rm -rf $SRCDIR
mkdir -p $SRCDIR
TARFLAGS=xjf
if [ $VERBOSE = 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
download_package toolchain
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"
mkdir -p $TOOLCHAIN_BUILD &&
cd $TOOLCHAIN_BUILD &&
export CFLAGS="$HOST_CFLAGS" &&
export LDFLAGS="$HOST_LDFLAGS" && run \
$TOOLCHAIN_SRC/configure --target=arm-eabi \
--disable-nls \
--prefix=$TOOLCHAIN_PREFIX \
--with-sysroot=$ANDROID_SYSROOT
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_SRC/COPYING $TOOLCHAIN_SRC/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."
mkdir -p $GDBSERVER_BUILD
cd $GDBSERVER_BUILD &&
CFLAGS="-g -O2 -static -mandroid -I$ANDROID_SYSROOT/usr/include" \
LDFLAGS= \
CC="$TOOLCHAIN_PREFIX/bin/arm-eabi-gcc" \
run $TOOLCHAIN_SRC/gdb-6.6/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/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
else
echo "prebuilt toolchain is in $TOOLCHAIN_TARBALL"
fi
echo "Done."
rm -f $TMPLOG