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的根目录,然后选择新建 > 文件。
注意:您可以在任何位置创建构建脚本。但是,在配置构建脚本时,您原生源文件和库的路径相对于构建脚本的位置。
- 输入“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 能够在编译时找到您的头文件,您需要将include_directories()
命令添加到您的 CMake 构建脚本中,并指定头文件的路径。
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 中删除旧版本的库之前清理项目。要清理项目,请从菜单栏中选择构建 > 清理项目。
Android Studio 会自动将源文件和头文件添加到项目窗格中的cpp组。通过使用多个add_library()
命令,您可以定义其他库,让 CMake 从其他源文件构建。
添加 NDK API
Android NDK 提供了一组您可能会发现有用的原生 API 和库。您可以通过在项目的CMakeLists.txt
脚本文件中包含NDK 库来使用任何这些 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 架构,同时允许您仅使用所需的库版本。要将库的多个 ABI 版本添加到 CMake 构建脚本中,而无需为每个版本的库编写多个命令,您可以使用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
此命令将生成可以执行以创建 Android 可执行库(.so
文件)的 Ninja 项目。CMAKE_TOOLCHAIN_FILE
是使用 NDK 的 CMake 支持所必需的。对于 CMake 3.21 或更高版本,可以使用 CMake 内置的 NDK 支持,但必须使用不同的变量组,如 CMake 的跨编译 Android文档中所述。