summaryrefslogtreecommitdiff
path: root/cffi
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2020-08-13 10:32:06 +0200
committerArmin Rigo <arigo@tunes.org>2020-08-13 10:32:06 +0200
commita4aa1122acec1ab59cd669cb0b3a12c7bdc76f90 (patch)
tree779cd79208c1ba53781cf23a6547b212e1323c4a /cffi
parentb43cd975844bce0c361e5b3cd05bb1350de496c9 (diff)
downloadcffi-a4aa1122acec1ab59cd669cb0b3a12c7bdc76f90.tar.gz
another attempt at Py_LIMITED_API on Windows on CPython >= 3.5
Diffstat (limited to 'cffi')
-rw-r--r--cffi/_cffi_include.h53
-rw-r--r--cffi/recompiler.py5
-rw-r--r--cffi/setuptools_ext.py4
3 files changed, 49 insertions, 13 deletions
diff --git a/cffi/_cffi_include.h b/cffi/_cffi_include.h
index 3129150..e4c0a67 100644
--- a/cffi/_cffi_include.h
+++ b/cffi/_cffi_include.h
@@ -8,20 +8,49 @@
the same works for the other two macros. Py_DEBUG implies them,
but not the other way around.
- Issue #350 is still open: on Windows, the code here causes it to link
- with PYTHON36.DLL (for example) instead of PYTHON3.DLL. A fix was
- attempted in 164e526a5515 and 14ce6985e1c3, but reverted: virtualenv
- does not make PYTHON3.DLL available, and so the "correctly" compiled
- version would not run inside a virtualenv. We will re-apply the fix
- after virtualenv has been fixed for some time. For explanation, see
- issue #355. For a workaround if you want PYTHON3.DLL and don't worry
- about virtualenv, see issue #350. See also 'py_limited_api' in
- setuptools_ext.py.
+ The implementation is messy (issue #350): on Windows, with _MSC_VER,
+ we have to define Py_LIMITED_API even before including pyconfig.h.
+ In that case, we guess what pyconfig.h will do to the macros above,
+ and check our guess after the #include.
+
+ Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv
+ version >= 16.0.0. With older versions of either, you don't get a
+ copy of PYTHON3.DLL in the virtualenv. We can't check the version of
+ CPython *before* we even include pyconfig.h. ffi.set_source() puts
+ a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is
+ running on Windows < 3.5, as an attempt at fixing it, but that's
+ arguably wrong because it may not be the target version of Python.
+ Still better than nothing I guess. As another workaround, you can
+ remove the definition of Py_LIMITED_API here.
+
+ See also 'py_limited_api' in cffi/setuptools_ext.py.
*/
#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API)
-# include <pyconfig.h>
-# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG)
-# define 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
+# endif
+# include <pyconfig.h>
+ /* sanity-check: Py_LIMITED_API will cause crashes if any of these
+ are also defined. Normally, the Python file PC/pyconfig.h does not
+ cause any of these to be defined, with the exception that _DEBUG
+ causes Py_DEBUG. Double-check that. */
+# ifdef Py_LIMITED_API
+# if defined(Py_DEBUG)
+# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set"
+# endif
+# if defined(Py_TRACE_REFS)
+# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set"
+# endif
+# if defined(Py_REF_DEBUG)
+# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set"
+# endif
+# endif
+# else
+# include <pyconfig.h>
+# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API)
+# define Py_LIMITED_API
+# endif
# endif
#endif
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
index 1309572..1aeae5b 100644
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -7,6 +7,9 @@ VERSION_BASE = 0x2601
VERSION_EMBEDDED = 0x2701
VERSION_CHAR16CHAR32 = 0x2801
+USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or
+ sys.version_info >= (3, 5))
+
class GlobalExpr:
def __init__(self, name, address, type_op, size=0, check_value=0):
@@ -283,6 +286,8 @@ class Recompiler:
prnt = self._prnt
if self.ffi._embedding is not None:
prnt('#define _CFFI_USE_EMBEDDING')
+ if not USE_LIMITED_API:
+ prnt('#define _CFFI_NO_LIMITED_API')
#
# first the '#include' (actually done by inlining the file's content)
lines = self._rel_readlines('_cffi_include.h')
diff --git a/cffi/setuptools_ext.py b/cffi/setuptools_ext.py
index dabf2f3..8fe3614 100644
--- a/cffi/setuptools_ext.py
+++ b/cffi/setuptools_ext.py
@@ -87,8 +87,10 @@ def _set_py_limited_api(Extension, kwds):
Recently (2020) we started shipping only >= 3.5 wheels, though. So
we'll give it another try and set py_limited_api on Windows >= 3.5.
"""
+ from cffi import recompiler
+
if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
- and (sys.platform != 'win32' or sys.version_info >= (3, 5))):
+ and recompiler.USE_LIMITED_API):
import setuptools
try:
setuptools_major_version = int(setuptools.__version__.partition('.')[0])