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