Skip to content

Commit e2c82f2

Browse files
committed
refactor: simplify hub repo toolchain creation
1 parent c383c3b commit e2c82f2

File tree

8 files changed

+305
-172
lines changed

8 files changed

+305
-172
lines changed

internal_dev_setup.bzl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,15 @@ def rules_python_internal_setup():
3434
name = "pythons_hub",
3535
minor_mapping = MINOR_MAPPING,
3636
default_python_version = "",
37-
toolchain_prefixes = [],
38-
toolchain_python_versions = [],
39-
toolchain_set_python_version_constraints = [],
40-
toolchain_user_repository_names = [],
4137
python_versions = sorted(TOOL_VERSIONS.keys()),
38+
toolchain_names = [],
39+
toolchain_repo_names = {},
40+
toolchain_target_compatible_with_map = {},
41+
toolchain_target_settings_map = {},
42+
toolchain_platform_keys = {},
43+
toolchain_python_versions = {},
44+
toolchain_set_python_version_constraints = {},
45+
base_toolchain_repo_names = [],
4246
)
4347

4448
runtime_env_repo(name = "rules_python_runtime_env_tc_info")

python/private/config_settings.bzl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ If the value is missing, then the default value is being used, see documentation
3131
{docs_url}/python/config_settings
3232
"""
3333

34+
# Indicates something needs public visibility so that other generated code can
35+
# access it, but it's not intended for general public usage.
36+
_NOT_ACTUALLY_PUBLIC = ["//visibility:public"]
37+
3438
def construct_config_settings(*, name, default_version, versions, minor_mapping, documented_flags): # buildifier: disable=function-docstring
3539
"""Create a 'python_version' config flag and construct all config settings used in rules_python.
3640
@@ -128,7 +132,30 @@ def construct_config_settings(*, name, default_version, versions, minor_mapping,
128132
# `whl_library` in the hub repo created by `pip.parse`.
129133
flag_values = {"current_config": "will-never-match"},
130134
# Only public so that PyPI hub repo can access it
131-
visibility = ["//visibility:public"],
135+
visibility = _NOT_ACTUALLY_PUBLIC,
136+
)
137+
138+
libc = Label("//python/config_settings:py_linux_libc")
139+
native.config_setting(
140+
name = "_is_libc_glibc",
141+
flag_values = {libc: "glibc"},
142+
visibility = _NOT_ACTUALLY_PUBLIC,
143+
)
144+
native.config_setting(
145+
name = "_is_libc_musl",
146+
flag_values = {libc: "glibc"},
147+
visibility = _NOT_ACTUALLY_PUBLIC,
148+
)
149+
freethreaded = Label("//python/config_settings:py_freethreaded")
150+
native.config_setting(
151+
name = "_is_freethreaded_yes",
152+
flag_values = {freethreaded: "yes"},
153+
visibility = _NOT_ACTUALLY_PUBLIC,
154+
)
155+
native.config_setting(
156+
name = "_is_freethreaded_no",
157+
flag_values = {freethreaded: "no"},
158+
visibility = _NOT_ACTUALLY_PUBLIC,
132159
)
133160

134161
def _python_version_flag_impl(ctx):

python/private/py_repositories.bzl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ def py_repositories():
3939
name = "pythons_hub",
4040
minor_mapping = MINOR_MAPPING,
4141
default_python_version = "",
42-
toolchain_prefixes = [],
43-
toolchain_python_versions = [],
44-
toolchain_set_python_version_constraints = [],
45-
toolchain_user_repository_names = [],
4642
python_versions = sorted(TOOL_VERSIONS.keys()),
43+
toolchain_names = [],
44+
toolchain_repo_names = {},
45+
toolchain_target_compatible_with_map = {},
46+
toolchain_target_settings_map = {},
47+
toolchain_platform_keys = {},
48+
toolchain_python_versions = {},
49+
toolchain_set_python_version_constraints = {},
50+
base_toolchain_repo_names = [],
4751
)
4852
http_archive(
4953
name = "bazel_skylib",

python/private/py_toolchain_suite.bzl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,20 @@ def py_toolchain_suite(
3434
python_version,
3535
set_python_version_constraint,
3636
flag_values,
37+
target_settings = [],
3738
target_compatible_with = []):
3839
"""For internal use only.
3940
4041
Args:
4142
prefix: Prefix for toolchain target names.
42-
user_repository_name: The name of the user repository.
43+
user_repository_name: The name of the repository with the toolchain
44+
implementation (it's assumed to have particular target names within
45+
it). Does not include the leading "@".
4346
python_version: The full (X.Y.Z) version of the interpreter.
4447
set_python_version_constraint: True or False as a string.
45-
flag_values: Extra flag values to match for this toolchain.
48+
flag_values: Extra flag values to match for this toolchain. These
49+
are prepended to target_settings.
50+
target_settings: Extra target_settings to match for this toolchain.
4651
target_compatible_with: list constraints the toolchains are compatible with.
4752
"""
4853

@@ -82,7 +87,7 @@ def py_toolchain_suite(
8287
match_any = match_any,
8388
visibility = ["//visibility:private"],
8489
)
85-
target_settings = [name]
90+
target_settings = [name] + target_settings
8691
else:
8792
fail(("Invalid set_python_version_constraint value: got {} {}, wanted " +
8893
"either the string 'True' or the string 'False'; " +

python/private/python.bzl

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,9 @@ load(":python_register_toolchains.bzl", "python_register_toolchains")
2222
load(":pythons_hub.bzl", "hub_repo")
2323
load(":repo_utils.bzl", "repo_utils")
2424
load(":semver.bzl", "semver")
25-
load(":text_util.bzl", "render")
2625
load(":toolchains_repo.bzl", "multi_toolchain_aliases")
2726
load(":util.bzl", "IS_BAZEL_6_4_OR_HIGHER")
2827

29-
# This limit can be increased essentially arbitrarily, but doing so will cause a rebuild of all
30-
# targets using any of these toolchains due to the changed repository name.
31-
_MAX_NUM_TOOLCHAINS = 9999
32-
_TOOLCHAIN_INDEX_PAD_LENGTH = len(str(_MAX_NUM_TOOLCHAINS))
33-
3428
def parse_modules(*, module_ctx, _fail = fail):
3529
"""Parse the modules and return a struct for registrations.
3630
@@ -240,9 +234,6 @@ def parse_modules(*, module_ctx, _fail = fail):
240234
# toolchain. We need the default last.
241235
toolchains.append(default_toolchain)
242236

243-
if len(toolchains) > _MAX_NUM_TOOLCHAINS:
244-
fail("more than {} python versions are not supported".format(_MAX_NUM_TOOLCHAINS))
245-
246237
# sort the toolchains so that the toolchain versions that are in the
247238
# `minor_mapping` are coming first. This ensures that `python_version =
248239
# "3.X"` transitions work as expected.
@@ -275,6 +266,9 @@ def parse_modules(*, module_ctx, _fail = fail):
275266
def _python_impl(module_ctx):
276267
py = parse_modules(module_ctx = module_ctx)
277268

269+
# dict[str version, list[str] platforms]; where version is full
270+
# python version string ("3.4.5"), and platforms are keys from
271+
# the PLATFORMS global.
278272
loaded_platforms = {}
279273
for toolchain_info in py.toolchains:
280274
# Ensure that we pass the full version here.
@@ -297,30 +291,82 @@ def _python_impl(module_ctx):
297291
**kwargs
298292
)
299293

300-
# Create the pythons_hub repo for the interpreter meta data and the
301-
# the various toolchains.
294+
# List of the base names ("python_3_10") for the toolchain repos
295+
base_toolchain_repo_names = []
296+
297+
# list[str] The infix to use for the resulting toolchain() `name` arg.
298+
toolchain_names = []
299+
300+
# dict[str i, str repo]; where repo is the full repo name
301+
# ("python_3_10_unknown-linux-x86_64") for the toolchain
302+
# i corresponds to index `i` in toolchain_names
303+
toolchain_repo_names = {}
304+
305+
# dict[str i, list[str] constraints]; where constraints is a list
306+
# of labels for target_compatible_with
307+
# i corresponds to index `i` in toolchain_names
308+
toolchain_tcw_map = {}
309+
310+
# dict[str i, list[str] settings]; where settings is a list
311+
# of labels for target_settings
312+
# i corresponds to index `i` in toolchain_names
313+
toolchain_ts_map = {}
314+
315+
# dict[str i, str set_constraint]; where set_constraint is the string
316+
# "True" or "False".
317+
# i corresponds to index `i` in toolchain_names
318+
toolchain_set_python_version_constraints = {}
319+
320+
# dict[str i, str python_version]; where python_version is the full
321+
# python version ("3.4.5").
322+
toolchain_python_versions = {}
323+
324+
# dict[str i, str platform_key]; where platform_key is the key within
325+
# the PLATFORMS global for this toolchain
326+
toolchain_platform_keys = {}
327+
328+
# Split the toolchain info into separate objects so they can be passed onto
329+
# the repository rule.
330+
for i, t in enumerate(py.toolchains):
331+
is_last = (i + 1) == len(py.toolchains)
332+
base_name = t.name
333+
base_toolchain_repo_names.append(base_name)
334+
fv = full_version(version = t.python_version, minor_mapping = py.config.minor_mapping)
335+
for platform in loaded_platforms[fv]:
336+
if platform not in PLATFORMS:
337+
continue
338+
key = str(len(toolchain_names))
339+
340+
full_name = "{}_{}".format(base_name, platform)
341+
toolchain_names.append(full_name)
342+
toolchain_repo_names[key] = full_name
343+
toolchain_tcw_map[key] = PLATFORMS[platform].compatible_with
344+
345+
# The target_settings attribute may not be present for users
346+
# patching python/versions.bzl.
347+
toolchain_ts_map[key] = getattr(PLATFORMS[platform], "target_settings", [])
348+
toolchain_platform_keys[key] = platform
349+
toolchain_python_versions[key] = fv
350+
351+
# The last toolchain is the default; it can't have version constraints
352+
# Despite the implication of the arg name, the values are strs, not bools
353+
toolchain_set_python_version_constraints[key] = (
354+
"True" if not is_last else "False"
355+
)
356+
302357
hub_repo(
303358
name = "pythons_hub",
304-
# Last toolchain is default
359+
toolchain_names = toolchain_names,
360+
toolchain_repo_names = toolchain_repo_names,
361+
toolchain_target_compatible_with_map = toolchain_tcw_map,
362+
toolchain_target_settings_map = toolchain_ts_map,
363+
toolchain_platform_keys = toolchain_platform_keys,
364+
toolchain_python_versions = toolchain_python_versions,
365+
toolchain_set_python_version_constraints = toolchain_set_python_version_constraints,
366+
base_toolchain_repo_names = [t.name for t in py.toolchains],
305367
default_python_version = py.default_python_version,
306368
minor_mapping = py.config.minor_mapping,
307369
python_versions = list(py.config.default["tool_versions"].keys()),
308-
toolchain_prefixes = [
309-
render.toolchain_prefix(index, toolchain.name, _TOOLCHAIN_INDEX_PAD_LENGTH)
310-
for index, toolchain in enumerate(py.toolchains)
311-
],
312-
toolchain_python_versions = [
313-
full_version(version = t.python_version, minor_mapping = py.config.minor_mapping)
314-
for t in py.toolchains
315-
],
316-
# The last toolchain is the default; it can't have version constraints
317-
# Despite the implication of the arg name, the values are strs, not bools
318-
toolchain_set_python_version_constraints = [
319-
"True" if i != len(py.toolchains) - 1 else "False"
320-
for i in range(len(py.toolchains))
321-
],
322-
toolchain_user_repository_names = [t.name for t in py.toolchains],
323-
loaded_platforms = loaded_platforms,
324370
)
325371

326372
# This is require in order to support multiple version py_test

0 commit comments

Comments
 (0)