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

VariableMeaningErrors 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

VariableMeaning
$(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 genrule cmd strings and a few other places that accept “Make variable substitution.” They don’t work in ctx.actions.run() — for custom rules, use file.path attributes instead.