1+ """Implement a flag for matching the dependency specifiers at analysis time."""
2+
13load ("@bazel_skylib//rules:common_settings.bzl" , "BuildSettingInfo" )
24load ("//python/private:toolchain_types.bzl" , "TARGET_TOOLCHAIN_TYPE" )
35load (":pep508_evaluate.bzl" , "evaluate" )
46
7+ # TODO @aignas 2025-04-29: this is copied from ./pep508_env.bzl
8+ _platform_machine_aliases = {
9+ # These pairs mean the same hardware, but different values may be used
10+ # on different host platforms.
11+ "amd64" : "x86_64" ,
12+ "arm64" : "aarch64" ,
13+ "i386" : "x86_32" ,
14+ "i686" : "x86_32" ,
15+ }
16+
517def env_marker_setting (** kwargs ):
618 _env_marker_setting (
719 # todo: copied from pep508_env.bzl
@@ -16,30 +28,72 @@ def env_marker_setting(**kwargs):
1628 }),
1729 # todo: copied from pep508_env.bzl
1830 sys_platform = select ({
19- "@platforms//os:windows" : "win32" ,
31+ # Taken from
32+ # https://docs.python.org/3/library/sys.html#sys.platform
33+ "@platforms//os:android" : "android" ,
34+ "@platforms//os:emscripten" : "emscripten" ,
35+ # NOTE, the below values here are from the time when the Python
36+ # interpreter is built and it is hard to know for sure, maybe this
37+ # should be something from the toolchain?
38+ "@platforms//os:freebsd" : "freebsd8" ,
39+ "@platforms//os:ios" : "ios" ,
2040 "@platforms//os:linux" : "linux" ,
41+ "@platforms//os:openbsd" : "openbsd6" ,
2142 "@platforms//os:osx" : "darwin" ,
22- # todo: what does spec say unknown value is?
43+ "@platforms//os:wasi" : "wasi" ,
44+ "@platforms//os:windows" : "win32" ,
2345 "//conditions:default" : "" ,
2446 }),
2547 # todo: copied from pep508_env.bzl
26- # todo: pep508_env and evaluate have an "aliases" thing that needs
27- # to be incorporated
28- # todo: there are many more cpus. Unfortunately, it doesn't look like
48+ # TODO: there are many cpus and unfortunately, it doesn't look like
2949 # the value is directly accessible to starlark. It might be possible to
3050 # get it via CcToolchain.cpu though.
3151 platform_machine = select ({
32- "@platforms//cpu:x86_64 " : "x86_64 " ,
52+ "@platforms//cpu:aarch32 " : "aarch32 " ,
3353 "@platforms//cpu:aarch64" : "aarch64" ,
34- # todo: what does spec say unknown value is?
54+ "@platforms//cpu:arm" : "arm" ,
55+ "@platforms//cpu:arm64" : "arm64" ,
56+ "@platforms//cpu:arm64_32" : "arm64_32" ,
57+ "@platforms//cpu:arm64e" : "arm64e" ,
58+ "@platforms//cpu:armv6-m" : "armv6-m" ,
59+ "@platforms//cpu:armv7" : "armv7" ,
60+ "@platforms//cpu:armv7-m" : "armv7-m" ,
61+ "@platforms//cpu:armv7e-m" : "armv7e-m" ,
62+ "@platforms//cpu:armv7e-mf" : "armv7e-mf" ,
63+ "@platforms//cpu:armv7k" : "armv7k" ,
64+ "@platforms//cpu:armv8-m" : "armv8-m" ,
65+ "@platforms//cpu:cortex-r52" : "cortex-r52" ,
66+ "@platforms//cpu:cortex-r82" : "cortex-r82" ,
67+ "@platforms//cpu:i386" : "i386" ,
68+ "@platforms//cpu:mips64" : "mips64" ,
69+ "@platforms//cpu:ppc" : "ppc" ,
70+ "@platforms//cpu:ppc32" : "ppc32" ,
71+ "@platforms//cpu:ppc64le" : "ppc64le" ,
72+ "@platforms//cpu:riscv32" : "riscv32" ,
73+ "@platforms//cpu:riscv64" : "riscv64" ,
74+ "@platforms//cpu:s390x" : "s390x" ,
75+ "@platforms//cpu:wasm32" : "wasm32" ,
76+ "@platforms//cpu:wasm64" : "wasm64" ,
77+ "@platforms//cpu:x86_32" : "x86_32" ,
78+ "@platforms//cpu:x86_64" : "x86_64" ,
79+ # The value is empty string if it cannot be determined:
80+ # https://docs.python.org/3/library/platform.html#platform.machine
3581 "//conditions:default" : "" ,
3682 }),
3783 # todo: copied from pep508_env.bzl
3884 platform_system = select ({
39- "@platforms//os:windows" : "Windows" ,
85+ # See https://peps.python.org/pep-0738/#platform
86+ "@platforms//os:android" : "Android" ,
87+ "@platforms//os:freebsd" : "FreeBSD" ,
88+ # See https://peps.python.org/pep-0730/#platform
89+ "@platforms//os:ios" : "iOS" , # can also be iPadOS?
4090 "@platforms//os:linux" : "Linux" ,
91+ "@platforms//os:netbsd" : "NetBSD" ,
92+ "@platforms//os:openbsd" : "OpenBSD" ,
4193 "@platforms//os:osx" : "Darwin" ,
42- # todo: what does spec say unknown value is?
94+ "@platforms//os:windows" : "Windows" ,
95+ # The value is empty string if it cannot be determined:
96+ # https://docs.python.org/3/library/platform.html#platform.machine
4397 "//conditions:default" : "" ,
4498 }),
4599 ** kwargs
@@ -83,10 +137,24 @@ def _impl(ctx):
83137 if platform_python_impl == "cpython" :
84138 platform_python_impl = "CPython"
85139 env ["platform_python_implementation" ] = platform_python_impl
140+
141+ # NOTE: Platform release for Android will be Android version:
142+ # https://peps.python.org/pep-0738/#platform
143+ # Similar for iOS:
144+ # https://peps.python.org/pep-0730/#platform
86145 env ["platform_release" ] = ctx .attr ._platform_release_config_flag [BuildSettingInfo ].value
87146 env ["platform_system" ] = ctx .attr .platform_system
88147 env ["platform_version" ] = ctx .attr ._platform_version_config_flag [BuildSettingInfo ].value
89148
149+ # TODO @aignas 2025-04-29: figure out how to correctly share the aliases
150+ # between the two. Maybe the select statements above should be part of the
151+ # `pep508_env.bzl` file?
152+ env = env | {
153+ "_aliases" : {
154+ "platform_machine" : _platform_machine_aliases ,
155+ },
156+ }
157+
90158 if evaluate (ctx .attr .expression , env = env ):
91159 # todo: better return value than "yes" and "no"
92160 # matched/unmatched, satisfied/unsatisfied ?
@@ -100,33 +168,50 @@ _env_marker_setting = rule(
100168 attrs = {
101169 "expression" : attr .string (),
102170 "os_name" : attr .string (),
103- "sys_platform" : attr .string (),
104171 "platform_machine" : attr .string (),
105172 "platform_system" : attr .string (),
173+ "sys_platform" : attr .string (),
174+ # todo: what to do with this?
175+ # NOTE(aignas) - with the `evaluate` function we can evaluate a
176+ # particular value. For example we can have an expression and just
177+ # evaluate extras. I.e. if the extras don't match, then the whole thing
178+ # is false, if it matches, then it is a string with a remaining
179+ # expression. This means that the `pypa_dependency_specification`
180+ # should not receive any `extra_flags` because these are not properties
181+ # of the target configuration, but rather of a particular package,
182+ # hence we could drop it.
183+ "_extra_flag" : attr .label (),
106184 "_platform_release_config_flag" : attr .label (
107185 default = "//python/config_settings:pip_platform_release_config" ,
108186 ),
109187 "_platform_version_config_flag" : attr .label (
110188 default = "//python/config_settings:pip_platform_version_config" ,
111189 ),
112- "_python_version_flag" : attr .label (
113- default = "//python/config_settings:python_version_major_minor" ,
114- ),
115190 "_python_full_version_flag" : attr .label (
116191 default = "//python/config_settings:python_version" ,
117192 ),
118- # todo: what to do with this?
119- "_extra_flag" : attr .label (),
193+ "_python_version_flag" : attr .label (
194+ default = "//python/config_settings:python_version_major_minor" ,
195+ ),
120196 },
121197 provides = [config_common .FeatureFlagInfo ],
122198 toolchains = [
123199 TARGET_TOOLCHAIN_TYPE ,
124200 ],
125201)
126202
127- # Adapted from spec code at:
128- # https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
129203def format_full_version (info ):
204+ """Format the full python interpreter version.
205+
206+ Adapted from spec code at:
207+ https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
208+
209+ Args:
210+ info: The provider from the Python runtime.
211+
212+ Returns:
213+ a {type}`str` with the version
214+ """
130215 kind = info .releaselevel
131216 if kind == "final" :
132217 kind = ""
0 commit comments