The Android NDK supports using CMake to
compile C and C++ code for your application. This page discusses how to use
CMake with the NDK via the Android Gradle Plugin's ExternalNativeBuild
or when
invoking CMake directly.
The CMake toolchain file
The NDK supports CMake via a toolchain file. Toolchain files are CMake files
that customize the behavior of the toolchain for cross-compiling. The toolchain
file used for the NDK is located in the NDK at
<NDK>/build/cmake/android.toolchain.cmake
.
Build parameters such as ABI, minSdkVersion
, etc. are given on the command
line when invoking cmake
. For a list of supported arguments, see the
Toolchain arguments section.
Usage
Gradle
Use of the CMake toolchain file is automatic when using
externalNativeBuild
. See Android Studio's Add C and C++ code to your
project guide for more information.
Command Line
When building with CMake outside of Gradle, the toolchain file itself and its arguments must be passed to CMake. For example:
$ cmake \
-DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=$ABI \
-DANDROID_PLATFORM=android-$MINSDKVERSION \
$OTHER_ARGS
Toolchain arguments
The following arguments can be passed to the CMake toolchain file. If building
with Gradle, add arguments to
android.defaultConfig.externalNativeBuild.cmake.arguments
as described in the
ExternalNativeBuild docs. If building from the command line, pass arguments to
CMake with -D
. For example, to force armeabi-v7a to always build with Neon
support, pass -DANDROID_ARM_NEON=TRUE
.
ANDROID_ABI
The target ABI. For information on supported ABIs, see Android ABIs.
Gradle
Gradle provides this argument automatically. Do not explicitly set this
argument in your build.gradle
file. To control what ABIs Gradle targets,
use abiFilters
as described in Android ABIs.
Command Line
CMake builds for a single target per build. To target more than one Android ABI, you must build once per ABI. It is recommended to use different build directories for each ABI to avoid collisions between builds.
Value | Notes |
---|---|
armeabi-v7a |
|
armeabi-v7a with NEON |
Same as -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON . |
arm64-v8a |
|
x86 |
|
x86_64 |
ANDROID_ARM_MODE
Specifies whether to generate arm or thumb instructions for armeabi-v7a. Has no effect for other ABIs. For more information, see the Android ABIs documentation.
Value | Notes |
---|---|
arm | |
thumb | Default behavior. |
ANDROID_ARM_NEON
Enables or disables NEON for armeabi-v7a. Has no effect for other ABIs. Defaults
to true for API level (minSdkVersion
or ANDROID_PLATFORM
) 23 or newer, false
otherwise. For more information, see the Neon support documentation.
Value | Notes |
---|---|
TRUE | Default for API level 23 or newer. |
FALSE | Default for API level 22 or older. |
ANDROID_LD
Selects which linker to use. lld is currently experimental for the NDK and can be enabled with this argument.
Value | Notes |
---|---|
lld | Enables lld. |
default | Use the default linker for the given ABI. |
ANDROID_NATIVE_API_LEVEL
Alias for ANDROID_PLATFORM.
ANDROID_PLATFORM
Specifies the minimum API level supported by the application or library. This
value corresponds to the application's minSdkVersion
.
Gradle
When using the Android Gradle Plugin, this value is automatically set to
match the application's minSdkVersion
and should not be set manually.
Command Line
When invoking CMake directly, this value defaults to the lowest API level supported by the NDK in use. For example, with NDK r20 this value defaults to API level 16.
Multiple formats are accepted for this parameter:
android-$API_LEVEL
$API_LEVEL
android-$API_LETTER
The $API_LETTER
format allows you to specify android-N
without the need to
determine the number associated with that release. Note that some releases
received an API increase without a letter increase. These APIs can be specified
by appending the -MR1
suffix. For example, API level 25 is android-N-MR1
.
ANDROID_STL
Specifies which STL to use for this application. For more information, see C++
library support. By default, c++_static
will be used.
Value | Notes |
---|---|
c++_shared | The shared library variant of libc++. |
c++_static | The static library variant of libc++. |
none | No C++ standard library suport. |
system | The system STL |
Understand the CMake build command
When debugging CMake build issues, it's helpful to know the specific build arguments that Gradle uses when cross-compiling for Android.
The Android Gradle Plugin saves the build arguments it uses for executing a
CMake build for each ABI and build type
pair to the build_command.txt
. These files are found in the following
directory:
<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/
The following snippet shows an example of the CMake arguments to build a
debuggable release of the hello-jni
sample targeting the armeabi-v7a
architecture.
Executable : ${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/src/main/cpp
-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DANDROID_PLATFORM=android-23
-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
-DCMAKE_SYSTEM_NAME=Android
-DCMAKE_SYSTEM_VERSION=23
-B${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/armeabi-v7a
-GNinja
jvmArgs :
Build command args: []
Version: 1
Use prebuilt libraries
If the prebuilt library you need to import is distributed as an AAR, follow Studio's dependency docs to import and use those. If you are not using AGP you can follow https://google.github.io/prefab/example-workflow.html, but it is likely much easier to migrate to AGP.
For libraries that are not distributed as an AAR, instructions on using prebuilt
libraries with CMake, see the add_library
documentation regarding IMPORTED
targets in the CMake manual.
Building third-party code
There are a handful of ways to build third-party code as part of your CMake project, and which option works best will depend on your situation. The best option will often be to not do this at all. Instead, build an AAR for the library and consume that in your application. You do not necessarily need to publish that AAR. It can be internal to your Gradle project.
If that's not an option:
- Vendor (i.e. copy) the third-party source into your repository and use add_subdirectory to build it. This only works if the other library is also built with CMake.
- Define an ExternalProject.
- Build the library separately from your project and follow Use prebuilt libraries to import it as a prebuilt.
YASM support in CMake
The NDK provides CMake support for building assembly code written in YASM to run on x86 and x86-64 architectures. YASM is an open-source assembler for x86 and x86-64 architectures, based on the NASM assembler.
To build assembly code with CMake, make the following changes in your project's
CMakeLists.txt
:
- Call
enable_language
with the value set toASM_NASM
. - Depending on whether you are building a shared library or an executable
binary, call
add_library
oradd_executable
. In the arguments, pass in a list of source files consisting of the.asm
files for the assembly program in YASM and the.c
files for the associated C libraries or functions.
The following snippet shows how you might configure your CMakeLists.txt
to
build a YASM program as a shared library.
cmake_minimum_required(VERSION 3.6.0)
enable_language(ASM_NASM)
add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)
For an example of how to build a YASM program as an executable, see the yasm test in the NDK git repository.
Report problems
If you run into any issues with the NDK or its CMake toolchain file, report them via the android-ndk/ndk issue tracker on GitHub. For Gradle or Android Gradle Plugin issues, report a Studio bug instead.