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.

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.

Reference