Skip to content

Commit ad72cb5

Browse files
committed
feat: support arbitrary target_settings in our platforms 3/n
Stacked on #2988 With this PR we can support arbitrary target settings instead of just plain `constraint_values`. We still have custom logic to ensure that all of the tests pass. However, the plan is to remove those tests once we have simplified the wheel selection mechanisms and the `pkg_aliases` macro. I.e. if we have at most 1 wheel per platform that the `pypi` bzlmod extension passes to the `pkg_aliases` macro, then we can just have a simple `selects.with_or` where we list out all of the target platform values. This PR may result in us creating more targets but that is the price that we have to pay if we want to do this incrementally. Work towards #2747 Work towards #2548 Work towards #260
1 parent 4c52622 commit ad72cb5

File tree

9 files changed

+81
-45
lines changed

9 files changed

+81
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ END_UNRELEASED_TEMPLATE
6464
### Added
6565
* (pypi) To configure the environment for `requirements.txt` evaluation, use the newly added
6666
developer preview of the `pip.default` tag class. Only `rules_python` and root modules can use
67-
this feature. You can also configure `constraint_values` using `pip.default`.
67+
this feature. You can also configure custom `target_settings` using `pip.default`.
6868

6969
{#v0-0-0-removed}
7070
### Removed

python/private/pypi/config_settings.bzl

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ suffix.
7070
:::
7171
"""
7272

73+
load("@bazel_skylib//lib:selects.bzl", "selects")
7374
load("//python/private:flags.bzl", "LibcFlag")
7475
load(":flags.bzl", "INTERNAL_FLAGS", "UniversalWhlFlag")
7576

@@ -112,7 +113,7 @@ def config_settings(
112113
muslc_versions = [],
113114
osx_versions = [],
114115
name = None,
115-
platform_constraint_values = {},
116+
platform_target_settings = {},
116117
**kwargs):
117118
"""Generate all of the pip config settings.
118119
@@ -126,7 +127,7 @@ def config_settings(
126127
configure config settings for.
127128
osx_versions (list[str]): The list of OSX OS versions to configure
128129
config settings for.
129-
platform_constraint_values: {type}`dict[str, list[str]]` the constraint
130+
platform_target_settings: {type}`dict[str, list[str]]` the constraint
130131
values to use instead of the default ones.
131132
**kwargs: Other args passed to the underlying implementations, such as
132133
{obj}`native`.
@@ -140,13 +141,24 @@ def config_settings(
140141
# TODO @aignas 2025-06-15: allowing universal2 and platform specific wheels in one
141142
# closure is making things maybe a little bit too complicated.
142143
"osx_universal2": ["@platforms//os:osx"],
143-
} | platform_constraint_values
144+
} | platform_target_settings
144145

145146
for python_version in python_versions:
146-
for platform_name, constraint_values in target_platforms.items():
147+
for platform_name, target_settings in target_platforms.items():
147148
suffix = "_{}".format(platform_name) if platform_name else ""
148149
os, _, cpu = platform_name.partition("_")
149150

151+
# We parse the target settings and if there is a "platforms//os" or
152+
# "platforms//cpu" value in here, we also add it into the constraint_values
153+
#
154+
# this is to ensure that we can still pass all of the unit tests for config
155+
# setting specialization.
156+
constraint_values = []
157+
for setting in target_settings:
158+
setting_label = Label(setting)
159+
if setting_label.repo_name == "platforms" and setting_label.package in ["os", "cpu"]:
160+
constraint_values.append(setting)
161+
150162
_dist_config_settings(
151163
suffix = suffix,
152164
plat_flag_values = _plat_flag_values(
@@ -156,6 +168,7 @@ def config_settings(
156168
glibc_versions = glibc_versions,
157169
muslc_versions = muslc_versions,
158170
),
171+
target_settings = target_settings,
159172
constraint_values = constraint_values,
160173
python_version = python_version,
161174
**kwargs
@@ -316,7 +329,7 @@ def _plat_flag_values(os, cpu, osx_versions, glibc_versions, muslc_versions):
316329

317330
return ret
318331

319-
def _dist_config_setting(*, name, compatible_with = None, native = native, **kwargs):
332+
def _dist_config_setting(*, name, compatible_with = None, selects = selects, native = native, target_settings = None, **kwargs):
320333
"""A macro to create a target for matching Python binary and source distributions.
321334
322335
Args:
@@ -325,6 +338,12 @@ def _dist_config_setting(*, name, compatible_with = None, native = native, **kwa
325338
compatible with the given dist config setting. For example, if only
326339
non-freethreaded python builds are allowed, add
327340
FLAGS.is_py_non_freethreaded here.
341+
target_settings: {type}`list[str | Label]` the list of target settings that must
342+
be matched before we try to evaluate the config_setting that we may create in
343+
this function.
344+
selects (struct): The struct containing config_setting_group function
345+
to use for creating config setting groups. Can be overridden for unit tests
346+
reasons.
328347
native (struct): The struct containing alias and config_setting rules
329348
to use for creating the objects. Can be overridden for unit tests
330349
reasons.
@@ -344,4 +363,14 @@ def _dist_config_setting(*, name, compatible_with = None, native = native, **kwa
344363
)
345364
name = dist_config_setting_name
346365

347-
native.config_setting(name = name, **kwargs)
366+
# first define the config setting that has all of the constraint values
367+
_name = "_" + name
368+
native.config_setting(
369+
name = _name,
370+
**kwargs
371+
)
372+
selects.config_setting_group(
373+
name = name,
374+
match_all = target_settings + [_name],
375+
visibility = kwargs.get("visibility"),
376+
)

python/private/pypi/extension.bzl

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
372372
),
373373
)
374374

375-
def _configure(config, *, platform, os_name, arch_name, constraint_values, override = False, **values):
375+
def _configure(config, *, platform, os_name, arch_name, target_settings, override = False, **values):
376376
"""Set the value in the config if the value is provided"""
377377
config.setdefault("platforms", {})
378378
if platform:
@@ -383,7 +383,7 @@ def _configure(config, *, platform, os_name, arch_name, constraint_values, overr
383383
name = platform.replace("-", "_").lower(),
384384
os_name = os_name,
385385
arch_name = arch_name,
386-
constraint_values = constraint_values,
386+
target_settings = target_settings,
387387
env = {
388388
k[4:]: v
389389
for k, v in values.items()
@@ -415,7 +415,7 @@ def _create_config(defaults):
415415
env_platform_version = "0",
416416
os_name = "linux",
417417
platform = "linux_{}".format(cpu),
418-
constraint_values = [
418+
target_settings = [
419419
"@platforms//os:linux",
420420
"@platforms//cpu:{}".format(cpu),
421421
],
@@ -432,7 +432,7 @@ def _create_config(defaults):
432432
env_platform_version = "14.0",
433433
os_name = "osx",
434434
platform = "osx_{}".format(cpu),
435-
constraint_values = [
435+
target_settings = [
436436
"@platforms//os:osx",
437437
"@platforms//cpu:{}".format(cpu),
438438
],
@@ -444,7 +444,7 @@ def _create_config(defaults):
444444
env_platform_version = "0",
445445
os_name = "windows",
446446
platform = "windows_x86_64",
447-
constraint_values = [
447+
target_settings = [
448448
"@platforms//os:windows",
449449
"@platforms//cpu:x86_64",
450450
],
@@ -513,7 +513,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
513513
_configure(
514514
defaults,
515515
arch_name = tag.arch_name,
516-
constraint_values = tag.constraint_values,
516+
target_settings = tag.target_settings,
517517
# The env_ values is only used if the `PIPSTAR` is enabled
518518
env_implementation_name = tag.env_implementation_name,
519519
env_os_name = tag.env_os_name,
@@ -698,9 +698,9 @@ You cannot use both the additive_build_content and additive_build_content_file a
698698
}
699699
for hub_name, extra_whl_aliases in extra_aliases.items()
700700
},
701-
platform_constraint_values = {
701+
platform_target_settings = {
702702
hub_name: {
703-
platform_name: sorted([str(Label(cv)) for cv in p.constraint_values])
703+
platform_name: sorted([str(Label(cv)) for cv in p.target_settings])
704704
for platform_name, p in config.platforms.items()
705705
}
706706
for hub_name in hub_whl_map
@@ -795,7 +795,7 @@ def _pip_impl(module_ctx):
795795
for key, values in whl_map.items()
796796
},
797797
packages = mods.exposed_packages.get(hub_name, []),
798-
platform_constraint_values = mods.platform_constraint_values.get(hub_name, {}),
798+
platform_target_settings = mods.platform_target_settings.get(hub_name, {}),
799799
groups = mods.hub_group_map.get(hub_name),
800800
)
801801

@@ -815,12 +815,6 @@ The CPU architecture name to be used.
815815
:::{note}
816816
Either this or {attr}`env_platform_machine` should be specified.
817817
:::
818-
""",
819-
),
820-
"constraint_values": attr.label_list(
821-
mandatory = True,
822-
doc = """\
823-
The constraint_values to use in select statements.
824818
""",
825819
),
826820
"os_name": attr.string(
@@ -839,6 +833,12 @@ If you are defining custom platforms in your project and don't want things to cl
839833
[isolation] feature.
840834
841835
[isolation]: https://bazel.build/rules/lib/globals/module#use_extension.isolate
836+
""",
837+
),
838+
"target_settings": attr.label_list(
839+
mandatory = True,
840+
doc = """\
841+
The target_settings that need to be matched for the platform to be selected.
842842
""",
843843
),
844844
} | {

python/private/pypi/hub_repository.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _impl(rctx):
3434
},
3535
extra_hub_aliases = rctx.attr.extra_hub_aliases,
3636
requirement_cycles = rctx.attr.groups,
37-
platform_constraint_values = rctx.attr.platform_constraint_values,
37+
platform_target_settings = rctx.attr.platform_target_settings,
3838
)
3939
for path, contents in aliases.items():
4040
rctx.file(path, contents)
@@ -84,7 +84,7 @@ hub_repository = repository_rule(
8484
The list of packages that will be exposed via all_*requirements macros. Defaults to whl_map keys.
8585
""",
8686
),
87-
"platform_constraint_values": attr.string_list_dict(
87+
"platform_target_settings": attr.string_list_dict(
8888
doc = "The constraint values for each platform name. The values are string canonical string Label representations",
8989
mandatory = False,
9090
),

python/private/pypi/render_pkg_aliases.bzl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,14 @@ def _major_minor_versions(python_versions):
155155
# Use a dict as a simple set
156156
return sorted({_major_minor(v): None for v in python_versions})
157157

158-
def render_multiplatform_pkg_aliases(*, aliases, platform_constraint_values = {}, **kwargs):
158+
def render_multiplatform_pkg_aliases(*, aliases, platform_target_settings = {}, **kwargs):
159159
"""Render the multi-platform pkg aliases.
160160
161161
Args:
162162
aliases: dict[str, list(whl_config_setting)] A list of aliases that will be
163163
transformed from ones having `filename` to ones having `config_setting`.
164-
platform_constraint_values: {type}`dict[str, list[str]]` contains all of the
165-
target platforms and their appropriate `constraint_values`.
164+
platform_target_settings: {type}`dict[str, list[str]]` contains all of the
165+
target platforms and their appropriate `target_settings`.
166166
**kwargs: extra arguments passed to render_pkg_aliases.
167167
168168
Returns:
@@ -189,20 +189,20 @@ def render_multiplatform_pkg_aliases(*, aliases, platform_constraint_values = {}
189189
muslc_versions = flag_versions.get("muslc_versions", []),
190190
osx_versions = flag_versions.get("osx_versions", []),
191191
python_versions = _major_minor_versions(flag_versions.get("python_versions", [])),
192-
platform_constraint_values = platform_constraint_values,
192+
platform_target_settings = platform_target_settings,
193193
visibility = ["//:__subpackages__"],
194194
)
195195
return contents
196196

197-
def _render_config_settings(platform_constraint_values, **kwargs):
197+
def _render_config_settings(platform_target_settings, **kwargs):
198198
return """\
199199
load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings")
200200
201201
{}""".format(render.call(
202202
"config_settings",
203203
name = repr("config_settings"),
204-
platform_constraint_values = render.dict(
205-
platform_constraint_values,
204+
platform_target_settings = render.dict(
205+
platform_target_settings,
206206
value_repr = render.list,
207207
),
208208
**_repr_dict(value_repr = render.list, **kwargs)

tests/pypi/config_settings/config_settings_tests.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ def config_settings_test_suite(name): # buildifier: disable=function-docstring
657657
glibc_versions = [(2, 14), (2, 17)],
658658
muslc_versions = [(1, 1)],
659659
osx_versions = [(10, 9), (11, 0)],
660-
platform_constraint_values = {
660+
platform_target_settings = {
661661
"linux_aarch64": [
662662
"@platforms//cpu:aarch64",
663663
"@platforms//os:linux",

tests/pypi/extension/extension_tests.bzl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,9 @@ def _parse_modules(env, enable_pipstar = 0, **kwargs):
7878

7979
def _default(
8080
arch_name = None,
81-
constraint_values = None,
81+
target_settings = None,
8282
os_name = None,
8383
platform = None,
84-
target_settings = None,
8584
env_implementation_name = None,
8685
env_os_name = None,
8786
env_platform_machine = None,
@@ -93,7 +92,6 @@ def _default(
9392
whl_platforms = None):
9493
return struct(
9594
arch_name = arch_name,
96-
constraint_values = constraint_values,
9795
os_name = os_name,
9896
platform = platform,
9997
target_settings = target_settings,
@@ -1063,7 +1061,7 @@ def _test_pipstar_platforms(env):
10631061
default = [
10641062
_default(
10651063
platform = "{}_{}".format(os, cpu),
1066-
constraint_values = [
1064+
target_settings = [
10671065
"@platforms//os:{}".format(os),
10681066
"@platforms//cpu:{}".format(cpu),
10691067
],

tests/pypi/pkg_aliases/pkg_aliases_test.bzl

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,9 @@ _tests.append(_test_multiplatform_whl_aliases_filename_versioned)
392392
def _mock_alias(container):
393393
return lambda name, **kwargs: container.append(name)
394394

395+
def _mock_config_setting_group(container):
396+
return lambda name, **kwargs: container.append(name)
397+
395398
def _mock_config_setting(container):
396399
def _inner(name, flag_values = None, constraint_values = None, **_):
397400
if flag_values or constraint_values:
@@ -417,9 +420,12 @@ def _test_config_settings_exist_legacy(env):
417420
python_versions = ["3.11"],
418421
native = struct(
419422
alias = _mock_alias(available_config_settings),
420-
config_setting = _mock_config_setting(available_config_settings),
423+
config_setting = _mock_config_setting([]),
421424
),
422-
platform_constraint_values = {
425+
selects = struct(
426+
config_setting_group = _mock_config_setting_group(available_config_settings),
427+
),
428+
platform_target_settings = {
423429
"linux_aarch64": [
424430
"@platforms//cpu:aarch64",
425431
"@platforms//os:linux",
@@ -454,7 +460,7 @@ def _test_config_settings_exist(env):
454460
"any": {},
455461
"macosx_11_0_arm64": {
456462
"osx_versions": [(11, 0)],
457-
"platform_constraint_values": {
463+
"platform_target_settings": {
458464
"osx_aarch64": [
459465
"@platforms//cpu:aarch64",
460466
"@platforms//os:osx",
@@ -463,7 +469,7 @@ def _test_config_settings_exist(env):
463469
},
464470
"manylinux_2_17_x86_64": {
465471
"glibc_versions": [(2, 17), (2, 18)],
466-
"platform_constraint_values": {
472+
"platform_target_settings": {
467473
"linux_x86_64": [
468474
"@platforms//cpu:x86_64",
469475
"@platforms//os:linux",
@@ -472,7 +478,7 @@ def _test_config_settings_exist(env):
472478
},
473479
"manylinux_2_18_x86_64": {
474480
"glibc_versions": [(2, 17), (2, 18)],
475-
"platform_constraint_values": {
481+
"platform_target_settings": {
476482
"linux_x86_64": [
477483
"@platforms//cpu:x86_64",
478484
"@platforms//os:linux",
@@ -481,7 +487,7 @@ def _test_config_settings_exist(env):
481487
},
482488
"musllinux_1_1_aarch64": {
483489
"muslc_versions": [(1, 2), (1, 1), (1, 0)],
484-
"platform_constraint_values": {
490+
"platform_target_settings": {
485491
"linux_aarch64": [
486492
"@platforms//cpu:aarch64",
487493
"@platforms//os:linux",
@@ -500,7 +506,10 @@ def _test_config_settings_exist(env):
500506
python_versions = ["3.11"],
501507
native = struct(
502508
alias = _mock_alias(available_config_settings),
503-
config_setting = _mock_config_setting(available_config_settings),
509+
config_setting = _mock_config_setting([]),
510+
),
511+
selects = struct(
512+
config_setting_group = _mock_config_setting_group(available_config_settings),
504513
),
505514
**kwargs
506515
)

tests/pypi/render_pkg_aliases/render_pkg_aliases_test.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def _test_bzlmod_aliases(env):
9393
},
9494
},
9595
extra_hub_aliases = {"bar_baz": ["foo"]},
96-
platform_constraint_values = {
96+
platform_target_settings = {
9797
"linux_x86_64": [
9898
"@platforms//os:linux",
9999
"@platforms//cpu:x86_64",
@@ -136,7 +136,7 @@ load("@rules_python//python/private/pypi:config_settings.bzl", "config_settings"
136136
137137
config_settings(
138138
name = "config_settings",
139-
platform_constraint_values = {
139+
platform_target_settings = {
140140
"linux_x86_64": [
141141
"@platforms//os:linux",
142142
"@platforms//cpu:x86_64",

0 commit comments

Comments
 (0)