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 depspec_flag (** kwargs ):
618 pypa_dependency_specification (
719 # todo: copied from pep508_env.bzl
@@ -16,30 +28,72 @@ def depspec_flag(**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 value = "yes"
92160 else :
@@ -98,32 +166,49 @@ pypa_dependency_specification = rule(
98166 attrs = {
99167 "expression" : attr .string (),
100168 "os_name" : attr .string (),
101- "sys_platform" : attr .string (),
102169 "platform_machine" : attr .string (),
103170 "platform_system" : attr .string (),
171+ "sys_platform" : attr .string (),
172+ # todo: what to do with this?
173+ # NOTE(aignas) - with the `evaluate` function we can evaluate a
174+ # particular value. For example we can have an expression and just
175+ # evaluate extras. I.e. if the extras don't match, then the whole thing
176+ # is false, if it matches, then it is a string with a remaining
177+ # expression. This means that the `pypa_dependency_specification`
178+ # should not receive any `extra_flags` because these are not properties
179+ # of the target configuration, but rather of a particular package,
180+ # hence we could drop it.
181+ "_extra_flag" : attr .label (),
104182 "_platform_release_config_flag" : attr .label (
105183 default = "//python/config_settings:pip_platform_release_config" ,
106184 ),
107185 "_platform_version_config_flag" : attr .label (
108186 default = "//python/config_settings:pip_platform_version_config" ,
109187 ),
110- "_python_version_flag" : attr .label (
111- default = "//python/config_settings:python_version_major_minor" ,
112- ),
113188 "_python_full_version_flag" : attr .label (
114189 default = "//python/config_settings:python_version" ,
115190 ),
116- # todo: what to do with this?
117- "_extra_flag" : attr .label (),
191+ "_python_version_flag" : attr .label (
192+ default = "//python/config_settings:python_version_major_minor" ,
193+ ),
118194 },
119195 toolchains = [
120196 TARGET_TOOLCHAIN_TYPE ,
121197 ],
122198)
123199
124- # Adapted from spec code at:
125- # https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
126200def format_full_version (info ):
201+ """Format the full python interpreter version.
202+
203+ Adapted from spec code at:
204+ https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
205+
206+ Args:
207+ info: The provider from the Python runtime.
208+
209+ Returns:
210+ a {type}`str` with the version
211+ """
127212 kind = info .releaselevel
128213 if kind == "final" :
129214 kind = ""
0 commit comments