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"""Conversion helper functions to legacy cc_toolchain_config_info.""" 15 16load( 17 "//cc:cc_toolchain_config_lib.bzl", 18 legacy_action_config = "action_config", 19 legacy_env_entry = "env_entry", 20 legacy_env_set = "env_set", 21 legacy_feature = "feature", 22 legacy_feature_set = "feature_set", 23 legacy_flag_set = "flag_set", 24 legacy_tool = "tool", 25 legacy_with_feature_set = "with_feature_set", 26) 27load( 28 "//cc/toolchains:cc_toolchain_info.bzl", 29 "ArgsListInfo", 30 "FeatureInfo", 31) 32 33visibility([ 34 "//cc/toolchains/...", 35 "//tests/rule_based_toolchain/...", 36]) 37 38# Note that throughout this file, we sort anything for which the order is 39# nondeterministic (eg. depset's .to_list(), dictionary iteration). 40# This allows our tests to call equals() on the output, 41# and *may* provide better caching properties. 42 43def _convert_actions(actions): 44 return sorted([action.name for action in actions.to_list()]) 45 46def convert_feature_constraint(constraint): 47 return legacy_with_feature_set( 48 features = sorted([ft.name for ft in constraint.all_of.to_list()]), 49 not_features = sorted([ft.name for ft in constraint.none_of.to_list()]), 50 ) 51 52def convert_args(args): 53 """Converts an ArgsInfo to flag_sets and env_sets. 54 55 Args: 56 args: (ArgsInfo) The args to convert 57 Returns: 58 struct(flag_sets = List[flag_set], env_sets = List[env_sets]) 59 """ 60 actions = _convert_actions(args.actions) 61 with_features = [ 62 convert_feature_constraint(fc) 63 for fc in args.requires_any_of 64 ] 65 66 flag_sets = [] 67 if args.nested != None: 68 flag_sets.append(legacy_flag_set( 69 actions = actions, 70 with_features = with_features, 71 flag_groups = [args.nested.legacy_flag_group], 72 )) 73 74 env_sets = [] 75 if args.env: 76 env_sets.append(legacy_env_set( 77 actions = actions, 78 with_features = with_features, 79 env_entries = [ 80 legacy_env_entry( 81 key = key, 82 value = value, 83 ) 84 for key, value in args.env.items() 85 ], 86 )) 87 return struct( 88 flag_sets = flag_sets, 89 env_sets = env_sets, 90 ) 91 92def _convert_args_sequence(args_sequence): 93 flag_sets = [] 94 env_sets = [] 95 for args in args_sequence: 96 legacy_args = convert_args(args) 97 flag_sets.extend(legacy_args.flag_sets) 98 env_sets.extend(legacy_args.env_sets) 99 100 return struct(flag_sets = flag_sets, env_sets = env_sets) 101 102def convert_feature(feature): 103 if feature.external: 104 return None 105 106 args = _convert_args_sequence(feature.args.args) 107 108 return legacy_feature( 109 name = feature.name, 110 enabled = feature.enabled, 111 flag_sets = args.flag_sets, 112 env_sets = args.env_sets, 113 implies = sorted([ft.name for ft in feature.implies.to_list()]), 114 requires = [ 115 legacy_feature_set(sorted([ 116 feature.name 117 for feature in requirement.features.to_list() 118 ])) 119 for requirement in feature.requires_any_of 120 ], 121 provides = [ 122 mutex.name 123 for mutex in feature.mutually_exclusive 124 ], 125 ) 126 127def convert_tool(tool): 128 return legacy_tool( 129 tool = tool.exe, 130 execution_requirements = list(tool.execution_requirements), 131 with_features = [ 132 convert_feature_constraint(fc) 133 for fc in tool.requires_any_of 134 ], 135 ) 136 137def _convert_action_type_config(atc): 138 implies = sorted([ft.name for ft in atc.implies.to_list()]) 139 if atc.args: 140 implies.append("implied_by_%s" % atc.action_type.name) 141 142 return legacy_action_config( 143 action_name = atc.action_type.name, 144 enabled = True, 145 tools = [convert_tool(tool) for tool in atc.tools], 146 implies = implies, 147 ) 148 149def convert_toolchain(toolchain): 150 """Converts a rule-based toolchain into the legacy providers. 151 152 Args: 153 toolchain: CcToolchainConfigInfo: The toolchain config to convert. 154 Returns: 155 A struct containing parameters suitable to pass to 156 cc_common.create_cc_toolchain_config_info. 157 """ 158 features = [convert_feature(feature) for feature in toolchain.features] 159 features.append(convert_feature(FeatureInfo( 160 # We reserve names starting with implied_by. This ensures we don't 161 # conflict with the name of a feature the user creates. 162 name = "implied_by_always_enabled", 163 enabled = True, 164 args = ArgsListInfo(args = toolchain.args), 165 implies = depset([]), 166 requires_any_of = [], 167 mutually_exclusive = [], 168 external = False, 169 ))) 170 action_configs = [] 171 for atc in toolchain.action_type_configs.values(): 172 # Action configs don't take in an env like they do a flag set. 173 # In order to support them, we create a feature with the env that the action 174 # config will enable, and imply it in the action config. 175 if atc.args: 176 features.append(convert_feature(FeatureInfo( 177 name = "implied_by_%s" % atc.action_type.name, 178 enabled = False, 179 args = ArgsListInfo(args = atc.args), 180 implies = depset([]), 181 requires_any_of = [], 182 mutually_exclusive = [], 183 external = False, 184 ))) 185 action_configs.append(_convert_action_type_config(atc)) 186 187 return struct( 188 features = sorted([ft for ft in features if ft != None], key = lambda ft: ft.name), 189 action_configs = sorted(action_configs, key = lambda ac: ac.action_name), 190 ) 191