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
This commit is contained in:
Googler 2024-02-23 13:54:01 -08:00 committed by Copybara-Service
parent 916074ec32
commit 837caeca75
6 changed files with 66 additions and 16 deletions

View File

@ -51,7 +51,15 @@ def _cc_args_impl(ctx):
) )
return [ return [
args, 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( cc_args = rule(

View File

@ -73,6 +73,8 @@ ArgsListInfo = provider(
fields = { fields = {
"label": "(Label) The label defining this provider. Place in error messages to simplify debugging", "label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
"args": "(Sequence[ArgsInfo]) The flag sets contained within", "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", "label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
"name": "(str) The name of the feature", "name": "(str) The name of the feature",
"enabled": "(bool) Whether this feature is enabled by default", "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", "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", "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.", "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( FeatureSetInfo = provider(

View File

@ -15,11 +15,19 @@
load( load(
"//cc/toolchains:cc_toolchain_info.bzl", "//cc/toolchains:cc_toolchain_info.bzl",
"ActionTypeInfo",
"ArgsInfo", "ArgsInfo",
"ArgsListInfo",
) )
visibility("private") 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): def _test_simple_args_impl(env, targets):
simple = env.expect.that_target(targets.simple).provider(ArgsInfo) simple = env.expect.that_target(targets.simple).provider(ArgsInfo)
simple.actions().contains_exactly([ simple.actions().contains_exactly([
@ -28,11 +36,13 @@ def _test_simple_args_impl(env, targets):
]) ])
simple.args().contains_exactly([targets.simple.label]) simple.args().contains_exactly([targets.simple.label])
simple.env().contains_exactly({"BAR": "bar"}) simple.env().contains_exactly({"BAR": "bar"})
simple.files().contains_exactly([ simple.files().contains_exactly(_SIMPLE_FILES)
"tests/rule_based_toolchain/testdata/file1",
"tests/rule_based_toolchain/testdata/multiple1", c_compile = env.expect.that_target(targets.simple).provider(ArgsListInfo).by_action().get(
"tests/rule_based_toolchain/testdata/multiple2", targets.c_compile[ActionTypeInfo],
]) )
c_compile.args().contains_exactly([targets.simple[ArgsInfo]])
c_compile.files().contains_exactly(_SIMPLE_FILES)
TARGETS = [ TARGETS = [
":simple", ":simple",

View File

@ -64,8 +64,9 @@ def generate_factory(type, name, attrs):
def validate(*, value, meta): def validate(*, value, meta):
got_keys = sorted(structs.to_dict(value).keys()) got_keys = sorted(structs.to_dict(value).keys())
if got_keys != want_keys: subjects.collection(got_keys, meta = meta.derive(details = [
meta.add_failure("Wanted a %s with keys %r, got %r" % (name, want_keys, got_keys), "") "Value was not a %s - it has a different set of fields" % name,
])).contains_exactly(want_keys).in_order()
def type_factory(value, *, meta): def type_factory(value, *, meta):
validate(value = value, meta = meta) validate(value = value, meta = meta)

View File

@ -120,3 +120,13 @@ struct_subject = lambda **attrs: lambda value, *, meta: subjects.struct(
meta = meta, meta = meta,
attrs = attrs, 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)),
),
)

View File

@ -23,6 +23,7 @@ load(
"ActionTypeSetInfo", "ActionTypeSetInfo",
"AddArgsInfo", "AddArgsInfo",
"ArgsInfo", "ArgsInfo",
"ArgsListInfo",
"FeatureConstraintInfo", "FeatureConstraintInfo",
"FeatureInfo", "FeatureInfo",
"FeatureSetInfo", "FeatureSetInfo",
@ -30,7 +31,7 @@ load(
"ToolInfo", "ToolInfo",
) )
load(":generate_factory.bzl", "ProviderDepset", "ProviderSequence", "generate_factory") 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/...") visibility("//tests/rule_based_toolchain/...")
@ -66,10 +67,10 @@ _MutuallyExclusiveCategoryFactory = generate_factory(
_FEATURE_FLAGS = dict( _FEATURE_FLAGS = dict(
name = _subjects.str, name = _subjects.str,
enabled = _subjects.bool, enabled = _subjects.bool,
flag_sets = None, args = None,
implies = None, implies = None,
requires_any_of = None, requires_any_of = None,
provides = ProviderSequence(_MutuallyExclusiveCategoryFactory), mutually_exclusive = ProviderSequence(_MutuallyExclusiveCategoryFactory),
known = _subjects.bool, known = _subjects.bool,
overrides = None, 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 # buildifier: disable=name-conventions
_FeatureFactory = generate_factory( _FeatureFactory = generate_factory(
FeatureInfo, FeatureInfo,
"FeatureInfo", "FeatureInfo",
_FEATURE_FLAGS | dict( _FEATURE_FLAGS | dict(
# Use .factory so it's not inlined.
args = _ArgsListFactory.factory,
implies = ProviderDepset(_FakeFeatureFactory), implies = ProviderDepset(_FakeFeatureFactory),
requires_any_of = ProviderSequence(_FeatureSetFactory), requires_any_of = ProviderSequence(_FeatureSetFactory),
overrides = _FakeFeatureFactory, overrides = optional_subject(_FakeFeatureFactory),
), ),
) )
@ -153,7 +170,7 @@ _ActionConfigFactory = generate_factory(
action = _ActionTypeFactory, action = _ActionTypeFactory,
enabled = _subjects.bool, enabled = _subjects.bool,
tools = ProviderSequence(_ToolFactory), tools = ProviderSequence(_ToolFactory),
flag_sets = ProviderSequence(_ArgsFactory), args = ProviderSequence(_ArgsFactory),
implies = ProviderDepset(_FeatureFactory), implies = ProviderDepset(_FeatureFactory),
files = _subjects.depset_file, files = _subjects.depset_file,
), ),
@ -185,6 +202,7 @@ FACTORIES = [
_ActionTypeSetFactory, _ActionTypeSetFactory,
_AddArgsFactory, _AddArgsFactory,
_ArgsFactory, _ArgsFactory,
_ArgsListFactory,
_MutuallyExclusiveCategoryFactory, _MutuallyExclusiveCategoryFactory,
_FeatureFactory, _FeatureFactory,
_FeatureConstraintFactory, _FeatureConstraintFactory,
@ -201,5 +219,6 @@ subjects = struct(
optional = optional_subject, optional = optional_subject,
struct = struct_subject, struct = struct_subject,
runfiles = runfiles_subject, runfiles = runfiles_subject,
dict_key = dict_key_subject,
) | {factory.name: factory.factory for factory in FACTORIES}) ) | {factory.name: factory.factory for factory in FACTORIES})
) )