如果您刚开始接触 Bazel,请先学习使用 Bazel 教程。
概览
Bazel 可以在许多不同的构建配置中运行,包括使用
Android 原生开发套件 (NDK) 工具链。这意味着
您可以直接在 Android 中编译 cc_library
和 cc_binary
规则
Bazel。Bazel 使用 android_ndk_repository
代码库完成此操作
规则。
前提条件
请确保您已安装 Android SDK 和 NDK。
如需设置 SDK 和 NDK,请将以下代码段添加到 WORKSPACE
中:
android_sdk_repository(
name = "androidsdk", # Required. Name *must* be "androidsdk".
path = "/path/to/sdk", # Optional. Can be omitted if `ANDROID_HOME` environment variable is set.
)
android_ndk_repository(
name = "androidndk", # Required. Name *must* be "androidndk".
path = "/path/to/ndk", # Optional. Can be omitted if `ANDROID_NDK_HOME` environment variable is set.
)
如需详细了解 android_ndk_repository
规则,请参阅构建
百科全书条目。
如果您使用的是最新版本的 Android NDK(r22 及更高版本),请使用
android_ndk_repository
的 Starlark 实现。
请按照
自述文件。
快速入门
如需构建适用于 Android 的 C++,只需将 cc_library
依赖项添加到您的
android_binary
或 android_library
规则。
例如,假设存在以下某个 Android 应用的 BUILD
文件:
# In <project>/app/src/main/BUILD.bazel
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
)
android_library(
name = "lib",
srcs = ["java/com/example/android/bazel/MainActivity.java"],
resource_files = glob(["res/**/*"]),
custom_package = "com.example.android.bazel",
manifest = "LibraryManifest.xml",
deps = [":jni_lib"],
)
android_binary(
name = "app",
deps = [":lib"],
manifest = "AndroidManifest.xml",
)
此 BUILD
文件会生成以下目标图表:
图 1. 具有 cc_library 依赖项的 Android 项目的构建图。
如需构建应用,只需运行以下命令:
bazel build //app/src/main:app
bazel build
命令会编译 Java 文件、Android 资源文件以及
cc_library
规则,并将所有内容打包到 APK 中:
$ zipinfo -1 bazel-bin/app/src/main/app.apk
nativedeps
lib/armeabi-v7a/libapp.so
classes.dex
AndroidManifest.xml
...
res/...
...
META-INF/CERT.SF
META-INF/CERT.RSA
META-INF/MANIFEST.MF
Bazel 会将所有 cc_library 编译成一个共享对象 (.so
) 文件,
针对 armeabi-v7a
ABI。要更改此 SDK 或针对
多个 ABI,请参阅关于配置目标
ABI 检索这些实体。
示例设置
在 BUILD.bazel
文件中,使用 android_binary
定义了三个目标,
android_library
和 cc_library
规则。
android_binary
顶级目标会构建 APK。
cc_library
目标包含具有 JNI 函数的单个 C++ 源文件
实现:
#include <jni.h>
#include <string>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_android_bazel_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
android_library
目标用于指定 Java 源文件、资源文件以及
依赖于 cc_library
目标。在此示例中,MainActivity.java
会加载
共享对象文件 libapp.so
,并定义了 JNI 的方法签名
函数:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
配置目标 ABI
如需配置目标 ABI,请使用 --android_platforms
标志,如下所示:
bazel build //:app --android_platforms=comma-separated list of platforms
与 --platforms
标志一样,传递给 --android_platforms
的值也为
platform
的标签
目标,并使用标准约束值来描述您的设备。
例如,对于具有 64 位 ARM 处理器的 Android 设备,您可以定义 您的平台,如下所示:
platform(
name = "android_arm64",
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:arm64",
],
)
每个 Android platform
都应使用 @platforms//os:android
操作系统限制条件。如需迁移 CPU 限制,请查看以下图表:
CPU 值 | 平台 |
---|---|
armeabi-v7a |
@platforms//cpu:armv7 |
arm64-v8a |
@platforms//cpu:arm64 |
x86 |
@platforms//cpu:x86_32 |
x86_64 |
@platforms//cpu:x86_64 |
当然,对于多架构 APK,您需要传递多个标签,
示例:--android_platforms=//:arm64,//:x86_64
(假设您在
顶级 BUILD.bazel
文件)。
Bazel 无法选择默认的 Android 平台,因此必须定义一个
使用 --android_platforms
指定。
根据 NDK 修订版本和 Android API 级别,以下 ABI 可 可用:
NDK 修订版本 | ABI |
---|---|
16 及更低版本 | armeabi、armeabi-v7a、arm64-v8a、mips、mips64、x86、x86_64 |
17 岁及以上 | armeabi-v7a、arm64-v8a、x86、x86_64 |
请参阅 NDK 文档 详细了解这些 ABI。
不建议在发布 build 中使用多 ABI Fat APK,因为它们会增加 APK 的大小,但对于开发和 QA 构建很有用。
选择 C++ 标准
使用以下标志根据 C++ 标准进行构建:
C++ 标准 | 标志 |
---|---|
C++98 | 默认,无需任何标志 |
C++11 | --cxxopt=-std=c++11 |
C++14 | --cxxopt=-std=c++14 |
C++17 语言 | --cxxopt=-std=c++17 |
例如:
bazel build //:app --cxxopt=-std=c++11
详细了解如何传递编译器标记和链接器标记(使用 --cxxopt
、--copt
和
--linkopt
中的用户手册。
编译器标记和链接器标记也可以指定为 cc_library
中的属性
使用 copts
和 linkopts
。例如:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
在不使用 android_binary
的情况下构建适用于 Android 的 cc_library
如需针对 Android 构建独立的 cc_binary
或 cc_library
,而不使用
android_binary
时,请使用 --platforms
标志。
例如,假设您在
my/platforms/BUILD
:
bazel build //my/cc/jni:target \
--platforms=//my/platforms:x86_64
使用此方法,整个 build 树都会受到影响。
这些标志可以放入 bazelrc
配置(每个 ABI 一个)中,
project/.bazelrc
:
common:android_x86 --platforms=//my/platforms:x86
common:android_armeabi-v7a --platforms=//my/platforms:armeabi-v7a
# In general
common:android_<abi> --platforms=//my/platforms:<abi>
然后,如需为 x86
构建 cc_library
,请运行以下命令:
bazel build //my/cc/jni:target --config=android_x86
通常,此方法适用于较低级别的目标(例如 cc_library
),或者在
您清楚自己要构建的是什么?依赖于自动配置
为您期望的高层级目标从 android_binary
转换
构建大量不受您控制的目标