构建配置是一组设置(比如 cpu = "arm64"
),其中每项设置都会为 Bazel 知道的已知配置变量分配一个配置值。这些值会影响 Bazel 的构建方式
build 配置可以看作是将变量名称(字符串键)映射到配置值(布尔值、整数、字符串、字符串列表、标签或标签列表)的不可变字典。
它们仅在 Bazel 分析阶段才有意义,并且通过其内容的唯一哈希在内部进行标识。它们没有标签,不能直接显示在 Bazel 构建文件或 Starlark 代码中。
每个 build 配置实例在 Bazel output_base
下都有自己的输出目录,即:
${output_base}/execroot/<workspace_name>/bazel-out/<config_dir>/bin/
在 build 配置上下文中评估的目标的 build 工件存储在其中。<config_dir>
值取决于 build 配置的内容。其计算是一个 Bazel 实现细节,实际上可能会因 Bazel 版本而异。
在最简单的情况下,<config_dir>
将类似于 ${cpu}-${compilation_mode}
(例如 k8-fastbuild
1 或 aarch64-dbg
),但复杂性可能会变得非常高。
下面是一些小型示例 Bazel 项目的 build 配置的一些 config_dir
值示例:
k8-fastbuild
k8-fastbuild-ST-6f89e1bee3ea
k8-fastbuild-ST-bd2abcc18995
k8-fastbuild-ST-ec22d3eeb595
k8-opt
k8-opt-exec-2B5CBBC6
k8-opt-exec-2B5CBBC6-ST-5934bb4653e4
请注意,上面的十六进制值与配置的 ID(即其唯一哈希值)无关。
通用 build 配置
默认情况下,Bazel 管理着两种配置:
默认配置,也称为目标配置,有歧义,因为它对应于必须在最终“目标”系统上运行的构建工件。
默认情况下,其设置与主机系统匹配,但可以使用命令行选项进行更改(请参阅下文)。
主机配置,对应于必须在运行 Bazel 的机器上运行的代码。此项包含的设置与默认配置相同,交叉编译(例如,使用
--cpu=<name>
进行编译)除外。
此外,还有:
- exec 配置,对应于在构建操作期间运行的代码。在实践中,这包含与主机相同的设置,但使用远程构建器时除外。
Bazel 项目还可以定义额外的配置来适应某些用例,例如在一次构建调用中针对多个目标架构进行交叉编译。
原生配置变量
bazel build
命令支持大量用于更改原生配置变量(也称为原生设置)的命令行选项,例如:
--cpu=<name>
和--host_cpu=<name>
:分别更改为默认配置或主机配置生成的代码的 CPU 架构。例如:
bazel build --cpu=arm64 --host_cpu=x86_64 ...
-c <mode>
、--compilation_mode=<mode>
或--host_compilation_mode=<mode>
:其中,
<mode>
是“fastbuild
”“dbg
”或“opt
”之一,用于描述一组编译器链接器标志。例如:bazel build -c opt --host_compilation_mode=dbg ...
--crosstool=<file_path>
或--host_crosstool=<file_path>
:指向一个
CROSSTOOL
文件,该文件用于向 Bazel 描述自定义 C++ 工具链,以便编译和关联目标或主机二进制文件。
有大量原生配置变量(和相关的命令行标志)。例如,Bazel 5.2.0 支持超过 340 种(包括 83 种实验性)。
自定义配置标志(已废弃)
您可以定义自定义配置变量(Bazel 文档中名称混乱的自定义配置标志),这些变量将在命令行中使用“--define <name>=<value>
”设置,其中 <name>
是任意 build 配置变量名称,<value>
记录为任意字符串(系统绝不会解释该值)。
您可以使用特殊构造在 BUILD.bazel
文件中测试这些名称,例如:
# This represents a named configuration condition which will be True whenever
# `--define foo=bar` is used in the `bazel build` command-line.
config_setting(
name = "is_foo_bar",
define_flags = {
"foo": "bar",
}
)
用户定义的 build 设置
为了克服自定义 --define
标志的限制,Bazel 项目现在可以定义符合以下条件的 build 配置变量:
使用标签(提供工作区和软件包范围,以及可用性检查)命名。
可以具有特定类型,类型包括布尔值、整数、字符串、字符串列表、标签和标签列表。
始终提供默认值。
您可以在命令行中使用“--<label>=<value>
”进行相关设置,如下所示:
# Set the build setting named enable_logs defined in # $WORKSPACE/my_settings/BUILD.bazel to True. # # Note that the double-slash must follow the double caret directly # without spaces between them.
bazel build --//my_settings:enable_logs=True …
它与必须出现在文件 $PROJECT/my_settings/BUILD.bazel
中的定义匹配,例如:
# From my_settings/BUILD.bazel
load("@bazel_skylib//rules/common_settings.bzl", "bool_flag")
bool_flag(
name = "enable_logs",
default_value = False
)
构建设置还可以在外部仓库中定义,如下所示:
# Set the build setting named enable_logs defined in the config/BUILD.bazel # file of the @project_settings external repository.
bazel build --@project_settings//config:enable_logs=True …
存储用户配置值
设置配置值的参数可存储在项目工作区目录顶部的 .bazelrc
文件中,而不是直接通过命令行传递,如下所示:
# from $PROJECT/.bazelrc
build --host_copt=-O3 -s
build --copt=-O1 -g -Wall
build --//my_settings:enable_logs=True
调用 bazel build <target>
时,.bazelrc
提供的选项会自动包含在内,因此生成的命令等同于:
bazel build --host_copy="-O3 -s" --copt="-O1 -g -Wall" --//my_settings:enable_logs=True <target>
您还可以使用自定义 name 对多个定义进行分组,如下所示:
# from $PROJECT/.bazelrc
build:conf_x64 --cpu=x86_64
build:conf_x64 --copt=-mavx2
build:conf_arm64 --cpu=aarch64
build:conf_arm64 --copt=-marmv8.1-a+simd
然后使用 --config=<name>
选择一个组中的所有选项,如下所示:
bazel build --config=conf_x64 <target>
这相当于:
bazel build --cpu=x86_64 --copt=-mavx2 <target>
您也可以将 --config
与其他选项结合使用,例如:
bazel build --config=conf_arm64 --copy="-DENABLE_ASSERTS=1" ...
===
重要提示:尽管名称是 --config
,但它不会创建新的 build 配置。这只是对用户的命令行选项进行分组的便捷方式。每个 <name>
都直接以递归方式扩展为其
规范元素,然后被 Bazel 完全忽略。
配置转换(快速概览)
除了标准目标、主机和执行配置之外,Bazel 还支持使用转换的概念创建额外的构建配置。
过渡是一项高级功能,我们在这里不会详述,但请务必了解:
从概念上来讲,build 配置只是将配置变量名称映射到配置值的字典。E.g.:
{ "copt": "-O2 -g", "cpu": "x86_64", "compiler": "gcc", "//my_settings:enable_logs": True, … }
过渡提供了一个函数,该函数将当前 build 配置作为输入,并返回新的 build 配置作为输出。
转换函数只能修改字典中的值,也就是说,它无法在输入中添加或移除键。
转换函数会在分析阶段(稍后介绍)下在特定条件下调用,但无法由用户通过命令行或
.bazelrc
文件直接触发。
检查 build 配置
运行 Bazel 构建命令后,您可以查看需要的所有配置。使用 bazel config
命令输出所有配置及其 config_dir
值的列表,例如:
$ bazel clean
$ bazel build //src:program
$ bazel config
Available configurations:
20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 k8-fastbuild
30f5a27e1bd054836d97b800bdfe61c6d1cffccdf6b82c9963e94020e3852026 k8-fastbuild-ST-bd2abcc18995
34e198ac81dafe34b82cf62466cc84f5b1af6ef8dce44b9283b3152a6635f64a k8-fastbuild-ST-6f89e1bee3ea
aaa26904110821b8e0f87aabfffcfb8e5003a5620aee74de3d7ddea9a654c0f6 k8-opt (host)
d6b1a93e6619d845f29ee752e338ec2636e7fbf4c88e50168602cc21f5ae6f13 k8-opt-exec-2B5CBBC6-ST-5934bb4653e4 (exec)
注意:配置信息会一直累积,直到下一次 bazel 清理完毕。
使用 bazel config <id>
将配置转储到 stdout,以检查其值。警告:输出内容很长。
$ bazel config 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 | wc -l
Loading:
INFO: Displaying config with id 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2
436
此处为实际输出的链接。
请注意,实际上,每个配置都是一组字典,每个字典涵盖一个特定主题。这些 fragment 称为 fragment,只有几个 fragment 可以直接从 Starlark 访问:
$ bazel config 20222e2616387f00ae3814d79f82a650829d1aea962d558edda5cf54c459f4a2 | grep FragmentOptions
FragmentOptions com.google.devtools.build.lib.analysis.PlatformOptions {
FragmentOptions com.google.devtools.build.lib.analysis.ShellConfiguration$Options {
FragmentOptions com.google.devtools.build.lib.analysis.config.CoreOptions {
FragmentOptions com.google.devtools.build.lib.analysis.test.CoverageConfiguration$CoverageOptions {
FragmentOptions com.google.devtools.build.lib.analysis.test.TestConfiguration$TestOptions {
FragmentOptions com.google.devtools.build.lib.bazel.rules.BazelRuleClassProvider$StrictActionEnvOptions {
FragmentOptions com.google.devtools.build.lib.bazel.rules.python.BazelPythonConfiguration$Options {
FragmentOptions com.google.devtools.build.lib.rules.android.AndroidConfiguration$Options {