2022 年 BazelCon 将于 11 月 16 日至 17 日在纽约和线上举办。
立即报名!

&makeot; 变量

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

"Make”变量是一类特殊的扩展字符串变量,可用于标记为 &q39;Make 变量' 替代变量 的属性。

例如,可用于将特定的工具链路径注入到用户构建的构建操作中。

Bazel 提供预定义变量(适用于所有目标)和自定义变量(在依赖项目标中定义),并仅适用于依赖于这些变量的目标。

添加“Make”一词的原因在于:这些变量的语法和语义原本打算与 GNU Make 保持一致。

使用

标记为 "Subject to 'Make variable' sub replace" 的属性可以引用“Make”变量 FOO,如下所示:

my_attr = "prefix $(FOO) suffix"

换句话说,任何与 $(FOO) 匹配的子字符串都会扩展为 FOO 的值。如果值为 "bar",则最终字符串将变为:

my_attr = "prefix bar suffix"

如果 FOO 不与使用方目标已知的变量相对应,则 Bazel 会失败并显示错误。

名称为非字母符号(如 @)的 & Makeot; Make 变量也可以仅使用美元符号引用,不带英文括号。例如:

my_attr = "prefix $@ suffix"

如需将 $ 写为字符串字面量(即,以防止变量扩展),请写入 $$

预定义变量

预定义“Make”变量可由任何目标上标记为 "Subject to 'Make variable' replaces”的任何属性引用。

如需查看这些变量及其针对一组指定构建选项的值的列表,请运行以下命令:

bazel info --show_make_env [build options]

并查看顶部的输出行(字母大写)。

查看预定义变量示例

工具链选项变量

  • COMPILATION_MODEfastbuilddbgopt。(了解详情

路径变量

  • BINDIR:为目标架构生成的二进制树的基础。

    请注意,在构建期间在主机架构上运行的程序可能会使用不同的树,以支持交叉编译。

    如果您想从 genrule 中运行某个工具,推荐的方法是获取其路径,其中 $(execpath toolname) 必须列在 genruletools 属性中的 toolname

  • GENDIR:生成的为目标架构的代码树的基础。

机器架构变量

  • TARGET_CPU:目标架构的 CPU,例如 k8

预定义的 genrule 变量

下面这些是 genrulecmd 属性特有的属性,通常对于确保该属性正常运行至关重要。

查看预定义的 genrule 变量示例

  • OUTSgenruleouts 列表。如果您只有一个输出文件,也可以使用 $@
  • SRCSgenrulesrcs 列表(或者更确切地说:与 srcs 列表中标签对应的文件的路径名称)。如果您只有一个源文件,也可以使用 $<
  • <SRCS(如果是单个文件)。否则会触发构建错误。
  • @OUTS(如果是单个文件)。否则会触发构建错误。
  • RULEDIR:目标的输出目录,即与 genfilesbin 树下包含目标的软件包名称对应的目录。对于 //my/pkg:my_genrule,即使 //my/pkg:my_genrule 的输出位于子目录中,这也始终以 my/pkg 结尾。

  • @D:输出目录。如果 outs 有一个条目,则扩展到包含该文件的目录。如果此文件有多个条目,即使所有输出文件都位于同一子目录中,此文件也会扩展为 genfiles 树中软件包的根目录!

    注意:使用 RULEDIR 而不是 @D,因为 RULEDIR 的语义更简单,并且行为方式相同,无论输出文件的数量是多少。

    如果该 genrule 需要生成临时中间文件(可能是因为使用编译器等其他工具),则应该尝试将这些文件写入 @D(虽然 /tmp 也可以写入),然后在完成之前将其移除。

    尤其要避免写入包含输入的目录。它们可能位于只读文件系统中。即使不这么做,源代码树也会被删除。

预定义的来源/输出路径变量

预定义的变量 execpathexecpathsrootpathrootpathslocationlocations 接受标签参数(例如 $(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-compilation_mode/genfiles 或主机工具的输出:bazel-out/host/bin)为前缀。在上面的示例中,//testapp:app 是一种主机工具,因为它显示在 show_app_outputtools 属性中。因此,其输出文件 app 会写入 bazel-myproject/bazel-out/host/bin/testapp/app。因此,执行路径为 bazel-out/host/bin/testapp/app。这样一来,就可以针对同一 build 中的两个不同 CPU 构建相同的目标,而不会使结果彼此损坏。

    传递给此变量的标签必须表示一个文件。对于表示源文件的标签,该字段自动为 true。对于表示规则的标签,规则必须只生成一个输出。如果此属性为 false 或标签格式有误,构建将会失败并显示错误。

  • rootpath:指示构建的二进制文件在运行时可用于查找其依赖项的 runfile 路径。

    此内容与 execpath 相同,但会剥离上述输出前缀。在上面的示例中,这意味着 empty.sourceapp 都使用纯工作区相对路径:testapp/empty.sourcetestapp/app

    这与execpath有相同的“一个输出”要求。

  • locationexecpathrootpath 的同义词,具体取决于正在展开的属性。这是 Starlark 之前版本的旧版行为,除非您非常了解它对特定规则的作用,否则我们不建议您这样做。如需了解详情,请参阅 #2475

execpathsrootpathslocations 分别是 execpathrootpathlocation 的复数变体。它们支持生成多个输出的标签,在这种情况下,每个输出都用空格分隔。零输出规则和格式有误的标签会生成构建错误。

所有引用的标签必须显示在使用对象的 srcs、输出文件或 deps 中。否则,构建会失败。C++ 目标还可以引用 data 中的标签。

标签不一定要采用规范格式:foo:foo//somepkg:foo 都可以。

自定义变量

自定义“Make”变量可以由任何标记为 "Subject to 'Make variable' replaces" 的属性引用,但只能依赖于那些定义这些变量的其他目标。

最佳做法是,除非有充分理由将这些变量烘焙到核心 Bazel 中,否则所有变量都应该是自定义的。这样一来,Bazel 便无需加载可能非常昂贵的依赖项,即可提供使用 tar 的不重要的变量。

C++ 工具链变量

下面这些定义在 C++ 工具链规则中定义,并可供任何设置 toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"](或 "@bazel_tools//tools/cpp:current_cc_host_toolchain" 用于托管工具链工具链)的规则使用。某些规则(如 java_binary)在其规则定义中隐式包含 C++ 工具链。它们会自动继承这些变量。

内置的 C++ 规则比“在其上运行编译器”更加复杂。为了支持 *SAN、ThinLTO(带/不带模块)等多样化的编译模式,并在多个平台上同时快速优化二进制文件、快速运行测试,内置规则会竭尽全力来确保在每个内部生成的每个操作上设置正确的输入、输出和命令行标记。

这些变量是语言专家在极少数情况下使用的后备机制。如果您想使用它们,请先与 Bazel 开发者联系

  • ABI:C++ ABI 版本。
  • AR:来自 crosstool 的“ar”命令。
  • C_COMPILER:C/C++ 编译器标识符,例如 llvm
  • CC:C 和 C++ 编译器命令。

    我们强烈建议始终将 CC_FLAGSCC 结合使用。如果您未能这样做,请自行承担风险。

  • CC_FLAGS:C/C++ 编译器可由 genrule 使用的最小标记集。特别是,当 CC 支持多个架构时,此标记包含用于选择正确架构的标志。
  • NM:来自 crosstool 的“nm”命令。
  • OBJCOPY:与 C/C++ 编译器位于同一套件中的 objcopy 命令。
  • STRIP:与 C/C++ 编译器位于同一套件中的删除命令。

Java 工具链变量

下面定义了 Java 工具链规则,可用于任何设置了 toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"](或 "@bazel_tools//tools/jdk:current_host_java_runtime" 表示主机工具链等效规则)的规则。

JDK 中的大多数工具不应直接使用。与上游工具相比,内置 Java 规则可以使用更加复杂的 Java 编译和打包方法,例如接口 Jar、头文件接口 Jars 以及高度优化的 Jar 打包和合并实现。

这些变量是语言专家在极少数情况下使用的后备机制。如果您想使用它们,请先与 Bazel 开发者联系

  • JAVA:"java”命令(Java 虚拟机)。请避免这种情况,并尽可能改用 java_binary 规则。可以是相对路径。如果您必须在调用 java 之前更改目录,则需要在更改之前捕获工作目录。
  • JAVABASE:包含 Java 实用程序的基本目录。可以是相对路径。该应用将具有一个“bin”子目录。

Starlark 定义的变量

规则和工具链写入器可以通过返回 TemplateVariableInfo 提供程序来定义完全自定义变量。然后,任何通过 toolchains 属性依赖于这些规则的规则都可以读取其值:

查看 Starlark 定义的变量示例