概览
要使用正确的选项调用编译器,Bazel 需要 编译器内部结构,例如 include 目录和重要标志。 换句话说,Bazel 需要一个简化的编译器模型才能理解 运行。
Bazel 需要具备以下知识:
- 编译器是否支持 thinLTO、模块、动态链接或 PIC (位置无关代码)。
- 所需工具(例如 gcc、ld、ar、objcopy 等)的路径。
- 内置系统包含目录。Bazel 需要使用它们来验证
在
BUILD
文件。 - 默认的 sysroot。
- 用于编译、链接和归档的标志。
- 用于支持的编译模式(opt、dbg、快速构建)的标志。
- 创建编译器专门所需的变量。
如果编译器支持多个架构,则 Bazel 需要配置 。
CcToolchainConfigInfo
是一个提供程序,提供必要级别的
用于配置 Bazel C++ 规则的行为的粒度。默认情况下
Bazel 会自动为您的构建配置 CcToolchainConfigInfo
,但您可以
可以选择手动配置为此,你需要一条 Starlark 规则
提供 CcToolchainConfigInfo
,并且您需要指向
将 cc_toolchain
的 toolchain_config
属性添加到您的规则。
您可以通过调用CcToolchainConfigInfo
cc_common.create_cc_toolchain_config_info()
。
您可以在
@rules_cc//cc:cc_toolchain_config_lib.bzl
。
当 C++ 目标进入分析阶段时,Bazel 会选择合适的
cc_toolchain
基于 BUILD
文件进行定位,并获取
CcToolchainConfigInfo
cc_toolchain.toolchain_config
属性。cc_toolchain
目标
通过 CcToolchainProvider
将这些信息传递给 C++ 目标。
例如,编译或链接操作,由诸如
cc_binary
或 cc_library
需要以下信息:
- 要使用的编译器或链接器
- 编译器/链接器的命令行标记
- 通过
--copt/--linkopt
选项传递的配置标志 - 环境变量
- 执行操作的沙盒中所需的工件
除沙盒中所需的工件外,上述所有信息均
在 cc_toolchain
指向的 Starlark 目标中指定。
要传送到沙盒的工件在 cc_toolchain
中声明。
目标。例如,借助 cc_toolchain.linker_files
属性,您可以
指定要装入沙盒的链接器二进制文件和工具链库。
工具链选择
工具链选择逻辑的运作方式如下:
用户在
BUILD
文件中指定了cc_toolchain_suite
目标,并点了 使用--crosstool_top
选项。cc_toolchain_suite
目标引用了多个工具链。通过--cpu
和--compiler
标志的值决定了 工具链,可以仅基于--cpu
标志值进行选择,或者 基于联合--cpu | --compiler
值。选择流程 如下:如果指定了
--compiler
选项,则 Bazel 会cc_toolchain_suite.toolchains
中的相应条目 属性替换为--cpu | --compiler
。如果 Bazel 找不到 相应的条目,则会抛出错误。如果未指定
--compiler
选项,则 Bazel 会cc_toolchain_suite.toolchains
中的相应条目 属性只使用--cpu
。如果未指定任何标志,则 Bazel 会检查宿主系统,
--cpu
值。请参阅 检查机制代码。
选择工具链后,相应的 feature
和 action_config
Starlark 规则中的对象来控制 build 的配置(即
)。这些消息允许
而无需修改 Bazel 中的成熟 C++ 功能
Bazel 二进制文件。C++ 规则支持多个唯一操作(详细说明)
Bazel 源代码中的方法。
功能
功能是指需要命令行标记、操作
执行环境限制条件,或依赖项更改。功能
可以非常简单,例如允许 BUILD
文件选择
标志,例如 treat_warnings_as_errors
,或者与 C++ 规则和
将新的编译操作和输入添加到编译中,例如
header_modules
或 thin_lto
。
理想情况下,CcToolchainConfigInfo
包含一个特征列表,其中每个特征
功能由一个或多个标志组组成,每个组定义一个标志列表
适用于特定 Bazel 操作的不同选项
地图项按名称指定,以便与 Starlark 完全分离
根据 Bazel 版本创建规则配置。换句话说,Bazel 版本
影响 CcToolchainConfigInfo
配置的行为,前提是这些
无需使用新功能。
您可以通过以下某种方式启用某项功能:
- 地图项的
enabled
字段设置为true
。 - Bazel 或规则所有者明确启用它。
- 用户通过
--feature
Bazel 选项或features
规则启用该功能 属性。
功能可以相互依赖,具体取决于命令行标志、BUILD
文件
设置和其他变量。
特征关系
依赖项通常直接通过 Bazel 管理, 功能特性的内在冲突 build 中定义的新值。工具链规范支持更精细的 可直接在管理地图项的 Starlark 规则内使用的约束条件 支持和扩展。它们是:
限制条件 | 说明 |
requires = [ feature_set (features = [ 'feature-name-1', 'feature-name-2' ]), ] |
特征级。只有指定的必需项支持该功能,
功能。例如,如果某个功能仅在
某些构建模式(opt 、dbg 或
fastbuild )。如果 `requires` 包含多个 `feature_set`
如果满足任意一个 `feature_set`,则该特征受支持
(启用所有指定的功能时)。
|
implies = ['feature'] |
特征级。此特征隐含指定的特征。 启用某个功能也会隐式启用它隐含的所有功能 (即,以递归方式运行)。 此外,它还可以将常见的部分功能 例如消毒程序的常见组成部分暗示 功能无法停用。 |
provides = ['feature'] |
特征级。表示此地图项是几个相互独立的
独有的备选功能例如,所有的消毒程序都可以
指定 这样可以在用户询问时列出替代项,从而改善错误处理情况 同时实现两项或多项互斥功能。 |
with_features = [ with_feature_set( features = ['feature-1'], not_features = ['feature-2'], ), ] |
标志集级别。一个地图项可以指定多个包含多个标志集的标志。
如果指定了 with_features ,该标志集仅会展开
如果至少有一个 with_feature_set ,则添加到 build 命令
指定features 中的所有特征集的特征
已启用,并且 not_features 中指定的所有功能
一组被停用。
如果未指定 with_features ,则标志集将
并无条件地应用于指定的每个操作。
|
操作
操作可让您灵活地修改具体情况
操作执行,而不假定操作的运行方式。一个
action_config
指定操作调用的工具二进制文件,而
feature
指定用于确定该工具如何
在调用操作时的行为。
特征会引用操作,以指示哪些 Bazel 操作
因为操作可以修改 Bazel 操作图。通过
CcToolchainConfigInfo
提供程序包含具有标志和工具的操作
例如 c++-compile
。为每项操作指定了标记
将它们与某项特征相关联。
每个操作名称表示 Bazel 执行的一类操作,例如
编译或链接然而,这两者之间是多对一的关系
操作和 Bazel 操作类型,其中 Bazel 操作类型是指 Java 类
实现某项操作(例如 CppCompileAction
)。具体而言,
"汇编程序操作"和“编译器操作”如下表所示:
CppCompileAction
,而关联操作为 CppLinkAction
。
汇编程序操作
操作 | 说明 |
preprocess-assemble
|
组装预处理。通常用于 .S 文件。
|
assemble
|
在不进行预处理的情况下进行组建。通常用于 .s 文件。
|
编译器操作
操作 | 说明 |
cc-flags-make-variable
|
将 CC_FLAGS 传播到 Genrule。
|
c-compile
|
编译为 C 语言。 |
c++-compile
|
编译为 C++。 |
c++-header-parsing
|
对头文件运行编译器的解析器,以确保头文件 是独立的,否则会产生编译错误。应用 仅适用于支持模块的工具链。 |
链接操作
操作 | 说明 |
c++-link-dynamic-library
|
关联包含其所有依赖项的共享库。 |
c++-link-nodeps-dynamic-library
|
关联仅包含 cc_library 个来源的共享库。
|
c++-link-executable
|
关联最终的可运行库。 |
AR 操作
AR 操作通过 ar
将对象文件汇编到归档库(.a
文件)中
并将一些语义编码到名称中。
操作 | 说明 |
c++-link-static-library
|
创建静态库(归档)。 |
LTO 操作
操作 | 说明 |
lto-backend
|
将位码编译到原生对象的 ThinLTO 操作。 |
lto-index
|
生成全局索引的 ThinLTO 操作。 |
使用 action_config
action_config
是描述 Bazel 的 Starlark 结构体
通过指定要在操作期间调用的工具(二进制文件)和
标志。这些标志会对操作的
执行。
action_config()
构造函数包含以下参数:
属性 | 说明 |
action_name
|
与此操作对应的 Bazel 操作。 Bazel 使用此属性来发现每项操作的工具和执行 要求。 |
tools
|
要调用的可执行文件。应用于该操作的工具将是 列表中的第一个工具,其特征集与 配置。必须提供默认值。 |
flag_sets
|
适用于一组操作的标志列表。这与 功能。 |
env_sets
|
适用于一组操作的环境限制条件列表。 与功能相同。 |
action_config
可以要求和暗示其他功能和
action_config
前面介绍的特征关系。此行为
与特征类似。
最后两个属性与
因为一些 Bazel 操作需要使用特定标志或
环境变量,目标是避免不必要的 action_config
+feature
,
对。通常,在多个 action_config
之间共享一个特征的方法如下:
。
不能使用相同的 action_name
定义多个 action_config
。这可以防止工具路径产生歧义
并强制执行 action_config
背后的意图,即操作的属性
工具链中的单个位置都有清楚说明。
使用工具构造函数
action_config
可以通过其 tools
参数指定一组工具。
tool()
构造函数可接受以下参数:
字段 | 说明 |
path
|
相关工具的路径(相对于当前位置)。 |
with_features
|
特征集列表,其中必须至少要满足其中一个特征集 才能应用此工具。 |
对于给定的 action_config
,仅应用一个 tool
将其工具路径和执行要求添加到 Bazel 操作已选择工具
方法是遍历 action_config
上的 tools
属性,直到工具
具有与功能配置匹配的 with_feature
集
(请参阅本页前面的特征关系)
)。您应在工具列表末尾使用默认值
对应的功能。
用法示例
可以结合使用特性和操作来实现 Bazel 操作
具有多样化的跨平台语义的特征。例如,调试符号生成在
macOS 要求在编译操作中生成符号,然后调用
在关联操作期间创建压缩 dsym 归档的专用工具,以及
然后解压缩该归档,以生成应用软件包和 .plist
文件的大小
借助 Bazel,您可以改为按如下方式实现此流程:
unbundle-debuginfo
是 Bazel 操作:
load("@rules_cc//cc:defs.bzl", "ACTION_NAMES")
action_configs = [
action_config (
action_name = ACTION_NAMES.cpp_link_executable,
tools = [
tool(
with_features = [
with_feature(features=["generate-debug-symbols"]),
],
path = "toolchain/mac/ld-with-dsym-packaging",
),
tool (path = "toolchain/mac/ld"),
],
),
]
features = [
feature(
name = "generate-debug-symbols",
flag_sets = [
flag_set (
actions = [
ACTION_NAMES.c_compile,
ACTION_NAMES.cpp_compile
],
flag_groups = [
flag_group(
flags = ["-g"],
),
],
)
],
implies = ["unbundle-debuginfo"],
),
]
在 Linux 中,此功能的实现方式完全不同,
fission
或 Windows 版,它会生成 .pdb
文件。例如,
基于 fission
的调试符号生成的实现可能如下所示:
如下:
load("@rules_cc//cc:defs.bzl", "ACTION_NAMES")
action_configs = [
action_config (
name = ACTION_NAMES.cpp_compile,
tools = [
tool(
path = "toolchain/bin/gcc",
),
],
),
]
features = [
feature (
name = "generate-debug-symbols",
requires = [with_feature_set(features = ["dbg"])],
flag_sets = [
flag_set(
actions = [ACTION_NAMES.cpp_compile],
flag_groups = [
flag_group(
flags = ["-gsplit-dwarf"],
),
],
),
flag_set(
actions = [ACTION_NAMES.cpp_link_executable],
flag_groups = [
flag_group(
flags = ["-Wl", "--gdb-index"],
),
],
),
],
),
]
标志组
CcToolchainConfigInfo
允许您将标记捆绑到不同的组中,以便
特定用途。您可以在 中使用预定义的变量来指定标志,
标记值内,当将标记添加到
build 命令。例如:
flag_group (
flags = ["%{output_execpath}"],
)
在这种情况下,该标志的内容将替换为输出文件路径 操作。
标志组会按照其显示顺序展开到构建命令中 。
适用于在添加到 build 时需要使用不同的值重复使用的标志
命令,该标志组可以迭代 list
类型的变量。例如,
类型为 list
的变量 include_path
:
flag_group (
iterate_over = "include_paths",
flags = ["-I%{include_paths}"],
)
对于 include_paths
列表中的每个路径元素,会展开为 -I<path>
。全部
标志组声明正文中的标志(或 flag_group
)会扩展为
一个单元。例如:
flag_group (
iterate_over = "include_paths",
flags = ["-I", "%{include_paths}"],
)
对于 include_paths
列表中的每个路径元素,会展开为 -I <path>
。
一个变量可以重复多次。例如:
flag_group (
iterate_over = "include_paths",
flags = ["-iprefix=%{include_paths}", "-isystem=%{include_paths}"],
)
扩展为:
-iprefix=<inc0> -isystem=<inc0> -iprefix=<inc1> -isystem=<inc1>
变量可以对应于可使用点分表示法访问的结构。例如:
flag_group (
flags = ["-l%{libraries_to_link.name}"],
)
结构可以嵌套,也可以包含序列。防止名称冲突 为明确指定,您必须通过各个字段指定完整路径。例如:
flag_group (
iterate_over = "libraries_to_link",
flag_groups = [
flag_group (
iterate_over = "libraries_to_link.shared_libraries",
flags = ["-l%{libraries_to_link.shared_libraries.name}"],
),
],
)
条件扩展
标志组支持根据特定
(使用 expand_if_available
、expand_if_not_available
、
expand_if_true
、expand_if_false
或 expand_if_equal
属性。例如:
flag_group (
iterate_over = "libraries_to_link",
flag_groups = [
flag_group (
iterate_over = "libraries_to_link.shared_libraries",
flag_groups = [
flag_group (
expand_if_available = "libraries_to_link.shared_libraries.is_whole_archive",
flags = ["--whole_archive"],
),
flag_group (
flags = ["-l%{libraries_to_link.shared_libraries.name}"],
),
flag_group (
expand_if_available = "libraries_to_link.shared_libraries.is_whole_archive",
flags = ["--no_whole_archive"],
),
],
),
],
)
CcToolchainConfigInfo 参考文档
本部分提供了有关 build 变量、功能 成功配置 C++ 规则所需的信息。
CcToolchainConfigInfo 构建变量
以下是 CcToolchainConfigInfo
build 变量的参考。
变量 | 操作 | 说明 |
source_file
|
compile | 要编译的源文件。 |
input_file
|
strip | 要去除的制品。 |
output_file
|
compile | 编译输出。 |
output_assembly_file
|
compile | 发出的汇编文件。仅当
compile 操作会发出汇编文本,通常在使用
--save_temps 标志。其内容与
output_file 。
|
output_preprocess_file
|
compile | 预处理的输出。仅适用于编译
只对源文件进行预处理的操作,通常在使用
--save_temps 标志。其内容与
output_file 。
|
includes
|
compile | 编译器必须使用的文件序列 包含在编译的源代码中。 |
include_paths
|
compile | 编译程序所在的序列目录
搜索使用 #include<foo.h> 包含的标头
和 #include "foo.h" 。
|
quote_include_paths
|
compile | “-iquote ”序列包括:
编译器会在其中搜索包含的头文件的目录
#include "foo.h" 。
|
system_include_paths
|
compile | “-isystem ”序列包括:
编译器会在其中搜索包含的头文件的目录
#include <foo.h> 。
|
dependency_file
|
compile | 编译器生成的 .d 依赖项文件。
|
preprocessor_defines
|
compile | defines 的序列,例如 --DDEBUG 。
|
pic
|
compile | 将输出编译为与位置无关的代码。 |
gcov_gcno_file
|
compile | gcov 覆盖率文件。
|
per_object_debug_info_file
|
compile | 每个对象的调试信息 (.dwp ) 文件。
|
stripotps
|
strip | stripopts 的序列。
|
legacy_compile_flags
|
compile | 旧版标志序列
CROSSTOOL 字段,例如 compiler_flag 、
optional_compiler_flag 、cxx_flag 和
optional_cxx_flag 。
|
user_compile_flags
|
compile | 来自
copt 规则属性或 --copt ,
--cxxopt 和 --conlyopt 标志。
|
unfiltered_compile_flags
|
compile | 从
unfiltered_cxx_flag 旧版 CROSSTOOL 字段或
unfiltered_compile_flags 功能。系统不会根据
nocopts 规则属性。
|
sysroot
|
sysroot 。
|
|
runtime_library_search_directories
|
链接 | 链接器运行时搜索路径(通常为
使用 -rpath 标志设置)。
|
library_search_directories
|
链接 | 链接器搜索路径中的条目(通常使用
-L 标志)。
|
libraries_to_link
|
链接 | 在链接器调用中提供要链接为输入的文件的标记。 |
def_file_path
|
链接 | 在 Windows 上通过 MSVC 使用的 def 文件的位置。 |
linker_param_file
|
链接 | 由 bazel 创建的链接器参数文件的位置 可突破命令行长度限制。 |
output_execpath
|
链接 | 链接器输出的执行路径。 |
generate_interface_library
|
链接 | "yes" 或 "no" ,具体取决于接口库是否应
错误。
|
interface_library_builder_path
|
链接 | 接口库构建器工具的路径。 |
interface_library_input_path
|
链接 | 接口库 ifso 构建器工具的输入。
|
interface_library_output_path
|
链接 | 使用 ifso 构建器工具生成接口库的路径。
|
legacy_link_flags
|
链接 | 来自旧版 CROSSTOOL 字段的链接器标记。
|
user_link_flags
|
链接 | 来自 --linkopt 的链接器标记
或 linkopts 属性。
|
linkstamp_paths
|
链接 | 提供 linkstamp 路径的 build 变量。 |
force_pic
|
链接 | 如果存在此变量,则表示 PIC/PIE 代码应该 (已传递 Bazel 选项 `--force_pic`)。 |
strip_debug_symbols
|
链接 | 如果存在此变量,则表示调试 符号。 |
is_cc_test
|
链接 | 当前操作为“cc_test ”时为真
关联操作,否则为 false。
|
is_using_fission
|
编译, 链接, compile, link | 如果存在此变量,则表示存在裂解(每个对象的调试信息)
已启用。调试信息将改为位于 .dwo 文件中
的 .o 文件,以及编译器和链接器需要知道这一点。
|
fdo_instrument_path
|
编译, 链接, compile, link | 存储 FDO 插桩配置文件的目录的路径。 |
fdo_profile_path
|
compile | FDO 配置文件的路径。 |
fdo_prefetch_hints_path
|
compile | 缓存预提取配置文件的路径。 |
csfdo_instrument_path
|
编译, 链接, compile, link | 存储上下文敏感 FDO 的目录的路径 插桩配置文件。 |
知名功能
以下是功能及其激活的参考 条件。
功能 | 文档 |
opt | dbg | fastbuild
|
根据编译模式默认处于启用状态。 |
static_linking_mode | dynamic_linking_mode
|
根据关联模式默认处于启用状态。 |
per_object_debug_info
|
如果指定了 supports_fission 功能且
并且当前编译模式是在
--fission 标志。
|
supports_start_end_lib
|
如果启用(并且设置了 --start_end_lib 选项),则 Bazel
不会链接到静态库,而是使用
用于链接到对象的 --start-lib/--end-lib 链接器选项
。这加快了构建速度,因为不需要 Bazel 进行构建
静态库
|
supports_interface_shared_libraries
|
如果启用(并且 --interface_shared_objects 选项为
设置),则 Bazel 会关联将 linkstatic 设置为
对接口共享 False(默认为 cc_test )
库。这样可以加快增量重新链接的速度。
|
supports_dynamic_linker
|
启用后,C++ 规则将知道工具链可以生成共享 库。 |
static_link_cpp_runtimes
|
启用后,Bazel 将以静态链接形式静态链接 C++ 运行时
模式以及在动态链接模式下动态显示。制品
在 cc_toolchain.static_runtime_lib 中指定或
cc_toolchain.dynamic_runtime_lib 属性(具体取决于
关联模式)。
|
supports_pic
|
启用后,工具链将知道将 PIC 对象用于动态库。 每当需要 PIC 编译时,“pic”变量都会显示。如果未启用 默认情况下,并且传递了 `--force_pic`,则 Bazel 将请求 `supports_pic` 和 确认该功能是否已启用该功能缺失或无法 因此无法使用 `--force_pic`。 |
static_linking_mode | dynamic_linking_mode
|
根据关联模式默认处于启用状态。 |
no_legacy_features
|
阻止 Bazel 将旧版功能添加到 C++ 配置(如果存在)。请查看 功能。 |
旧版功能修补逻辑
Bazel 会将以下更改应用于工具链的功能,以便向后兼容 兼容性:
- 将
legacy_compile_flags
功能移至工具链顶部 - 将
default_compile_flags
功能移至工具链顶部 - 在工具链顶部添加
dependency_file
(如果不存在)功能 - 在工具链顶部添加
pic
(如果不存在)功能 - 在工具链顶部添加
per_object_debug_info
(如果不存在)功能 - 在工具链顶部添加
preprocessor_defines
(如果不存在)功能 - 在工具链顶部添加
includes
(如果不存在)功能 - 在工具链顶部添加
include_paths
(如果不存在)功能 - 在工具链顶部添加
fdo_instrument
(如果不存在)功能 - 在工具链顶部添加
fdo_optimize
(如果不存在)功能 - 在工具链顶部添加
cs_fdo_instrument
(如果不存在)功能 - 在工具链顶部添加
cs_fdo_optimize
(如果不存在)功能 - 在工具链顶部添加
fdo_prefetch_hints
(如果不存在)功能 - 在工具链顶部添加
autofdo
(如果不存在)功能 - 在工具链顶部添加
build_interface_libraries
(如果不存在)功能 - 在工具链顶部添加
dynamic_library_linker_tool
(如果不存在)功能 - 在工具链顶部添加
shared_flag
(如果不存在)功能 - 在工具链顶部添加
linkstamps
(如果不存在)功能 - 在工具链顶部添加
output_execpath_flags
(如果不存在)功能 - 在工具链顶部添加
runtime_library_search_directories
(如果不存在)功能 - 在工具链顶部添加
library_search_directories
(如果不存在)功能 - 在工具链顶部添加
archiver_flags
(如果不存在)功能 - 在工具链顶部添加
libraries_to_link
(如果不存在)功能 - 在工具链顶部添加
force_pic_flags
(如果不存在)功能 - 在工具链顶部添加
user_link_flags
(如果不存在)功能 - 在工具链顶部添加
legacy_link_flags
(如果不存在)功能 - 在工具链顶部添加
static_libgcc
(如果不存在)功能 - 在工具链顶部添加
fission_support
(如果不存在)功能 - 在工具链顶部添加
strip_debug_symbols
(如果不存在)功能 - 在工具链顶部添加
coverage
(如果不存在)功能 - 在工具链顶部添加
llvm_coverage_map_format
(如果不存在)功能 - 在工具链顶部添加
gcc_coverage_map_format
(如果不存在)功能 - 向工具链底部添加
fully_static_link
(如果不存在)功能 - 向工具链底部添加
user_compile_flags
(如果不存在)功能 - 向工具链底部添加
sysroot
(如果不存在)功能 - 向工具链底部添加
unfiltered_compile_flags
(如果不存在)功能 - 向工具链底部添加
linker_param_file
(如果不存在)功能 - 向工具链底部添加
compiler_input_flags
(如果不存在)功能 - 向工具链底部添加
compiler_output_flags
(如果不存在)功能
功能列表很长。我们计划将它们清除一次
Starlark 中的 Crosstool
完成。对于有兴趣的读者,请参阅
CppActionConfigs,
对于生产工具链,请考虑添加 no_legacy_features
工具链的独立性