Skip to content

Commit e8d4ad8

Browse files
committed
BUG: adapt to platform-specific abi3 and abi3t filename suffixes
Python 3.15.0rc1 introduced platform-specific filename suffixes for stable ABI extension modules alongside the generic ".abi3" and ".abi3t". Fixes #875.
1 parent f915043 commit e8d4ad8

2 files changed

Lines changed: 29 additions & 21 deletions

File tree

mesonpy/__init__.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class InvalidLicenseExpression(Exception): # type: ignore[no-redef]
9999
_MESON_ARGS_KEYS = ['dist', 'setup', 'compile', 'install']
100100

101101
_SUFFIXES = importlib.machinery.all_suffixes()
102-
_EXTENSION_SUFFIX_REGEX = re.compile(r'^[^.]+\.(?:(?P<abi>[^.]+)\.)?(?:so|pyd|dll)$')
102+
_EXTENSION_SUFFIX_REGEX = re.compile(r'^[^.]+(?P<suffix>\.(?:(?P<abi>[^.]+)\.)?(?:so|pyd|dll))$')
103103
assert all(re.match(_EXTENSION_SUFFIX_REGEX, f'foo{x}') for x in importlib.machinery.EXTENSION_SUFFIXES)
104104

105105
# Map Meson installation path placeholders to wheel installation paths.
@@ -332,6 +332,29 @@ def _is_native(file: Path) -> bool:
332332
return f.read(4) == b'\x7fELF' # ELF
333333

334334

335+
def _get_abi3_suffix() -> str | None:
336+
"""Get the filename suffix identifying stable ABI extension modules."""
337+
338+
# EXTENSION_SUFFIXES is ordered from the more to the less specific ABI.
339+
# On Python 3.15 or later, this resolves to ".abi3t-${platform}" for
340+
# free-threaded builds and to ".abi3-${platform}" on regular builds.
341+
# Python 3.15 and later also accepts the generic ".abi3t" or ".abi3"
342+
# suffixes, but we ignore this for the moment.
343+
#
344+
# Older Python versions do not support a stable ABI for free-threaded
345+
# build, and do not support a platform-specific filename suffix, and this
346+
# resolves to simply ".abi3".
347+
#
348+
# On Windows, Python does not use a dedicated filename suffix for stable
349+
# ABI extension modules.
350+
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
351+
if suffix.startswith('.abi3'):
352+
return suffix
353+
if suffix == '.pyd':
354+
return suffix
355+
return None
356+
357+
335358
@dataclasses.dataclass
336359
class _WheelBuilder():
337360
"""Helper class to build wheels from projects."""
@@ -429,12 +452,11 @@ def _stable_abi(self) -> Optional[str]:
429452
# not use the stable ABI filename suffix and wheels should not
430453
# be tagged with the abi3 tag.
431454
if self._limited_api and '__pypy__' not in sys.builtin_module_names:
432-
# On free-threaded Python 3.15.0b2+, we expect to be
455+
# On free-threaded Python 3.15 and later, we expect to be
433456
# building 'abi3t' wheels for the time being. In the future
434457
# we will want an option to target 'abi3t' from GIL-enabled
435458
# Python too.
436-
abi3t = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) and sys.version_info >= (3, 15)
437-
expected_abi = 'abi3t' if abi3t else 'abi3'
459+
abi3 = _get_abi3_suffix()
438460

439461
# Verify stable ABI compatibility: examine files installed
440462
# in {platlib} that look like extension modules, and raise
@@ -443,12 +465,11 @@ def _stable_abi(self) -> Optional[str]:
443465
for entry in self._manifest['platlib']:
444466
match = _EXTENSION_SUFFIX_REGEX.match(entry.dst.name)
445467
if match:
446-
abi = match.group('abi')
447-
if abi is not None and abi != expected_abi:
468+
if match.group('abi') is not None and match.group('suffix') != abi3:
448469
raise BuildError(
449470
f'The package declares compatibility with Python limited API but extension '
450471
f'module {os.fspath(entry.dst)!r} is tagged for a specific Python version.')
451-
return 'abi3.abi3t' if abi3t else 'abi3'
472+
return 'abi3.abi3t' if abi3.startswith('.abi3t') else 'abi3'
452473
return None
453474

454475
def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path) -> None:

tests/test_tags.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#
33
# SPDX-License-Identifier: MIT
44

5-
import importlib.machinery
65
import os
76
import pathlib
87
import platform
@@ -27,20 +26,8 @@
2726
INTERPRETER = tag.interpreter
2827
PLATFORM = adjust_packaging_platform_tag(tag.platform)
2928

30-
31-
def get_abi3_suffix():
32-
# EXTENSION_SUFFIXES are ordered in preference order, and more specific ABI is preferred.
33-
# On free-threaded 3.15+, this will match ".abi3t" as the only supported stable ABI.
34-
# On GIL-enabled 3.15+, it will match plain ".abi3" first, since that ABI is more specific.
35-
for suffix in importlib.machinery.EXTENSION_SUFFIXES:
36-
if '.abi3' in suffix: # Unix
37-
return suffix
38-
elif suffix == '.pyd': # Windows
39-
return suffix
40-
41-
4229
SUFFIX = sysconfig.get_config_var('EXT_SUFFIX')
43-
ABI3SUFFIX = get_abi3_suffix()
30+
ABI3SUFFIX = mesonpy._get_abi3_suffix()
4431

4532

4633
def test_wheel_tag():

0 commit comments

Comments
 (0)