Skip to main content
CMake is the recommended build system for Android native development. The Android NDK includes a CMake toolchain file (android.toolchain.cmake) that configures CMake for cross-compilation.

Toolchain configuration

To use the Android toolchain, specify it when invoking CMake:
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=arm64-v8a \
      -DANDROID_PLATFORM=android-21 \
      ..

Platform variables

These variables configure the target Android platform and architecture.
ANDROID_ABI
string
required
Target Application Binary Interface (ABI). Determines the instruction set and calling conventions.
set(ANDROID_ABI "arm64-v8a")

Supported ABI values

ABIDescriptionArchitecture
arm64-v8aARMv8-A 64-bitModern ARM devices (recommended)
armeabi-v7aARMv7-A 32-bit with NEONOlder ARM devices
x86_64x86 64-bitIntel/AMD 64-bit emulators and devices
x86x86 32-bitIntel/AMD 32-bit emulators
For new applications, target arm64-v8a and x86_64. The armeabi, mips, and mips64 ABIs are deprecated and removed.
ANDROID_PLATFORM
string
required
Minimum Android API level to target. Determines available APIs and system libraries.
set(ANDROID_PLATFORM "android-21")
Android 5.0 (API 21) is the minimum supported version for 64-bit ABIs. Use API 21 or higher for modern applications.
ANDROID_NDK
path
Path to the Android NDK. Automatically set by Android Studio, but can be specified manually.
set(ANDROID_NDK "/path/to/android-ndk")

C++ configuration

CMake provides variables to configure the C++ standard library and language features.
ANDROID_STL
string
C++ Standard Library implementation to use. Default is c++_shared.
set(ANDROID_STL "c++_shared")

STL options

OptionDescriptionUse case
c++_sharedLLVM libc++ shared libraryRecommended for most apps
c++_staticLLVM libc++ static librarySingle shared library projects
noneNo C++ standard libraryC-only projects
systemSystem C++ runtimeDeprecated, minimal support
If using c++_static, ensure all shared libraries in your app use the same STL to avoid violations of the One Definition Rule (ODR).
CMAKE_CXX_STANDARD
integer
C++ language standard version. Common values: 11, 14, 17, 20.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
CMAKE_CXX_FLAGS
string
Additional C++ compiler flags.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -frtti -fexceptions")
CMAKE_C_FLAGS
string
Additional C compiler flags.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror")

Compilation settings

ANDROID_ARM_MODE
string
ARM instruction set mode for 32-bit ARM builds: arm (32-bit) or thumb (16-bit, default).
set(ANDROID_ARM_MODE "arm")
ANDROID_ARM_NEON
boolean
Enable ARM NEON SIMD instructions for armeabi-v7a. Default is TRUE.
set(ANDROID_ARM_NEON TRUE)
ANDROID_DISABLE_FORMAT_STRING_CHECKS
boolean
Disable compiler format string security checks. Default is FALSE. Not recommended.
set(ANDROID_DISABLE_FORMAT_STRING_CHECKS FALSE)
ANDROID_CCACHE
path
Path to ccache executable for faster rebuilds.
set(ANDROID_CCACHE "/usr/bin/ccache")

Linking configuration

CMAKE_SHARED_LINKER_FLAGS
string
Linker flags for shared libraries.
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--build-id")
ANDROID_LD
string
Linker to use: lld (default, recommended) or deprecated (old GNU linkers).
set(ANDROID_LD "lld")
The LLD linker is faster and produces smaller binaries. The deprecated GNU linkers (gold, bfd) are removed in newer NDK versions.

Library linking

Link Android system libraries using target_link_libraries:
target_link_libraries(native-lib
    # Android system libraries
    android
    log
    EGL
    GLESv2
    OpenSLES
)

Common Android libraries

LibraryDescriptionUse case
logAndroid loggingDebug and diagnostic output
androidAndroid native app glueNativeActivity support
EGLEGL graphicsOpenGL ES context management
GLESv2OpenGL ES 2.02D/3D graphics rendering
GLESv3OpenGL ES 3.0+Advanced graphics features
OpenSLESOpenSL ESLow-latency audio
mediandkMedia APIsVideo/audio codec access
camera2ndkCamera2 NDKCamera hardware access
vulkanVulkan graphicsModern graphics API
jnigraphicsBitmap accessDirect bitmap manipulation
zzlib compressionData compression

Complete CMakeLists.txt example

cmake_minimum_required(VERSION 3.22.1)

project("native-audio")

# Configure C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -DDEBUG")

# Add library
add_library(native-audio SHARED
    native-audio.cpp
    audio-engine.cpp
    audio-player.cpp
)

# Include directories
target_include_directories(native-audio PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Link libraries
target_link_libraries(native-audio
    android
    log
    OpenSLES
)

# Preprocessor definitions
target_compile_definitions(native-audio PRIVATE
    VERSION="1.0.0"
    $<$<CONFIG:Debug>:ENABLE_LOGGING>
)

Build types

CMake supports different build configurations:
CMAKE_BUILD_TYPE
string
Build configuration: Debug, Release, RelWithDebInfo, or MinSizeRel.
set(CMAKE_BUILD_TYPE Release)
Build TypeOptimizationDebug InfoUse case
DebugNone (-O0)Full (-g)Development and debugging
ReleaseMaximum (-O3)NoneProduction builds
RelWithDebInfoOptimized (-O2)Full (-g)Profiling and stack traces
MinSizeRelSize (-Os)NoneSize-constrained environments

Architecture-specific code

Use CMake variables to conditionally compile architecture-specific code:
if(ANDROID_ABI STREQUAL "armeabi-v7a")
    target_sources(native-lib PRIVATE neon_impl.cpp)
    target_compile_options(native-lib PRIVATE -mfpu=neon)
elseif(ANDROID_ABI STREQUAL "arm64-v8a")
    target_sources(native-lib PRIVATE neon64_impl.cpp)
elseif(ANDROID_ABI MATCHES "x86.*")
    target_sources(native-lib PRIVATE sse_impl.cpp)
endif()

Useful CMake variables

VariableDescription
ANDROIDAlways TRUE when using Android toolchain
ANDROID_ABITarget ABI (e.g., arm64-v8a)
ANDROID_PLATFORM_LEVELNumeric API level (e.g., 21)
CMAKE_ANDROID_ARCH_ABISame as ANDROID_ABI
CMAKE_SYSTEM_NAMEAlways Android
CMAKE_SYSTEM_VERSIONAndroid API level

Finding and using libraries

Using find_library

Find system libraries at runtime:
find_library(log-lib log)
find_library(android-lib android)

target_link_libraries(native-lib
    ${log-lib}
    ${android-lib}
)

Importing prebuilt libraries

add_library(third-party SHARED IMPORTED)
set_target_properties(third-party PROPERTIES
    IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_ABI}/libthirdparty.so
)

target_link_libraries(native-lib third-party)

Using external projects

include(ExternalProject)

ExternalProject_Add(
    external-lib
    PREFIX ${CMAKE_BINARY_DIR}/external
    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/lib
    CMAKE_ARGS
        -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
        -DANDROID_ABI=${ANDROID_ABI}
        -DANDROID_PLATFORM=${ANDROID_PLATFORM}
        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
)

Gradle integration

Android Studio uses Gradle to invoke CMake. Configure CMake in build.gradle:
android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++17 -frtti -fexceptions"
                abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64'
                arguments "-DANDROID_STL=c++_shared"
            }
        }
    }
    
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.22.1'
        }
    }
}

Gradle CMake arguments

ArgumentDescription
cppFlagsAdditional C++ compiler flags
cFlagsAdditional C compiler flags
abiFiltersList of ABIs to build
argumentsAdditional CMake arguments
targetsSpecific CMake targets to build

Advanced configuration

Custom toolchain configuration

# Set before project()
set(CMAKE_TOOLCHAIN_FILE "${ANDROID_NDK}/build/cmake/android.toolchain.cmake")
set(ANDROID_ABI "arm64-v8a")
set(ANDROID_PLATFORM "android-21")
set(ANDROID_STL "c++_shared")

project("myproject")

# Custom compiler flags
add_compile_options(
    -Wall
    -Wextra
    -Werror
    $<$<CONFIG:RELEASE>:-O3>
    $<$<CONFIG:DEBUG>:-O0 -g>
)

Strip symbols in release builds

if(CMAKE_BUILD_TYPE STREQUAL "Release")
    add_custom_command(TARGET native-lib POST_BUILD
        COMMAND ${CMAKE_STRIP} --strip-unneeded $<TARGET_FILE:native-lib>
        COMMENT "Stripping symbols from release build"
    )
endif()

Multiple ABI builds

# In CMakeLists.txt, detect ABI and configure accordingly
message(STATUS "Building for ABI: ${ANDROID_ABI}")

if(ANDROID_ABI STREQUAL "arm64-v8a" OR ANDROID_ABI STREQUAL "armeabi-v7a")
    message(STATUS "Enabling ARM-specific optimizations")
    target_compile_definitions(native-lib PRIVATE ARM_OPTIMIZATIONS=1)
endif()
For production apps, build for at least arm64-v8a and armeabi-v7a to support both modern and older devices. The Play Store requires 64-bit support.

Debugging CMake configuration

Enable verbose CMake output:
# Command line
cmake -DCMAKE_VERBOSE_MAKEFILE=ON ..

# Or in CMakeLists.txt
set(CMAKE_VERBOSE_MAKEFILE ON)
Print configuration variables:
message(STATUS "Android ABI: ${ANDROID_ABI}")
message(STATUS "Android Platform: ${ANDROID_PLATFORM}")
message(STATUS "Android STL: ${ANDROID_STL}")
message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}")
message(STATUS "C++ Flags: ${CMAKE_CXX_FLAGS}")

Build docs developers (and LLMs) love