CMake

Android NDK 支持使用 CMake 编译应用的 C 和 C++ 代码。本页介绍了如何通过 Android Gradle 插件的 ExternalNativeBuild 或通过直接调用 CMake 将 CMake 用于 NDK。

CMake 工具链文件

NDK 通过工具链文件支持 CMake。工具链文件是用于自定义交叉编译工具链行为的 CMake 文件。用于 NDK 的工具链文件位于 NDK 中的 <NDK>/build/cmake/android.toolchain.cmake 内。

在调用 cmake 时,命令行会提供 ABI 和 minSdkVersion 等构建参数。如需查看支持的参数的列表,请参阅工具链参数部分。

用法

Gradle

使用 externalNativeBuild 时,系统会自动使用 CMake 工具链文件。详情请参阅 Android Studio 的向您的项目添加 C 和 C++ 代码指南。

命令行

在 Gradle 之外使用 CMake 进行构建时,工具链文件本身及其参数必须传递给 CMake。例如:

$ cmake \
    -DCMAKE_TOOLCHAIN_FILE=$NDK/build/cmake/android.toolchain.cmake \
    -DANDROID_ABI=$ABI \
    -DANDROID_NATIVE_API_LEVEL=$MINSDKVERSION \
    $OTHER_ARGS

工具链参数

以下参数可以传递给 CMake 工具链文件。如果使用 Gradle 进行构建,请按照 ExternalNativeBuild 文档中所述向 android.defaultConfig.externalNativeBuild.cmake.arguments 添加参数。如果通过命令行进行构建,则将参数传递给 CMake 并加上 -D。例如,要强制 armeabi-v7a 始终使用 Neon 支持构建,请传递 -DANDROID_ARM_NEON=TRUE

ANDROID_ABI

目标 ABI。如需了解支持的 ABI,请参阅 Android ABI

Gradle

Gradle 会自动提供此参数。请勿在您的 build.gradle 文件中明确设置此参数。如需控制 ABI Gradle 的目标,请按照 Android ABI 中所述使用 abiFilters

命令行

CMake 针对每个版本的单个目标进行构建。如需以多个 Android ABI 为目标,您必须为每个 ABI 构建一次。建议对每个 ABI 使用不同的构建目录,以避免 build 之间发生冲突。

备注
armeabi-v7a
armeabi-v7a with NEON -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON 相同。
arm64-v8a
x86
x86_64

ANDROID_ARM_MODE

指定是为 armeabi-v7a 生成 arm 还是 thumb 指令。对其他 ABI 没有影响。如需了解详情,请参阅 Android ABI 文档。

备注
ARM
Thumb 默认行为。

ANDROID_ARM_NEON

为 armeabi-v7a 启用或停用 NEON。对其他 ABI 没有影响。对于 API 级别(minSdkVersionANDROID_PLATFORM)23 或更高级别,默认为 true,否则为 false。如需了解详情,请参阅 Neon 文档。

备注
TRUE API 级别 23 或更高版本的默认值。
FALSE API 级别 22 或更低版本的默认值。

ANDROID_LD

选择要使用的链接器。lld 目前处于 NDK 实验阶段,可通过此参数启用。

备注
lld 启用 lld。
默认 对于给定的 ABI 使用默认链接器。

ANDROID_NATIVE_API_LEVEL

ANDROID_PLATFORM 的别名。

ANDROID_PLATFORM

指定应用或库所支持的最低 API 级别。此值对应于应用的 minSdkVersion

Gradle

使用 Android Gradle 插件时,此值会自动设置为与应用的 minSdkVersion 相匹配,因此不应手动设置。

命令行

当直接调用 CMake 时,此值默认为所使用的 NDK 支持的最低 API 级别。例如,对于 NDK r20,此值默认为 API 级别 16。

此参数支持多种格式:

  • android-$API_LEVEL
  • $API_LEVEL
  • android-$API_LETTER

$API_LETTER 格式允许您指定 android-N,而无需确定与该版本关联的编号。请注意,某些版本的 API 增加了,但没有增加字母。您可以通过附加 -MR1 后缀来指定这些 API。例如,API 级别 25 为 android-N-MR1

ANDROID_STL

指定要为此应用使用的 STL。如需了解详情,请参阅 C++ 库支持。默认情况下将使用 c++_static

备注
c++_shared libc++ 的共享库变体。
c++_static libc++ 的静态库变体。
不支持 C++ 标准库。
系统 系统 STL

了解 CMake 构建命令

在调试 CMake 构建问题时,了解 Gradle 在为 Android 交叉编译时使用的具体构建参数会很有帮助。

Android Gradle 插件会将用于为每个 ABI 和构建类型执行 CMake 构建的构建参数保存至 cmake_build_command.txt。这些文件位于以下目录中:

<project-root>/<module-root>/.cxx/cmake/<build-type>/<ABI>/

以下代码段会显示一个 CMake 参数示例,用于构建面向 armeabi-v7a 架构的 hello-jni 示例的可调试版本。

Executable : ${HOME}/Android/Sdk/cmake/3.6.3155560/bin/cmake
arguments :
-H${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/src/main/cpp
-B${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/.cxx/cmake/arm7Debug/armeabi-v7a
-GAndroid Gradle - Ninja
-DANDROID_ABI=armeabi-v7a
-DANDROID_NDK=${HOME}/Android/Sdk/ndk-bundle
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/android-ndk/hello-jni/app/build/intermediates/cmake/arm7/debug/obj/armeabi-v7a
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.6.3155560/bin/ninja
-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk-bundle/build/cmake/android.toolchain.cmake
-DANDROID_NATIVE_API_LEVEL=23
-DANDROID_TOOLCHAIN=clang
jvmArgs :

使用预构建库

如需了解如何在 CMake 中使用预构建库,请参阅 CMake 手册中关于 IMPORTED 目标的 add_library 文档。

CMake 中的 YASM 支持

NDK 为构建 YASM 汇编代码提供 CMake 支持,以便在 x86 和 x86-64 架构上运行。YASM 是 x86 和 x86-64 架构的开源汇编程序,它基于 NASM 汇编程序。

如需使用 CMake 构建汇编代码,请在项目的 CMakeLists.txt 中进行以下更改:

  1. 调用 enable_language,并将值设置为 ASM_NASM
  2. 如果要构建共享库,则调用 add_library;如果要构建可执行的二进制文件,则调用 add_executable{.external}。在参数中传入源文件列表,该列表包含用于 YASM 中的汇编程序的 .asm 文件和用于相关 C 库或函数的 .c 文件。

以下代码段展示了如何配置 CMakeLists.txt 来将 YASM 程序构建为共享库。

cmake_minimum_required(VERSION 3.6.0)

enable_language(ASM_NASM)

add_library(test-yasm SHARED jni/test-yasm.c jni/print_hello.asm)

如需查看如何将 YASM 程序构建为可执行程序的示例,请参阅 NDK git 代码库中的 yasm 测试

报告问题

如果您在 NDK 或其 CMake 工具链文件方面遇到任何问题,请通过 GitHub 上的 android-ndk/ndk 问题跟踪器报告这些问题。