From 735f8af6a6a26ea3758e4a595908d8fd0d491ccc Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Sun, 11 Aug 2024 10:43:45 +0200 Subject: [PATCH 1/5] gh-122917 Allow stable API extensions to include a multiarch tuple in the filename This permits stable ABI extensions for multiple architectures to be co-installed into the same directory, without clashing with each other, the same way (non-stable ABI) regular extensions can. It is listed below the current .abi3 suffix because setuptools will select the first suffix containing .abi3, as the target filename. We do this to protect older Python versions predating this patch. --- Doc/whatsnew/3.16.rst | 8 ++++++++ .../C_API/2024-08-12-09-48-04.gh-issue-122931.QwHc2l.rst | 2 ++ Python/dynload_shlib.c | 6 ++++++ configure | 4 ++++ configure.ac | 2 ++ pyconfig.h.in | 3 +++ 6 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/C_API/2024-08-12-09-48-04.gh-issue-122931.QwHc2l.rst diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index cff0b8bbe32f0b..39c6db95bae135 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -75,6 +75,14 @@ New features Other language changes ====================== +* Stable ABI extensions may now include a multiarch tuple in the + filename, e.g. ``foo.abi3-x86-64-linux-gnu.so``. + This permits stable ABI extensions for multiple architectures to be + co-installed into the same directory, without clashing with each + other, as regular dynamic extensions do. Build tools will not generate + these multiarch tagged filenames, by default, while still supporting + older Python versions that don't recognize these filenames. + (Contributed by Stefano Rivera in :gh:`122931`.) New modules diff --git a/Misc/NEWS.d/next/C_API/2024-08-12-09-48-04.gh-issue-122931.QwHc2l.rst b/Misc/NEWS.d/next/C_API/2024-08-12-09-48-04.gh-issue-122931.QwHc2l.rst new file mode 100644 index 00000000000000..d1caad2e98482d --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-08-12-09-48-04.gh-issue-122931.QwHc2l.rst @@ -0,0 +1,2 @@ +Allow importing stable ABI C extensions that include a multiarch tuple +in their filename, e.g. ``foo.abi3-x86-64-linux-gnu.so``. diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c index 0ff88ad330fd09..e2dc8f9e0fc780 100644 --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -47,8 +47,14 @@ const char *_PyImport_DynLoadFiletab[] = { #endif #ifndef Py_GIL_DISABLED ".abi" PYTHON_ABI_STRING ".so", +#ifdef SOABI_PLATFORM + ".abi" PYTHON_ABI_STRING "-" SOABI_PLATFORM ".so", +#endif /* SOABI_PLATFORM */ #endif /* Py_GIL_DISABLED */ ".abi" PYTHON_ABI_STRING "t.so", +#ifdef SOABI_PLATFORM + ".abi" PYTHON_ABI_STRING "t-" SOABI_PLATFORM ".so", +#endif /* SOABI_PLATFORM */ ".so", #endif /* __CYGWIN__ */ NULL, diff --git a/configure b/configure index 63b41117957cab..d93dd09197c818 100755 --- a/configure +++ b/configure @@ -7252,6 +7252,10 @@ case $ac_sys_system in #( ;; esac + +printf "%s\n" "#define SOABI_PLATFORM \"${SOABI_PLATFORM}\"" >>confdefs.h + + if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" fi diff --git a/configure.ac b/configure.ac index 6df5d1bee31c67..85f0bf6053d009 100644 --- a/configure.ac +++ b/configure.ac @@ -1212,6 +1212,8 @@ AS_CASE([$ac_sys_system], [SOABI_PLATFORM=$PLATFORM_TRIPLET] ) +AC_DEFINE_UNQUOTED([SOABI_PLATFORM], ["${SOABI_PLATFORM}"], [Platform tag, used in binary module extension filenames.]) + if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" fi diff --git a/pyconfig.h.in b/pyconfig.h.in index 7ef83fcd0b9e0b..50a2d26b5081c7 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1851,6 +1851,9 @@ /* The size of '_Bool', as computed by sizeof. */ #undef SIZEOF__BOOL +/* Platform tag, used in binary module extension filenames. */ +#undef SOABI_PLATFORM + /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS From 25cc5ae1648904a579cc2cbf97996a5f6ad7ab96 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Mon, 18 May 2026 17:23:07 -0700 Subject: [PATCH 2/5] Order the multiarch-tagged extensions first --- Doc/whatsnew/3.16.rst | 6 +++--- Python/dynload_shlib.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 39c6db95bae135..ad043dd0321d49 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -79,9 +79,9 @@ Other language changes filename, e.g. ``foo.abi3-x86-64-linux-gnu.so``. This permits stable ABI extensions for multiple architectures to be co-installed into the same directory, without clashing with each - other, as regular dynamic extensions do. Build tools will not generate - these multiarch tagged filenames, by default, while still supporting - older Python versions that don't recognize these filenames. + other, as regular dynamic extensions do. Build may tools will generate + these multiarch tagged filenames, by default, when targeting + compatibility with at least Python 3.15. (Contributed by Stefano Rivera in :gh:`122931`.) diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c index e2dc8f9e0fc780..f7f7c922920085 100644 --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -46,15 +46,15 @@ const char *_PyImport_DynLoadFiletab[] = { "." ALT_SOABI ".so", #endif #ifndef Py_GIL_DISABLED - ".abi" PYTHON_ABI_STRING ".so", #ifdef SOABI_PLATFORM ".abi" PYTHON_ABI_STRING "-" SOABI_PLATFORM ".so", #endif /* SOABI_PLATFORM */ + ".abi" PYTHON_ABI_STRING ".so", #endif /* Py_GIL_DISABLED */ - ".abi" PYTHON_ABI_STRING "t.so", #ifdef SOABI_PLATFORM ".abi" PYTHON_ABI_STRING "t-" SOABI_PLATFORM ".so", #endif /* SOABI_PLATFORM */ + ".abi" PYTHON_ABI_STRING "t.so", ".so", #endif /* __CYGWIN__ */ NULL, From 81f5862f9646992e235e06c15f46a65b67aa42df Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 19 May 2026 23:49:42 -0400 Subject: [PATCH 3/5] Test for presence of multiarch extension suffixes --- Lib/test/test_importlib/extension/test_finder.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index dc77fa78a203fd..da7f31d98e4bd4 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -5,6 +5,7 @@ import unittest import sys +import sysconfig class FinderTests(abc.FinderTests): @@ -68,11 +69,22 @@ def test_abi3_extension_suffixes(self): pass else: if Py_GIL_DISABLED: - self.assertNotIn(".abi3.so", suffixes) + self.assertFalse(any(".abi3" in suffix) for suffix in suffixes) else: self.assertIn(".abi3.so", suffixes) self.assertIn(".abi3t.so", suffixes) + @unittest.skipIf( + not sysconfig.get_config_var("SOABI_PLATFORM").strip('"'), + "Linux-only test" + ) + def test_multiarch_abi3_extension_suffixes(self): + suffixes = self.machinery.EXTENSION_SUFFIXES + platform = sysconfig.get_config_var("SOABI_PLATFORM").strip('"') + if Py_GIL_DISABLED: + self.assertIn(f".abi3-{platform}.so", suffixes) + self.assertIn(f".abi3t-{platform}.so", suffixes) + (Frozen_FinderTests, Source_FinderTests From 09ae8d556208a2a5fd115ff60646c8fd96e31c07 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 20 May 2026 11:10:16 -0400 Subject: [PATCH 4/5] Fix editing error in NEWS and improve clarity --- Doc/whatsnew/3.16.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index ad043dd0321d49..974c37a4ae438b 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -75,11 +75,11 @@ New features Other language changes ====================== -* Stable ABI extensions may now include a multiarch tuple in the +* Stable ABI extensions now include a multiarch tuple in the filename, e.g. ``foo.abi3-x86-64-linux-gnu.so``. This permits stable ABI extensions for multiple architectures to be co-installed into the same directory, without clashing with each - other, as regular dynamic extensions do. Build may tools will generate + other, as regular dynamic extensions do. Build tools will generate these multiarch tagged filenames, by default, when targeting compatibility with at least Python 3.15. (Contributed by Stefano Rivera in :gh:`122931`.) From 7b071c21bfb28a4ccf0f2b3ac0160cc1cb35af88 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 20 May 2026 11:41:42 -0400 Subject: [PATCH 5/5] Fix up the test --- Lib/test/test_importlib/extension/test_finder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index da7f31d98e4bd4..686f502bf5b368 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -69,19 +69,21 @@ def test_abi3_extension_suffixes(self): pass else: if Py_GIL_DISABLED: - self.assertFalse(any(".abi3" in suffix) for suffix in suffixes) + self.assertNotIn(".abi3.so", suffixes) else: self.assertIn(".abi3.so", suffixes) self.assertIn(".abi3t.so", suffixes) @unittest.skipIf( - not sysconfig.get_config_var("SOABI_PLATFORM").strip('"'), + not (sysconfig.get_config_var("SOABI_PLATFORM") or "").strip('"'), "Linux-only test" ) def test_multiarch_abi3_extension_suffixes(self): suffixes = self.machinery.EXTENSION_SUFFIXES platform = sysconfig.get_config_var("SOABI_PLATFORM").strip('"') if Py_GIL_DISABLED: + self.assertNotIn(f".abi3-{platform}.so", suffixes) + else: self.assertIn(f".abi3-{platform}.so", suffixes) self.assertIn(f".abi3t-{platform}.so", suffixes)