From a3e64bfa596d617816dc7b54fdd14475bba58879 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 12:55:10 -0700 Subject: [PATCH 1/3] 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 3ca6c3ebc3a1f64f96e18cc853b70a6f0d97a901 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 13:42:41 -0700 Subject: [PATCH 2/3] 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 495b897a..6099482c 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 c7ed1432a57af1391ab1414b48d1a2bee83e8845 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Mon, 2 Mar 2026 14:07:36 -0700 Subject: [PATCH 3/3] 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