From 837caeca75a64d4a8b399d17e14a49f2991f51ff Mon Sep 17 00:00:00 2001 From: Googler Date: Fri, 23 Feb 2024 13:54:01 -0800 Subject: [PATCH] BEGIN_PUBLIC Pull more info into ArgsListInfo. This allows us to make queries such as "get me all the flags / files required for this specific action". This will allow us to implement cc_action_config more easily and efficiently. END_PUBLIC PiperOrigin-RevId: 609828504 Change-Id: Ie3978674c5027f892d2e5e4c8d937a52c59fde5d --- cc/toolchains/args.bzl | 10 ++++++- cc/toolchains/cc_toolchain_info.bzl | 8 +++-- tests/rule_based_toolchain/args/args_test.bzl | 20 +++++++++---- .../rule_based_toolchain/generate_factory.bzl | 5 ++-- tests/rule_based_toolchain/generics.bzl | 10 +++++++ tests/rule_based_toolchain/subjects.bzl | 29 +++++++++++++++---- 6 files changed, 66 insertions(+), 16 deletions(-) diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl index e8c1c2b..3409d00 100644 --- a/cc/toolchains/args.bzl +++ b/cc/toolchains/args.bzl @@ -51,7 +51,15 @@ def _cc_args_impl(ctx): ) return [ args, - ArgsListInfo(label = ctx.label, args = tuple([args])), + ArgsListInfo( + label = ctx.label, + args = tuple([args]), + files = files, + by_action = tuple([ + struct(action = action, args = [args], files = files) + for action in actions.to_list() + ]), + ), ] cc_args = rule( diff --git a/cc/toolchains/cc_toolchain_info.bzl b/cc/toolchains/cc_toolchain_info.bzl index 5efdda9..c105364 100644 --- a/cc/toolchains/cc_toolchain_info.bzl +++ b/cc/toolchains/cc_toolchain_info.bzl @@ -73,6 +73,8 @@ ArgsListInfo = provider( fields = { "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "args": "(Sequence[ArgsInfo]) The flag sets contained within", + "files": "(depset[File]) The files required for all of the arguments", + "by_action": "(Sequence[struct(action=ActionTypeInfo, args=List[ArgsInfo], files=depset[Files])]) Relevant information about the args keyed by the action type.", }, ) @@ -83,12 +85,12 @@ FeatureInfo = provider( "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "name": "(str) The name of the feature", "enabled": "(bool) Whether this feature is enabled by default", - "args": "(Sequence[ArgsInfo]) Flag sets enabled by this feature", + "args": "(ArgsListInfo) Args enabled by this feature", "implies": "(depset[FeatureInfo]) Set of features implied by this feature", "requires_any_of": "(Sequence[FeatureSetInfo]) A list of feature sets, at least one of which is required to enable this feature. This is semantically equivalent to the requires attribute of rules_cc's FeatureInfo", - "provides": "(Sequence[MutuallyExclusiveCategoryInfo]) Indicates that this feature is one of several mutually exclusive alternate features.", + "mutually_exclusive": "(Sequence[MutuallyExclusiveCategoryInfo]) Indicates that this feature is one of several mutually exclusive alternate features.", "known": "(bool) Whether the feature is a known feature. Known features are assumed to be defined elsewhere.", - "overrides": "(Optional[FeatureInfo]) The feature that this overrides", + "overrides": "(Optional[FeatureInfo]) The feature that this overrides. Must be a known feature", }, ) FeatureSetInfo = provider( diff --git a/tests/rule_based_toolchain/args/args_test.bzl b/tests/rule_based_toolchain/args/args_test.bzl index 859cc6c..d4937b7 100644 --- a/tests/rule_based_toolchain/args/args_test.bzl +++ b/tests/rule_based_toolchain/args/args_test.bzl @@ -15,11 +15,19 @@ load( "//cc/toolchains:cc_toolchain_info.bzl", + "ActionTypeInfo", "ArgsInfo", + "ArgsListInfo", ) visibility("private") +_SIMPLE_FILES = [ + "tests/rule_based_toolchain/testdata/file1", + "tests/rule_based_toolchain/testdata/multiple1", + "tests/rule_based_toolchain/testdata/multiple2", +] + def _test_simple_args_impl(env, targets): simple = env.expect.that_target(targets.simple).provider(ArgsInfo) simple.actions().contains_exactly([ @@ -28,11 +36,13 @@ def _test_simple_args_impl(env, targets): ]) simple.args().contains_exactly([targets.simple.label]) simple.env().contains_exactly({"BAR": "bar"}) - simple.files().contains_exactly([ - "tests/rule_based_toolchain/testdata/file1", - "tests/rule_based_toolchain/testdata/multiple1", - "tests/rule_based_toolchain/testdata/multiple2", - ]) + simple.files().contains_exactly(_SIMPLE_FILES) + + c_compile = env.expect.that_target(targets.simple).provider(ArgsListInfo).by_action().get( + targets.c_compile[ActionTypeInfo], + ) + c_compile.args().contains_exactly([targets.simple[ArgsInfo]]) + c_compile.files().contains_exactly(_SIMPLE_FILES) TARGETS = [ ":simple", diff --git a/tests/rule_based_toolchain/generate_factory.bzl b/tests/rule_based_toolchain/generate_factory.bzl index 72c9680..7697a4c 100644 --- a/tests/rule_based_toolchain/generate_factory.bzl +++ b/tests/rule_based_toolchain/generate_factory.bzl @@ -64,8 +64,9 @@ def generate_factory(type, name, attrs): def validate(*, value, meta): got_keys = sorted(structs.to_dict(value).keys()) - if got_keys != want_keys: - meta.add_failure("Wanted a %s with keys %r, got %r" % (name, want_keys, got_keys), "") + subjects.collection(got_keys, meta = meta.derive(details = [ + "Value was not a %s - it has a different set of fields" % name, + ])).contains_exactly(want_keys).in_order() def type_factory(value, *, meta): validate(value = value, meta = meta) diff --git a/tests/rule_based_toolchain/generics.bzl b/tests/rule_based_toolchain/generics.bzl index 2244b0b..4551f2e 100644 --- a/tests/rule_based_toolchain/generics.bzl +++ b/tests/rule_based_toolchain/generics.bzl @@ -120,3 +120,13 @@ struct_subject = lambda **attrs: lambda value, *, meta: subjects.struct( meta = meta, attrs = attrs, ) + +# We can't do complex assertions on containers. This allows you to write +# assert.that_value({"foo": 1), factory=dict_key_subject(subjects.int)) +# .get("foo").equals(1) +dict_key_subject = lambda factory: lambda value, *, meta: struct( + get = lambda key: factory( + value[key], + meta = meta.derive(".get({})".format(key)), + ), +) diff --git a/tests/rule_based_toolchain/subjects.bzl b/tests/rule_based_toolchain/subjects.bzl index 5e5ca62..fbda2d9 100644 --- a/tests/rule_based_toolchain/subjects.bzl +++ b/tests/rule_based_toolchain/subjects.bzl @@ -23,6 +23,7 @@ load( "ActionTypeSetInfo", "AddArgsInfo", "ArgsInfo", + "ArgsListInfo", "FeatureConstraintInfo", "FeatureInfo", "FeatureSetInfo", @@ -30,7 +31,7 @@ load( "ToolInfo", ) load(":generate_factory.bzl", "ProviderDepset", "ProviderSequence", "generate_factory") -load(":generics.bzl", "optional_subject", "result_subject", "struct_subject", _result_fn_wrapper = "result_fn_wrapper") +load(":generics.bzl", "dict_key_subject", "optional_subject", "result_subject", "struct_subject", _result_fn_wrapper = "result_fn_wrapper") visibility("//tests/rule_based_toolchain/...") @@ -66,10 +67,10 @@ _MutuallyExclusiveCategoryFactory = generate_factory( _FEATURE_FLAGS = dict( name = _subjects.str, enabled = _subjects.bool, - flag_sets = None, + args = None, implies = None, requires_any_of = None, - provides = ProviderSequence(_MutuallyExclusiveCategoryFactory), + mutually_exclusive = ProviderSequence(_MutuallyExclusiveCategoryFactory), known = _subjects.bool, overrides = None, ) @@ -122,14 +123,30 @@ _ArgsFactory = generate_factory( ), ) +# buildifier: disable=name-conventions +_ArgsListFactory = generate_factory( + ArgsListInfo, + "ArgsListInfo", + dict( + args = ProviderSequence(_ArgsFactory), + by_action = lambda values, *, meta: dict_key_subject(struct_subject( + args = _subjects.collection, + files = _subjects.depset_file, + ))({value.action: value for value in values}, meta = meta), + files = _subjects.depset_file, + ), +) + # buildifier: disable=name-conventions _FeatureFactory = generate_factory( FeatureInfo, "FeatureInfo", _FEATURE_FLAGS | dict( + # Use .factory so it's not inlined. + args = _ArgsListFactory.factory, implies = ProviderDepset(_FakeFeatureFactory), requires_any_of = ProviderSequence(_FeatureSetFactory), - overrides = _FakeFeatureFactory, + overrides = optional_subject(_FakeFeatureFactory), ), ) @@ -153,7 +170,7 @@ _ActionConfigFactory = generate_factory( action = _ActionTypeFactory, enabled = _subjects.bool, tools = ProviderSequence(_ToolFactory), - flag_sets = ProviderSequence(_ArgsFactory), + args = ProviderSequence(_ArgsFactory), implies = ProviderDepset(_FeatureFactory), files = _subjects.depset_file, ), @@ -185,6 +202,7 @@ FACTORIES = [ _ActionTypeSetFactory, _AddArgsFactory, _ArgsFactory, + _ArgsListFactory, _MutuallyExclusiveCategoryFactory, _FeatureFactory, _FeatureConstraintFactory, @@ -201,5 +219,6 @@ subjects = struct( optional = optional_subject, struct = struct_subject, runfiles = runfiles_subject, + dict_key = dict_key_subject, ) | {factory.name: factory.factory for factory in FACTORIES}) )