概览
要使用正确的选项调用编译器,Bazel 需要 编译器内部结构,例如 include 目录和重要标志。 换句话说,Bazel 需要一个简化的编译器模型来了解其工作原理。
Bazel 需要知道以下信息:
- 编译器是否支持 thinLTO、模块、动态链接或 PIC (位置无关代码)。
- 所需工具(例如 gcc、ld、ar、objcopy 等)的路径。
- 内置系统包含目录。Bazel 需要使用它们来验证
在
BUILD
文件。 - 默认的 sysroot。
- 用于编译、链接和归档的标志。
- 用于支持的编译模式(opt、dbg、fastboot)的标志。
- 创建编译器专门所需的变量。
如果编译器支持多个架构,则 Bazel 需要配置 。
CcToolchainConfigInfo
是一个提供程序,提供必要级别的
用于配置 Bazel C++ 规则的行为的粒度。默认情况下,Bazel 会自动为您的 build 配置 CcToolchainConfigInfo
,但您也可以选择手动进行配置。为此,您需要一个提供 CcToolchainConfigInfo
的 Starlark 规则,并且需要将 cc_toolchain
的 toolchain_config
属性指向您的规则。您可以通过调用CcToolchainConfigInfo
cc_common.create_cc_toolchain_config_info()
。
您可以在
@rules_cc//cc:cc_toolchain_config_lib.bzl
。
当 C++ 目标进入分析阶段时,Bazel 会根据 BUILD
文件选择适当的 cc_toolchain
目标,并从 cc_toolchain.toolchain_config
属性中指定的目标中获取 CcToolchainConfigInfo
提供程序。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
选项将 Bazel 指向该目标。cc_toolchain_suite
目标引用了多个工具链。通过--cpu
和--compiler
标志的值决定了 工具链,可以仅基于--cpu
标志值进行选择,或者 基于联合--cpu | --compiler
值。选择流程如下:如果指定了
--compiler
选项,Bazel 会使用--cpu | --compiler
从cc_toolchain_suite.toolchains
属性中选择相应的条目。如果 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 进行管理的,Bazel 只会强制执行要求并管理构建中定义的功能固有的冲突。借助工具链规范,您可以使用更精细的约束条件,直接在用于管理功能支持和扩展的 Starlark 规则中使用。它们是:
限制条件 | 说明 |
requires = [ feature_set (features = [ 'feature-name-1', 'feature-name-2' ]), ] |
功能级。只有在启用指定的必需功能后,系统才支持此功能。例如,当某项功能仅在特定 build 模式(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
是一种 Starlark 结构体,用于描述 Bazel
通过指定要在操作期间调用的工具(二进制文件)和
标志。这些标志会对操作的
执行。
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"],
),
]
在使用 fission
的 Linux 或生成 .pdb
文件的 Windows 中,此同一功能的实现方式可能完全不同。例如,
基于 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、strip | 编译输出。 |
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 ) 文件。
|
stripopts
|
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 | 缓存预提取配置文件的路径。 |
cs_fdo_instrument_path
|
编译、链接 | 用于存储上下文感知型 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
,以使工具链更加独立。