@@ -30,6 +30,7 @@ load(":hub_repository.bzl", "hub_repository", "whl_config_settings_to_json")
3030load (":parse_requirements.bzl" , "parse_requirements" )
3131load (":parse_whl_name.bzl" , "parse_whl_name" )
3232load (":pep508_env.bzl" , "env" )
33+ load (":pep508_evaluate.bzl" , "evaluate" )
3334load (":pip_repository_attrs.bzl" , "ATTRS" )
3435load (":requirements_files_by_platform.bzl" , "requirements_files_by_platform" )
3536load (":simpleapi_download.bzl" , "simpleapi_download" )
@@ -83,6 +84,10 @@ def _platforms(*, python_version, minor_mapping, config):
8384 os = values .os_name ,
8485 arch = values .arch_name ,
8586 )) | values .env
87+
88+ if values .marker and not evaluate (values .marker , env = env_ ):
89+ continue
90+
8691 platforms [key ] = struct (
8792 env = env_ ,
8893 want_abis = [
@@ -190,17 +195,19 @@ def _create_whl_repos(
190195 whl_group_mapping = {}
191196 requirement_cycles = {}
192197
198+ platforms = _platforms (
199+ python_version = pip_attr .python_version ,
200+ minor_mapping = minor_mapping ,
201+ config = config ,
202+ )
203+
193204 if evaluate_markers :
194205 # This is most likely unit tests
195206 pass
196207 elif config .enable_pipstar :
197208 evaluate_markers = lambda _ , requirements : evaluate_markers_star (
198209 requirements = requirements ,
199- platforms = _platforms (
200- python_version = pip_attr .python_version ,
201- minor_mapping = minor_mapping ,
202- config = config ,
203- ),
210+ platforms = platforms ,
204211 )
205212 else :
206213 # NOTE @aignas 2024-08-02: , we will execute any interpreter that we find either
@@ -235,18 +242,14 @@ def _create_whl_repos(
235242 requirements_osx = pip_attr .requirements_darwin ,
236243 requirements_windows = pip_attr .requirements_windows ,
237244 extra_pip_args = pip_attr .extra_pip_args ,
238- platforms = sorted (config . platforms ), # here we only need keys
245+ platforms = sorted (platforms ), # here we only need keys
239246 python_version = full_version (
240247 version = pip_attr .python_version ,
241248 minor_mapping = minor_mapping ,
242249 ),
243250 logger = logger ,
244251 ),
245- platforms = _platforms (
246- python_version = pip_attr .python_version ,
247- minor_mapping = minor_mapping ,
248- config = config ,
249- ),
252+ platforms = platforms ,
250253 extra_pip_args = pip_attr .extra_pip_args ,
251254 get_index_urls = get_index_urls ,
252255 evaluate_markers = evaluate_markers ,
@@ -385,7 +388,7 @@ def _whl_repo(*, src, whl_library_args, is_multiple_versions, download_only, net
385388 ),
386389 )
387390
388- def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, want_abis , platform_tags , override = False ):
391+ def _configure (config , * , platform , os_name , arch_name , config_settings , env = {}, want_abis , platform_tags , marker , override = False ):
389392 """Set the value in the config if the value is provided"""
390393 config .setdefault ("platforms" , {})
391394 if platform and (os_name or arch_name or config_settings or platform_tags or env ):
@@ -406,21 +409,25 @@ def _configure(config, *, platform, os_name, arch_name, config_settings, env = {
406409 # the lowest priority one needs to be the first one
407410 platform_tags = ["any" ] + platform_tags
408411
412+ want_abis = want_abis or [
413+ "cp{0}{1}" ,
414+ "abi3" ,
415+ "none" ,
416+ ]
417+ env = {
418+ # default to this
419+ "implementation_name" : "cpython" ,
420+ } | env
421+
409422 config ["platforms" ][platform ] = struct (
410423 name = platform .replace ("-" , "_" ).lower (),
411- os_name = os_name ,
412424 arch_name = arch_name ,
413425 config_settings = config_settings ,
414- want_abis = want_abis or [
415- "cp{0}{1}" ,
416- "abi3" ,
417- "none" ,
418- ],
426+ env = env ,
427+ marker = marker ,
428+ os_name = os_name ,
419429 platform_tags = platform_tags ,
420- env = {
421- # default to this
422- "implementation_name" : "cpython" ,
423- } | env ,
430+ want_abis = want_abis ,
424431 )
425432 else :
426433 config ["platforms" ].pop (platform )
@@ -432,79 +439,106 @@ def _set_defaults(defaults):
432439 a little problematic.
433440 """
434441
435- # NOTE: We have this so that it is easier to maintain unit tests assuming certain
436- # defaults
437- for cpu in [
438- "x86_64" ,
439- "aarch64" ,
440- # TODO @aignas 2025-05-19: only leave tier 0-1 cpus when stabilizing the
441- # `pip.default` extension. i.e. drop the below values - users will have to
442- # define themselves if they need them.
443- "arm" ,
444- "ppc" ,
445- "s390x" ,
446- ]:
447- _configure (
448- defaults ,
449- arch_name = cpu ,
450- os_name = "linux" ,
451- platform = "linux_{}" .format (cpu ),
452- want_abis = [],
453- config_settings = [
454- "@platforms//os:linux" ,
455- "@platforms//cpu:{}" .format (cpu ),
442+ for suffix , config in {
443+ "" : struct (
444+ want_abis = [
445+ "cp{0}{1}" ,
446+ "abi3" ,
447+ "none" ,
456448 ],
457- platform_tags = [
458- "linux_*_{}" .format (cpu ),
459- "manylinux_*_{}" .format (cpu ),
449+ freethreaded = "no" ,
450+ marker = "" ,
451+ ),
452+ "_freethreaded" : struct (
453+ want_abis = [
454+ "cp{0}{1}t" ,
455+ "none" ,
460456 ],
461- env = {
462- "platform_version" : "0" ,
463- },
464- )
465- for cpu , platform_tag_cpus in {
466- "aarch64" : ["universal2" , "arm64" ],
467- "x86_64" : ["universal2" , "x86_64" ],
457+ freethreaded = "yes" ,
458+ marker = "python_version ~= \" 3.13\" " ,
459+ ),
468460 }.items ():
469- _configure (
470- defaults ,
471- arch_name = cpu ,
472- os_name = "osx" ,
473- platform = "osx_{}" .format (cpu ),
474- config_settings = [
475- "@platforms//os:osx" ,
476- "@platforms//cpu:{}" .format (cpu ),
477- ],
478- want_abis = [],
479- platform_tags = [
480- "macosx_*_{}" .format (suffix )
481- for suffix in platform_tag_cpus
482- ],
483- # We choose the oldest non-EOL version at the time when we release `rules_python`.
484- # See https://endoflife.date/macos
485- env = {
486- "platform_version" : "14.0" ,
487- },
488- )
461+ freethreaded_flag = Label ("//python/config_settings:_is_py_freethreaded_{}" .format (config .freethreaded ))
462+
463+ # NOTE: We have this so that it is easier to maintain unit tests assuming certain
464+ # defaults
465+ for cpu in [
466+ "x86_64" ,
467+ "aarch64" ,
468+ # TODO @aignas 2025-05-19: only leave tier 0-1 cpus when stabilizing the
469+ # `pip.default` extension. i.e. drop the below values - users will have to
470+ # define themselves if they need them.
471+ "arm" ,
472+ "ppc" ,
473+ "s390x" ,
474+ ]:
475+ _configure (
476+ defaults ,
477+ arch_name = cpu ,
478+ os_name = "linux" ,
479+ platform = "linux_{}{}" .format (cpu , suffix ),
480+ want_abis = config .want_abis ,
481+ marker = config .marker ,
482+ config_settings = [
483+ "@platforms//os:linux" ,
484+ "@platforms//cpu:{}" .format (cpu ),
485+ freethreaded_flag ,
486+ ],
487+ platform_tags = [
488+ "linux_*_{}" .format (cpu ),
489+ "manylinux_*_{}" .format (cpu ),
490+ ],
491+ env = {
492+ "platform_version" : "0" ,
493+ },
494+ )
495+ for cpu , platform_tag_cpus in {
496+ "aarch64" : ["universal2" , "arm64" ],
497+ "x86_64" : ["universal2" , "x86_64" ],
498+ }.items ():
499+ _configure (
500+ defaults ,
501+ arch_name = cpu ,
502+ os_name = "osx" ,
503+ platform = "osx_{}{}" .format (cpu , suffix ),
504+ config_settings = [
505+ "@platforms//os:osx" ,
506+ "@platforms//cpu:{}" .format (cpu ),
507+ freethreaded_flag ,
508+ ],
509+ want_abis = config .want_abis ,
510+ marker = config .marker ,
511+ platform_tags = [
512+ "macosx_*_{}" .format (suffix )
513+ for suffix in platform_tag_cpus
514+ ],
515+ # We choose the oldest non-EOL version at the time when we release `rules_python`.
516+ # See https://endoflife.date/macos
517+ env = {
518+ "platform_version" : "14.0" ,
519+ },
520+ )
489521
490- for cpu , platform_tags in {
491- "x86_64" : ["win_amd64" ],
492- }.items ():
493- _configure (
494- defaults ,
495- arch_name = cpu ,
496- os_name = "windows" ,
497- platform = "windows_{}" .format (cpu ),
498- config_settings = [
499- "@platforms//os:windows" ,
500- "@platforms//cpu:{}" .format (cpu ),
501- ],
502- want_abis = [],
503- platform_tags = platform_tags ,
504- env = {
505- "platform_version" : "0" ,
506- },
507- )
522+ for cpu , platform_tags in {
523+ "x86_64" : ["win_amd64" ],
524+ }.items ():
525+ _configure (
526+ defaults ,
527+ arch_name = cpu ,
528+ os_name = "windows" ,
529+ platform = "windows_{}{}" .format (cpu , suffix ),
530+ config_settings = [
531+ "@platforms//os:windows" ,
532+ "@platforms//cpu:{}" .format (cpu ),
533+ freethreaded_flag ,
534+ ],
535+ want_abis = config .want_abis ,
536+ marker = config .marker ,
537+ platform_tags = platform_tags ,
538+ env = {
539+ "platform_version" : "0" ,
540+ },
541+ )
508542
509543def parse_modules (
510544 module_ctx ,
@@ -573,6 +607,7 @@ You cannot use both the additive_build_content and additive_build_content_file a
573607 env = tag .env ,
574608 os_name = tag .os_name ,
575609 platform = tag .platform ,
610+ marker = tag .marker ,
576611 platform_tags = tag .platform_tags ,
577612 want_abis = tag .want_abis ,
578613 override = mod .is_root ,
@@ -905,6 +940,12 @@ Supported keys:
905940::::{note}
906941This is only used if the {envvar}`RULES_PYTHON_ENABLE_PIPSTAR` is enabled.
907942::::
943+ """ ,
944+ ),
945+ "marker" : attr .string (
946+ doc = """\
947+ A marker which will be evaluated to disable the target platform for certain python versions. This
948+ is especially useful when defining freethreaded platform variants.
908949""" ,
909950 ),
910951 # The values for PEP508 env marker evaluation during the lock file parsing
0 commit comments