• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    "ActionTypeSetInfo",
19    "ArgsListInfo",
20    "FeatureSetInfo",
21    "ToolInfo",
22)
23
24visibility([
25    "//cc/toolchains/...",
26    "//tests/rule_based_toolchain/...",
27])
28
29def collect_provider(targets, provider):
30    """Collects providers from a label list.
31
32    Args:
33        targets: (List[Target]) An attribute from attr.label_list
34        provider: (provider) The provider to look up
35    Returns:
36        A list of the providers
37    """
38    return [target[provider] for target in targets]
39
40def collect_defaultinfo(targets):
41    """Collects DefaultInfo from a label list.
42
43    Args:
44        targets: (List[Target]) An attribute from attr.label_list
45    Returns:
46        A list of the associated defaultinfo
47    """
48    return collect_provider(targets, DefaultInfo)
49
50def _make_collector(provider, field):
51    def collector(targets, direct = [], transitive = []):
52        # Avoid mutating what was passed in.
53        transitive = transitive[:]
54        for value in collect_provider(targets, provider):
55            transitive.append(getattr(value, field))
56        return depset(direct = direct, transitive = transitive)
57
58    return collector
59
60collect_action_types = _make_collector(ActionTypeSetInfo, "actions")
61collect_features = _make_collector(FeatureSetInfo, "features")
62collect_files = _make_collector(DefaultInfo, "files")
63
64def collect_data(ctx, targets):
65    """Collects from a 'data' attribute.
66
67    This is distinguished from collect_files by the fact that data attributes
68    attributes include runfiles.
69
70    Args:
71        ctx: (Context) The ctx for the current rule
72        targets: (List[Target]) A list of files or executables
73
74    Returns:
75        A depset containing all files for each of the targets, and all runfiles
76        required to run them.
77    """
78    return ctx.runfiles(transitive_files = collect_files(targets)).merge_all([
79        info.default_runfiles
80        for info in collect_defaultinfo(targets)
81        if info.default_runfiles != None
82    ])
83
84def collect_tools(ctx, targets, fail = fail):
85    """Collects tools from a label_list.
86
87    Each entry in the label list may either be a cc_tool or a binary.
88
89    Args:
90        ctx: (Context) The ctx for the current rule
91        targets: (List[Target]) A list of targets. Each of these targets may be
92          either a cc_tool or an executable.
93        fail: (function) The fail function. Should only be used in tests.
94
95    Returns:
96        A List[ToolInfo], with regular executables creating custom tool info.
97    """
98    tools = []
99    for target in targets:
100        info = target[DefaultInfo]
101        if ToolInfo in target:
102            tools.append(target[ToolInfo])
103        elif info.files_to_run != None and info.files_to_run.executable != None:
104            tools.append(ToolInfo(
105                label = target.label,
106                exe = info.files_to_run.executable,
107                runfiles = collect_data(ctx, [target]),
108                execution_requirements = tuple(),
109                allowlist_include_directories = depset(),
110                capabilities = 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        allowlist_include_directories = depset(
147            transitive = [a.allowlist_include_directories for a in args],
148        ),
149        by_action = tuple([
150            struct(
151                action = k,
152                args = tuple(v.args),
153                files = depset(transitive = v.transitive_files),
154            )
155            for k, v in by_action.items()
156        ]),
157    )
158