A typical use case for Bazel macros that we discussed previously is producing several dependent targets. For example, we might want to generate a checksum file for our binary as a part of the build. These artifacts are tightly coupled yet different, and a macro provides a convenient way to represent that.
Implementation #
Our BUILD
file will load and call the macro as usual:
load(":rules.bzl", "demo_outputs")
demo_outputs(
name = "multiple_outputs",
srcs = [
"english.sh",
"french.sh",
],
)
The macro will now instantiate two rules, one to build the script and another to build the SHA256 checksum file. The checksum target is the default as we expect it to be required in most cases; however, this is an assumption and we could have easily made it an additional optional target instead.
def demo_outputs(name, srcs, out = None, **kwargs):
out = "{}.sh".format(name) if out == None else out
_demo_binary(
name = "{}.script".format(name),
srcs = srcs,
out = out,
**kwargs
)
_demo_sha256(
name = name,
out = "{}.sha256".format(out),
src = out,
**kwargs
)
_demo_sha256
is a simple regular rule:
_demo_sha256 = rule(
implementation = _demo_sha256_impl,
attrs = {
"out": attr.output(mandatory = True),
"src": attr.label(
mandatory = True,
allow_single_file = True,
),
},
)
Its implementation function is more interesting because it produces a
non-executable predeclared output so we don’t have to use
ctx.actions.declare_file
or returning a provider explicitly:
_demo_sha256 = rule(
implementation = _demo_sha256_impl,
attrs = {
"out": attr.output(mandatory = True),
"src": attr.label(
mandatory = True,
allow_single_file = True,
),
},
)
Building the example is straightforward:
bazel build //multiple_outputs
...
Target //multiple_outputs:multiple_outputs up-to-date:
bazel-bin/multiple_outputs/multiple_outputs.sh.sha256
...
Running the script demonstrates the
custom verbs pattern
where the target label name is in the object.verb
format:
bazel run //multiple_outputs:multiple_outputs.script
...
Target //multiple_outputs:multiple_outputs.script up-to-date:
bazel-bin/multiple_outputs/multiple_outputs.sh
...
Hello, World!
Bonjour monde!
If necessary, we could extend the list of verbs to implement any number
of actions that we could use with bazel run
.
K8s rules are a
well-known example of this approach.
The complete code for this example is in the repo.