[pypy-commit] cffi cffi-1.0: Tweak tweak tweak: use an initialization sequence on CPython that is closer

arigo noreply at buildbot.pypy.org
Mon May 11 11:14:49 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1966:897b96412b7a
Date: 2015-05-11 11:15 +0200
http://bitbucket.org/cffi/cffi/changeset/897b96412b7a/

Log:	Tweak tweak tweak: use an initialization sequence on CPython that is
	closer to the PyPy one. Should make future version checking more
	uniform in CPython and PyPy.

diff --git a/_cffi1/_cffi_include.h b/_cffi1/_cffi_include.h
--- a/_cffi1/_cffi_include.h
+++ b/_cffi1/_cffi_include.h
@@ -51,14 +51,6 @@
 #ifndef PYPY_VERSION
 
 
-#if PY_MAJOR_VERSION < 3
-# undef PyCapsule_CheckExact
-# undef PyCapsule_GetPointer
-# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
-# define PyCapsule_GetPointer(capsule, name) \
-    (PyCObject_AsVoidPtr(capsule))
-#endif
-
 #if PY_MAJOR_VERSION >= 3
 # define PyInt_FromLong PyLong_FromLong
 #endif
@@ -143,10 +135,7 @@
     ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
 #define _cffi_convert_array_from_object                                  \
     ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
-#define _cffi_init_module                                                \
-    ((PyObject *(*)(char *, const struct _cffi_type_context_s *))        \
-                                                      _cffi_exports[25])
-#define _CFFI_NUM_EXPORTS 26
+#define _CFFI_NUM_EXPORTS 25
 
 typedef struct _ctypedescr CTypeDescrObject;
 
@@ -156,41 +145,37 @@
     assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
     (CTypeDescrObject *)_cffi_types[index])
 
-static int _cffi_init(void)
+static PyObject *_cffi_init(char *module_name, Py_ssize_t version,
+                            const struct _cffi_type_context_s *ctx)
 {
-    PyObject *module, *c_api_object = NULL;
-    void *src;
+    PyObject *module, *o_arg, *new_module;
+    void *raw[] = {
+        (void *)module_name,
+        (void *)version,
+        (void *)_cffi_exports,
+        (void *)ctx,
+    };
 
     module = PyImport_ImportModule("_cffi_backend");
     if (module == NULL)
         goto failure;
 
-    c_api_object = PyObject_GetAttrString(module, "_C_API");
-    if (c_api_object == NULL)
+    o_arg = PyLong_FromVoidPtr((void *)raw);
+    if (o_arg == NULL)
         goto failure;
-    if (!PyCapsule_CheckExact(c_api_object)) {
-        PyErr_SetNone(PyExc_ImportError);
-        goto failure;
-    }
-    src = PyCapsule_GetPointer(c_api_object, "cffi");
-    if ((uintptr_t)(((void **)src)[0]) < _CFFI_NUM_EXPORTS) {
-        PyErr_SetString(PyExc_ImportError,
-                        "the _cffi_backend module is an outdated version");
-        goto failure;
-    }
-    memcpy(_cffi_exports, src, _CFFI_NUM_EXPORTS * sizeof(void *));
 
+    new_module = PyObject_CallMethod(
+                    module, "_init_cffi_1_0_external_module", "O", o_arg);
+
+    Py_DECREF(o_arg);
     Py_DECREF(module);
-    Py_DECREF(c_api_object);
-    return 0;
+    return new_module;
 
   failure:
     Py_XDECREF(module);
-    Py_XDECREF(c_api_object);
-    return -1;
+    return NULL;
 }
 
-
 #endif
 /**********  end CPython-specific section  **********/
 
diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c
--- a/_cffi1/cffi1_module.c
+++ b/_cffi1/cffi1_module.c
@@ -103,16 +103,9 @@
     return -1;
 }
 
-static PyObject *_cffi_init_module(char *module_name,
-                                   const struct _cffi_type_context_s *ctx)
+static PyObject *_my_Py_InitModule(char *module_name)
 {
-    PyObject *m;
-    FFIObject *ffi;
-    LibObject *lib;
-
 #if PY_MAJOR_VERSION >= 3
-    /* note: the module_def leaks, but anyway the C extension module cannot
-       be unloaded */
     struct PyModuleDef *module_def, local_module_def = {
         PyModuleDef_HEAD_INIT,
         module_name,
@@ -120,17 +113,57 @@
         -1,
         NULL, NULL, NULL, NULL, NULL
     };
+    /* note: the 'module_def' is allocated dynamically and leaks,
+       but anyway the C extension module can never be unloaded */
     module_def = PyMem_Malloc(sizeof(struct PyModuleDef));
     if (module_def == NULL)
         return PyErr_NoMemory();
     *module_def = local_module_def;
-    m = PyModule_Create(module_def);
+    return PyModule_Create(module_def);
 #else
-    m = Py_InitModule(module_name, NULL);
+    return Py_InitModule(module_name, NULL);
 #endif
+}
+
+#define CFFI_VERSION_MIN    0x2600
+#define CFFI_VERSION_MAX    0x260F
+
+static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg)
+{
+    PyObject *m;
+    FFIObject *ffi;
+    LibObject *lib;
+    Py_ssize_t version;
+    char *module_name, *exports;
+    void **raw;
+    const struct _cffi_type_context_s *ctx;
+
+    raw = (void **)PyLong_AsVoidPtr(arg);
+    if (raw == NULL)
+        return NULL;
+
+    module_name = (char *)raw[0];
+    version = (Py_ssize_t)raw[1];
+    exports = (char *)raw[2];
+    ctx = (const struct _cffi_type_context_s *)raw[3];
+
+    if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
+        if (!PyErr_Occurred())
+            PyErr_Format(PyExc_ImportError,
+                         "cffi extension module '%s' has unknown version %p",
+                         module_name, (void *)version);
+        return NULL;
+    }
+
+    /* initialize the exports array */
+    memcpy(exports, (char *)cffi_exports, sizeof(cffi_exports));
+
+    /* make the module object */
+    m = _my_Py_InitModule(module_name);
     if (m == NULL)
         return NULL;
 
+    /* build the FFI and Lib object inside this new module */
     ffi = ffi_internal_new(&FFI_Type, ctx);
     Py_XINCREF(ffi);    /* make the ffi object really immortal */
     if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
diff --git a/_cffi1/recompiler.py b/_cffi1/recompiler.py
--- a/_cffi1/recompiler.py
+++ b/_cffi1/recompiler.py
@@ -227,7 +227,7 @@
         prnt('};')
         prnt()
         #
-        # the init function, loading _cffi_backend and calling a method there
+        # the init function
         base_module_name = self.module_name.split('.')[-1]
         prnt('#ifdef PYPY_VERSION')
         prnt('PyMODINIT_FUNC')
@@ -251,18 +251,14 @@
         prnt('PyMODINIT_FUNC')
         prnt('PyInit_%s(void)' % (base_module_name,))
         prnt('{')
-        prnt('  if (_cffi_init() < 0)')
-        prnt('    return NULL;')
-        prnt('  return _cffi_init_module("%s", &_cffi_type_context);' % (
+        prnt('  return _cffi_init("%s", 0x2600, &_cffi_type_context);' % (
             self.module_name,))
         prnt('}')
         prnt('#else')
         prnt('PyMODINIT_FUNC')
         prnt('init%s(void)' % (base_module_name,))
         prnt('{')
-        prnt('  if (_cffi_init() < 0)')
-        prnt('    return;')
-        prnt('  _cffi_init_module("%s", &_cffi_type_context);' % (
+        prnt('  _cffi_init("%s", 0x2600, &_cffi_type_context);' % (
             self.module_name,))
         prnt('}')
         prnt('#endif')
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5763,6 +5763,10 @@
     return Py_None;
 }
 
+static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *);
+/* forward, see _cffi1/cffi1_module.c */
+
+
 static PyMethodDef FFIBackendMethods[] = {
     {"load_library", b_load_library, METH_VARARGS},
     {"new_primitive_type", b_new_primitive_type, METH_VARARGS},
@@ -5796,6 +5800,7 @@
     {"_get_types", b__get_types, METH_NOARGS},
     {"_testfunc", b__testfunc, METH_VARARGS},
     {"_testbuff", b__testbuff, METH_VARARGS},
+    {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, METH_O},
     {NULL,     NULL}    /* Sentinel */
 };
 
@@ -5908,10 +5913,8 @@
 }
 #endif
 
-#include "../_cffi1/cffi1_module.c"
-
 static void *cffi_exports[] = {
-    (void *)26,
+    NULL,
     _cffi_to_c_i8,
     _cffi_to_c_u8,
     _cffi_to_c_i16,
@@ -5941,11 +5944,14 @@
     _cffi_to_c__Bool,
     _prepare_pointer_call_argument,
     convert_array_from_object,
-    _cffi_init_module,
 };
 
 /************************************************************/
 
+#include "../_cffi1/cffi1_module.c"
+
+/************************************************************/
+
 #if PY_MAJOR_VERSION >= 3
 static struct PyModuleDef FFIBackendModuleDef = {
   PyModuleDef_HEAD_INIT,
@@ -6016,11 +6022,12 @@
                                           "__name__", v) < 0)
         INITERROR;
 
+    /* this is for backward compatibility only */
     v = PyCapsule_New((void *)cffi_exports, "cffi", NULL);
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("1.0.0b2");
+    v = PyText_FromString("1.0.0");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
diff --git a/cffi/__init__.py b/cffi/__init__.py
--- a/cffi/__init__.py
+++ b/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.0.0b2"
-__version_info__ = (1, 0, 0, "beta", 2)
+__version__ = "1.0.0"
+__version_info__ = (1, 0, 0)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__


More information about the pypy-commit mailing list