创建变量

报告问题 查看来源 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

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

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

之所以使用“Make”一词,是因为历史原因:这些变量的语法和语义最初旨在与 GNU Make 保持一致。

使用

标记为“可进行‘变量化’替换”的属性可以引用“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

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 the genrule's tools 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: The genrule's outs list. If you have only one output file, you can also use $@.
  • SRCS: The genrule's srcs list (or more precisely: the path names of the files corresponding to labels in the srcs 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 the genfiles or bin tree. For //my/pkg:my_genrule this always ends in my/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 the genfiles tree, even if all output files are in the same subdirectory!

    Note: Use RULEDIR over @D because RULEDIR 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 规则。

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

预定义变量 execpathexecpathsrootpathrootpathslocationlocations 接受标签参数(例如 $(execpath //foo:bar)),并替换由该标签表示的文件路径。

对于源文件,这是相对于工作区根目录的路径。 对于作为规则输出的文件,这是文件的输出路径(请参阅下文中有关输出文件的说明)。

查看预定义路径变量的示例

  • execpath:表示 execroot 下 Bazel 运行 build 操作的路径。

    在上述示例中,Bazel 会在工作区根目录中由 bazel-myproject 符号链接关联的目录中运行所有 build 操作。源文件 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 默认情况下未启用此功能。请改用 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 分别是 execpathrootpathrlocationpathlocation 的复数形式。它们支持生成多个输出的标签,在这种情况下,每个输出都会列出,并以空格分隔。零输出规则和格式错误的标签会导致构建错误。

所有被引用的标签都必须出现在使用方目标的 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_FLAGSCC 结合使用。否则,您需自行承担风险。

  • CC_FLAGS:一组最小的标志,供 C/C++ 编译器通过 genrule 使用。特别是,如果 CC 支持多种架构,则此变量包含用于选择正确架构的标志。
  • DUMPBIN:Microsoft Visual Studio 中的 Microsoft COFF 二进制文件转储程序 (dumpbin.exe)。
  • NM:来自 crosstool 的“nm”命令。
  • OBJCOPY:与 C/C++ 编译器属于同一套件的 objcopy 命令。
  • STRIP:与 C/C++ 编译器属于同一套件的 strip 命令。

Java 工具链变量

以下内容在 Java 工具链规则中定义,并且可供任何设置了 toolchains = ["@rules_java//toolchains:current_java_runtime"](或 "@rules_java//toolchains:current_host_java_runtime",用于等效的主机工具链)的规则使用。

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

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

  • JAVA:“java”命令(Java 虚拟机)。请避免使用此规则,尽可能改用 java_binary 规则。可以是相对路径。如果您必须在调用 java 之前更改目录,则需要在更改之前捕获工作目录。
  • JAVABASE:包含 Java 实用程序的根目录。可以是相对路径。它将包含一个“bin”子目录。

Starlark 定义的变量

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

查看 Starlark 定义的变量的示例