blob: a69be376b4c70e3e4db46da7816b040149eba2ee [file] [log] [blame]
Ignas Anikevicius8f114a52024-01-31 14:41:20 +09001# Copyright 2022 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
15"""Create the toolchain defs in a BUILD.bazel file."""
16
17load("@bazel_skylib//lib:selects.bzl", "selects")
Richard Levasseurdd5db652024-10-15 16:33:37 -070018load(":text_util.bzl", "render")
Richard Levasseur37308032024-05-18 09:44:18 -070019load(
20 ":toolchain_types.bzl",
21 "EXEC_TOOLS_TOOLCHAIN_TYPE",
22 "PY_CC_TOOLCHAIN_TYPE",
23 "TARGET_TOOLCHAIN_TYPE",
24)
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090025
Ignas Anikeviciuscf1f36d2024-06-19 13:08:58 +090026_IS_EXEC_TOOLCHAIN_ENABLED = Label("//python/config_settings:is_exec_tools_toolchain_enabled")
27
Richard Levasseur68c30482024-07-16 16:22:22 -070028# buildifier: disable=unnamed-macro
29def py_toolchain_suite(
30 *,
31 prefix,
32 user_repository_name,
33 python_version,
34 set_python_version_constraint,
35 flag_values,
36 target_compatible_with = []):
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090037 """For internal use only.
38
39 Args:
40 prefix: Prefix for toolchain target names.
41 user_repository_name: The name of the user repository.
42 python_version: The full (X.Y.Z) version of the interpreter.
43 set_python_version_constraint: True or False as a string.
Ignas Anikevicius7de43d12024-06-06 17:20:01 +090044 flag_values: Extra flag values to match for this toolchain.
Richard Levasseur68c30482024-07-16 16:22:22 -070045 target_compatible_with: list constraints the toolchains are compatible with.
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090046 """
47
48 # We have to use a String value here because bzlmod is passing in a
Richard Levasseurac3abf62024-06-17 16:28:33 -070049 # string as we cannot have list of bools in build rule attributes.
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090050 # This if statement does not appear to work unless it is in the
51 # toolchain file.
Ignas Anikevicius7de43d12024-06-06 17:20:01 +090052 if set_python_version_constraint in ["True", "False"]:
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090053 major_minor, _, _ = python_version.rpartition(".")
Ignas Anikevicius7de43d12024-06-06 17:20:01 +090054 python_versions = [major_minor, python_version]
55 if set_python_version_constraint == "False":
56 python_versions.append("")
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090057
Ignas Anikevicius7de43d12024-06-06 17:20:01 +090058 match_any = []
59 for i, v in enumerate(python_versions):
60 name = "{prefix}_{python_version}_{i}".format(
61 prefix = prefix,
62 python_version = python_version,
63 i = i,
64 )
65 match_any.append(name)
66 native.config_setting(
67 name = name,
68 flag_values = flag_values | {
69 Label("@rules_python//python/config_settings:python_version"): v,
70 },
71 visibility = ["//visibility:private"],
72 )
73
74 name = "{prefix}_version_setting_{python_version}".format(
75 prefix = prefix,
76 python_version = python_version,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090077 visibility = ["//visibility:private"],
78 )
Ignas Anikevicius7de43d12024-06-06 17:20:01 +090079 selects.config_setting_group(
80 name = name,
81 match_any = match_any,
82 visibility = ["//visibility:private"],
83 )
84 target_settings = [name]
Ignas Anikevicius8f114a52024-01-31 14:41:20 +090085 else:
86 fail(("Invalid set_python_version_constraint value: got {} {}, wanted " +
87 "either the string 'True' or the string 'False'; " +
88 "(did you convert bool to string?)").format(
89 type(set_python_version_constraint),
90 repr(set_python_version_constraint),
91 ))
92
Richard Levasseur68c30482024-07-16 16:22:22 -070093 _internal_toolchain_suite(
94 prefix = prefix,
95 runtime_repo_name = user_repository_name,
96 target_settings = target_settings,
97 target_compatible_with = target_compatible_with,
98 )
99
100def _internal_toolchain_suite(prefix, runtime_repo_name, target_compatible_with, target_settings):
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900101 native.toolchain(
102 name = "{prefix}_toolchain".format(prefix = prefix),
Richard Levasseur68c30482024-07-16 16:22:22 -0700103 toolchain = "@{runtime_repo_name}//:python_runtimes".format(
104 runtime_repo_name = runtime_repo_name,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900105 ),
Richard Levasseur37308032024-05-18 09:44:18 -0700106 toolchain_type = TARGET_TOOLCHAIN_TYPE,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900107 target_settings = target_settings,
Richard Levasseur68c30482024-07-16 16:22:22 -0700108 target_compatible_with = target_compatible_with,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900109 )
110
111 native.toolchain(
112 name = "{prefix}_py_cc_toolchain".format(prefix = prefix),
Richard Levasseur68c30482024-07-16 16:22:22 -0700113 toolchain = "@{runtime_repo_name}//:py_cc_toolchain".format(
114 runtime_repo_name = runtime_repo_name,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900115 ),
Richard Levasseur37308032024-05-18 09:44:18 -0700116 toolchain_type = PY_CC_TOOLCHAIN_TYPE,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900117 target_settings = target_settings,
Richard Levasseur68c30482024-07-16 16:22:22 -0700118 target_compatible_with = target_compatible_with,
Ignas Anikevicius8f114a52024-01-31 14:41:20 +0900119 )
Richard Levasseur37308032024-05-18 09:44:18 -0700120
121 native.toolchain(
122 name = "{prefix}_py_exec_tools_toolchain".format(prefix = prefix),
Richard Levasseur68c30482024-07-16 16:22:22 -0700123 toolchain = "@{runtime_repo_name}//:py_exec_tools_toolchain".format(
124 runtime_repo_name = runtime_repo_name,
Richard Levasseur37308032024-05-18 09:44:18 -0700125 ),
126 toolchain_type = EXEC_TOOLS_TOOLCHAIN_TYPE,
Ignas Anikeviciuscf1f36d2024-06-19 13:08:58 +0900127 target_settings = select({
128 _IS_EXEC_TOOLCHAIN_ENABLED: target_settings,
129 # Whatever the default is, it has to map to a `config_setting`
130 # that will never match. Since the default branch is only taken if
131 # _IS_EXEC_TOOLCHAIN_ENABLED is false, then it will never match
132 # when later evaluated during toolchain resolution.
133 # Note that @platforms//:incompatible can't be used here because
134 # the RHS must be a `config_setting`.
135 "//conditions:default": [_IS_EXEC_TOOLCHAIN_ENABLED],
136 }),
Richard Levasseur68c30482024-07-16 16:22:22 -0700137 exec_compatible_with = target_compatible_with,
Richard Levasseur37308032024-05-18 09:44:18 -0700138 )
139
140 # NOTE: When adding a new toolchain, for WORKSPACE builds to see the
141 # toolchain, the name must be added to the native.register_toolchains()
142 # call in python/repositories.bzl. Bzlmod doesn't need anything; it will
143 # register `:all`.
Richard Levasseur68c30482024-07-16 16:22:22 -0700144
145def define_local_toolchain_suites(name, version_aware_repo_names, version_unaware_repo_names):
146 """Define toolchains for `local_runtime_repo` backed toolchains.
147
148 This generates `toolchain` targets that can be registered using `:all`. The
149 specific names of the toolchain targets are not defined. The priority order
150 of the toolchains is the order that is passed in, with version-aware having
151 higher priority than version-unaware.
152
153 Args:
154 name: `str` Unused; only present to satisfy tooling.
155 version_aware_repo_names: `list[str]` of the repo names that will have
156 version-aware toolchains defined.
157 version_unaware_repo_names: `list[str]` of the repo names that will have
158 version-unaware toolchains defined.
159 """
160 i = 0
161 for i, repo in enumerate(version_aware_repo_names, start = i):
162 prefix = render.left_pad_zero(i, 4)
163 _internal_toolchain_suite(
164 prefix = prefix,
165 runtime_repo_name = repo,
166 target_compatible_with = ["@{}//:os".format(repo)],
167 target_settings = ["@{}//:is_matching_python_version".format(repo)],
168 )
169
170 # The version unaware entries must go last because they will match any Python
171 # version.
172 for i, repo in enumerate(version_unaware_repo_names, start = i + 1):
173 prefix = render.left_pad_zero(i, 4)
174 _internal_toolchain_suite(
175 prefix = prefix,
176 runtime_repo_name = repo,
177 target_settings = [],
178 target_compatible_with = ["@{}//:os".format(repo)],
179 )