“Make”变量是一种特殊的可展开字符串变量类,适用于标记为“Subject to 'Make variable' substitution”的属性。
例如,这些选项可用于将特定的工具链路径注入用户构建的构建操作。
Bazel 同时提供预定义变量(适用于所有目标)和自定义变量(在依赖项目标中定义,仅适用于依赖于它们的目标)。
之所以使用“Make”一词,是因为历史原因:这些变量的语法和语义原本旨在与 GNU Make 保持一致。
使用
标记为 "Subject to 'Make variable' substitution" 的属性可按如下方式引用“Make”变量 FOO
:
my_attr = "prefix $(FOO) suffix"
换句话说,与 $(FOO)
匹配的任何子字符串都会展开为 FOO
的值。如果该值为 "bar"
,则最终字符串将变为:
my_attr = "prefix bar suffix"
如果 FOO
与使用方目标已知的变量不对应,Bazel 将失败并显示错误。
名称为非字母符号的“Make”变量(例如 @
)也可仅使用美元符号(不带括号)进行引用。例如:
my_attr = "prefix $@ suffix"
如需将 $
作为字符串字面量写入(即防止变量展开),请编写 $$
.
Predefined variables
Predefined "Make" variables can be referenced by any attribute marked as "Subject to 'Make variable' substitution" on any target.
To see the list of these variables and their values for a given set of build options, run
bazel info --show_make_env [build options]
and look at the top output lines with capital letters.
See an example of predefined variables.
Toolchain option variables
COMPILATION_MODE
:fastbuild
,dbg
, oropt
. (more details)
Path variables
-
BINDIR
: The base of the generated binary tree for the target architecture.Note that a different tree may be used for programs that run during the build on the host architecture, to support cross-compiling.
If you want to run a tool from within a
genrule
, the recommended way to get its path is$(execpath toolname)
, where toolname must be listed in thegenrule
'stools
attribute. GENDIR
: The base of the generated code tree for the target architecture.
Machine architecture variables
-
TARGET_CPU
: The target architecture's CPU, e.g.k8
.
Predefined genrule variables
The following are specially available to genrule
's
cmd
attribute and are
generally important for making that attribute work.
See an example of predefined genrule variables.
OUTS
: Thegenrule
'souts
list. If you have only one output file, you can also use$@
.-
SRCS
: Thegenrule
'ssrcs
list (or more precisely: the path names of the files corresponding to labels in thesrcs
list). If you have only one source file, you can also use$<
. -
<
:SRCS
, if it is a single file. Else triggers a build error. -
@
:OUTS
, if it is a single file. Else triggers a build error. -
RULEDIR
: The output directory of the target, that is, the directory corresponding to the name of the package containing the target under thegenfiles
orbin
tree. For//my/pkg:my_genrule
this always ends inmy/pkg
, even if//my/pkg:my_genrule
's outputs are in subdirectories. -
@D
: The output directory. If outs has one entry, this expands to the directory containing that file. If it has multiple entries, this expands to the package's root directory in thegenfiles
tree, even if all output files are in the same subdirectory!Note: Use
RULEDIR
over@D
becauseRULEDIR
has simpler semantics and behaves the same way regardless of the number of output files.If the genrule needs to generate temporary intermediate files (perhaps as a result of using some other tool like a compiler), it should attempt to write them to
@D
(although/tmp
will also be writable) and remove them before finishing.Especially avoid writing to directories containing inputs. They may be on read-only filesystems. Even if not, doing so would trash the source tree.
Note: If the filenames corresponding to the input labels or the output
filenames contain spaces, '
, or other special characters (or your
genrule is part of a Starlark macro which downstream users may invoke on such
files), then $(SRCS)
and $(OUTS)
are not suitable
for interpolation into a command line, as they do not have the semantics that
"${@}"
would in Bash.
One workaround is to convert to a Bash array, with
mapfile SRCS <<< "$$(sed -e 's/ /\\n/g' <<'genrule_srcs_expansion' $(SRC) genrule_srcs_expansion )
,然后在后续命令行中使用"$$\{SRCS[@]}"
代替$(SRCS)
。更可靠的做法是改为编写 Starlark 规则。预定义的源/输出路径变量
预定义变量
execpath
、execpaths
、rootpath
、rootpaths
、location
和locations
接受标签参数(例如$(execpath //foo:bar)
),并替换该标签表示的文件路径。对于源文件,这是相对于工作区根目录的路径。 对于规则的输出文件,这是文件的输出路径(请参阅下文中对输出文件的说明)。
-
execpath
:表示 Bazel 运行构建操作的 execroot 下的路径。在上述示例中,Bazel 会在工作区根目录中通过
bazel-myproject
符号链接关联的目录中运行所有构建操作。源文件empty.source
已在路径bazel-myproject/testapp/empty.source
处关联。因此,其执行路径(即根目录下的子路径)为testapp/empty.source
。这是构建操作可用于查找该文件的路径。输出文件的阶段处理方式与此类似,但前缀为子路径
bazel-out/cpu-compilation_mode/bin
(对于工具的输出,则为bazel-out/cpu-opt-exec-hash/bin
)。在上例中,//testapp:app
是工具,因为它显示在show_app_output
的tools
属性中。 因此,其输出文件app
会写入bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app
。 因此,执行路径为bazel-out/cpu-opt-exec-hash/bin/testapp/app
。借助这个额外的前缀,您可以在同一个 build 中为两个不同的 CPU 构建相同的目标,而不会出现结果冲突的情况。传递给此变量的标签必须仅代表一个文件。对于表示源文件的标签,此值自动为 true。对于表示规则的标签,规则必须生成一个且只有一个输出。如果该值为 false 或标签的格式不正确,则构建会失败并报错。
-
rootpath
:表示构建的二进制文件可用于在运行时相对于其 runfiles 目录的子目录(对应于主代码库)查找依赖项的路径。 注意:只有在启用--enable_runfiles
的情况下,此方法才有效,而 Windows 上默认情况下未启用--enable_runfiles
。如需跨平台支持,请改用rlocationpath
。这与
execpath
类似,但会移除上述配置前缀。在上面的示例中,这意味着empty.source
和app
都使用纯粹的相对工作区路径:testapp/empty.source
和testapp/app
。外部代码库
repo
中文件的rootpath
将以../repo/
开头,后跟相对于代码库的路径。这与
execpath
具有相同的“仅一个输出”要求。 -
rlocationpath
:构建的二进制文件可以将路径传递给 runfiles 库的Rlocation
函数,以便在运行时在 runfiles 目录(如果有)中或使用 runfiles 清单查找依赖项。这与
rootpath
类似,因为它不包含配置前缀,不同之处在于它始终以代码库的名称开头。在上面的示例中,这意味着empty.source
和app
会生成以下路径:myproject/testapp/empty.source
和myproject/testapp/app
。外部代码库
repo
中文件的rlocationpath
将以repo/
开头,后跟相对于代码库的路径。在运行时查找依赖项的首选方法是将此路径传递给二进制文件并使用 runfiles 库将其解析为文件系统路径。与
rootpath
相比,它的优势在于,它适用于所有平台,即使 runfiles 目录不可用也是如此。这与
execpath
的“仅限一个输出”要求相同。 -
location
:execpath
或rootpath
的同义词,具体取决于要展开的属性。这是 Starlark 之前的旧行为,除非您确实知道它对特定规则的具体作用,否则不建议使用。如需了解详情,请参阅 #2475。
execpaths
、rootpaths
、rlocationpaths
和 locations
分别是 execpath
、rootpath
、rlocationpath
和 location
的复数变体。它们支持生成多个输出的标签,在这种情况下,每个输出都列在空格分隔的列表中。零输出规则和格式错误的标签会导致构建错误。
所有引用的标签必须显示在使用方目标的 srcs
、输出文件或 deps
中。否则,构建将失败。C++ 目标还可以引用 data
中的标签。
标签不必采用规范形式:foo
、:foo
和 //somepkg:foo
均可。
自定义变量
任何标记为“要替换为‘make 变量’”的属性都可以引用自定义“make”变量,但仅限于依赖于定义这些变量的其他目标的目标。
最佳实践是,除非有非常好的理由将变量嵌入到核心 Bazel 中,否则所有变量都应是自定义变量。这样一来,Bazel 就不必加载可能很昂贵的依赖项来提供使用目标可能不关心的变量。
C++ 工具链变量
以下内容在 C++ 工具链规则中定义,可供设置 toolchains =
["@bazel_tools//tools/cpp:toolchain_type"]
的任何规则使用。某些规则(例如 java_binary
)会在其规则定义中隐式包含 C++ 工具链。它们会自动继承这些变量。
内置的 C++ 规则比“对其运行编译器”要复杂得多。为了支持 *SAN、ThinLTO 等多种不同的编译模式,以及有/无模块和精心优化的二进制文件,同时在多个平台上快速运行测试,内置规则会竭尽全力确保在内部生成的可能多个操作中的每个操作上设置正确的输入、输出和命令行标志。
这些变量是一种回退机制,供语言专家在极少数情况下使用。如果您想使用这些功能,请先与 Bazel 开发者联系。
ABI
:C++ ABI 版本。-
AR
:crosstool 中的“ar”命令。 -
C_COMPILER
:C/C++ 编译器标识符,例如llvm
。 -
CC
:C 和 C++ 编译器命令。我们强烈建议始终将
CC_FLAGS
与CC
结合使用。否则,您需自担风险。 CC_FLAGS
:一组最少的 C/C++ 编译器标志,可供 genrules 使用。具体而言,如果CC
支持多个架构,则此文件包含用于选择正确架构的标志。-
DUMPBIN
:Microsoft Visual Studio 中的 Microsoft COFF 二进制文件转储工具 (dumpbin.exe)。 -
NM
:crosstool 中的“nm”命令。 -
OBJCOPY
:与 C/C++ 编译器来自同一套件的 objcopy 命令。 -
STRIP
:与 C/C++ 编译器来自同一套件的 strip 命令。
Java 工具链变量
以下变量在 Java 工具链规则中定义,可供设置 toolchains =
["@bazel_tools//tools/jdk:current_java_runtime"]
(或设置主机工具链等效项的 "@bazel_tools//tools/jdk:current_host_java_runtime"
)的任何规则使用。
JDK 中的大多数工具不应直接使用。与上游工具可表达的 Java 编译和打包方法相比,内置 Java 规则使用了更为复杂的方法,例如接口 Jar、头文件接口 Jar 以及高度优化的 Jar 打包和合并实现。
在极少数情况下,这些变量是语言专家使用的后备机制。如果您想使用它们,请先与 Bazel 开发者联系。
-
JAVA
:“java”命令(Java 虚拟机)。请避免这种情况,并尽可能改用java_binary
规则。可以是相对路径。如果您必须先更改目录,然后才能调用java
,则需要先捕获工作目录,然后再进行更改。 JAVABASE
:包含 Java 实用程序的基准目录。可以是相对路径。它将有一个“bin”子目录。
Starlark 定义的变量
规则和工具链写入者可以通过返回 TemplateVariableInfo 提供程序来定义完全自定义变量。然后,通过 toolchains
属性依赖于这些值的任何规则都可以读取其值: