• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Implementation of the pw_cc_toolchain rule."""
15
16load("//features:builtin_features.bzl", "BUILTIN_FEATURES")
17load(
18    ":providers.bzl",
19    "PwActionConfigSetInfo",
20    "PwActionNameSetInfo",
21    "PwExtraActionFilesSetInfo",
22    "PwFeatureInfo",
23    "PwFeatureSetInfo",
24    "PwFlagSetInfo",
25    "PwToolchainConfigInfo",
26)
27load(
28    ":utils.bzl",
29    "ALL_FILE_GROUPS",
30    "to_untyped_config",
31)
32
33# These attributes of pw_cc_toolchain are deprecated.
34PW_CC_TOOLCHAIN_DEPRECATED_TOOL_ATTRS = {
35    "ar": "Path to the tool to use for `ar` (static link) actions",
36    "cpp": "Path to the tool to use for C++ compile actions",
37    "gcc": "Path to the tool to use for C compile actions",
38    "gcov": "Path to the tool to use for generating code coverage data",
39    "ld": "Path to the tool to use for link actions",
40    "objcopy": "Path to the tool to use for objcopy actions",
41    "objdump": "Path to the tool to use for objdump actions",
42    "strip": "Path to the tool to use for strip actions",
43}
44
45PW_CC_TOOLCHAIN_CONFIG_ATTRS = {
46    "abi_libc_version": "See documentation for cc_common.create_cc_toolchain_config_info()",
47    "abi_version": "See documentation for cc_common.create_cc_toolchain_config_info()",
48    "action_configs": "List of `pw_cc_action_config` labels that bind tools to the appropriate actions",
49    "builtin_sysroot": "See documentation for cc_common.create_cc_toolchain_config_info()",
50    "cc_target_os": "See documentation for cc_common.create_cc_toolchain_config_info()",
51    "compiler": "See documentation for cc_common.create_cc_toolchain_config_info()",
52    "cxx_builtin_include_directories": "See documentation for cc_common.create_cc_toolchain_config_info()",
53    "extra_action_files": "Files that are required to run specific actions.",
54    "flag_sets": "List of `pw_cc_flag_set`s to unconditionally apply to their respective action configs",
55    "host_system_name": "See documentation for cc_common.create_cc_toolchain_config_info()",
56    "target_cpu": "See documentation for cc_common.create_cc_toolchain_config_info()",
57    "target_libc": "See documentation for cc_common.create_cc_toolchain_config_info()",
58    "target_system_name": "See documentation for cc_common.create_cc_toolchain_config_info()",
59    "toolchain_features": "List of `pw_cc_feature`s that this toolchain supports",
60
61    # Attributes originally part of create_cc_toolchain_config_info.
62    "toolchain_identifier": "See documentation for cc_common.create_cc_toolchain_config_info()",
63}
64
65PW_CC_TOOLCHAIN_SHARED_ATTRS = ["toolchain_identifier"]
66
67PW_CC_TOOLCHAIN_BLOCKED_ATTRS = {
68    "artifact_name_patterns": "pw_cc_toolchain does not yet support artifact name patterns",
69    "features": "Use toolchain_features to add pw_cc_toolchain_feature deps to the toolchain",
70    "make_variables": "pw_cc_toolchain does not yet support make variables",
71    "tool_paths": "pw_cc_toolchain does not support tool_paths, use \"action_configs\" to set toolchain tools",
72    "toolchain_config": "pw_cc_toolchain includes a generated toolchain config",
73}
74
75def _pw_cc_toolchain_config_impl(ctx):
76    """Rule that provides a CcToolchainConfigInfo.
77
78    Args:
79        ctx: The context of the current build rule.
80
81    Returns:
82        CcToolchainConfigInfo
83    """
84    builtin_include_dirs = ctx.attr.cxx_builtin_include_directories if ctx.attr.cxx_builtin_include_directories else []
85    sysroot_dir = ctx.attr.builtin_sysroot if ctx.attr.builtin_sysroot else None
86
87    feature_set = PwFeatureSetInfo(features = depset(
88        [ft[PwFeatureInfo] for ft in ctx.attr._builtin_features],
89        transitive = [
90            feature_set[PwFeatureSetInfo].features
91            for feature_set in ctx.attr.toolchain_features
92        ],
93    ))
94    action_config_set = PwActionConfigSetInfo(
95        label = ctx.label,
96        action_configs = depset(transitive = [
97            acs[PwActionConfigSetInfo].action_configs
98            for acs in ctx.attr.action_configs
99        ]),
100    )
101    extra_action_files = PwExtraActionFilesSetInfo(srcs = depset(transitive = [
102        ffa[PwExtraActionFilesSetInfo].srcs
103        for ffa in ctx.attr.extra_action_files
104    ]))
105    flag_sets = [fs[PwFlagSetInfo] for fs in ctx.attr.flag_sets]
106    out = to_untyped_config(feature_set, action_config_set, flag_sets, extra_action_files)
107
108    extra = []
109    return [
110        cc_common.create_cc_toolchain_config_info(
111            ctx = ctx,
112            action_configs = out.action_configs,
113            features = out.features,
114            cxx_builtin_include_directories = builtin_include_dirs,
115            toolchain_identifier = ctx.attr.toolchain_identifier,
116            host_system_name = ctx.attr.host_system_name,
117            target_system_name = ctx.attr.target_system_name,
118            target_cpu = ctx.attr.target_cpu,
119            target_libc = ctx.attr.target_libc,
120            compiler = ctx.attr.compiler,
121            abi_version = ctx.attr.abi_version,
122            abi_libc_version = ctx.attr.abi_libc_version,
123            builtin_sysroot = sysroot_dir,
124            cc_target_os = ctx.attr.cc_target_os,
125        ),
126        PwToolchainConfigInfo(action_to_files = out.action_to_files),
127        DefaultInfo(files = depset(transitive = extra + out.action_to_files.values())),
128    ]
129
130pw_cc_toolchain_config = rule(
131    implementation = _pw_cc_toolchain_config_impl,
132    attrs = {
133        "abi_libc_version": attr.string(),
134        "abi_version": attr.string(),
135        # Attributes new to this rule.
136        "action_configs": attr.label_list(providers = [PwActionConfigSetInfo]),
137        "builtin_sysroot": attr.string(),
138        "cc_target_os": attr.string(),
139        "compiler": attr.string(),
140        "cxx_builtin_include_directories": attr.string_list(),
141        "extra_action_files": attr.label_list(providers = [PwExtraActionFilesSetInfo]),
142        "flag_sets": attr.label_list(providers = [PwFlagSetInfo]),
143        "host_system_name": attr.string(),
144        "target_cpu": attr.string(),
145        "target_libc": attr.string(),
146        "target_system_name": attr.string(),
147        "toolchain_features": attr.label_list(providers = [PwFeatureSetInfo]),
148
149        # Attributes from create_cc_toolchain_config_info.
150        "toolchain_identifier": attr.string(),
151        "_builtin_features": attr.label_list(default = BUILTIN_FEATURES),
152    },
153    provides = [CcToolchainConfigInfo, PwToolchainConfigInfo],
154)
155
156def _check_args(rule_label, kwargs):
157    """Checks that args provided to pw_cc_toolchain are valid.
158
159    Args:
160        rule_label: The label of the pw_cc_toolchain rule.
161        kwargs: All attributes supported by pw_cc_toolchain.
162
163    Returns:
164        None
165    """
166    for attr_name, msg in PW_CC_TOOLCHAIN_BLOCKED_ATTRS.items():
167        if attr_name in kwargs:
168            fail(
169                "Toolchain {} has an invalid attribute \"{}\": {}".format(
170                    rule_label,
171                    attr_name,
172                    msg,
173                ),
174            )
175
176def _split_args(kwargs, filter_dict):
177    """Splits kwargs into two dictionaries guided by a filter.
178
179    All items in the kwargs dictionary whose keys are present in the filter
180    dictionary are returned as a new dictionary as the first item in the tuple.
181    All remaining arguments are returned as a dictionary in the second item of
182    the tuple.
183
184    Args:
185        kwargs: dictionary of args to split.
186        filter_dict: The dictionary used as the filter.
187
188    Returns:
189        tuple[dict, dict]
190    """
191    filtered_args = {}
192    remainder = {}
193
194    for attr_name, val in kwargs.items():
195        if attr_name in ALL_FILE_GROUPS:
196            fail("Don't use %s. Instead, use pw_cc_action_files" % attr_name)
197        elif attr_name in filter_dict:
198            filtered_args[attr_name] = val
199        else:
200            remainder[attr_name] = val
201
202    return filtered_args, remainder
203
204def _cc_file_collector_impl(ctx):
205    actions = depset(transitive = [
206        names[PwActionNameSetInfo].actions
207        for names in ctx.attr.actions
208    ]).to_list()
209    action_to_files = ctx.attr.config[PwToolchainConfigInfo].action_to_files
210
211    extra = []
212    return [DefaultInfo(files = depset(transitive = [
213        action_to_files[action]
214        for action in actions
215    ] + extra))]
216
217_cc_file_collector = rule(
218    implementation = _cc_file_collector_impl,
219    attrs = {
220        "actions": attr.label_list(providers = [PwActionNameSetInfo], mandatory = True),
221        "config": attr.label(providers = [PwToolchainConfigInfo], mandatory = True),
222    },
223)
224
225def pw_cc_toolchain(name, action_config_flag_sets = None, **kwargs):
226    """A suite of cc_toolchain, pw_cc_toolchain_config, and *_files rules.
227
228    Generated rules:
229        {name}: A `cc_toolchain` for this toolchain.
230        _{name}_config: A `pw_cc_toolchain_config` for this toolchain.
231        _{name}_*_files: Generated rules that group together files for
232            "ar_files", "as_files", "compiler_files", "coverage_files",
233            "dwp_files", "linker_files", "objcopy_files", and "strip_files"
234            normally enumerated as part of the `cc_toolchain` rule.
235
236    Args:
237        name: str: The name of the label for the toolchain.
238        action_config_flag_sets: Deprecated. Do not use.
239        **kwargs: All attributes supported by either cc_toolchain or pw_cc_toolchain_config.
240    """
241
242    # TODO(b/322872628): Remove this once it's no longer in use.
243    if action_config_flag_sets != None:
244        kwargs["flag_sets"] = action_config_flag_sets
245
246    _check_args(native.package_relative_label(name), kwargs)
247
248    # Split args between `pw_cc_toolchain_config` and `native.cc_toolchain`.
249    cc_toolchain_config_args, cc_toolchain_args = _split_args(kwargs, PW_CC_TOOLCHAIN_CONFIG_ATTRS | PW_CC_TOOLCHAIN_DEPRECATED_TOOL_ATTRS)
250
251    # Bind pw_cc_toolchain_config and the cc_toolchain.
252    config_name = "_{}_config".format(name)
253    pw_cc_toolchain_config(
254        name = config_name,
255        visibility = ["//visibility:private"],
256        compatible_with = kwargs.get("compatible_with", None),
257        target_compatible_with = kwargs.get("target_compatible_with", None),
258        exec_compatible_with = kwargs.get("exec_compatible_with", None),
259        tags = kwargs.get("tags", None),
260        **cc_toolchain_config_args
261    )
262
263    for group, actions in ALL_FILE_GROUPS.items():
264        group_name = "_{}_{}".format(name, group)
265        _cc_file_collector(
266            name = group_name,
267            config = config_name,
268            actions = actions,
269            visibility = ["//visibility:private"],
270            compatible_with = kwargs.get("compatible_with", None),
271            target_compatible_with = kwargs.get("target_compatible_with", None),
272            exec_compatible_with = kwargs.get("exec_compatible_with", None),
273            tags = kwargs.get("tags", None),
274        )
275        cc_toolchain_args[group] = group_name
276
277    # Copy over arguments that should be shared by both rules.
278    for arg_name in PW_CC_TOOLCHAIN_SHARED_ATTRS:
279        if arg_name in cc_toolchain_config_args:
280            cc_toolchain_args[arg_name] = cc_toolchain_config_args[arg_name]
281
282    native.cc_toolchain(
283        name = name,
284        toolchain_config = config_name,
285        # TODO: b/321268080 - Remove after transition of this option is complete.
286        exec_transition_for_inputs = False,
287        all_files = config_name,
288        **cc_toolchain_args
289    )
290