xref: /aosp_15_r20/external/bazelbuild-rules_cc/cc/toolchains/impl/collect.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
1# Copyright 2024 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Helper functions to allow us to collect data from attr.label_list."""
15
16load(
17    "//cc/toolchains:cc_toolchain_info.bzl",
18    "ActionTypeConfigSetInfo",
19    "ActionTypeSetInfo",
20    "ArgsListInfo",
21    "FeatureSetInfo",
22    "ToolInfo",
23)
24
25visibility([
26    "//cc/toolchains/...",
27    "//tests/rule_based_toolchain/...",
28])
29
30def collect_provider(targets, provider):
31    """Collects providers from a label list.
32
33    Args:
34        targets: (List[Target]) An attribute from attr.label_list
35        provider: (provider) The provider to look up
36    Returns:
37        A list of the providers
38    """
39    return [target[provider] for target in targets]
40
41def collect_defaultinfo(targets):
42    """Collects DefaultInfo from a label list.
43
44    Args:
45        targets: (List[Target]) An attribute from attr.label_list
46    Returns:
47        A list of the associated defaultinfo
48    """
49    return collect_provider(targets, DefaultInfo)
50
51def _make_collector(provider, field):
52    def collector(targets, direct = [], transitive = []):
53        # Avoid mutating what was passed in.
54        transitive = transitive[:]
55        for value in collect_provider(targets, provider):
56            transitive.append(getattr(value, field))
57        return depset(direct = direct, transitive = transitive)
58
59    return collector
60
61collect_action_types = _make_collector(ActionTypeSetInfo, "actions")
62collect_features = _make_collector(FeatureSetInfo, "features")
63collect_files = _make_collector(DefaultInfo, "files")
64
65def collect_data(ctx, targets):
66    """Collects from a 'data' attribute.
67
68    This is distinguished from collect_files by the fact that data attributes
69    attributes include runfiles.
70
71    Args:
72        ctx: (Context) The ctx for the current rule
73        targets: (List[Target]) A list of files or executables
74
75    Returns:
76        A depset containing all files for each of the targets, and all runfiles
77        required to run them.
78    """
79    return ctx.runfiles(transitive_files = collect_files(targets)).merge_all([
80        info.default_runfiles
81        for info in collect_defaultinfo(targets)
82        if info.default_runfiles != None
83    ])
84
85def collect_tools(ctx, targets, fail = fail):
86    """Collects tools from a label_list.
87
88    Each entry in the label list may either be a cc_tool or a binary.
89
90    Args:
91        ctx: (Context) The ctx for the current rule
92        targets: (List[Target]) A list of targets. Each of these targets may be
93          either a cc_tool or an executable.
94        fail: (function) The fail function. Should only be used in tests.
95
96    Returns:
97        A List[ToolInfo], with regular executables creating custom tool info.
98    """
99    tools = []
100    for target in targets:
101        info = target[DefaultInfo]
102        if ToolInfo in target:
103            tools.append(target[ToolInfo])
104        elif info.files_to_run != None and info.files_to_run.executable != None:
105            tools.append(ToolInfo(
106                label = target.label,
107                exe = info.files_to_run.executable,
108                runfiles = collect_data(ctx, [target]),
109                requires_any_of = tuple(),
110                execution_requirements = tuple(),
111            ))
112        else:
113            fail("Expected %s to be a cc_tool or a binary rule" % target.label)
114
115    return tools
116
117def collect_args_lists(targets, label):
118    """Collects a label_list of ArgsListInfo into a single ArgsListInfo
119
120    Args:
121        targets: (List[Target]) A label_list of targets providing ArgsListInfo
122        label: The label to attach to the resulting ArgsListInfo
123    Returns:
124        An ArgsListInfo that is the result of joining all of the ArgsListInfos
125        together.
126    """
127    args = []
128    by_action = {}
129    transitive_files = []
130    for target in targets:
131        args_list = target[ArgsListInfo]
132        args.extend(args_list.args)
133        transitive_files.extend([args_info.files for args_info in args_list.args])
134        for value in args_list.by_action:
135            out = by_action.setdefault(
136                value.action,
137                struct(args = [], transitive_files = [], action = value.action),
138            )
139            out.args.extend(value.args)
140            out.transitive_files.append(value.files)
141
142    return ArgsListInfo(
143        label = label,
144        args = tuple(args),
145        files = depset(transitive = transitive_files),
146        by_action = tuple([
147            struct(
148                action = k,
149                args = tuple(v.args),
150                files = depset(transitive = v.transitive_files),
151            )
152            for k, v in by_action.items()
153        ]),
154    )
155
156def collect_action_type_config_sets(targets, label, fail = fail):
157    """Collects several `cc_action_type_config` labels together.
158
159    Args:
160        targets: (List[Target]) A list of targets providing ActionTypeConfigSetInfo
161        label: The label to apply to the resulting config.
162        fail: (function) The fail function. Should only be used in tests.
163    Returns:
164        A combined ActionTypeConfigSetInfo representing a variety of action
165        types.
166    """
167    configs = {}
168    for atcs in collect_provider(targets, ActionTypeConfigSetInfo):
169        for action_type, config in atcs.configs.items():
170            if action_type in configs:
171                fail("The action type %s is configured by both %s and %s. Each action type may only be configured once." % (action_type.label, config.label, configs[action_type].label))
172            configs[action_type] = config
173    return ActionTypeConfigSetInfo(label = label, configs = configs)
174