Android NDK开发详解之CMake工具链

Android NDK 支持使用 CMake 编译应用的 C 和 C++ 代码。本页介绍了如何通过 Android Gradle 插件的 ExternalNativeBuild 或通过直接调用 CMake 将 CMake 与 NDK 搭配使用。
注意:如果您使用的是 Android Studio,请参阅向您的项目添加 C 和 C++ 代码,了解以下方面的基础知识:向项目中添加原生源代码,创建 CMake 构建脚本,将 CMake 项目添加为 Gradle 依赖项,以及使用比 SDK 中的 CMake 版本更高的 CMake。

CMake 工具链文件

NDK 通过工具链文件支持 CMake。工具链文件是用于自定义交叉编译工具链行为的 CMake 文件。用于 NDK 的工具链文件位于 NDK 中以下位置:/build/cmake/android.toolchain.cmake。
注意:如果安装了 Android SDK,则 NDK 安装在 SDK 目录的以下位置:ndk/version/ 或 ndk-bundle/。

在调用 cmake 时,命令行会提供 ABI 和 minSdkVersion 等构建参数。如需查看支持的参数的列表,请参阅工具链参数部分。
警告:CMake 拥有自己的内置 NDK 支持。在 CMake 3.21 之前,此工作流程不受 Android 支持,并且经常会被新的 NDK 版本中断。从 CMake 3.21 开始,这些实现将被合并。CMake 的内置支持与 NDK 工具链文件具有类似的行为,但变量名称有所不同。从 Android NDK r23 开始,工具链文件将在使用 CMake 3.21 或更高版本时委托给 CMake 的内置支持。 如需了解详情,请参阅问题 463。请注意,Android Gradle 插件仍会自动使用 NDK 的工具链文件。

用法

Gradle

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

命令行

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

工具链参数

以下参数可以传递给 CMake 工具链文件。如果使用 Gradle 进行构建,请按照 ExternalNativeBuild 文档中所述向 android.defaultConfig.externalNativeBuild.cmake.arguments 添加参数。如果通过命令行进行构建,请使用 -D 将参数传递给 CMake。例如,要强制 armeabi-v7a 始终使用 Neon 支持进行构建,请传递 -DANDROID_ARM_NEON=TRUE。
注意:任何必需参数均由 Gradle 自动传递,只有在通过命令行构建时才需明确传递。

ANDROID_ABI

注意:这是必需参数。

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

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

命令行

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

在这里插入图片描述

ANDROID_ARM_MODE

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

在这里插入图片描述

ANDROID_ARM_NEON

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

在这里插入图片描述

ANDROID_LD

选择要使用的链接器。lld 目前处于 NDK 实验阶段,可通过此参数启用。
在这里插入图片描述

ANDROID_NATIVE_API_LEVEL

ANDROID_PLATFORM 的别名。

ANDROID_PLATFORM

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

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

命令行

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

警告:NDK 库无法在 API 级别低于构建代码所用的 ANDROID_PLATFORM 值的设备上运行。

此参数支持多种格式:

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。
注意:默认行为只适用于部分应用。选择 STL 之前,请务必先阅读 C++ 库支持指南,尤其是有关静态运行时的部分。
值 备注
c++_shared libc++ 的共享库变体。
c++_static libc++ 的静态库变体。
none 不支持 C++ 标准库。
system 系统 STL

了解 CMake 构建命令

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

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

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

以下代码段举例说明了如何使用 CMake 参数构建面向 armeabi-v7a 架构的 hello-jni 示例的可调试版本。

                    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

使用预构建库

如果您需要导入的预构建库是作为 AAR 分发的,请按照 Studio 的依赖项文档进行导入和使用。如果您未使用 AGP,可以按照 https://google.github.io/prefab/example-workflow.html 中的说明操作,但迁移到 AGP 可能要容易得多。

对于未作为 AAR 分发的库,如需了解有关如何将预构建库与 CMake 搭配使用的说明,请参阅 CMake 手册中关于 IMPORTED 目标的 add_library 文档。

构建第三方代码

将第三方代码作为 CMake 项目的一部分进行构建有多种方式,至于哪个方法最适合,则取决于您的具体情况。通常,最好的选择是别这样做。相反,请为相应的库构建 AAR,并在您的应用中使用该 AAR。倒不一定非要发布该 AAR。它可以作为 Gradle 项目的内部资源。

如果不行,请执行以下操作:

    将第三方源代码提供(即复制)到您的代码库中,然后使用 add_subdirectory 构建相应源代码。只有在另一个库也使用 CMake 构建的情况下,这种方法才有效。
    定义一个 ExternalProject。
    独立于您的项目构建该库,然后按照使用预构建库中的说明将其导入为预构建库。

CMake 中的 YASM 支持

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

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

    调用 enable_language,并将值设置为 ASM_NASM。
    如果要构建共享库,则调用 add_library;如果要构建可执行的二进制文件,则调用 add_executable。在参数中传入源文件列表,该列表包含用于 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 问题跟踪器报告这些问题。对于 Gradle 或 Android Gradle 插件问题,请改为报告 Studio bug。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android NDK开发是指利用NDK(Native Development Kit)将C/C++开发的代码编译成so库,然后通过JNI(Java Native Interface)让Java程序调用。在Android开发中,默认使用的是Android SDK进行Java语言的开发,而对于一些需要使用C/C++的高性能计算、底层操作或跨平台需求的场景,可以使用NDK进行开发。 在Android Studio中进行NDK开发相对于Eclipse来说更加方便,特别是在Android Studio 3.0及以上版本中,配置更加简化,并引入了CMake工具,使得开发更加便捷。首先要进行NDK开发,需要配置环境,包括导入NDK、LLDB和CMake工具。可以通过打开Android Studio的SDK Manager,选择SDK Tools,在其中选中相应的工具进行导入。 在项目的build.gradle文件中,可以配置一些NDK相关的参数,例如编译版本、ABI过滤器等。其中,可以通过externalNativeBuild配置CMake的相关设置,包括CMakeLists.txt文件的路径和版本号。此外,在sourceSets.main中还可以设置jniLibs.srcDirs,指定so库的位置。 在进行NDK开发时,可以在jni文件夹中编写C/C++代码,并通过JNI调用相关的函数。通过JNI接口,可以实现Java与C/C++之间的相互调用,从而实现跨语言的开发。 综上所述,Android NDK开发是指利用NDK将C/C++开发的代码编译成so库,并通过JNI实现与Java的相互调用。在Android Studio中进行NDK开发相对方便,可以通过配置环境和相应的参数来进行开发。<span class="em">1</span><span class="em">2</span><span class="em">3</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值