| # 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. | |
| """Conversion helper functions to legacy cc_toolchain_config_info.""" | |
| load( | |
| "//cc:cc_toolchain_config_lib.bzl", | |
| legacy_action_config = "action_config", | |
| legacy_artifact_name_pattern = "artifact_name_pattern", | |
| legacy_env_entry = "env_entry", | |
| legacy_env_set = "env_set", | |
| legacy_feature = "feature", | |
| legacy_feature_set = "feature_set", | |
| legacy_flag_set = "flag_set", | |
| legacy_make_variable = "make_variable", | |
| legacy_tool = "tool", | |
| legacy_tool_path = "tool_path", # buildifier: disable=deprecated-function | |
| legacy_with_feature_set = "with_feature_set", | |
| ) | |
| visibility([ | |
| "//cc/toolchains/...", | |
| "//tests/rule_based_toolchain/...", | |
| ]) | |
| # Note that throughout this file, we sort anything for which the order is | |
| # nondeterministic (eg. depset's .to_list(), dictionary iteration). | |
| # This allows our tests to call equals() on the output, | |
| # and *may* provide better caching properties. | |
| def _convert_actions(actions): | |
| return sorted([action.name for action in actions.to_list()]) | |
| def convert_feature_constraint(constraint): | |
| return legacy_with_feature_set( | |
| features = sorted([ft.name for ft in constraint.all_of.to_list()]), | |
| not_features = sorted([ft.name for ft in constraint.none_of.to_list()]), | |
| ) | |
| def convert_args(args, strip_actions = False): | |
| """Converts an ArgsInfo to flag_sets and env_sets. | |
| Args: | |
| args: (ArgsInfo) The args to convert | |
| strip_actions: (bool) Whether to strip the actions from the resulting flag_set. | |
| Returns: | |
| struct(flag_sets = List[flag_set], env_sets = List[env_sets]) | |
| """ | |
| actions = _convert_actions(args.actions) | |
| with_features = [ | |
| convert_feature_constraint(fc) | |
| for fc in args.requires_any_of | |
| ] | |
| flag_sets = [] | |
| if args.nested != None: | |
| flag_sets.append(legacy_flag_set( | |
| actions = [] if strip_actions else actions, | |
| with_features = with_features, | |
| flag_groups = [args.nested.legacy_flag_group], | |
| )) | |
| env_sets = [] | |
| if args.env.entries: | |
| # NOTE: Use kwargs to support older bazel versions | |
| kwargs = {} | |
| if args.env.requires_not_none: | |
| kwargs["expand_if_available"] = args.env.requires_not_none | |
| env_sets.append(legacy_env_set( | |
| actions = actions, | |
| with_features = with_features, | |
| env_entries = [ | |
| legacy_env_entry( | |
| key = key, | |
| value = value, | |
| **kwargs | |
| ) | |
| for key, value in args.env.entries.items() | |
| ], | |
| )) | |
| return struct( | |
| flag_sets = flag_sets, | |
| env_sets = env_sets, | |
| ) | |
| def _convert_args_sequence(args_sequence, strip_actions = False): | |
| flag_sets = [] | |
| env_sets = [] | |
| for args in args_sequence: | |
| legacy_args = convert_args(args, strip_actions) | |
| flag_sets.extend(legacy_args.flag_sets) | |
| env_sets.extend(legacy_args.env_sets) | |
| return struct(flag_sets = flag_sets, env_sets = env_sets) | |
| def _convert_tool_env(tool, action_name): | |
| if not tool.env: | |
| return None | |
| return legacy_env_set( | |
| actions = [action_name], | |
| env_entries = [ | |
| legacy_env_entry(key = key, value = value) | |
| for key, value in sorted(tool.env.items()) | |
| ], | |
| ) | |
| def convert_feature(feature, enabled = False): | |
| if feature.external: | |
| return None | |
| args = _convert_args_sequence(feature.args.args) | |
| return legacy_feature( | |
| name = feature.name, | |
| enabled = enabled or feature.enabled, | |
| flag_sets = args.flag_sets, | |
| env_sets = args.env_sets, | |
| implies = sorted([ft.name for ft in feature.implies.to_list()]), | |
| requires = [ | |
| legacy_feature_set(sorted([ | |
| feature.name | |
| for feature in requirement.features.to_list() | |
| ])) | |
| for requirement in feature.requires_any_of | |
| ], | |
| provides = [ | |
| mutex.name | |
| for mutex in feature.mutually_exclusive | |
| ], | |
| ) | |
| def convert_tool(tool): | |
| return legacy_tool( | |
| tool = tool.exe, | |
| execution_requirements = list(tool.execution_requirements), | |
| with_features = [], | |
| ) | |
| def convert_capability(capability): | |
| return legacy_feature( | |
| name = capability.name, | |
| enabled = False, | |
| ) | |
| def _convert_tool_map(tool_map, args_by_action): | |
| action_configs = [] | |
| caps = {} | |
| for action_type, tool in tool_map.configs.items(): | |
| action_args = args_by_action.get(action_type.name, default = None) | |
| flag_sets = action_args.flag_sets if action_args != None else [] | |
| action_configs.append(legacy_action_config( | |
| action_name = action_type.name, | |
| enabled = True, | |
| flag_sets = flag_sets, | |
| tools = [convert_tool(tool)], | |
| implies = [cap.feature.name for cap in tool.capabilities], | |
| )) | |
| for cap in tool.capabilities: | |
| caps[cap] = None | |
| cap_features = [ | |
| legacy_feature(name = cap.feature.name, enabled = False) | |
| for cap in caps | |
| ] | |
| return action_configs, cap_features | |
| def convert_toolchain(toolchain): | |
| """Converts a rule-based toolchain into the legacy providers. | |
| Args: | |
| toolchain: (ToolchainConfigInfo) The toolchain config to convert. | |
| Returns: | |
| A struct containing parameters suitable to pass to | |
| cc_common.create_cc_toolchain_config_info. | |
| """ | |
| # Ordering of arguments is important! Intended argument ordering is: | |
| # 1. Arguments listed in `args`. | |
| # 2. Legacy/built-in features. | |
| # 3. User-defined features. | |
| # While we could just attach arguments to a feature, legacy/built-in features will appear | |
| # before the user-defined features if we do not bind args directly to the action configs. | |
| # For that reason, there's additional logic in this function to ensure that the args are | |
| # attached to the action configs directly, as that is the only way to ensure the correct | |
| # ordering. | |
| args_by_action = {} | |
| for a in toolchain.args.by_action: | |
| args = args_by_action.setdefault(a.action.name, struct(flag_sets = [], env_sets = [])) | |
| new_args = _convert_args_sequence(a.args, strip_actions = True) | |
| args.flag_sets.extend(new_args.flag_sets) | |
| args.env_sets.extend(new_args.env_sets) | |
| toolchain_args = _convert_args_sequence(toolchain.args.args) | |
| tool_env_sets = [] | |
| for action_type in sorted(toolchain.tool_map.configs.keys(), key = lambda action: action.name): | |
| env_set = _convert_tool_env(toolchain.tool_map.configs[action_type], action_type.name) | |
| if env_set: | |
| tool_env_sets.append(env_set) | |
| action_configs, cap_features = _convert_tool_map(toolchain.tool_map, args_by_action) | |
| features = [ | |
| convert_feature(feature, enabled = feature in toolchain.enabled_features) | |
| for feature in toolchain.features | |
| ] | |
| features.extend(cap_features) | |
| features.append(legacy_feature( | |
| # We reserve names starting with implied_by. This ensures we don't | |
| # conflict with the name of a feature the user creates. | |
| name = "implied_by_always_enabled_env_sets", | |
| enabled = True, | |
| env_sets = tool_env_sets + toolchain_args.env_sets, | |
| )) | |
| cxx_builtin_include_directories = [ | |
| "%workspace%/" + d.path | |
| for d in toolchain.allowlist_include_directories.to_list() | |
| ] | |
| cxx_builtin_include_directories += toolchain.allowlist_absolute_include_directories.to_list() | |
| artifact_name_patterns = [ | |
| legacy_artifact_name_pattern( | |
| category_name = p.category.name, | |
| prefix = p.prefix, | |
| extension = p.extension, | |
| ) | |
| for p in toolchain.artifact_name_patterns | |
| ] | |
| make_variables = [ | |
| legacy_make_variable( | |
| name = m.key, | |
| value = m.value, | |
| ) | |
| for m in toolchain.make_variables | |
| ] | |
| tool_paths = [ | |
| legacy_tool_path( | |
| name = lt.name, | |
| path = lt.path, | |
| ) | |
| for lt in toolchain.legacy_tools | |
| ] | |
| return struct( | |
| features = [ft for ft in features if ft != None], | |
| action_configs = sorted(action_configs, key = lambda ac: ac.action_name), | |
| cxx_builtin_include_directories = cxx_builtin_include_directories, | |
| artifact_name_patterns = artifact_name_patterns, | |
| make_variables = make_variables, | |
| tool_paths = tool_paths, | |
| ) |