Using the NDK with other build systems

The NDK contains official support for ndk-build and CMake. Most users should refer to one of those guides for building application code. The purpose of this document is to describe how to build existing code that uses other build systems. This is often the case with third-party dependencies that are not Android-specific, such as OpenSSL and libbzip2.

Build system maintainers looking to add native NDK support to their build systems should instead read the Build System Maintainers Guide.

Overview

As of NDK r19, the toolchains installed by default with the NDK may be used in-place. The make_standalone_toolchain.py script is no longer needed for interfacing with arbitrary build systems.

To ensure that you build for the correct architecture, either pass the appropriate target with -target when invoking Clang, or invoke the target-prefixed Clang. For example, to compile for 64-bit ARM Android with a minSdkVersion of 21, either of the following will work and you may use whichever you find most convenient:

$ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/clang++ \
    -target aarch64-linux-android21 foo.cpp
$ $NDK/toolchains/llvm/prebuilt/$HOST_TAG/aarch64-linux-android21-clang++ \
    foo.cpp

In both cases, replace $NDK with the path to the NDK and $HOST_TAG to match the NDK you downloaded according to the following table:

NDK OS Variant Host Tag
macOS darwin-x86_64
Linux linux-x86_64
32-bit Windows windows
64-bit Windows windows-x86_64

The format of the prefix or target argument here is the target triple with a suffix denoting the minSdkVersion. This suffix is only used with clang/clang++; the binutils tools (such as ar and strip) do not require a suffix because they are unaffected by minSdkVersion. Android's supported target triples are as follows:

ABI Triple
armeabi-v7a armv7a-linux-androideabi
arm64-v8a aarch64-linux-android
x86 i686-linux-android
x86-64 x86_64-linux-android

Many projects' build scripts will expect GCC-style cross compilers where each compiler targets only one OS/architecture combination and so may not handle -target cleanly. In these cases, it is better to use the triple-prefixed Clang binaries.

Autoconf

Autoconf projects allow you to specify the toolchain to use with environment variables. For example, the following shows how to build libpng for 64-bit Android ARM with a minSdkVersion of API level 21.

$ git clone https://github.com/glennrp/libpng
$ cd libpng
$ export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
$ export AR=$TOOLCHAIN/bin/aarch64-linux-android-ar
$ export AS=$TOOLCHAIN/bin/aarch64-linux-android-as
$ export CC=$TOOLCHAIN/bin/aarch64-linux-android21-clang
$ export CXX=$TOOLCHAIN/bin/aarch64-linux-android21-clang++
$ export LD=$TOOLCHAIN/bin/aarch64-linux-android-ld
$ export RANLIB=$TOOLCHAIN/bin/aarch64-linux-android-ranlib
$ export STRIP=$TOOLCHAIN/bin/aarch64-linux-android-strip
$ ./configure --host aarch64-linux-android
$ make

To target a different architecture or API level, use the appropriately prefixed tools.

Non-Autoconf make projects

Some makefile projects allow cross compilation by overriding the same variables that you would with an autoconf project. As an example, the following shows how to build libbzip2 for 32-bit Android ARM with a minSdkVersion of 16.

$ git clone https://gitlab.com/bzip/bzip2.git
$ cd bzip2
$ export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/$HOST_TAG
$ make \
    CC=$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang \
    AR=$TOOLCHAIN/bin/arm-linux-androideabi-ar \
    RANLIB=$TOOLCHAIN/bin/arm-linux-androideabi-ranlib \
    bzip2

As with autoconf, to target a different architecture or API level, use the appropriately prefixed tools.