blob: b2b2a2ec1671920b93fe71e07c70e109dd40104d [file] [log] [blame]
USING THE ANDROID TOOLCHAIN AS A STANDALONE COMPILER
======================================================
It is now possible to use the toolchains provided with the Android NDK as
standalone compilers. This can be useful if you already have your own build
system, and only need to ability to invoke the cross-compiler to add support
to Android for it.
A typical use case if invoking the 'configure' script of an open-source
library that expects a cross-compiler in the CC environment variable.
This document explains how to do that:
1/ Selecting your toolchain:
----------------------------
Before anything else, you need to decide whether your standalone toolchain
is going to target ARM-based devices, x86-based, or MIPS-based one.
Each architecture corresponds to a different toolchain name. For example:
* arm-linux-androideabi-4.6 => targeting ARM-based Android devices
* x86-4.6 => targeting x86-based Android devices
* mipsel-linux-android-4.6 => targeting MIPS-based Android devices
2/ Selecting your sysroot:
--------------------------
The second thing you need to know is which Android native API level you want
to target. Each one of them provides a different various APIs, which are
documented under doc/STABLE-APIS.html, and correspond to the sub-directories
of $NDK/platforms.
This allows you to define the path to your 'sysroot', a GCC term for a
directory containing the system headers and libraries of your target.
Usually, this will be something like:
SYSROOT=$NDK/platforms/android-<level>/arch-<arch>/
Where <level> is the API level number, and <arch> is the architecture
("arm", "x86", and "mips" are the supported values). For example, if you're
targeting Android 2.2 (a.k.a. Froyo), you would use:
SYSROOT=$NDK/platforms/android-8/arch-arm
IMPORTANT: Note that X86 and MIPS architectures are only supported at android-9 and later.
3/ Invoking the compiler (the hard way):
----------------------------------------
Invoke the compiler using the --sysroot option to indicate where the system
files for the platform you're targeting are located. For example, do:
export CC="$NDK/toolchains/<name>/prebuilt/<system>/bin/<prefix>gcc --sysroot=$SYSROOT"
$CC -o foo.o -c foo.c
Where <name> is the toolchain's name, <system> is the host tag for your system,
and <prefix> is a toolchain-specific prefix. For example, if you are on Linux
using the NDK r5 toolchain, you would use:
export CC="$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
As you can see, this is rather verbose, but it works!
IMPORTANT NOTE:
> Using the NDK toolchain directly has a serious limitation:
You won't be able to use any C++ STL (STLport, libc++,
the GNU libstdc++) with it. Also no exceptions and no RTTI.
> For clang, you need to add correct "-target" for given architecture, and add
"-gcc-toolchain" to path of GNU-based toolchain for "as" and "ld", eg.
1. Add "-target armv7-none-linux-androideabi" for armeabi-v7a, "-target armv5te-none-linux-androideabi"
for armeabi, "-target i686-none-linux-android" for x86, "-target mipsel-none-linux-android" for mips, and
2. Add "-gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64"
4/ Invoking the compiler (the easy way):
----------------------------------------
The NDK allows you to create a "customized" toolchain installation to make
life easier. For example, consider the following command:
$NDK/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/tmp/my-android-toolchain
This will create a directory named /tmp/my-android-toolchain containing a
copy of the android-5/arch-arm sysroot, and of the toolchain binaries.
Note that by default, the 32-bit ARM-based GCC 4.6 toolchain will be selected by the script.
Use the '--arch=x86' option to specify the x86 GCC 4.6, or add '--arch=mips' option
to specify the MIPS GCC 4.6, or alternatively
'--toolchain=<name>'. For example:
--toolchain=x86-4.8 # select x86 GCC 4.8 compiler
--toolchain=arm-linux-androideabi-4.7 # select ARM GCC 4.7 compiler
--toolchain=mipsel-linux-android-4.6 # select MIPS GCC 4.6 compiler, same as --arch=mips
If you wish, add '--llvm-version=3.3' to also copy clang/llvm 3.3, or
use --toolchain with '-clang3.3' suffix. For example:
--toolchain=arm-linux-androideabi-clang3.3 # same as --arch=arm --llvm-version=3.3
You may specify --system=linux-x86_64 on 64-bit Linux or --system=darwin-x86_64 on 64-bit
MacOSX to make 64-bit host toolchain instead of the 32-bit one (default).
See IV of NDK-BUILD.html
You may specify --stl=stlport to copy libstlport instead of libgnustl. Note that
to link against the shared library, you will have to explicitely use -lstlport_shared
in this case, just like you need to use -lgnustl_shared for the GNU libstdc++ case.
Static linking doesn't require anything special.
Likewise you may specify --stl=libc++ to copy LLVM libc++ headers and libraries. Note that
to link against the shared library, you will have to explicitely use -lc++_shared.
You can later use it directly with something like:
export PATH=/tmp/my-android-toolchain/bin:$PATH
export CC=arm-linux-androideabi-gcc # or export CC=clang
export CXX=arm-linux-androideabi-g++ # or export CXX=clang++
Note that without the --install-dir option, make-standalone-toolchain.sh will
create a tarball in /tmp/ndk/<toolchain-name>.tar.bz2. This allows you to
archive and redistribute the binaries easily.
Another important benefit is that this standalone toolchain will contain a
working copy of a C++ STL library, with working exceptions and RTTI support.
Use --help for more options and details.
> IMPORTANT: The toolchain binaries do not depend or contain host-specific paths,
in other words, they can be installed in any location, or even
moved if you need to.
> NOTE: You can still use the --sysroot option with the new toolchain, but it
is now simply optional!
5/ About Clang
---------------------
It is possible to also install Clang binaries in the standalone
installation by using the --llvm-version=<version> option, where
<version> is a LLVM/Clang version number (e.g. `3.2` or `3.3`). E.g.:
build/tools/make-standalone-toolchain.sh \
--install-dir=/tmp/mydir \
--toolchain=arm-linux-androideabi-4.7 \
--llvm-version=3.3
Note that Clang binaries are copied in addition to the GCC ones, because
they rely on the same assembler, linker, headers, libraries and C++
STL implementation.
This also installs two scripts under <install-dir>/bin/ named '`clang`'
and '`clang++`' which invoke the real clang binary with default
target architecture flags. In other words, they should "just work" and
you should be able to use them in your own builds by setting CC and CXX
environment variables to point to them.
The rest of this section gives more detail about how these work, in case
you encounter some unexpected problems.
For example, in an ARM standalone installation built with
`--llvm-version=3.3`, `clang` is a one-liner that looks like this on Unix:
`dirname $0`/clang31 -target armv5te-none-linux-androideabi "$@"
And `clang++` invokes `clang++31` in the same way.
Note that for ARM, `clang` will change target based on the presence of
subsequent option "`-march=armv7-a`" and/or "`-mthumb`". ie.
1. With "`-march=armv7-a`", -target becomes `armv7-none-linux-androideabi`.
2. With "`-mthumb`", -target becomes `thumb-none-linux-androideabi`.
3. With both, -target becomes `thumbv7-none-linux-androideabi`.
You may override with your own -target if you wish.
There is no need for "-gcc-toolchain" because clang locates "as" and "ld" in
predefined relative location in standalone package.
Extra efforts have been made to make clang/clang++ easier drop-in
replacements for gcc/g++ in Makefile. When in doubt, use the following
common techniques to check:
1. Add option "`-v`" to dump commands compiler driver issues
2. Add option "`-###`" to dump command line options, including those
implicitly predefined.
3. Use "`-x c` `/dev/null` `-dM` `-E`" to dump predefined preprocessor definitions
4. Add option "`-save-temps`" and compare the preprocessed files `*.i` or `*.ii`
See http://clang.llvm.org/ , especially the GCC compatibility section.
6/ ABI Compatibility:
---------------------
The machine code generated by the ARM toolchain should be compatible with
the official Android 'armeabi' ABI (see docs/CPU-ARCH-ABIS.html) by default.
It is recommended to use the -mthumb compiler flag to force the generation
of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones).
If you want to target the 'armeabi-v7a' ABI, you will need ensure that the
following flags are being used:
CFLAGS='-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16'
Note: The first flag enables Thumb-2 instructions, and the second one
enables H/W FPU instructions while ensuring that floating-point
parameters are passed in core registers, which is critical for
ABI compatibility. Do *not* use these flags separately before
NDK r9b!
If you want to use Neon instructions, you will need to change the -mfpu
compiler flag:
CFLAGS='-march=armv7-a -mfloat-abi=softfp -mfpu=neon'
Note that this forces the use of VFPv3-D32, as per the ARM specification.
Also, make sure the following two flags are provided to linker:
LDFLAGS='-march=armv7-a -Wl,--fix-cortex-a8'
Note: The first flag instructs linker to pick libgcc.a, libgcov.a and
crt*.o tailored for armv7-a. The 2nd flag is *required* to route
around a CPU bug in some Cortex-A8 implementations:
Since NDK r9b, all Android native APIs taking or returning double/float
has __attribute__((pcs("aapcs"))) for ARM. It's possible to compile
user code in -mhard-float (which implies -mfloat-abi=hard) and still
link with Android native APIs which follow softfp ABI. Please see
tests/device/hard-float/jni/Android.mk for details.
If you want to use Neon intrinsics on x86 they can be translated to the native
x86 SSE ones using special C/C++ language header with the same name as
standard arm neon intrinsics header "arm_neon.h".
By default x86 ABI supports SIMD up to SSE3 and the header covers ~83% NEON
functions (1551 of total 1872). It is recommended to use the -mssse3 compiler
flag which extends SIMD up to SSSE3 and in this case the header will cover
~98% NEON functions (1827 of total 1872):
CFLAGS='-mssse3'
To learn more about it, see docs/CPU-X86.html
If none of the above makes sense to you, it's probably better not to use
the standalone toolchain, and stick to the NDK build system instead, which
will handle all the details for you.
You don't have to use any specific compiler flag when targeting the MIPS ABI.
7/ Warnings and Limitations:
--------------------------
### 7.1/ Windows support:
The Windows binaries do *not* depend on Cygwin. The good news is that they
are thus faster, the bad news is that they do not understand the Cygwin
path specification like `/cygdrive/c/foo/bar` (instead of `C:/foo/bar`).
The NDK build system ensures that all paths passed to the compiler from Cygwin
are automatically translated, and deals with other horrors for you. If you have
a custom build system, you may need to deal with the problem yourself.
NOTE: There is no plan to support Cygwin / MSys at the moment, but
contributions are welcome. Contact the android-ndk forum for details.
### 7.2/ wchar_t support:
As documented, the Android platform did not really support wchar_t until
Android 2.3. What this means in practical terms is that:
- If you target platform android-9 or higher, the size of wchar_t is
4 bytes, and most wide-char functions are available in the C library
(with the exception of multi-byte encoding/decoding functions and
wsprintf/wsscanf).
- If you target any prior API level, the size of wchar_t will be 1 byte
and none of the wide-char functions will work anyway.
We recommend any developer to get rid of any dependencies on the wchar_t type
and switch to better representations. The support provided in Android is only
there to help you migrate existing code.
### 7.3/ Exceptions, RTTI and STL:
The toolchain binaries *do* support C++ exceptions and RTTI by default.
They are enabled by default, so use -fno-exceptions and -fno-rtti if you
want to disable them when building sources with them (e.g. to generate
smaller machine code).
NOTE: If you use the GNU libstdc++, you will need to explicitly link with
libsupc++ if you use these features. To do this, use -lsupc++ when
linking binaries, as in:
arm-linux-androideabi-g++ .... -lsupc++
This is not needed when using the STLport or libc++ library.
### 7.4/ C++ STL support:
The standalone toolchain includes a copy of a C++ Standard Template Library
implementation, either the GNU libstdc++, STLport, or libc++, determined by your
use of the --stl=<name> option described previously. To use this STL
implementation, you however need to link your project with the proper
library:
* Use -lstdc++ to link against the _static_ library version of any
implementation. This ensures that all required C++ STL code is
included into your final binary. This is ideal if you are only
generating a **single** shared library or executable.
This is the recommended way to do it.
* Use -lgnustl_shared to link against the _shared_ library version of
GNU libstdc++. If you use this option, you need to ensure that
`libgnustl_shared.so` is also copied to your device for your code to
load properly. The file is at:
$TOOLCHAIN/arm-linux-androideabi/lib/ for ARM toolchains.
$TOOLCHAIN/i686-linux-android/lib/ for x86 ones.
$TOOLCHAIN/mipsel-linux-android/lib/ for MIPS toolchains.
IMPORTANT: The GNU libstdc++ is licensed under the **GPLv3** with a
linking exception. See the following URL for details:
> http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01s02.html
> If you cannot comply with its requirements, i.e. you cannot redistribute
the shared library, do not use it in your project.
* Use -lstlport_shared to link against the _shared_ library version of
STLport. If you use this option, you need to ensure that
`libstlport_shared.so` is also copied to your device for your code
to load properly. They are found at the same locations than those
for `gnustl_shared`.
**VERY** **IMPORTANT** **NOTE**:
If your project contains _multiple_ shared libraries or
executables, you **must** link against a shared library STL implementation.
Otherwise, some global variables won't be defined uniquely, which can
result in all kind of weird behaviour at runtime, like crashes, exceptions
not being caught properly, and more surprises.
The reason the shared version of the libraries is not simply called
`libstdc++.so` is not called libstdc++.so is because this would conflict
at runtime with the system's own minimal C++ runtime, which is
`/system/lib/libstdc++.so`. This enforces a new name for the GNU ELF
library. This is not a problem for the static library.