Search code examples
bazelbuild-dependencies

How to specify flags for dependencies of a bazel target?


Suppose I have a Bazel target with some dependencies that are other targets:

cc_test(
    name = "my_test",
    srcs = [...],
    deps = [
        "//my/path:my_dep_target",
    ],
)

and then in another BUILD file

cc_library(
    name = "my_dep_target",
    hdrs = [...],
    visibility = ["//visibility:public"],
    deps = [
        #permanent deps
        ...
    ] +
    select({
        ":option1": [":real_target1"],
        ":option2": [":real_target2"],
        "//conditions:default": [":auto_amsr"],
    })
)

config_setting(
    name = "option1",
    flag_values = {
        ":my_flag": "opt1"
    }
)

config_setting(
    name = "option2",
    flag_values = {
        ":my_flag": "opt2"
    }
)

For seek of brevity I will skip the rule but just let me say that when building my_dep_target from terminal with

bazel build //my/path:my_dep_target --//my/path/to/other/build:my_flag=opt1

everything works fine (also with opt2).

I would like to be able to specify the flag value, (not using a default value) in the dependency of my_dep_target, something like:

cc_test(
    name = "my_test",
    srcs = [...],
    deps = [
        "//my/path:my_dep_target --//my/path/to/other/build:my_flag=opt1",
    ],
)

although I know this syntax is not correct.

Is it possible in bazel targets to specify flags for their dependencies?


Solution

  • You're looking for an outgoing-edge user-defined transition. Something like this in a .bzl file somewhere:

    def _set_opt1_impl(settings, attr):
        return [
            {"//my/path/to/other/build:my_flag" : "opt1"},
        ]
    
    set_opt1 = transition(
        implementation = _set_opt1_impl,
        inputs = [],
        outputs = ["//my/path/to/other/build:my_flag"]
    )
    
    def _my_rule_impl(ctx):
        return [ctx.attr.dep[0][CcInfo]]
    
    my_rule = rule(
        implementation = _my_rule_impl,
        attrs = {
            "dep": attr.label(cfg = set_opt1),
        },
        "_allowlist_function_transition": attr.label(
             default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
         ),
    )
    

    and then use it like this in a BUILD file (after using load to import things from above in the .bzl file):

    my_rule(
        name = "my_dep_target_opt1",
        dep = "//my/path:my_dep_target",
    )
    
    cc_test(
        name = "my_test",
        srcs = [...],
        deps = [
            ":my_dep_target_opt1",
        ],
    )
    

    _set_opt1_impl can look at the attributes passed in attr to do something more sophisticated than setting a hard-coded value if you want.