From fd9f1ce21e1e673f208522d9e9911d1a546a78aa Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 12:55:10 -0700 Subject: [PATCH 01/10] allow limited API builds on free-threaded 3.15 and newer --- src/cffi/setuptools_ext.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index 5cdd246f..5c0b7fe3 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -104,10 +104,9 @@ def _set_py_limited_api(Extension, kwds): # warning. kwds['py_limited_api'] = True - if sysconfig.get_config_var("Py_GIL_DISABLED"): + if sysconfig.get_config_var("Py_GIL_DISABLED") and sys.version_info < (3, 15): if kwds.get('py_limited_api'): log.info("Ignoring py_limited_api=True for free-threaded build.") - kwds['py_limited_api'] = False if kwds.get('py_limited_api') is False: From facf9958f18d7ce54e0f4a244a75de66c60c1c34 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 13:42:41 -0700 Subject: [PATCH 02/10] set _Py_OPAQUE_PYOBJECT for limited API free-threaded builds --- src/cffi/recompiler.py | 2 +- src/cffi/setuptools_ext.py | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cffi/recompiler.py b/src/cffi/recompiler.py index 83ee5c7d..6f2debe5 100644 --- a/src/cffi/recompiler.py +++ b/src/cffi/recompiler.py @@ -9,7 +9,7 @@ USE_LIMITED_API = ((sys.platform != 'win32' or sys.version_info < (3, 0) or sys.version_info >= (3, 5)) and - not sysconfig.get_config_var("Py_GIL_DISABLED")) # free-threaded doesn't yet support limited API + (not sysconfig.get_config_var("Py_GIL_DISABLED") or sys.version_info >= (3, 15))) # free-threaded doesn't yet support limited API class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index 5c0b7fe3..fadec63d 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -104,10 +104,13 @@ def _set_py_limited_api(Extension, kwds): # warning. kwds['py_limited_api'] = True - if sysconfig.get_config_var("Py_GIL_DISABLED") and sys.version_info < (3, 15): - if kwds.get('py_limited_api'): - log.info("Ignoring py_limited_api=True for free-threaded build.") - kwds['py_limited_api'] = False + if sysconfig.get_config_var("Py_GIL_DISABLED"): + if sys.version_info < (3, 15): + if kwds.get('py_limited_api'): + log.info("Ignoring py_limited_api=True for free-threaded build.") + kwds['py_limited_api'] = False + else: + kwds.setdefault("define_macros", []).append(("_Py_OPAQUE_PYOBJECT", None)) if kwds.get('py_limited_api') is False: # avoid setting Py_LIMITED_API if py_limited_api=False From 6fd5d460190f7e23a19f62aaaba0cc71a7e5ac89 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 14:07:36 -0700 Subject: [PATCH 03/10] define Py_LIMITED_API manually. This seems questionable --- src/cffi/setuptools_ext.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index fadec63d..225d4cdc 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -111,6 +111,7 @@ def _set_py_limited_api(Extension, kwds): kwds['py_limited_api'] = False else: kwds.setdefault("define_macros", []).append(("_Py_OPAQUE_PYOBJECT", None)) + kwds["define_macros"].append(("Py_LIMITED_API", "0x030f0000")) if kwds.get('py_limited_api') is False: # avoid setting Py_LIMITED_API if py_limited_api=False From 3e06a12ec4e965678f4b2ab9e97d4d8cc5aca240 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 16 Apr 2026 08:29:55 -0600 Subject: [PATCH 04/10] Use 3.15t for free-threaded CI --- .github/workflows/ci.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 55cc1b1b..1d35fda4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -504,9 +504,9 @@ jobs: with: matrix_yaml: | include: - - { runner: ubuntu-24.04, python-version: 3.14t } - - { runner: macos-26, python-version: 3.14t } - - { runner: windows-2025, python-version: 3.14t } + - { runner: ubuntu-24.04, python-version: 3.15t-dev } + - { runner: macos-26, python-version: 3.15t-dev } + - { runner: windows-2025, python-version: 3.15t-dev } pytest-run-parallel: needs: make_run_parallel_matrix @@ -536,7 +536,7 @@ jobs: clang_TSAN: runs-on: ubuntu-24.04 - container: ghcr.io/nascheme/numpy-tsan:3.14t + container: ghcr.io/nascheme/numpy-tsan:3.15t-dev steps: - uses: actions/checkout@v4 From a0178d894ecd3776b7a9b14c5f088fb11ec5975a Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 16 Apr 2026 09:06:33 -0600 Subject: [PATCH 05/10] Update for merged PEP 803 implementation --- src/cffi/_cffi_include.h | 13 +++++++++++-- src/cffi/setuptools_ext.py | 3 +-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/cffi/_cffi_include.h b/src/cffi/_cffi_include.h index c7186307..c8c6d343 100644 --- a/src/cffi/_cffi_include.h +++ b/src/cffi/_cffi_include.h @@ -28,8 +28,13 @@ #if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) # ifdef _MSC_VER # if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif # endif + # include /* sanity-check: Py_LIMITED_API will cause crashes if any of these are also defined. Normally, the Python file PC/pyconfig.h does not @@ -49,7 +54,11 @@ # else # include # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif # endif # endif #endif diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index 225d4cdc..319ab0f2 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -110,8 +110,7 @@ def _set_py_limited_api(Extension, kwds): log.info("Ignoring py_limited_api=True for free-threaded build.") kwds['py_limited_api'] = False else: - kwds.setdefault("define_macros", []).append(("_Py_OPAQUE_PYOBJECT", None)) - kwds["define_macros"].append(("Py_LIMITED_API", "0x030f0000")) + kwds["define_macros"].append(("Py_TARGET_ABI3T", "0x030f0000")) if kwds.get('py_limited_api') is False: # avoid setting Py_LIMITED_API if py_limited_api=False From 4638bf41d317a4d67ea9a6e9e596d71719250861 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 8 Jun 2026 10:19:46 -0600 Subject: [PATCH 06/10] Drop python 3.9, add Python 3.15 CI --- .github/workflows/ci.yaml | 84 +++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1d35fda4..80f08cde 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -72,25 +72,26 @@ jobs: matrix_yaml: | include: # x86_64 manylinux - - { spec: cp39-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { 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 } - - { spec: cp314t-manylinux_x86_64, arch: x86_64 } + - { spec: cp314-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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: cp39-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { 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 } - - { spec: cp314t-musllinux_x86_64, arch: x86_64 } + - { spec: cp314-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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: cp39-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { 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 }} } @@ -98,46 +99,49 @@ jobs: # omit i686 releases > 3.13 # i686 musllinux - - { spec: cp39-musllinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-musllinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-musllinux_i686, arch: i686 } # omit i686 releases after 3.11 # aarch64 manylinux - - { spec: cp39-manylinux_aarch64, arch: aarch64 } - { 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 } - - { spec: cp314t-manylinux_aarch64, arch: aarch64 } + - { spec: cp314-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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: cp39-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { 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 } - - { spec: cp314t-musllinux_aarch64, arch: aarch64 } + - { spec: cp314-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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: cp39-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp310-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { 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, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp314-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp315t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } # s390x manylinux - - { spec: cp39-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp310-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { 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, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp314t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp314-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp315t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } linux: needs: [python_sdist, make_linux_matrix] @@ -218,22 +222,24 @@ jobs: matrix_yaml: | include: # x86_64 macos - - { spec: cp39-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_x86_64, runs_on: [macos-15-intel] } - - { spec: cp314t-macosx_x86_64, runs_on: [macos-15-intel] } + - { spec: cp314-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-macosx_x86_64, runs_on: [macos-15-intel] } + - { spec: cp315t-macosx_x86_64, runs_on: [macos-15-intel] } # arm64 macos - - { spec: cp39-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp310-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs}} } + - { spec: cp310-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } - - { spec: cp314t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } + - { spec: cp314-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } + - { spec: cp315t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } macos: needs: [python_sdist, make_macos_matrix] @@ -309,8 +315,10 @@ 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 } - - { spec: cp314t-win_amd64 } + - { spec: cp314-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-win_amd64 } + - { spec: cp315t-win_amd64 } # x86 windows - { spec: cp39-win32, omit: ${{ env.skip_ci_redundant_jobs }} } @@ -318,15 +326,19 @@ 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 } - - { spec: cp314t-win32 } + - { spec: cp314-win32, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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 } - - { spec: cp314t-win_arm64, runs_on: windows-11-arm } + - { spec: cp314-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } + - { 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: needs: [python_sdist, make_windows_matrix] @@ -393,10 +405,12 @@ jobs: # arm64 iOS device - { 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] From 417336d49628cb6053f26a579f863132b7f24459 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 8 Jun 2026 11:07:07 -0600 Subject: [PATCH 07/10] set CIBW_ENABLE=cpython_prerelease for all builds --- .github/workflows/ci.yaml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 80f08cde..4a27735a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -128,20 +128,20 @@ 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, omit: ${{ env.skip_slow_jobs }} omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp315t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_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, omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp315-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp315t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_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 }} } linux: needs: [python_sdist, make_linux_matrix] @@ -167,6 +167,7 @@ jobs: CFLAGS: -Dffi_call=cffistatic_ffi_call # override name for ffi_call to break hard if we linked against someone else's libffi CIBW_ARCHS_LINUX: all CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_BEFORE_BUILD: | set -eux && \ curl -L -O https://github.com/libffi/libffi/archive/v3.4.6.tar.gz && \ @@ -274,6 +275,7 @@ jobs: id: build env: CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools CIBW_TEST_COMMAND: pip install pip --upgrade; cd {project}; PYTHONUNBUFFERED=1 pytest MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment_target || '10.13' }} @@ -363,6 +365,7 @@ jobs: id: build env: CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools CIBW_TEST_COMMAND: ${{ matrix.test_cmd || 'python -m pytest {package}/src/c' }} # FIXME: /testing takes ~45min on Windows and has some failures... From d48c46dabada03634fb94c33fd5228a46c838966 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 8 Jun 2026 11:14:49 -0600 Subject: [PATCH 08/10] ensure define_macros exists before appending to it --- src/cffi/setuptools_ext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index 319ab0f2..946afb45 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -110,7 +110,7 @@ def _set_py_limited_api(Extension, kwds): log.info("Ignoring py_limited_api=True for free-threaded build.") kwds['py_limited_api'] = False else: - kwds["define_macros"].append(("Py_TARGET_ABI3T", "0x030f0000")) + kwds.setdefault("define_macros", []).append(("Py_TARGET_ABI3T", "0x030f0000")) if kwds.get('py_limited_api') is False: # avoid setting Py_LIMITED_API if py_limited_api=False From 3ccad47024da52e13239ddd985879bccdfa0036e Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 8 Jun 2026 11:27:52 -0600 Subject: [PATCH 09/10] Tweak test that expects limited API builds to fail on ft build --- testing/cffi0/test_zintegration.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/cffi0/test_zintegration.py b/testing/cffi0/test_zintegration.py index 69c3d01f..20436913 100644 --- a/testing/cffi0/test_zintegration.py +++ b/testing/cffi0/test_zintegration.py @@ -181,7 +181,10 @@ def test_set_py_limited_api(self): pytest.skip(str(e)) orig_version = setuptools.__version__ # free-threaded Python does not yet support limited API - expecting_limited_api = not hasattr(sys, 'gettotalrefcount') and not sysconfig.get_config_var("Py_GIL_DISABLED") + expecting_limited_api = ( + not hasattr(sys, 'gettotalrefcount') and not + (sysconfig.get_config_var("Py_GIL_DISABLED") and sys.version_info < (3, 15)) + ) try: setuptools.__version__ = '26.0.0' from setuptools import Extension From a1e083c1baa02e888b80cdda3b45b80eaefd1987 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 8 Jun 2026 11:37:30 -0600 Subject: [PATCH 10/10] fix test_get_set_errno --- testing/cffi1/test_verify1.py | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py index 479b164a..9483d913 100644 --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -781,6 +781,7 @@ def test_get_set_errno(): ffi = FFI() ffi.cdef("int foo(int);") lib = ffi.verify(""" + #include static int foo(int x) { errno += 1;