Skip to main content
The Android NDK provides multiple build system options for compiling native code. Understanding the differences helps you choose the right tool for your project.

Available build systems

The NDK supports two primary build systems:

ndk-build

Traditional NDK build system using Android.mk files

CMake

Cross-platform build system with modern syntax
Both systems integrate with the Android Gradle Plugin to build your native libraries alongside your Android app.

Comparison

Pros:
  • Simple syntax for Android-specific builds
  • Direct NDK integration with built-in variables
  • Smaller learning curve for simple projects
  • Extensive documentation and examples
Cons:
  • Android-specific, not portable to other platforms
  • Limited functionality compared to CMake
  • Based on GNU Make syntax
  • Less flexible for complex build configurations
Best for:
  • Android-only projects
  • Simple native libraries
  • Legacy codebases using Android.mk

Choosing a build system

Use this decision tree to select the appropriate build system:
1

Evaluate portability needs

If your native code needs to run on multiple platforms (iOS, desktop, etc.), choose CMake for cross-platform compatibility.
2

Consider existing codebase

If you have existing Android.mk files or a legacy ndk-build setup, you can continue using ndk-build or migrate to CMake.
3

Assess complexity

For simple Android-only libraries with straightforward build requirements, ndk-build may be sufficient. For complex dependencies and build configurations, CMake provides more flexibility.
4

Check team expertise

If your team has experience with CMake from other projects, leverage that knowledge. Otherwise, ndk-build’s simpler syntax may be easier to learn.
Google recommends CMake for new projects due to its cross-platform nature and industry-standard tooling.

Build system features

Module support

Both build systems support building multiple native modules:
  • Static libraries (.a) - Linked at compile time
  • Shared libraries (.so) - Loaded at runtime
  • Executables - For command-line tools

ABI management

Both systems can target multiple Android ABIs:
android {
    defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
}
Building for all ABIs increases APK size. Target only the ABIs your users need.

Compiler flags and optimizations

Both systems allow you to customize:
  • Compiler flags (warnings, optimizations)
  • Preprocessor definitions
  • Include paths
  • Linker flags and library dependencies

Integration with Gradle

Both build systems integrate with the Android Gradle Plugin through the externalNativeBuild configuration:
build.gradle
android {
    externalNativeBuild {
        ndkBuild {
            path file('src/main/jni/Android.mk')
        }
    }
}
See Gradle integration for complete configuration details.

Migration between systems

You can migrate from ndk-build to CMake when needed:
1

Convert module definitions

Transform Android.mk module definitions into CMakeLists.txt targets using add_library() commands.
2

Map variables

Convert NDK-specific variables to CMake equivalents. For example, LOCAL_SRC_FILES becomes the source list in add_library().
3

Update dependencies

Convert LOCAL_SHARED_LIBRARIES and LOCAL_STATIC_LIBRARIES to target_link_libraries() calls.
4

Update Gradle configuration

Change externalNativeBuild.ndkBuild to externalNativeBuild.cmake in your build.gradle file.
5

Test thoroughly

Verify that all modules build correctly and run your test suite to ensure functionality is preserved.

Next steps

Using ndk-build

Learn about Android.mk and Application.mk files

Using CMake

Configure CMake for Android NDK projects

Gradle integration

Integrate native builds with Android Gradle

ABIs

Understand Android binary interfaces

Build docs developers (and LLMs) love