Typically, when writing a Bazel rule, we produce outputs using the DefaultInfo provider. However, there are cases where we want to produce additional outputs only on demand.
Enter output groups
Simply put, output groups are a way to tell Bazel to produce different sets of outputs instead of—or in addition to—the default outputs. For example, we might want to generate debug symbols, but we don’t need them unless explicitly requested.
Smallest possible example
Here is a minimal rule that demonstrates the use of output groups:
def _impl(ctx):
out1 = ctx.actions.declare_file("main.txt")
out2 = ctx.actions.declare_file("debug.txt")
ctx.actions.write(out1, "main output")
ctx.actions.write(out2, "debug output")
return [
DefaultInfo(files = depset([out1])),
OutputGroupInfo(
debug = depset([out2]),
),
]
my_rule = rule(
implementation = _impl,
)
Notice how easy it is to use output groups. OutputGroupInfo is just another provider—a key-value mapping where, in this case, debug is the key (the output group name), and out2 is the value wrapped in a depset.
Requesting the debug output
If we instantiate this rule in a BUILD file:
my_rule(
name = "groups",
)
We can build it:
bazel build :groups
This produces:
INFO: Analyzed target //:groups (5 packages loaded, 7 targets configured).
INFO: Found 1 target...
Target //:groups up-to-date:
bazel-bin/main.txt
INFO: Elapsed time: 0.119s, Critical Path: 0.00s
INFO: 2 processes: 2 internal.
INFO: Build completed successfully, 2 total actions
The important part here is bazel-bin/main.txt. This happens because we did not tell Bazel to include outputs from the debug output group.
To do that, we use the --output_groups flag and specify the group name (in this case, debug):
bazel build :groups --output_groups=debug
Output:
INFO: Analyzed target //:groups (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:groups up-to-date:
bazel-bin/debug.txt
INFO: Elapsed time: 0.065s, Critical Path: 0.00s
INFO: 2 processes: 2 internal.
INFO: Build completed successfully, 2 total actions
Now the debug file is produced.
An important detail: debug.txt is produced instead of main.txt, not in addition to it. To request both the default outputs and an output group at the same time, use the + prefix:
bazel build :groups --output_groups=+debug
This produces both files:
INFO: Analyzed target //:groups (5 packages loaded, 7 targets configured).
INFO: Found 1 target...
Target //:groups up-to-date:
bazel-bin/debug.txt
bazel-bin/main.txt
INFO: Elapsed time: 0.108s, Critical Path: 0.00s
INFO: 3 processes: 3 internal.
INFO: Build completed successfully, 3 total actions
Conclusion
Output groups are simple to use, both when defining rules and when consuming them. They’re a small feature, but an extremely useful one.