Bazel BUILD files use Starlark (a Python dialect) but have their own conventions for referencing targets, files, and paths. These come up constantly in srcs, deps, data attributes and especially in genrule cmd strings.
Label Syntax
A label is how you reference a target or file in Bazel. The full format is //package/path:target_name, where the // is the workspace root and the colon separates the package path from the target name.
deps = [
"//python/my_app:app", # fully qualified — package //python/my_app, target app
"//rust/my_module:my_module_rs", # another package
":my_module_rename", # shorthand — same package, target my_module_rename
"@crate_index//:pyo3", # external repo @crate_index, root package, target pyo3
]Shorthand rules:
":target_name"— same package. The colon is the convention; always use it for clarity."target_name"without a colon also works but is ambiguous — could be a file or a target. Prefer the colon prefix."//pkg"without a target name is shorthand for"//pkg:pkg"(target name = last component of the package path).
External repositories use the @ prefix: @rules_rust//rust:defs.bzl means “inside the rules_rust external repo, the file rust/defs.bzl.”
genrule Automatic Variables
genrule is Bazel’s escape hatch for running arbitrary shell commands. Its cmd string uses Make-style automatic variables to reference inputs and outputs:
Single-file variables
| Variable | Meaning | Errors if |
|---|---|---|
$< | The single input file (from srcs) | srcs has more than one file |
$@ | The single output file (from outs) | outs has more than one file |
genrule(
name = "rename_so",
srcs = [":my_module_rs"], # one input
outs = ["my_module.abi3.so"], # one output
cmd = "cp $< $@", # cp <input> <output>
)Multi-file variables
| Variable | Meaning |
|---|---|
$(SRCS) | Space-separated list of all input file paths |
$(OUTS) | Space-separated list of all output file paths |
genrule(
name = "concat_sources",
srcs = ["a.txt", "b.txt", "c.txt"],
outs = ["combined.txt"],
cmd = "cat $(SRCS) > $@",
)$(location) for specific targets
When you need the path of a specific target (not just “all srcs”), use $(location :target):
genrule(
name = "process",
srcs = [":input_data"],
outs = ["output.json"],
tools = [":my_tool"],
cmd = "$(location :my_tool) --input $(location :input_data) --output $@",
)$(location :target)— path to the single output of:target. Errors if it has multiple outputs.$(locations :target)— space-separated paths to all outputs of:target. Use when a target produces multiple files.
Tip
These variables are only available inside
genrulecmdstrings and a few other places that accept “Make variable substitution.” They don’t work inctx.actions.run()— for custom rules, usefile.pathattributes instead.