"Make" Variables
"Make" variables are a special class of expandable string variables available to attributes marked as "Subject to 'Make variable' substitution".
These can be used, for example, to inject specific toolchain paths into user-constructed build actions.
Bazel provides both predefined variables, which are available to all rules, and custom variables, which are defined in dependency rules and only available to rules that depend on them.
The reason for the term "Make" is historical: the syntax and semantics of these variables were originally intended to match GNU Make.
Use
Attributes marked as "Subject to 'Make variable' substitution" can
reference the "Make" variable FOO
as follows:
my_attr = "prefix $(FOO) suffix"
In other words, any substring matching $(FOO)
gets expanded
to FOO
's value. If that value is "bar"
, the final
string becomes:
my_attr = "prefix bar suffix"
If FOO
doesn't correspond to a variable known to the consuming
rule, Bazel fails with an error.
To write $
as a a string literal (i.e. to prevent variable
expansion), write $$
.
Predefined variables
Predefined "Make" variables can be referenced by any attribute marked as "Subject to 'Make variable' substitution" on any rule.
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.
Toolchain option variables
COMPILATION_MODE
: "fastbuild", "dbg", or "opt". (more details)
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 thegenrule
'stools
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.
OUTS
: Thegenrule
'souts
list. If you have only one output file, you can also use$@
.-
SRCS
: Thegenrule
'ssrcs
list (or more precisely: the path names of the files corresponding to labels in thesrcs
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 rule, that is, the directory corresponding to the name of the package containing the rule under thegenfiles
or thebin
tree. -
WARNING: The Make variable
RULEDIR
should be used instead because it has simpler semantics and behaves in the same way regardless of the number of output files of the rule.@D
: The output directory. If there is only one file name in outs, this expands to the directory containing that file. If there are multiple files, this instead expands to the package's root directory in thegenfiles
tree, even if all generated files belong to the same subdirectory!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.
Predefined source/output path variables
The predefined variables execpath
, execpaths
,
rootpath
, rootpaths
, location
, and
locations
take label parameters (e.g. $(execpath
//foo:bar)
) and substitute the file paths denoted by that label.
For source files, this is the path relative to your workspace root. For files that are outputs of rules, this is the file's output path (see the explanation of output files below).
Example:
$ cat testapp/BUILD cc_binary( name = "app", srcs = ["app.cc"] ) genrule( name = "show_app_output", srcs = ["empty.source"], outs = ["app_output"], cmd = """cat <<EOF > $@ :app output paths execpath: $(execpath :app) runfiles: $(rootpath :app) location: $(location :app) source file paths execpath: $(execpath empty.source) runfiles: $(rootpath empty.source) location: $(location empty.source) EOF""", tools = [":app"]) $ bazel build //testapp:show_app_output && cat bazel-genfiles/testapp/app_output Target //testapp:show_app_output up-to-date: bazel-genfiles/testapp/app_output INFO: Build completed successfully, 1 total action :app output paths execpath: bazel-out/host/bin/testapp/app runfiles: testapp/app location: bazel-out/host/bin/testapp/app source file paths execpath: testapp/empty.source runfiles: testapp/empty.source location: testapp/empty.source
-
execpath
: Denotes the path beneath the execroot where Bazel runs build actions.In the above example, Bazel runs all build actions in the directory linked by the
bazel-myproject
symlink in your workspace root. The source fileempty.source
is linked at the pathbazel-myproject/testapp/empty.source
. So its exec path (which is the subpath below the root) istestapp/empty.source
. This is the path build actions can use to find the file.Output files are staged similarly, but are also prefixed with the subpath
bazel-out/cpu-compilation_mode/bin
(or for certain outputs:bazel-out/cpu-compilation_mode/genfiles
, or for the outputs of host tools:bazel-out/host/bin
). In the above example,//testapp:app
is a host tool because it appears inshow_app_output
'stools
attribute. So its output fileapp
is written tobazel-myproject/bazel-out/host/bin/testapp/app
. The exec path is thusbazel-out/host/bin/testapp/app
. This extra prefix makes it possible to build the same rule for, say, two different CPUs in the same build without the results clobbering each other.The label passed to this variable must represent exactly one file. For labels representing source files, this is automatically true. For labels representing rules, the rule must generate exactly one output. If this is false or the label is malformed, the build fails with an error.
-
rootpath
: Denotes the runfiles path that a built binary can use to find its dependencies at runtime.This is the same as
execpath
but strips the output prefixes described above. In the above example this means bothempty.source
andapp
use pure workspace-relative paths:testapp/empty.source
andtestapp/app
.This has the same "one output only" requirements as
execpath
. -
location
: A synonym for eitherexecpath
orrootpath
, depending on the attribute being expanded. This is legacy pre-Starlark behavior and not recommended unless you really know what it does for a particular rule. See #2475 for details.
execpaths
, rootpaths
, and locations
are
the plural variations of execpath
, rootpath
, and
location
, respectively. They support labels producing multiple
outputs, in which case each output is listed separated by a space. Zero-output
rules and malformed labels produce build errors.
All referenced labels must appear in the consuming rule's srcs
,
output files, or deps
. Otherwise the build fails. C++ rules can
also reference labels in data
.
Labels don't have to be in canonical form: foo
, :foo
and //somepkg:foo
are all fine.
Custom variables
Custom "Make" variables can be referenced by any attribute marked as "Subject to 'Make variable' substitution", but only on rules that depend on other rules that define these variables.
As best practice all variables should be custom unless there's a really good reason to bake them into core Bazel. This saves Bazel from having to load potentially expensive dependencies to supply variables consuming rules may not care about.
C++ toolchain variables
The following are defined in C++ toolchain rules and available to any rule
that sets toolchains =
["@bazel_tools//tools/cpp:current_cc_toolchain"]
(or
"@bazel_tools//tools/cpp:current_cc_host_toolchain"
for the host toolchain equivalent). Some rules, like java_binary
, implicitly
include the C++ toolchain in their rule definition. They inherit these variables
automatically.
The built-in C++ rules are much more sophisticated than "run the compiler on it". In order to support compilation modes as diverse as *SAN, ThinLTO, with/without modules, and carefully optimized binaries at the same time as fast running tests on multiple platforms, the built-in rules go to great lengths to ensure the correct inputs, outputs, and command-line flags are set on each of potentially multiple internally generated actions.
These variables are a fallback mechanism to be used by language experts in rare cases. If you are tempted to use them, please contact the Bazel devs first.
ABI
: The C++ ABI version.-
AR
: The "ar" command from crosstool. -
C_COMPILER
: The C/C++ compiler identifier, e.g. "llvm". -
CC
: The C and C++ compiler command.We strongly recommended always using
CC_FLAGS
in combination withCC
. Fail to do so at your own risk. CC_FLAGS
: A minimal set of flags for the C/C++ compiler to be usable by genrules. In particular, this contains flags to select the correct architecture ifCC
supports multiple architectures.-
NM
: The "nm" command from crosstool. -
OBJCOPY
: The objcopy command from the same suite as the C/C++ compiler. -
STRIP
: The strip command from the same suite as the C/C++ compiler.
Java toolchain variables
The following are defined in Java toolchain rules and available to any rule
that sets toolchains =
["@bazel_tools//tools/jdk:current_java_runtime"]
(or
"@bazel_tools//tools/jdk:current_host_java_runtime"
for the host toolchain equivalent).
Most of the tools in the JDK should not be used directly. The built-in Java rules use much more sophisticated approaches to Java compilation and packaging than upstream tools can express, such as interface Jars, header interface Jars, and highly optimized Jar packaging and merging implementations.
These variables are a fallback mechanism to be used by language experts in rare cases. If you are tempted to use them, please contact the Bazel devs first.
-
JAVA
: The "java" command (a Java virtual machine). Avoid this, and use ajava_binary
rule instead where possible. May be a relative path. If you must change directories before invokingjava
, you need to capture the working directory before changing it. JAVABASE
: The base directory containing the Java utilities. May be a relative path. It will have a "bin" subdirectory.
Starlark-defined variables
Rule and toolchain writers can define
completely custom variables by returning a TemplateVariableInfo
provider. Any rules depending on these through the
toolchains
attribute can then read their values:
$ cat testapp/defs.bzl def _var_providing_rule_impl(ctx): return [ platform_common.TemplateVariableInfo({ "FOO": ctx.attr.var_value }) ] var_providing_rule = rule( implementation = _var_providing_rule_impl, attrs = { "var_value": attr.string() } ) $ cat testapp/BUILD load("//testapp:defs.bzl", "var_providing_rule") var_providing_rule( name = "set_foo_to_bar", var_value = "bar" ) genrule( name = "g", srcs = [], outs = ["g.out"], cmd = "echo FOO is equal to $(FOO)! > $@", toolchains = [":set_foo_to_bar"] ) $ bazel build //testapp:g && cat bazel-genfiles/testapp/g.out Target //testapp:g up-to-date: bazel-genfiles/testapp/g.out INFO: Build completed successfully, 1 total action FOO is equal to bar!