CMake 构建脚本是一个纯文本文件,您必须将其命名为 CMakeLists.txt
,其中包含 CMake 用于构建 C/C++ 库的命令。如果您的原生源文件尚未包含 CMake 构建脚本,您需要自行创建一个并包含相应的 CMake 命令。如需了解如何安装 CMake,请参阅安装和配置 NDK 和 CMake。
本部分介绍了一些您应包含在构建脚本中的基本命令,以便告诉 CMake 在创建原生库时要使用哪些源文件。要了解更多信息,请阅读关于CMake 命令的官方文档。
配置新的 CMake 构建脚本后,您需要配置 Gradle 以将您的 CMake 项目作为构建依赖项包含在内,以便 Gradle 构建原生库并将其与您的应用 APK 一起打包。
注意:如果您的项目使用 ndk-build,则无需创建 CMake 构建脚本。您只需配置 Gradle,通过提供 Android.mk
文件的路径来包含您现有的原生库项目。
创建 CMake 构建脚本
要创建可用作 CMake 构建脚本的纯文本文件,请按以下步骤操作:
- 从 IDE 的左侧打开项目窗格,然后从下拉菜单中选择项目视图。
- 右键点击 your-module 的根目录,然后选择 New > File。
注意:您可以将构建脚本创建在任何您想创建的位置。但是,在配置构建脚本时,原生源文件和库的路径是相对于构建脚本的位置的。
- 输入“CMakeLists.txt”作为文件名,然后点击确定。
现在,您可以通过添加 CMake 命令来配置构建脚本。要指示 CMake 从原生源代码创建原生库,请将 cmake_minimum_required()
和 add_library()
命令添加到构建脚本中:
# Sets the minimum version of CMake required to build your native library. # This ensures that a certain set of CMake features is available to # your build. cmake_minimum_required(VERSION 3.4.1) # Specifies a library name, specifies whether the library is STATIC or # SHARED, and provides relative paths to the source code. You can # define multiple libraries by adding multiple add_library() commands, # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. add_library( # Specifies the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp )
提示:与您告知 CMake 从源文件创建原生库的方式类似,您可以使用 add_executable()
命令告知 CMake 转而从这些源文件创建可执行文件。但是,从原生源文件构建可执行文件是可选的,构建要打包到 APK 中的原生库可以满足大多数项目要求。
当您使用 add_library()
将源文件或库添加到 CMake 构建脚本时,在您同步项目后,Android Studio 也会在项目视图中显示相关的头文件。但是,为了让 CMake 在编译时找到您的头文件,您需要在 CMake 构建脚本中添加 include_directories()
命令并指定头文件的路径:
add_library(...) # Specifies a path to native header files. include_directories(src/main/cpp/include/)
CMake 命名库文件的惯例如下:
liblibrary-name.so
例如,如果您在构建脚本中将共享库的名称指定为“native-lib”,CMake 会创建一个名为 libnative-lib.so
的文件。但是,在您的 Java 或 Kotlin 代码中加载此库时,请使用您在 CMake 构建脚本中指定的名称:
Kotlin
companion object { init { System.loadLibrary("native-lib"); } }
Java
static { System.loadLibrary("native-lib"); }
注意:如果您在 CMake 构建脚本中重命名或移除库,您需要先清理项目,然后 Gradle 才能应用更改或从 APK 中移除旧版本的库。要清理项目,请从菜单栏中选择 Build > Clean Project。
Android Studio 会自动将源文件和头文件添加到项目窗格中的 cpp 组。通过使用多个 add_library()
命令,您可以为 CMake 定义要从其他源文件构建的其他库。
添加 NDK API
Android NDK 提供了一组您可能会觉得有用的原生 API 和库。您可以通过将 NDK 库包含在项目的 CMakeLists.txt
脚本文件中来使用这些 API 中的任何一个。
预构建的 NDK 库已经存在于 Android 平台上,因此您无需构建它们或将其打包到您的 APK 中。由于 NDK 库已经是 CMake 搜索路径的一部分,您甚至无需在本地 NDK 安装中指定库的位置,您只需向 CMake 提供您要使用的库的名称,并将其链接到您自己的原生库。
将 find_library()
命令添加到您的 CMake 构建脚本中,以定位 NDK 库并将其路径存储为变量。您可以使用此变量在构建脚本的其他部分引用 NDK 库。以下示例定位 Android 特定的日志支持库并将其路径存储在 log-lib
中:
find_library( # Defines the name of the path variable that stores the # location of the NDK library. log-lib # Specifies the name of the NDK library that # CMake needs to locate. log )
为了让您的原生库调用 log
库中的函数,您需要在 CMake 构建脚本中使用 target_link_libraries()
命令链接库:
find_library(...) # Links your native library against one or more other native libraries. target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. ${log-lib} )
NDK 还包含一些作为源代码的库,您需要构建这些库并将其链接到您的原生库。您可以使用 CMake 构建脚本中的 add_library()
命令将源代码编译成原生库。要提供本地 NDK 库的路径,您可以使用 ANDROID_NDK
路径变量,Android Studio 会自动为您定义此变量。
以下命令告知 CMake 构建 android_native_app_glue.c
(它管理 NativeActivity
生命周期事件和触摸输入)为一个静态库,并将其链接到 native-lib
:
add_library( app-glue STATIC ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ) # You need to link static libraries against your shared native library. target_link_libraries( native-lib app-glue ${log-lib} )
添加其他预构建库
添加预构建库类似于指定另一个要由 CMake 构建的原生库。但是,由于库已构建,您需要使用 IMPORTED
标志来告知 CMake 您只想将库导入到您的项目中:
add_library( imported-lib SHARED IMPORTED )
然后,您需要使用 set_target_properties()
命令指定库的路径,如下所示。
某些库为特定的 CPU 架构或应用二进制接口 (ABI) 提供单独的软件包,并将其组织到单独的目录中。这种方法有助于库利用某些 CPU 架构,同时允许您只使用您想要的库版本。要在 CMake 构建脚本中添加多个 ABI 版本的库,而无需为库的每个版本编写多个命令,您可以使用 ANDROID_ABI
路径变量。此变量使用NDK 支持的默认 ABI 列表,或者您手动配置 Gradle 以使用的已过滤 ABI 列表。例如:
add_library(...) set_target_properties( # Specifies the target library. imported-lib # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import. imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
为了让 CMake 在编译时找到您的头文件,您需要使用 include_directories()
命令并包含头文件的路径:
include_directories( imported-lib/include/ )
注意:如果您想打包一个非构建时依赖项的预构建库(例如,添加一个作为 imported-lib
依赖项的预构建库),则无需执行以下说明来链接该库。
要将预构建库链接到您自己的原生库,请将其添加到 CMake 构建脚本中的 target_link_libraries()
命令:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
要将预构建库打包到您的 APK 中,您需要使用 sourceSets
块手动配置 Gradle,以包含您的 .so
文件的路径。构建 APK 后,您可以使用 APK 分析器验证 Gradle 将哪些库打包到您的 APK 中。
包含其他 CMake 项目
如果您想构建多个 CMake 项目并将其输出包含在您的 Android 项目中,您可以使用一个 CMakeLists.txt
文件作为顶层 CMake 构建脚本(即您链接到 Gradle 的那个文件),并将其他 CMake 项目作为该构建脚本的依赖项添加。以下顶层 CMake 构建脚本使用 add_subdirectory()
命令指定另一个 CMakeLists.txt
文件作为构建依赖项,然后像处理任何其他预构建库一样链接其输出。
# Sets lib_src_DIR to the path of the target CMake project. set( lib_src_DIR ../gmath ) # Sets lib_build_DIR to the path of the desired output directory. set( lib_build_DIR ../gmath/outputs ) file(MAKE_DIRECTORY ${lib_build_DIR}) # Adds the CMakeLists.txt file located in the specified directory # as a build dependency. add_subdirectory( # Specifies the directory of the CMakeLists.txt file. ${lib_src_DIR} # Specifies the directory for the build outputs. ${lib_build_DIR} ) # Adds the output of the additional CMake build as a prebuilt static # library and names it lib_gmath. add_library( lib_gmath STATIC IMPORTED ) set_target_properties( lib_gmath PROPERTIES IMPORTED_LOCATION ${lib_build_DIR}/${ANDROID_ABI}/lib_gmath.a ) include_directories( ${lib_src_DIR}/include ) # Links the top-level CMake build output against lib_gmath. target_link_libraries( native-lib ... lib_gmath )
从命令行调用 CMake
使用以下命令调用 CMake 以在 Android Studio 之外生成 Ninja 项目:
cmake
-Hpath/to/cmakelists/folder
-Bpath/to/generated/ninja/project/debug/ABI
-DANDROID_ABI=ABI // For example, arm64-v8a
-DANDROID_PLATFORM=platform-version-string // For example, android-16
-DANDROID_NDK=android-sdk/ndk/ndk-version
-DCMAKE_TOOLCHAIN_FILE=android-sdk/ndk/ndk-version/build/cmake/android.toolchain.cmake
-G Ninja
此命令将生成可执行的 Ninja 项目,以创建 Android 可执行库(.so
文件)。CMAKE_TOOLCHAIN_FILE
是使用 NDK 的 CMake 支持所必需的。对于 CMake 3.21 或更高版本,可以使用 CMake 的内置 NDK 支持,但必须使用不同的变量组,如 CMake 的Android 交叉编译文档中所述。