@@ -20,20 +20,21 @@ that matches the target platform. We can leverage this fact to ensure that the
2020most specialized wheels are used by default with the users being able to
2121configure string_flag values to select the less specialized ones.
2222
23- The list of specialization of the dists goes like follows:
23+ The list of specialization of the dists goes like follows (cpxyt stands for freethreaded
24+ environments):
2425* sdist
2526* py*-none-any.whl
2627* py*-abi3-any.whl
27- * py*-cpxy-any.whl
28+ * py*-cpxy-any.whl or py*-cpxyt-any.whl
2829* cp*-none-any.whl
2930* cp*-abi3-any.whl
30- * cp*-cpxy-plat .whl
31+ * cp*-cpxy-any.whl or cp*-cpxyt-any .whl
3132* py*-none-plat.whl
3233* py*-abi3-plat.whl
33- * py*-cpxy-plat.whl
34+ * py*-cpxy-plat.whl or py*-cpxyt-plat.whl
3435* cp*-none-plat.whl
3536* cp*-abi3-plat.whl
36- * cp*-cpxy-plat.whl
37+ * cp*-cpxy-plat.whl or cp*-cpxyt-plat.whl
3738
3839Note, that here the specialization of musl vs manylinux wheels is the same in
3940order to ensure that the matching fails if the user requests for `musl` and we don't have it or vice versa.
@@ -46,19 +47,24 @@ FLAGS = struct(
4647 ** {
4748 f : str (Label ("//python/config_settings:" + f ))
4849 for f in [
49- "python_version" ,
50+ "is_pip_whl_auto" ,
51+ "is_pip_whl_no" ,
52+ "is_pip_whl_only" ,
53+ "is_py_freethreaded" ,
54+ "is_py_non_freethreaded" ,
5055 "pip_whl_glibc_version" ,
5156 "pip_whl_muslc_version" ,
5257 "pip_whl_osx_arch" ,
5358 "pip_whl_osx_version" ,
5459 "py_linux_libc" ,
55- "is_pip_whl_no" ,
56- "is_pip_whl_only" ,
57- "is_pip_whl_auto" ,
60+ "python_version" ,
5861 ]
5962 }
6063)
6164
65+ _DEFAULT = "//conditions:default"
66+ _INCOMPATIBLE = "@platforms//:incompatible"
67+
6268# Here we create extra string flags that are just to work with the select
6369# selecting the most specialized match. We don't allow the user to change
6470# them.
@@ -170,52 +176,70 @@ def _dist_config_settings(*, suffix, plat_flag_values, **kwargs):
170176 ** kwargs
171177 )
172178
173- for name , f in [
174- ("py_none" , _flags .whl_py2_py3 ),
175- ("py3_none" , _flags .whl_py3 ),
176- ("py3_abi3" , _flags .whl_py3_abi3 ),
177- ("cp3x_none" , _flags .whl_pycp3x ),
178- ("cp3x_abi3" , _flags .whl_pycp3x_abi3 ),
179- ("cp3x_cp" , _flags .whl_pycp3x_abicp ),
179+ used_flags = {}
180+
181+ # NOTE @aignas 2024-12-01: the abi3 is not compatible with freethreaded
182+ # builds as per PEP703 (https://peps.python.org/pep-0703/#backwards-compatibility)
183+ #
184+ # The discussion here also reinforces this notion:
185+ # https://discuss.python.org/t/pep-703-making-the-global-interpreter-lock-optional-3-12-updates/26503/99
186+
187+ for name , f , abi in [
188+ ("py_none" , _flags .whl_py2_py3 , None ),
189+ ("py3_none" , _flags .whl_py3 , None ),
190+ ("py3_abi3" , _flags .whl_py3_abi3 , (FLAGS .is_py_non_freethreaded ,)),
191+ ("cp3x_none" , _flags .whl_pycp3x , None ),
192+ ("cp3x_abi3" , _flags .whl_pycp3x_abi3 , (FLAGS .is_py_non_freethreaded ,)),
193+ # The below are not specializations of one another, they are variants
194+ ("cp3x_cp" , _flags .whl_pycp3x_abicp , (FLAGS .is_py_non_freethreaded ,)),
195+ ("cp3x_cpt" , _flags .whl_pycp3x_abicp , (FLAGS .is_py_freethreaded ,)),
180196 ]:
181- if f in flag_values :
197+ if ( f , abi ) in used_flags :
182198 # This should never happen as all of the different whls should have
183- # unique flag values.
199+ # unique flag values
184200 fail ("BUG: the flag {} is attempted to be added twice to the list" .format (f ))
185201 else :
186202 flag_values [f ] = ""
203+ used_flags [(f , abi )] = True
187204
188205 _dist_config_setting (
189206 name = "{}_any{}" .format (name , suffix ),
190207 flag_values = flag_values ,
191208 is_pip_whl = FLAGS .is_pip_whl_only ,
209+ abi = abi ,
192210 ** kwargs
193211 )
194212
195213 generic_flag_values = flag_values
214+ generic_used_flags = used_flags
196215
197216 for (suffix , flag_values ) in plat_flag_values :
217+ used_flags = {(f , None ): True for f in flag_values } | generic_used_flags
198218 flag_values = flag_values | generic_flag_values
199219
200- for name , f in [
201- ("py_none" , _flags .whl_plat ),
202- ("py3_none" , _flags .whl_plat_py3 ),
203- ("py3_abi3" , _flags .whl_plat_py3_abi3 ),
204- ("cp3x_none" , _flags .whl_plat_pycp3x ),
205- ("cp3x_abi3" , _flags .whl_plat_pycp3x_abi3 ),
206- ("cp3x_cp" , _flags .whl_plat_pycp3x_abicp ),
220+ for name , f , abi in [
221+ ("py_none" , _flags .whl_plat , None ),
222+ ("py3_none" , _flags .whl_plat_py3 , None ),
223+ ("py3_abi3" , _flags .whl_plat_py3_abi3 , (FLAGS .is_py_non_freethreaded ,)),
224+ ("cp3x_none" , _flags .whl_plat_pycp3x , None ),
225+ ("cp3x_abi3" , _flags .whl_plat_pycp3x_abi3 , (FLAGS .is_py_non_freethreaded ,)),
226+ # The below are not specializations of one another, they are variants
227+ ("cp3x_cp" , _flags .whl_plat_pycp3x_abicp , (FLAGS .is_py_non_freethreaded ,)),
228+ ("cp3x_cpt" , _flags .whl_plat_pycp3x_abicp , (FLAGS .is_py_freethreaded ,)),
207229 ]:
208- if f in flag_values :
230+ if ( f , abi ) in used_flags :
209231 # This should never happen as all of the different whls should have
210232 # unique flag values.
211233 fail ("BUG: the flag {} is attempted to be added twice to the list" .format (f ))
212234 else :
213235 flag_values [f ] = ""
236+ used_flags [(f , abi )] = True
214237
215238 _dist_config_setting (
216239 name = "{}_{}" .format (name , suffix ),
217240 flag_values = flag_values ,
218241 is_pip_whl = FLAGS .is_pip_whl_only ,
242+ abi = abi ,
219243 ** kwargs
220244 )
221245
@@ -285,7 +309,7 @@ def _plat_flag_values(os, cpu, osx_versions, glibc_versions, muslc_versions):
285309
286310 return ret
287311
288- def _dist_config_setting (* , name , is_python , python_version , is_pip_whl = None , native = native , ** kwargs ):
312+ def _dist_config_setting (* , name , is_python , python_version , is_pip_whl = None , abi = None , native = native , ** kwargs ):
289313 """A macro to create a target that matches is_pip_whl_auto and one more value.
290314
291315 Args:
@@ -294,6 +318,10 @@ def _dist_config_setting(*, name, is_python, python_version, is_pip_whl = None,
294318 `is_pip_whl_auto` when evaluating the config setting.
295319 is_python: The python version config_setting to match.
296320 python_version: The python version name.
321+ abi: {type}`tuple[Label]` A collection of ABI config settings that are
322+ compatible with the given dist config setting. For example, if only
323+ non-freethreaded python builds are allowed, add
324+ FLAGS.is_py_non_freethreaded here.
297325 native (struct): The struct containing alias and config_setting rules
298326 to use for creating the objects. Can be overridden for unit tests
299327 reasons.
@@ -306,9 +334,9 @@ def _dist_config_setting(*, name, is_python, python_version, is_pip_whl = None,
306334 native .alias (
307335 name = "is_cp{}_{}" .format (python_version , name ) if python_version else "is_{}" .format (name ),
308336 actual = select ({
309- # First match by the python version
310- is_python : _name ,
311- "//conditions:default" : is_python ,
337+ # First match by the python version and then by ABI
338+ is_python : _name + ( "_abi" if abi else "" ) ,
339+ _DEFAULT : _INCOMPATIBLE ,
312340 }),
313341 visibility = visibility ,
314342 )
@@ -325,12 +353,23 @@ def _dist_config_setting(*, name, is_python, python_version, is_pip_whl = None,
325353 config_setting_name = _name + "_setting"
326354 native .config_setting (name = config_setting_name , ** kwargs )
327355
356+ if abi :
357+ native .alias (
358+ name = _name + "_abi" ,
359+ actual = select (
360+ {k : _name for k in abi } | {
361+ _DEFAULT : _INCOMPATIBLE ,
362+ },
363+ ),
364+ visibility = visibility ,
365+ )
366+
328367 # Next match by the `pip_whl` flag value and then match by the flags that
329368 # are intrinsic to the distribution.
330369 native .alias (
331370 name = _name ,
332371 actual = select ({
333- "//conditions:default" : FLAGS . is_pip_whl_auto ,
372+ _DEFAULT : _INCOMPATIBLE ,
334373 FLAGS .is_pip_whl_auto : config_setting_name ,
335374 is_pip_whl : config_setting_name ,
336375 }),
0 commit comments