创建变量

“Make”变量是一种特殊的扩展字符串变量,可用于标记为“受‘Make 变量’替换”的属性。

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

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

之所以使用“Make”这个术语,是因为这些变量的语法和语义最初旨在与 GNU Make 匹配。

使用

标记为 “受‘Make 变量’替换” 的属性可以 按如下方式引用“Make”变量 FOO

my_attr = "prefix $(FOO) suffix"

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

my_attr = "prefix bar suffix"

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

名称为非字母符号(例如 @)的“Make”变量也可以仅使用美元符号(不带括号)进行引用。例如:

my_attr = "prefix $@ suffix"

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

预定义变量

预定义的“Make”变量可由任何目标上标记为 “受‘Make 变量’替换”的任何属性引用。

如需查看这些变量的列表及其针对给定构建 选项集的值,请运行

bazel info --show_make_env [build options]

并查看以大写字母开头的顶部输出行。

查看预定义变量的示例

工具链选项变量

  • COMPILATION_MODEfastbuilddbgopt。(更多 详情

路径变量

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

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

    如果您想从 genrule 中运行工具,建议使用 $(execpath toolname) 获取其路径,其中 toolname 必须列在 genruletools 属性中。

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

机器架构变量

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

预定义 genrule 变量

以下变量专门适用于 genrule's cmd 属性,对于使该属性正常运行通常非常重要。

查看预定义 genrule 变量的示例

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

  • @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. 因此,其 exec 路径(即根目录下的子路径)为 testapp/empty.source。这是构建操作可用于查找文件的路径。

    输出文件的暂存方式类似,但也会以子路径 bazel-out/cpu-compilation_mode/bin(或对于工具的输出:bazel-out/cpu-opt-exec-hash/bin)为前缀。在上面的示例中,//testapp:app 是一个工具,因为它出现在show_app_outputtools 属性中。因此,其输出文件 app 会写入 bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. 因此,exec 路径为 bazel-out/cpu-opt-exec-hash/bin/testapp/app。借助此额外的前缀 ,可以在同一构建中为(例如)两个不同的 CPU 构建同一目标,而不会导致结果相互覆盖。

    传递给此变量的标签必须恰好表示一个文件。对于 表示源文件的标签,这会自动成立。对于表示规则的标签,该规则必须恰好生成一个输出。如果此条件为 false 或标签格式不正确,构建会失败并显示错误。

  • rootpath:表示构建的二进制文件在运行时可用于查找依赖项的路径,该路径相对于其 runfiles 目录的子目录(与主代码库对应)。注意:此路径仅在启用 --enable_runfiles 时有效,而默认情况下 Windows 上并非如此。请改用 rlocationpath 以实现 跨平台支持。

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

    外部代码库 repo 中文件的 rootpath 将以 ../repo/ 开头,后跟 代码库相对路径。

    这与 "one output only" 具有相同的要求,例如 execpath

  • rlocationpath:构建的二进制文件可以传递给 runfiles 库的 Rlocation 函数的路径,以便在运行时查找依赖项,无论是在 runfiles 目录中(如果可用)还是使用 runfiles 清单。

    这与 rootpath 类似,因为它不包含 配置前缀,但不同之处在于它始终以 代码库的名称开头。在上面的示例中,这意味着 empty.sourceapp 会生成以下 路径:myproject/testapp/empty.source myproject/testapp/app

    外部代码库 repo 中文件的 rlocationpath 将以 repo/ 开头,后跟代码库相对路径。

    将此路径传递给二进制文件并使用 runfiles 库将其解析为文件系统路径,是在运行时查找依赖项的首选方法。与 rootpath 相比,它的优势在于它适用于所有平台,即使 runfiles 目录不可用也是如此。

    这与 "one output only" 具有相同的要求,例如 execpath

  • locationexecpathrootpath 的同义词,具体取决于要展开的属性。这是 旧版 Starlark 之前的行为,除非您确实知道它对特定规则的作用,否则不建议使用 。如需了解详情,请参阅 #2475

execpathsrootpathsrlocationpaths、 和 locations 分别是 execpathrootpathrlocationpathslocation、 的复数形式。它们支持生成多个输出的标签,在这种情况下 每个输出都会列出,并以空格分隔。零输出规则和格式不正确的 标签会生成构建错误。

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

标签不必采用规范形式:foo:foo//somepkg:foo 都可以。

自定义变量

自定义“Make”变量可由任何标记为 “受‘Make 变量’替换”的属性引用,但仅适用于 依赖于其他目标(这些目标 定义了这些变量)的目标。

最佳实践是,所有变量都应该是自定义变量,除非有充分的理由将其内置到核心 Bazel 中。 这样可以避免 Bazel 加载 可能开销较高的依赖项,以提供使用目标可能 不关心的变量。

C++ 工具链变量

以下变量在 C++ 工具链规则中定义,适用于任何 设置了 toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"] 的规则。某些规则(例如 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:供 genrule 使用的 C/C++ 编译器的最小标志集。特别是,如果 CC 支持多种架构,则此标志集包含用于选择正确架构的标志。
  • 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 属性依赖于这些规则的规则都可以读取其值:

查看 Starlark 定义的变量的示例