创建变量

报告问题 查看源代码 每夜 build · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

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

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”变量。

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

bazel info --show_make_env [build options]

然后,查看输出顶部的大写字母行。

查看预定义变量的示例

工具链选项变量

  • COMPILATION_MODEfastbuilddbgopt。(了解详情

路径变量

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

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

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

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

机器架构变量

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

预定义的 genrule 变量

以下内容专门适用于 genrulecmd 属性,通常对该属性的正常运行至关重要。

查看预定义 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 处关联。因此,其执行路径(即根目录下的子路径)为 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。 因此,执行路径为 bazel-out/cpu-opt-exec-hash/bin/testapp/app。借助这个额外的前缀,您可以在同一个 build 中为两个不同的 CPU 构建相同的目标,而不会出现结果冲突的情况。

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

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

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

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

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

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

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

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

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

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

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

execpathsrootpathsrlocationpathslocations 分别是 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_FLAGSCC 结合使用。否则,您需自担风险。

  • CC_FLAGS:一组最少的 C/C++ 编译器标志,可供 genrules 使用。具体而言,如果 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 定义的变量示例