xref: /aosp_15_r20/external/bazelbuild-rules_cc/cc/toolchains/impl/legacy_converter.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
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