| # Copyright 2024 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """Helper functions to allow us to collect data from attr.label_list.""" |
| |
| load( |
| "//cc/toolchains:cc_toolchain_info.bzl", |
| "ActionTypeConfigSetInfo", |
| "ActionTypeSetInfo", |
| "ArgsListInfo", |
| "FeatureSetInfo", |
| "ToolInfo", |
| ) |
| |
| visibility([ |
| "//cc/toolchains/...", |
| "//tests/rule_based_toolchain/...", |
| ]) |
| |
| def collect_provider(targets, provider): |
| """Collects providers from a label list. |
| |
| Args: |
| targets: (List[Target]) An attribute from attr.label_list |
| provider: (provider) The provider to look up |
| Returns: |
| A list of the providers |
| """ |
| return [target[provider] for target in targets] |
| |
| def collect_defaultinfo(targets): |
| """Collects DefaultInfo from a label list. |
| |
| Args: |
| targets: (List[Target]) An attribute from attr.label_list |
| Returns: |
| A list of the associated defaultinfo |
| """ |
| return collect_provider(targets, DefaultInfo) |
| |
| def _make_collector(provider, field): |
| def collector(targets, direct = [], transitive = []): |
| # Avoid mutating what was passed in. |
| transitive = transitive[:] |
| for value in collect_provider(targets, provider): |
| transitive.append(getattr(value, field)) |
| return depset(direct = direct, transitive = transitive) |
| |
| return collector |
| |
| collect_action_types = _make_collector(ActionTypeSetInfo, "actions") |
| collect_features = _make_collector(FeatureSetInfo, "features") |
| collect_files = _make_collector(DefaultInfo, "files") |
| |
| def collect_data(ctx, targets): |
| """Collects from a 'data' attribute. |
| |
| This is distinguished from collect_files by the fact that data attributes |
| attributes include runfiles. |
| |
| Args: |
| ctx: (Context) The ctx for the current rule |
| targets: (List[Target]) A list of files or executables |
| |
| Returns: |
| A depset containing all files for each of the targets, and all runfiles |
| required to run them. |
| """ |
| return ctx.runfiles(transitive_files = collect_files(targets)).merge_all([ |
| info.default_runfiles |
| for info in collect_defaultinfo(targets) |
| if info.default_runfiles != None |
| ]) |
| |
| def collect_tools(ctx, targets, fail = fail): |
| """Collects tools from a label_list. |
| |
| Each entry in the label list may either be a cc_tool or a binary. |
| |
| Args: |
| ctx: (Context) The ctx for the current rule |
| targets: (List[Target]) A list of targets. Each of these targets may be |
| either a cc_tool or an executable. |
| fail: (function) The fail function. Should only be used in tests. |
| |
| Returns: |
| A List[ToolInfo], with regular executables creating custom tool info. |
| """ |
| tools = [] |
| for target in targets: |
| info = target[DefaultInfo] |
| if ToolInfo in target: |
| tools.append(target[ToolInfo]) |
| elif info.files_to_run != None and info.files_to_run.executable != None: |
| tools.append(ToolInfo( |
| label = target.label, |
| exe = info.files_to_run.executable, |
| runfiles = collect_data(ctx, [target]), |
| requires_any_of = tuple(), |
| execution_requirements = tuple(), |
| )) |
| else: |
| fail("Expected %s to be a cc_tool or a binary rule" % target.label) |
| |
| return tools |
| |
| def collect_args_lists(targets, label): |
| """Collects a label_list of ArgsListInfo into a single ArgsListInfo |
| |
| Args: |
| targets: (List[Target]) A label_list of targets providing ArgsListInfo |
| label: The label to attach to the resulting ArgsListInfo |
| Returns: |
| An ArgsListInfo that is the result of joining all of the ArgsListInfos |
| together. |
| """ |
| args = [] |
| by_action = {} |
| transitive_files = [] |
| for target in targets: |
| args_list = target[ArgsListInfo] |
| args.extend(args_list.args) |
| transitive_files.extend([args_info.files for args_info in args_list.args]) |
| for value in args_list.by_action: |
| out = by_action.setdefault( |
| value.action, |
| struct(args = [], transitive_files = [], action = value.action), |
| ) |
| out.args.extend(value.args) |
| out.transitive_files.append(value.files) |
| |
| return ArgsListInfo( |
| label = label, |
| args = tuple(args), |
| files = depset(transitive = transitive_files), |
| by_action = tuple([ |
| struct( |
| action = k, |
| args = tuple(v.args), |
| files = depset(transitive = v.transitive_files), |
| ) |
| for k, v in by_action.items() |
| ]), |
| ) |
| |
| def collect_action_type_config_sets(targets, label, fail = fail): |
| """Collects several `cc_action_type_config` labels together. |
| |
| Args: |
| targets: (List[Target]) A list of targets providing ActionTypeConfigSetInfo |
| label: The label to apply to the resulting config. |
| fail: (function) The fail function. Should only be used in tests. |
| Returns: |
| A combined ActionTypeConfigSetInfo representing a variety of action |
| types. |
| """ |
| configs = {} |
| for atcs in collect_provider(targets, ActionTypeConfigSetInfo): |
| for action_type, config in atcs.configs.items(): |
| if action_type in configs: |
| 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)) |
| configs[action_type] = config |
| return ActionTypeConfigSetInfo(label = label, configs = configs) |