#!/bin/sh
#
# A small script used to rebuild the Android goldfish kernel image
# See docs/KERNEL.TXT for usage instructions.
#
export LANG=C
export LC_ALL=C
PROGNAME=$(basename "$0")
MACHINE=goldfish
VARIANT=goldfish
OUTPUT=/tmp/kernel-qemu
CROSSPREFIX=arm-linux-androideabi-
CONFIG=goldfish
GCC_VERSION=4.9
VALID_ARCHS="arm x86 x86_64 mips arm64 mips64"
# Determine the host architecture, and which default prebuilt tag we need.
# For the toolchain auto-detection.
#
HOST_OS=`uname -s`
case "$HOST_OS" in
Darwin)
HOST_OS=darwin
HOST_TAG=darwin-x86
BUILD_NUM_CPUS=$(sysctl -n hw.ncpu)
;;
Linux)
# note that building 32-bit binaries on x86_64 is handled later
HOST_OS=linux
HOST_TAG=linux-x86
BUILD_NUM_CPUS=$(grep -c processor /proc/cpuinfo)
;;
*)
echo "ERROR: Unsupported OS: $HOST_OS"
exit 1
esac
# Default number of parallel jobs during the build: cores * 2
JOBS=$(( $BUILD_NUM_CPUS * 2 ))
ARCH=arm
OPTION_HELP=no
OPTION_ARMV7=yes
OPTION_OUT=
OPTION_CROSS=
OPTION_ARCH=
OPTION_CONFIG=
OPTION_SAVEDEFCONFIG=no
OPTION_JOBS=
OPTION_VERBOSE=
OPTION_GCC_VERSION=
CCACHE=
case "$USE_CCACHE" in
"")
CCACHE=
;;
*)
# use ccache bundled in AOSP source tree
CCACHE=${ANDROID_BUILD_TOP:-$(dirname $0)/../..}/prebuilts/misc/$HOST_TAG/ccache/ccache
[ -x $CCACHE ] || CCACHE=
;;
esac
for opt do
optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
case $opt in
--help|-h|-\?) OPTION_HELP=yes
;;
--arch=*)
OPTION_ARCH=$optarg
;;
--armv5)
OPTION_ARMV7=no
;;
--armv7)
OPTION_ARMV7=yes
;;
--ccache=*)
CCACHE=$optarg
;;
--config=*)
OPTION_CONFIG=$optarg
;;
--cross=*)
OPTION_CROSS=$optarg
;;
--gcc-version=*)
OPTION_GCC_VERSION=$optarg
;;
-j*|--jobs=*)
OPTION_JOBS=$optarg
;;
--out=*)
OPTION_OUT=$optarg
;;
--savedefconfig)
OPTION_SAVEDEFCONFIG=yes
;;
--verbose)
OPTION_VERBOSE=true
;;
*)
echo "unknown option '$opt', use --help"
exit 1
esac
done
if [ $OPTION_HELP = "yes" ] ; then
echo "Rebuild the prebuilt kernel binary for Android's emulator."
echo ""
echo "options (defaults are within brackets):"
echo ""
echo " --help print this message"
echo " --arch=<arch> change target architecture [$ARCH]"
echo " --armv5 build ARMv5 binaries"
echo " --armv7 build ARMv7 binaries (default. see note below)"
echo " --out=<directory> output directory [$OUTPUT]"
echo " --cross=<prefix> cross-toolchain prefix [$CROSSPREFIX]"
echo " --config=<name> kernel config name [$CONFIG]"
echo " --savedefconfig run savedefconfig"
echo " --ccache=<path> use compiler cache [${CCACHE:-not set}]"
echo " --gcc-version=<version> use specific GCC version [$GCC_VERSION]"
echo " --verbose show build commands"
echo " -j<number> launch <number> parallel build jobs [$JOBS]"
echo ""
echo "NOTE: --armv7 is equivalent to --config=goldfish_armv7. It is"
echo " ignored if --config=<name> is used."
echo ""
exit 0
fi
if [ ! -f include/linux/vermagic.h ]; then
echo "ERROR: You must be in the top-level kernel source directory to run this script."
exit 1
fi
# Extract kernel version, we'll need to put this in the final binaries names
# to ensure the emulator can trivially know it without probing the binary with
# 'file' or other unreliable heuristics.
KERNEL_MAJOR=$(awk '$1 == "VERSION" { print $3; }' Makefile)
KERNEL_MINOR=$(awk '$1 == "PATCHLEVEL" { print $3; }' Makefile)
KERNEL_PATCH=$(awk '$1 == "SUBLEVEL" { print $3; }' Makefile)
KERNEL_VERSION="$KERNEL_MAJOR.$KERNEL_MINOR.$KERNEL_PATCH"
echo "Found kernel version: $KERNEL_VERSION"
if [ -n "$OPTION_ARCH" ]; then
ARCH=$OPTION_ARCH
fi
if [ -n "$OPTION_GCC_VERSION" ]; then
GCC_VERSION=$OPTION_GCC_VERSION
else
if [ "$ARCH" = "x86" ]; then
# Work-around a nasty bug.
# Hence 132637 is 2.6.29.
if [ "$KERNEL_VERSION" = "2.6.29" ]; then
GCC_VERSION=4.6
echo "WARNING: android-goldfish-$KERNEL_VERSION doesn't build --arch=$ARCH with GCC 4.7"
fi
fi
if [ "$ARCH" = "arm64" ]; then
# There is no GCC 4.7 toolchain to build AARCH64 binaries.
GCC_VERSION=4.8
fi
if [ "$ARCH" = "mips64" ]; then
GCC_VERSION=4.9
fi
if [ "$ARCH" = "mips" ]; then
GCC_VERSION=4.9
fi
echo "Autoconfig: --gcc-version=$GCC_VERSION"
fi
if [ -n "$OPTION_CONFIG" ]; then
CONFIG=$OPTION_CONFIG
else
case $ARCH in
arm)
CONFIG=goldfish_armv7
if [ "$OPTION_ARMV7" = "no" ]; then
CONFIG=goldfish
fi
;;
x86)
# Warning: this is ambiguous, should be 'goldfish' before 3.10,
# and 'i386_emu" after it.
if [ -f "arch/x86/configs/i386_emu_defconfig" ]; then
CONFIG=i386_emu
else
CONFIG=goldfish
fi
;;
x86_64)
CONFIG=x86_64_emu
;;
mips)
CONFIG=goldfish
;;
mips64)
CONFIG=ranchu64
;;
arm64)
CONFIG=ranchu
;;
*)
echo "ERROR: Invalid arch '$ARCH', try one of $VALID_ARCHS"
exit 1
esac
echo "Auto-config: --config=$CONFIG"
fi
# Check output directory.
if [ -n "$OPTION_OUT" ] ; then
if [ ! -d "$OPTION_OUT" ] ; then
echo "Output directory '$OPTION_OUT' does not exist ! Aborting."
exit 1
fi
OUTPUT=$OPTION_OUT
else
OUTPUT=$OUTPUT/${ARCH}-${KERNEL_VERSION}
case $CONFIG in
vbox*)
OUTPUT=${OUTPUT}-vbox
;;
goldfish)
if [ "$ARCH" = "arm" ]; then
OUTPUT=${OUTPUT}-armv5
fi
;;
esac
echo "Auto-config: --out=$OUTPUT"
mkdir -p $OUTPUT
fi
if [ -n "$OPTION_CROSS" ] ; then
CROSSPREFIX="$OPTION_CROSS"
CROSSTOOLCHAIN=${CROSSPREFIX}$GCC_VERSION
else
case $ARCH in
arm)
CROSSPREFIX=arm-linux-androideabi-
;;
x86)
CROSSPREFIX=x86_64-linux-android-
# NOTE: kernel-toolchain/toolbox.sh will add -m32
;;
x86_64)
CROSSPREFIX=x86_64-linux-android-
;;
mips)
CROSSPREFIX=mips64el-linux-android-
;;
mips64)
CROSSPREFIX=mips64el-linux-android-
;;
arm64)
CROSSPREFIX=aarch64-linux-android-
;;
*)
echo "ERROR: Unsupported architecture!"
exit 1
;;
esac
CROSSTOOLCHAIN=${CROSSPREFIX}$GCC_VERSION
echo "Auto-config: --cross=$CROSSPREFIX"
fi
ZIMAGE=zImage
case $ARCH in
x86|x86_64)
ZIMAGE=bzImage
;;
arm64)
ZIMAGE=Image
;;
mips)
ZIMAGE=
;;
mips64)
ZIMAGE=
;;
esac
# If the cross-compiler is not in the path, try to find it automatically
CROSS_COMPILER="${CROSSPREFIX}gcc"
CROSS_COMPILER_VERSION=$($CROSS_COMPILER --version 2>/dev/null)
if [ $? != 0 ] ; then
BUILD_TOP=$ANDROID_BUILD_TOP
if [ -z "$BUILD_TOP" ]; then
# Assume this script is under external/qemu/distrib/ in the
# Android source tree.
BUILD_TOP=$(dirname $0)/../..
if [ ! -d "$BUILD_TOP/prebuilts" ]; then
BUILD_TOP=
else
BUILD_TOP=$(cd $BUILD_TOP && pwd)
fi
fi
case $ARCH in
x86_64)
# x86_46 binaries are under prebuilts/gcc/<host>/x86 !!
PREBUILT_ARCH=x86
;;
arm64)
PREBUILT_ARCH=aarch64
;;
mips64)
PREBUILT_ARCH=mips
;;
*)
PREBUILT_ARCH=$ARCH
;;
esac
CROSSPREFIX=$BUILD_TOP/prebuilts/gcc/$HOST_TAG/$PREBUILT_ARCH/$CROSSTOOLCHAIN/bin/$CROSSPREFIX
echo "Checking for ${CROSSPREFIX}gcc"
if [ "$BUILD_TOP" -a -f ${CROSSPREFIX}gcc ]; then
echo "Auto-config: --cross=$CROSSPREFIX"
else
echo "It looks like $CROSS_COMPILER is not in your path ! Aborting."
exit 1
fi
fi
if [ "$CCACHE" ] ; then
echo "Using ccache program: $CCACHE"
CROSSPREFIX="$CCACHE $CROSSPREFIX"
fi
export CROSS_COMPILE="$CROSSPREFIX" ARCH SUBARCH=$ARCH
if [ "$OPTION_JOBS" ]; then
JOBS=$OPTION_JOBS
else
echo "Auto-config: -j$JOBS"
fi
# Special magic redirection with our magic toolbox script
# This is needed to add extra compiler flags to compiler.
# See kernel-toolchain/android-kernel-toolchain-* for details
#
export REAL_CROSS_COMPILE="$CROSS_COMPILE"
CROSS_COMPILE=$(dirname "$0")/kernel-toolchain/android-kernel-toolchain-
MAKE_FLAGS=
if [ "$OPTION_VERBOSE" ]; then
MAKE_FLAGS="$MAKE_FLAGS V=1"
fi
case $CONFIG in
defconfig)
MAKE_DEFCONFIG=$CONFIG
;;
*)
MAKE_DEFCONFIG=${CONFIG}_defconfig
;;
esac
ORG_ARCH=$ARCH
case $ARCH in
mips64)
# MIPS64 Kernel code base is under arch/mips
ARCH=mips
;;
esac
# Do the build
#
rm -f include/asm &&
make $MAKE_DEFCONFIG && # configure the kernel
make -j$JOBS $MAKE_FLAGS # build it
if [ $? != 0 ] ; then
echo "Could not build the kernel. Aborting !"
exit 1
fi
if [ "$OPTION_SAVEDEFCONFIG" = "yes" ]; then
case $ARCH in
x86_64)
DEFCONFIG_ARCH=x86
;;
*)
DEFCONFIG_ARCH=$ARCH
;;
esac
make savedefconfig
mv -f defconfig arch/$DEFCONFIG_ARCH/configs/${CONFIG}_defconfig
fi
# Note: The exact names of the output files are important for the Android build,
# do not change the definitions lightly.
KERNEL_PREFIX=kernel-$KERNEL_VERSION
# Naming conventions for the kernel image files:
#
# 1) The kernel image is called kernel-qemu, except for 32-bit ARM
# where it must be called kernel-qemu-armv7
#
# 2) The debug symbol file is called vmlinux-qemu, except for 32-bit
# ARM where it must be called vmlinux-qemu-armv7
#
OUTPUT_KERNEL=kernel-qemu
OUTPUT_VMLINUX=vmlinux-qemu
if [ "$CONFIG" = "goldfish_armv7" ]; then
OUTPUT_KERNEL=${OUTPUT_KERNEL}-armv7
OUTPUT_VMLINUX=${OUTPUT_VMLINUX}-armv7
fi
cp -f vmlinux $OUTPUT/$OUTPUT_VMLINUX
if [ ! -z $ZIMAGE ]; then
cp -f arch/$ARCH/boot/$ZIMAGE $OUTPUT/$OUTPUT_KERNEL
else
cp -f vmlinux $OUTPUT/$OUTPUT_KERNEL
fi
echo "Kernel $CONFIG prebuilt images ($OUTPUT_KERNEL and $OUTPUT_VMLINUX) copied to $OUTPUT successfully !"
cp COPYING $OUTPUT/LINUX_KERNEL_COPYING
cat > $OUTPUT/README <<EOF
This directory contains kernel images to be used with the Android emulator
program, for the $ORG_ARCH CPU architecture. It was built with the $PROGNAME
script. For more details, read:
\$AOSP/external/qemu/docs/ANDROID-KERNEL.TXT
EOF
exit 0