bazelbuild / bazel

a fast, scalable, multi-language and extensible build system
https://bazel.build
Apache License 2.0
23.22k stars 4.07k forks source link

Implement a `select`-like operator to resolve `config_common.FeatureFlagInfo` or similar provider #18911

Open alexander-shiryaev opened 1 year ago

alexander-shiryaev commented 1 year ago

Description of the feature request:

I would like to pass a computed string to an arbitrary rule. If the string can only take a finite number of values, the problem can be solved by implementing a rule that returns config_common.FeatureFlagInfo and a set of config_setting, one for each of the allowed values (see resolve_feature_flag_emulation).

def resolve_feature_flag_emulation(allowed_values):
    def _(feature_flag_name):
        cases = {}

        for index, feature_flag_value in enumerate(allowed_values):
            config_setting_name = "{}-{}".format(feature_flag_name, index)

            native.config_setting(
                name = config_setting_name,
                flag_values = {feature_flag_name: feature_flag_value},
                visibility = ["//visibility:private"],
            )

            cases[config_setting_name] = feature_flag_value

        return select(cases, no_match_error = "unable to resolve feature flag: allowed_values = {}".format(allowed_values))

    return _

However, if the string can have an unlimited number of values, there is currently no way to achieve the desired functionality.

In this example, you can see how the value of the shared_lib_name attribute should be computed based on the given string_flag.

My suggestion is to implement the resolve_feature_flag operator, which would function similarly to select and convert the value from config_common.FeatureFlagInfo to a string, similar to how resolve_feature_flag_emulation works. However, it should support an unlimited set of values.

What underlying problem are you trying to solve with this feature?

I want to have an ability to pass computed values to the rule attributes.

What is the output of bazel info release?

release 6.1.0

Have you found anything relevant by searching the web?

No.

Any other information, logs, or outputs that you want to share?

Code for this proposal: https://github.com/alexander-shiryaev/bazel_issue/tree/main/feature_request/feature_flag_value

fmeum commented 1 year ago

Would https://github.com/bazelbuild/bazel-skylib/pull/440 help with your use case?

alexander-shiryaev commented 1 year ago

@fmeum Actually it would not help, because I want a calculated string (and by "calculated" I mean target-provided), not a user-defined one.

gregestren commented 1 year ago

To be clear,

You're saying you'd like

my_target(
  name = "value_provider",
  value = "the actual value"

when can be referenced by any string attribute on any other target, and resolves that attribute to "the actual value"?

alexander-shiryaev commented 1 year ago

@gregestren

Yes, exactly (but the underlying provider should be public). That would allow a lot of interesting patterns, like analyzing targets in transitions.

cc_shared_library(
    name = "mylib",
    shared_lib_name = resolve_feature_flag("mylib_name"),
)
TsynkPavel commented 3 weeks ago

Feature will help me too! @gregestren, maybe it will be possible to include it in the new release?

gregestren commented 3 weeks ago

Aside from the implementation, what use case are you trying to solve?

alexander-shiryaev commented 2 weeks ago

@gregestren Are you asking me or @TsynkPavel?

gregestren commented 2 weeks ago

Either! I'm wondering if other Starlark tricks could also fulfill it.

alexander-shiryaev commented 2 weeks ago

I want to be able to pass calculated values ​​to rule attributes. This will allow me to examine these values ​​in transitions. In particular, I want to pass to transition the index of the field that should be removed from the string_list. And I currently have no other way than to create a bunch of config_settings (as in the example in the original post). Which, of course, negatively affects overall performance.