创建变量

报告问题 查看源代码 每夜 build · 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"

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

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:表示 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 分别是 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++ 编译器标志,可供 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 属性依赖于这些值的任何规则都可以读取其值:

请参阅 Starlark 定义的变量示例