Bazel 构建配置

build 配置是一组设置,例如 cpu = "arm64",其中 每项设置都会向已知的设备分配一个“配置值” 配置变量。这些值会影响 构建应用。

build 配置可被视为不可变字典映射变量 名称(字符串键)映射到配置值(布尔值、整数、字符串、列表) 字符串、标签或标签列表)。

它们仅在 Bazel 分析阶段才有意义, 其内容的唯一哈希值来表示。它们没有标签 不能直接出现在 Bazel 构建文件或 Starlark 代码中。

每个构建配置实例在 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-fastbuild1aarch64-dbg, 但很容易变得复杂得多。

小型 build 配置的一些示例 config_dir 值 但非常重要的示例 Bazel 项目

  • 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>

    指向用于向 Bazel 描述自定义 C++ 工具链的 CROSSTOOL 文件。 用于编译和链接目标或主机二进制文件。

存在大量的原生配置变量(以及相关的 命令行标志)。例如,Bazel 5.2.0 支持超过 340 种 (包括 83 个实验性 API)。

自定义配置标志(已弃用)

您可以定义自定义配置变量(名称混淆) 自定义配置标志,这些标志将在 命令行中的“--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",
  }
)

用户定义的构建设置

为了克服自定义 --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 配置。

转场是一种高级功能,本文不做详细介绍, 需要注意的是:

  • build 配置从概念上来说只是 映射到配置值E.g.:

    {
       "copt": "-O2 -g",
       "cpu": "x86_64",
       "compiler": "gcc",
       "//my_settings:enable_logs": True,
       
    }
    
  • 过渡提供了一个函数,该函数采用“当前 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,而 只有几个可以直接从 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 {

  1. k8 是现在称为 x86_64 CPU 架构的旧命名惯例。