CMake

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

  1. Call enable_language with the value set to ASM_NASM.
  2. Depending on whether you are building a shared library or an executable binary, call add_library or add_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.