| 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. |