From ff7bc5d67b179c8f3deca2f1cd35714ebf4cfc1b Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Tue, 8 Sep 2026 20:18:00 -0400 Subject: [PATCH 1/3] workflows: ci: add riscv64 musllinux build Signed-off-by: Trevor Gamblin --- .github/workflows/ci.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eab17d70..7f3e9a25 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -152,6 +152,16 @@ jobs: - { spec: cp314-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_slow_jobs }} } - { spec: cp314t-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_slow_jobs }} } + # riscv64 musllinux + - { spec: cp310-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp311-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp312-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp313-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-musllinux_riscv64, arch: riscv64 } + - { spec: cp315t-musllinux_riscv64, arch: riscv64 } + linux: needs: [python_sdist, make_linux_matrix] runs-on: ${{ (matrix.arch == 'aarch64') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} From fa6c35d4d1c4944df6f02a5fd46d403d6f0d7a41 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Wed, 9 Sep 2026 09:24:08 -0400 Subject: [PATCH 2/3] setup.py: enable stable ABI builds for Python 3.10+ Set a STABLE_ABI_BUILD variable to check so that the freethreaded builds can be handled separately. Signed-off-by: Trevor Gamblin --- setup.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/setup.py b/setup.py index 50b487ea..126b03bf 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,12 @@ "Upgrade to free-threaded 3.14 or newer to use CFFI with the " "free-threaded build.") +# no stable ABI for free-threaded builds yet, and Py_LIMITED_API 0x030A0000 needs 3.10+ headers +STABLE_ABI_BUILD = not FREE_THREADED_BUILD and sys.version_info >= (3, 10) + +if STABLE_ABI_BUILD: + define_macros.append(('Py_LIMITED_API', '0x030A0000')) + def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False): pkg_config = os.environ.get('PKG_CONFIG','pkg-config') try: @@ -201,5 +207,6 @@ def has_ext_modules(self): extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, extra_objects=forced_extra_objs, + py_limited_api=STABLE_ABI_BUILD, )] if cpython else [], ) From b2bbe7cb944a49226e4dd41e3241790578cb79a6 Mon Sep 17 00:00:00 2001 From: Trevor Gamblin Date: Wed, 9 Sep 2026 09:53:30 -0400 Subject: [PATCH 3/3] workflows: ci: convert linux to stable ABI build Also drop the cp39 build for riscv64, to make it consistent with the other platforms. Signed-off-by: Trevor Gamblin --- .github/workflows/ci.yaml | 115 +++++++------------------------------- 1 file changed, 19 insertions(+), 96 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7f3e9a25..8820f85b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -72,94 +72,47 @@ jobs: matrix_yaml: | include: # x86_64 manylinux - - { spec: cp310-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-manylinux_x86_64, arch: x86_64 } - { spec: cp314t-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_x86_64, arch: x86_64 } - { spec: cp315t-manylinux_x86_64, arch: x86_64 } - # x86_64 musllinux - - { spec: cp310-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-musllinux_x86_64, arch: x86_64 } - { spec: cp314t-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-musllinux_x86_64, arch: x86_64 } - { spec: cp315t-musllinux_x86_64, arch: x86_64 } # i686 manylinux - - { spec: cp310-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_i686, arch: i686 } - # omit i686 releases > 3.13 + - { spec: cp310-manylinux_i686, arch: i686 } # i686 musllinux - - { spec: cp310-musllinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-musllinux_i686, arch: i686 } - # omit i686 releases after 3.11 + - { spec: cp310-musllinux_i686, arch: i686 } # aarch64 manylinux - - { spec: cp310-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-manylinux_aarch64, arch: aarch64 } - { spec: cp314t-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_aarch64, arch: aarch64 } - { spec: cp315t-manylinux_aarch64, arch: aarch64 } # aarch64 musllinux - - { spec: cp310-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-musllinux_aarch64, arch: aarch64 } - { spec: cp314t-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-musllinux_aarch64, arch: aarch64 } - { spec: cp315t-musllinux_aarch64, arch: aarch64 } # ppc64le manylinux - { spec: cp310-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp311-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - { spec: cp315t-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } # s390x manylinux - { spec: cp310-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp311-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp314t-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - { spec: cp315t-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - # riscv64 manylinux - - { spec: cp39-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp310-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp311-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp312-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp313-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_slow_jobs }} } + # riscv64: cp39 is below the abi3 floor (Py_LIMITED_API 0x030A0000), keep it a full build + - { spec: cp310-manylinux_riscv64, arch: riscv64, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - { spec: cp314t-manylinux_riscv64, arch: riscv64, omit: ${{ env.skip_slow_jobs }} } # riscv64 musllinux - - { spec: cp310-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-musllinux_riscv64, arch: riscv64 } - { spec: cp314t-musllinux_riscv64, arch: riscv64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-musllinux_riscv64, arch: riscv64 } - { spec: cp315t-musllinux_riscv64, arch: riscv64 } linux: @@ -242,24 +195,14 @@ jobs: with: matrix_yaml: | include: - # x86_64 macos - - { spec: cp310-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } + # x86_64 macos: cp310 builds the abi3 wheel covering 3.10-3.15; free-threaded has no stable ABI + - { spec: cp310-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel } - { spec: cp314t-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel } - { spec: cp315t-macosx_x86_64, deployment_target: '10.15', runs_on: macos-15-intel } # arm64 macos - - { spec: cp310-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-macosx_arm64, deployment_target: '11.0' } - { spec: cp314t-macosx_arm64, deployment_target: '11.0', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-macosx_arm64, deployment_target: '11.0' } - { spec: cp315t-macosx_arm64, deployment_target: '11.0' } macos: @@ -330,33 +273,19 @@ jobs: with: matrix_yaml: | include: - # x86_64 windows - - { spec: cp310-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } + # x86_64 windows: cp310 builds the abi3 wheel covering 3.10-3.15; free-threaded has no stable ABI + - { spec: cp310-win_amd64 } - { spec: cp314t-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-win_amd64 } - { spec: cp315t-win_amd64 } - + # x86 windows - - { spec: cp310-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp311-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win32, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp310-win32 } - { spec: cp314t-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-win32 } - { spec: cp315t-win32 } - # arm64 windows - - { spec: cp311-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp312-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp313-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } + # arm64 windows: no cp310 build available, cp311 is the abi3 floor here + - { spec: cp311-win_arm64, runs_on: windows-11-arm } - { spec: cp314t-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp315-win_arm64, runs_on: windows-11-arm } - { spec: cp315t-win_arm64, runs_on: windows-11-arm } windows: @@ -422,15 +351,9 @@ jobs: with: matrix_yaml: | include: - # arm64 iOS device + # arm64 iOS: cp313 is the abi3 floor here, builds the wheel covering 3.13-3.15 - { spec: cp313-ios_arm64_iphoneos, platform: 'iphoneos' } - - { spec: cp314-ios_arm64_iphoneos, platform: 'iphoneos' } - - { spec: cp315-ios_arm64_iphoneos, platform: 'iphoneos' } - - # arm64 iOS simulator - { spec: cp313-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } - - { spec: cp314-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } - - { spec: cp315-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } ios: needs: [python_sdist, make_ios_matrix]