Build Android Toolchain
Generating or building a set of standalone Android toolchain is not an easy task. This article summarizes several issues I met when I tried to build binutils for ARM Android platform (arm-linux-androideabi
). My setup is a Ubuntu 14.04 machine (x86_64-linux-gnu
) with all AOSP building environment.
Build on host=x86_linux-gnu
If you want a standalone toolchain which can be used in your x86_64
machine, you don't need to build from scratch. You can simply generate from Android NDK package.
- download and install the latest NDK package from https://developer.android.com/ndk/downloads/index.html
- change into
$NDK_HOME/build/tools
directory - utilize
make-standalone-toolchain.sh
script to build a set of toolchain
Build on host=arm-linux-androideabi
If you need a toolchain running on Android, things became a little complicated. For example, I want to run gcc
or objdump
on ARM Android. Because we cannot get toolchain build for ARM, let's try to build from scratch.
Preparation
Because Android maintain their own toolchain forked from GNU, we need first clone the source code from Google's repository.
repo init -u https://android.googlesource.com/toolchain/manifest
Besides the toolchain source codes, we also need Android NDK package.
We can get some building information from toolchain/build/README file. This toolchain only supports:
1. Supported platforms.
The Android tool-chain supports the following hosts:
a. i686-linux-gnu (32-bit x86 Linux)
b. x86_64-linux-gnu (64-bit x86 Linux)
c. i686-apple-darwin* (OS X 10.4 and 10.5)
The Android toolchain supports the following targets:
a. arm-linux-androideabi
b. arm-eabi (for Android kernel)
c. arm-newlib-eabi (for runnng gcc regression tests)
d. i[3456]86-*-linux-gnu, x86_64-*-linux-gnu (for x86 targets)
The host
means which machine can run the toolchain, and the target
means which target machine is this toolchain used for. What we need here is host=arm-linux-androideabi
and target=arm-linux-androideabi
. That's why we need some extra modification on the source code.
Configure & Make
Firstly, we find the source code of binutils in toolchain/binutils/binutils-2.25
.
Secondly, create a build script with configure in it like mine:
#!/bin/bash
export PWD=`pwd`
export PREFIX=${PWD}/system
export NDK_HOME=/xxx/android-ndk-r10e
export CROSS_COMPILE=${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
export PATH=${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
export SYSROOT=${NDK_HOME}/platforms/android-21/arch-arm
make distclean
rm */config.cache
./configure \
--prefix=$PREFIX \
--host=arm-linux-androideabi \
--target=arm-linux-androideabi \
--disable-option-checking \
CC=${CROSS_COMPILE}gcc \
CXX=${CROSS_COMPILE}g++ \
CFLAGS="-g -I -O2 -mandroid -mbionic -I${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/include -I${SYSROOT}/usr/include/ --sysroot=${SYSROOT} -Wno-error -fPIE" \
LDFLAGS="-L${NDK_HOME}/platforms/android-21/arch-arm/usr/lib -pie" \
CPP=${CROSS_COMPILE}cpp \
CPPFLAGS="-I${NDK_HOME}/platforms/android-21/arch-arm/usr/include/" \
AR=${CROSS_COMPILE}ar
make -j4
mkdir -p $PREFIX
make install
Then, let's try it first with ./build.sh
. However, we may face these following errors.
Cannot find stdio_ext.h
header:
./fopen_unlocked.c:76:23: fatal error: stdio_ext.h: No such file or directory
#include
^
compilation terminated.
checking for stdint.h... make[2]: *** [fopen_unlocked.o] Error 1
make[2]: Leaving directory `/media/mssun/1cb9a33d-c5f6-4bba-b0ed-b4c6cbad345c/aosp/toolchain/binutils/binutils-2.25/libiberty'
make[1]: *** [all-libiberty] Error 2
make[1]: *** Waiting for unfinished jobs....
To solve this issue, just comment this include statement in fopen_unlocked.c
file.
$ find . -type f -name "fopen_unlocked.c"
./libiberty/fopen_unlocked.c
comment the statements:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
/* #ifdef HAVE_STDIO_EXT_H */
/* #include */
/* #endif */
Cannot find sys/sysctl.h
header
checking minix/config.h presence... ./physmem.c:52:25: fatal error: sys/sysctl.h: No such file or directory
## include <sys/sysctl.h>
^
compilation terminated.
make[2]: *** [physmem.o] Error 1
make[2]: Leaving directory `/media/mssun/1cb9a33d-c5f6-4bba-b0ed-b4c6cbad345c/aosp/toolchain/binutils/binutils-2.25/libiberty'
make[1]: *** [all-libiberty] Error 2
make[1]: *** Waiting for unfinished jobs....
The solution is same as previous issue, comment this header in physmen.c
file.
$ find . -type f -name physmem.c
./libiberty/physmem.c
comments the header statements:
/* #if HAVE_SYS_SYSCTL_H */
/* # include <sys/sysctl.h> */
/* #endif */
Cannot find crtbegin_so.o
and crtend_so.o
The last error is:
/android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtbegin_so.o: No such file or directory
/android-ndk-r10e/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.9/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtend_so.o: No such file or directory
collect2: error: ld returned 1 exit status
The solution is copy these two files from NDK sysroot to ld directory. So, change our building scripts as:
#!/bin/bash
export PWD=`pwd`
export PREFIX=${PWD}/system
export NDK_HOME=/xxx/android-ndk-r10e
export CROSS_COMPILE=${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-
export PATH=${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin:$PATH
export SYSROOT=${NDK_HOME}/platforms/android-21/arch-arm
make distclean
rm */config.cache
./configure \
--prefix=$PREFIX \
--host=arm-linux-androideabi \
--target=arm-linux-androideabi \
--disable-option-checking \
CC=${CROSS_COMPILE}gcc \
CXX=${CROSS_COMPILE}g++ \
CFLAGS="-g -I -O2 -mandroid -mbionic -I${NDK_HOME}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9/include -I${SYSROOT}/usr/include/ --sysroot=${SYSROOT} -Wno-error -fPIE" \
LDFLAGS="-L${NDK_HOME}/platforms/android-21/arch-arm/usr/lib -pie" \
CPP=${CROSS_COMPILE}cpp \
CPPFLAGS="-I${NDK_HOME}/platforms/android-21/arch-arm/usr/include/" \
AR=${CROSS_COMPILE}ar
ln -s ${NDK_HOME}/platforms/android-21/arch-arm/usr/lib/crtbegin_so.o ld/
ln -s ${NDK_HOME}/platforms/android-21/arch-arm/usr/lib/crtend_so.o ld/
make -j4
mkdir -p $PREFIX
make install
At last, we got:
$ ls system/bin/
addr2line ar as c++filt elfedit gprof ld ld.bfd nm objcopy objdump ranlib readelf size strings strip
$ file system/bin/readelf
system/bin/readelf: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Remarks
Pay attention the -fPIE
and -pie
flags in compiling and linking. Because Android only support position independent executable, we need to add flags to make PIE binaries. For Arch Linux users, you may meet /lib/cpp
error. Just link /usr/bin/cpp
as lib/cpp
will solve this issue.
At last, I haven't see any consequences after deleting those headers. Perhaps, some related functions will be affected. If you have any question or better solution, please leave a comment. Thank you.