Practical Bazel: Writing a Rule That Supports Both Build and Run
Practical Bazel bazel
Published: 2020-11-13
Practical Bazel: Writing a Rule That Supports Both Build and Run

When I first started writing custom Bazel rules, I often created separate rules for the build and run commands in Bazel. This was a mistake.

For example, I once wrote rules that looked something like:

1
2
3
4
5
6
7
8
9
azure_function_app_build(
    name = "my_app",
    srcs = ["..."],
)

azure_function_app_run(
    name = "run_app",
    app = ":my_app",
)

My expectation that users would bazel build //:my_app and bazel run //:run_app.

This separation is silly and unnecessary. A Bazel rule can support both build and run at the same time. All you have to do is declare the rule as executable and have it return a DefaultInfo() object with both an executable and a files attribute.

For example, here is an example of a extremely simplistic cc_binary() rule:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# my_cc_binary.bzl
def _impl(ctx):
    executable = ctx.actions.declare_file(ctx.attr.name)

    args = ctx.actions.args()
    args.add("-o", executable)
    args.add_all(ctx.files.srcs)

    ctx.actions.run(
        inputs = ctx.files.srcs,
        outputs = [executable],
        # This is for demo purposes.  In a real Bazel rule you'd
        # want to use cc_common.
        executable = "/usr/bin/gcc",
        arguments = [args],
    )
    return [
        DefaultInfo(
            executable = executable,
            files = depset([executable]),
        ),
    ]

my_cc_binary = rule(
    implementation = _impl,
    attrs = {
        "srcs": attr.label_list(
            mandatory = True,
            allow_files = True,
        ),
    },
    executable = True,
)
1
2
3
4
5
6
7
# BUILD
load("my_cc_binary.bzl", "my_cc_binary")

my_cc_binary(
    name = "exe",
    srcs = ["main.c"],
)

With this rule definition, you can generate the executable with bazel build //:exe and run it with bazel run //:exe.

The above sample code can also be found at https://github.com/sengelha/practical_bazel_examples/tree/master/build_and_run_rule.