如果您不使用 CMake 或 ndk-build,但希望将 Android Gradle 插件 (AGP) C/C++ build 与 Android Studio 完全集成,则可以通过创建一个采用 Ninja 构建文件格式写入构建信息的 Shell 脚本,来创建自定义 C/C++ 构建系统。
Android Studio 和 AGP 中已添加了对自定义 C/C++ 构建系统的实验性支持。此功能在 Android Studio Dolphin | 2021.3.1 Canary 4 及更高版本中提供。
概览
C/C++ 项目(尤其是以多个平台为目标的项目)的一个常见模式是,根据某个底层表示形式为各个平台生成项目。CMake 就是此模式的一个突出例子。CMake 可以根据保存在 CMakeLists.txt
文件中的单个底层表示形式针对 Android、iOS 及其他平台生成项目。
虽然 AGP 直接支持 CMake,但还有其他项目生成器并不直接支持:
这些类型的项目生成器要么支持 Ninja 作为 C/C++ build 的后端表示形式,要么可以进行调整以生成 Ninja 作为后端表示形式。
如果配置正确,具有集成的 C/C++ 项目系统生成器的 AGP 项目可让用户执行以下操作:
从命令行和 Android Studio 构建。
在 Android Studio 中修改具有完整语言服务支持的源代码(例如,go-to definition)。
使用 Android Studio 调试程序调试原生进程和混合进程。
如何修改 build 以使用自定义 C/C++ build 配置脚本
本部分会详细介绍在 AGP 中使用自定义 C/C++ build 配置脚本的步骤。
第 1 步:修改模块级 build.gradle
文件以引用配置脚本
如需在 AGP 中启用 Ninja 支持,请在模块级 build.gradle
文件中配置 experimentalProperties
:
android {
defaultConfig {
externalNativeBuild {
experimentalProperties["ninja.abiFilters"] = [ "x86", "arm64-v8a" ]
experimentalProperties["ninja.path"] = "source-file-list.txt"
experimentalProperties["ninja.configure"] = "configure-ninja"
experimentalProperties["ninja.arguments"] = [
"\${ndk.moduleMakeFile}",
"--variant=\${ndk.variantName}",
"--abi=Android-\${ndk.abi}",
"--configuration-dir=\${ndk.configurationDir}",
"--ndk-version=\${ndk.moduleNdkVersion}",
"--min-sdk-version=\${ndk.minSdkVersion}"
]
}
}
AGP 会对这些属性进行解读,如下所示:
ninja.abiFilters
是要构建的 ABI 列表。有效值为x86
、x86-64
、armeabi-v7a
和arm64-v8a
。ninja.path
是 C/C++ 项目文件的路径。此文件可以采用您希望的任意格式。更改此文件将会在 Android Studio 中触发同步 Gradle 的提示。ninja.configure
是当需要配置 C/C++ 项目时,Gradle 将执行的脚本文件的路径。项目在以下情况下进行配置:首次构建时、在 Android Studio 中同步 Gradle 期间,或在某项配置脚本输入发生更改时。ninja.arguments
是将传递给 ninja.configure 定义的脚本的参数列表。此列表中的元素可以引用一组宏,这些宏的值取决于 AGP 中的当前配置上下文:${ndk.moduleMakeFile}
是ninja.configure
文件的完整路径。因此,在此示例中为C:\path\to\configure-ninja.bat
。${ndk.variantName}
是正在构建的当前 AGP 变体的名称。例如,调试或发布。${ndk.abi}
是正在构建的当前 AGP ABI 的名称。例如,x86
或arm64-v8a
。
${ndk.buildRoot}
是 AGP 生成的文件夹的名称,脚本会将其输出写入该文件夹。第 2 步:创建配置脚本中会对此进行详细介绍。${ndk.ndkVersion}
是要使用的 NDK 的版本。这通常是build.gradle
文件中传递给 android.ndkVersion 的值;如果不存在,则为默认值。${ndk.minPlatform}
是 AGP 请求的最小目标 Android 平台。
ninja.targets
是应构建的特定 Ninja 目标的列表。
第 2 步:创建配置脚本
配置脚本(上述示例中的 configure-ninja.bat
)的最低职责是生成一个 build.ninja
文件,在使用 Ninja 构建时,此文件会编译和关联项目的所有原生输出。这类文件通常为 .o
(对象)、.a
(归档)和 .so
(共享对象)文件。
配置脚本可以根据您的需要,在两个不同的位置写入 build.ninja
文件。
如果 AGP 可以选择位置,则配置脚本会在
${ndk.buildRoot}
宏中设置的位置写入build.ninja
。如果配置脚本需要选择
build.ninja
文件的位置,则它还会在${ndk.buildRoot}
宏中设置的位置写入一个名为build.ninja.txt
的文件。此文件包含配置脚本写入的build.ninja
文件的完整路径。
build.ninja
文件的结构
通常,大多数能够准确表示 Android C/C++ build 的结构均可以正常运作。AGP 和 Android Studio 所需的关键元素包括:
C/C++ 源代码文件列表,以及 Clang 编译这些文件所需的标志。
输出库列表。这些库通常是
.so
(共享对象)文件,但也可以是.a
(归档)文件或可执行文件(无扩展名)。
如果需要有关如何生成 build.ninja
文件的示例,您可以在使用 build.ninja
生成器时查看 CMake 的输出。
以下是最小 build.ninja
模板的示例。
rule COMPILE
command = /path/to/ndk/clang -c $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
build source.o : COMPILE source.cpp
build lib.so : LINK source.o
最佳做法
除了满足要求(源代码文件列表和输出库列表)之外,还建议遵循下面的最佳做法。
使用 phony
规则声明已命名输出
如有可能,建议 build.ninja
结构使用 phony
规则为构建输出设置简单易懂的名称。例如,如果您有一个名为 c:/path/to/lib.so
的输出,可以为其设置如下所示的简单易懂的名称。
build curl: phony /path/to/lib.so
这样做的好处是,晚些时候您可以在 build.gradle
文件中将此名称指定为构建目标。例如,
android {
defaultConfig {
externalNativeBuild {
...
experimentalProperties["ninja.targets"] = [ "curl" ]
指定“all”目标
如果您指定了 all
目标,那么当 build.gradle
文件中未明确指定任何目标时,这将是 AGP 构建的默认库集。
rule COMPILE
command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
build foo.o : COMPILE foo.cpp
build bar.o : COMPILE bar.cpp
build libfoo.so : LINK foo.o
build libbar.so : LINK bar.o
build all: phony libfoo.so libbar.so
指定其他构建方法(可选)
更高级的用例是,封装并非基于 Ninja 的现有构建系统。在此用例中,您仍然需要表示所有源代码文件及其标志,以及输出库,以便 Android Studio 可以显示适当的语言服务功能,如自动补全和 go-to definition。然而,您希望 AGP 在实际构建期间遵从底层构建系统。
为此,您可以使用包含特定扩展名 .passthrough
的 Ninja 构建输出。
举一个更具体的例子,我们假设您想要封装 MSBuild。您的配置脚本将照常生成 build.ninja
,但它还会添加一个直通目标,用于定义 AGP 如何调用 MSBuild。
rule COMPILE
command = /path/to/ndk/clang $in -o $out {other flags}
rule LINK
command = /path/to/ndk/clang $in -o $out {other flags}
rule MBSUILD_CURL
command = /path/to/msbuild {flags to build curl with MSBuild}
build source.o : COMPILE source.cpp
build lib.so : LINK source.o
build curl : phony lib.so
build curl.passthrough : MBSUILD_CURL
提供反馈
此功能是实验性功能,因此如果您能提供反馈,我们将不胜感激。您可以通过以下渠道提供反馈:
对于一般性反馈,请向此 bug 添加评论。
如要报告 bug,请打开 Android Studio,然后依次点击 Help > Submit Feedback。请务必引用“自定义 C/C++ 构建系统”,以帮助定位 bug。
如果您没有安装 Android Studio,并且要报告 bug,请使用此模板提交 bug。