Bazel options in BUILD file

Viewed 303

I need to set some build options every time I invoke bazel for a specific target. For example, bazel build --collect_code_coverage //:target. How can I avoid providing the build options at the command line explicitly, so that bazel build //:target implicitly has the build option --collect_code_coverage applied?

The closest solution I found was using the bazelrc file, but it does not allow me to configure build options at a target level.

1 Answers

This is doable with user defined transitions, there are some performance considerations here that are worth reading over. It's also relatively complicated.

# transition.bzl
def _platform_transition_impl(settings, attr):
    _ignore = settings
    return {"//command_line_option:collect_code_coverage": True}

coverage_transition = transition(
    implementation = _coverage_transition_impl,
    inputs = [],
    outputs = ["//command_line_option:collect_code_coverage"],
)

def _coverage_impl(ctx):
    executable = ctx.actions.declare_file(ctx.attr.name)
    ctx.actions.symlink(output = executable, target_file = ctx.file.target)
    return [DefaultInfo(executable = executable)]

build_with_collect_coverage = rule(
    implementation = _coverage_impl,
    attrs = {
        "target": attr.label(mandatory = True, allow_single_file = True, cfg = coverage_transition),
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
        ),
    },
)

Then add the transition rule to BUILD.bazel e.g.

load(":transition.bzl", "build_with_collect_coverage")
cc_binary(
   name = "target"
   #...
)

build_with_collect_coverage(
   name = "target_with_coverage_collection",
   target = ":target",
)

Note: While this is a generic solution that is incredibly powerful and supports any language you might simply be able to get away with using the features attribute e.g.

cc_binary(
   name = "target",
   #...
   features = ["coverage"],
)
Related