From 989c77951177b92c1a49ed6358f4d79ef0240194 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Sun, 11 Aug 2024 10:43:45 +0200 Subject: [PATCH 1/6] 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 80f13e4d759dd30..9169ca76c85bf1c 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 000000000000000..d1caad2e98482d6 --- /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 0ff88ad330fd09c..e2dc8f9e0fc780d 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 e96b87989793a8f..0dc65b339c97611 100755 --- a/configure +++ b/configure @@ -7266,6 +7266,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 cd1883f0195c47e..c803c3b9ab8e208 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 a05cd8ecc91e197..b2d343735e87ce6 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1890,6 +1890,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 39fb3a413e4da69ffe2c0b12f3b33732a5908537 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Mon, 18 May 2026 17:23:07 -0700 Subject: [PATCH 2/6] 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 9169ca76c85bf1c..36c3e872abe8b5c 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 e2dc8f9e0fc780d..f7f7c9229200857 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 8324a7f15f8a9d12926df8fdbab4076bd5393782 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 19 May 2026 23:49:42 -0400 Subject: [PATCH 3/6] 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 dc77fa78a203fdb..da7f31d98e4bd46 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 5684c14b9ed552b704a484490b5ad984a4bcb457 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 20 May 2026 11:10:16 -0400 Subject: [PATCH 4/6] 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 36c3e872abe8b5c..bbdd2b87a3c1735 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 dfddd07fc5539ae00546108fc516386f498e1a39 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 20 May 2026 11:41:42 -0400 Subject: [PATCH 5/6] 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 da7f31d98e4bd46..686f502bf5b3686 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) From 67e2548a837ee7bff9eeacdcac861ab570a5dbc2 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Fri, 26 Jun 2026 08:08:56 -0400 Subject: [PATCH 6/6] Only target abi3t (for expediency) --- Doc/whatsnew/3.16.rst | 8 -------- .../test_importlib/extension/test_finder.py | 19 +++++-------------- ...-08-12-09-48-04.gh-issue-122931.QwHc2l.rst | 3 +-- Python/dynload_shlib.c | 6 ++---- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index bbdd2b87a3c1735..80f13e4d759dd30 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -75,14 +75,6 @@ New features Other language changes ====================== -* 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 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`.) New modules diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index 686f502bf5b3686..c460ff01d9f0d26 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -62,6 +62,7 @@ def test_failure(self): def test_abi3_extension_suffixes(self): suffixes = self.machinery.EXTENSION_SUFFIXES + platform = sysconfig.get_config_var("SOABI_PLATFORM") if 'win32' in sys.platform: # Either "_d.pyd" or ".pyd" must be in suffixes self.assertTrue({"_d.pyd", ".pyd"}.intersection(suffixes)) @@ -72,20 +73,10 @@ def test_abi3_extension_suffixes(self): 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") 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) + if platform: + self.assertIn(f".abi3t-{platform}.so", suffixes) + else: + self.assertIn(".abi3t.so", suffixes) (Frozen_FinderTests, 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 index d1caad2e98482d6..734547c86dbfbda 100644 --- 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 @@ -1,2 +1 @@ -Allow importing stable ABI C extensions that include a multiarch tuple -in their filename, e.g. ``foo.abi3-x86-64-linux-gnu.so``. +Linux: Include multiarch tuples in ``abi3t`` stable ABI C extension filenames, e.g. ``foo.abi3t-x86-64-linux-gnu.so``. diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c index f7f7c9229200857..a60cd1850c7df14 100644 --- a/Python/dynload_shlib.c +++ b/Python/dynload_shlib.c @@ -46,15 +46,13 @@ const char *_PyImport_DynLoadFiletab[] = { "." ALT_SOABI ".so", #endif #ifndef Py_GIL_DISABLED -#ifdef SOABI_PLATFORM - ".abi" PYTHON_ABI_STRING "-" SOABI_PLATFORM ".so", -#endif /* SOABI_PLATFORM */ ".abi" PYTHON_ABI_STRING ".so", #endif /* Py_GIL_DISABLED */ #ifdef SOABI_PLATFORM ".abi" PYTHON_ABI_STRING "t-" SOABI_PLATFORM ".so", -#endif /* SOABI_PLATFORM */ +#else ".abi" PYTHON_ABI_STRING "t.so", +#endif /* SOABI_PLATFORM */ ".so", #endif /* __CYGWIN__ */ NULL,