[pypy-commit] cffi default: Simplify the module setup logic; add high-level comments.

arigo noreply at buildbot.pypy.org
Fri Jun 15 20:17:45 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r372:f8adb916ed0c
Date: 2012-06-15 20:17 +0200
http://bitbucket.org/cffi/cffi/changeset/f8adb916ed0c/

Log:	Simplify the module setup logic; add high-level comments.

diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -19,34 +19,47 @@
             return num
 
     def verify(self, preamble, **kwds):
+        """Produce an extension module, compile it and import it.
+        Then make a fresh FFILibrary class, of which we will return
+        an instance.  Finally, we copy all the API elements from
+        the module to the class or the instance as needed.
+        """
         modname = ffiplatform.undercffi_module_name()
         tmpdir = ffiplatform.tmpdir()
         filebase = os.path.join(tmpdir, modname)
-        self.chained_list_constants = None
-        
+
+        # The new module will have a _cffi_setup() function that receives
+        # objects from the ffi world, and that calls some setup code in
+        # the module.  This setup code is split in several independent
+        # functions, e.g. one per constant.  The functions are "chained"
+        # by ending in a tail call to each other.  The following
+        # 'chained_list_constants' attribute contains the head of this
+        # chained list, as a string that gives the call to do, if any.
+        self.chained_list_constants = '0'
+
         with open(filebase + '.c', 'w') as f:
             self.f = f
+            # first paste some standard set of lines that are mostly '#define'
             self.prnt(cffimod_header)
             self.prnt()
+            # then paste the C source given by the user, verbatim.
             self.prnt(preamble)
             self.prnt()
             #
+            # call generate_cpy_xxx_decl(), for every xxx found from
+            # ffi._parser._declarations.  This generates all the functions.
             self.generate("decl")
             #
-            self.prnt('static PyObject *_cffi_setup_custom(void)')
+            # implement this function as calling the head of the chained list.
+            self.prnt('static int _cffi_setup_custom(PyObject *lib)')
             self.prnt('{')
-            self.prnt('  PyObject *dct = PyDict_New();')
-            if self.chained_list_constants is not None:
-                self.prnt('  if (dct == NULL)')
-                self.prnt('    return NULL;')
-                self.prnt('  if (%s(dct) < 0) {' % self.chained_list_constants)
-                self.prnt('    Py_DECREF(dct);')
-                self.prnt('    return NULL;')
-                self.prnt('  }')
-            self.prnt('  return dct;')
+            self.prnt('  return %s;' % self.chained_list_constants)
             self.prnt('}')
             self.prnt()
             #
+            # produce the method table, including the entries for the
+            # generated Python->C function wrappers, which are done
+            # by generate_cpy_function_method().
             self.prnt('static PyMethodDef _cffi_methods[] = {')
             self.generate("method")
             self.prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS},')
@@ -54,6 +67,7 @@
             self.prnt('};')
             self.prnt()
             #
+            # standard init.
             self.prnt('PyMODINIT_FUNC')
             self.prnt('init%s(void)' % modname)
             self.prnt('{')
@@ -63,26 +77,41 @@
             #
             del self.f
 
+        # compile this C source
         outputfilename = ffiplatform.compile(tmpdir, modname, **kwds)
         #
+        # import it as a new extension module
         import imp
         try:
             module = imp.load_dynamic(modname, outputfilename)
         except ImportError, e:
             raise ffiplatform.VerificationError(str(e))
         #
+        # call loading_cpy_struct() to get the struct layout inferred by
+        # the C compiler
         self.load(module, 'loading')
         #
+        # the C code will need the <ctype> objects.  Collect them in
+        # order in a list.
         revmapping = dict([(value, key)
                            for (key, value) in self.typesdict.items()])
         lst = [revmapping[i] for i in range(len(revmapping))]
         lst = map(self.ffi._get_cached_btype, lst)
-        dct = module._cffi_setup(lst, ffiplatform.VerificationError)
         #
+        # build the FFILibrary class and instance and call _cffi_setup().
+        # this will set up some fields like '_cffi_types', and only then
+        # it will invoke the chained list of functions that will really
+        # build (notably) the constant objects, as <cdata> if they are
+        # pointers, and store them as attributes on the 'library' object.
         class FFILibrary(object):
             pass
         library = FFILibrary()
-        library.__dict__.update(dct)
+        module._cffi_setup(lst, ffiplatform.VerificationError, library)
+        #
+        # finally, call the loaded_cpy_xxx() functions.  This will perform
+        # the final adjustments, like copying the Python->C wrapper
+        # functions from the module to the 'library' object, and setting
+        # up the FFILibrary class with properties for the global C variables.
         self.load(module, 'loaded', library=library)
         return library
 
@@ -322,28 +351,18 @@
     # ----------
     # constants, likely declared with '#define'
 
-    def _generate_chain_header(self, funcname, *vardecls):
+    def _generate_cpy_const(self, is_int, name, tp=None, category='const'):
         prnt = self.prnt
-        prnt('static int %s(PyObject *dct)' % funcname)
+        funcname = '_cffi_%s_%s' % (category, name)
+        prnt('static int %s(PyObject *lib)' % funcname)
         prnt('{')
-        for decl in vardecls:
-            prnt('  ' + decl)
-        if self.chained_list_constants is not None:
-            prnt('  if (%s(dct) < 0)' % self.chained_list_constants)
-            prnt('    return -1;')
-        self.chained_list_constants = funcname
-
-    def _generate_cpy_const(self, is_int, name, tp=None, category='const'):
-        vardecls = ['PyObject *o;',
-                    'int res;']
+        prnt('  PyObject *o;')
+        prnt('  int res;')
         if not is_int:
-            vardecls.append('%s;' % tp.get_c_name(' i'))
+            prnt('  %s;' % tp.get_c_name(' i'))
         else:
             assert category == 'const'
-        self._generate_chain_header('_cffi_%s_%s' % (category, name),
-                                    *vardecls)
         #
-        prnt = self.prnt
         if not is_int:
             if category == 'var':
                 realexpr = '&' + name
@@ -361,9 +380,12 @@
                  '(unsigned long long)(%s));' % (name,))
         prnt('  if (o == NULL)')
         prnt('    return -1;')
-        prnt('  res = PyDict_SetItemString(dct, "%s", o);' % name)
+        prnt('  res = PyObject_SetAttrString(lib, "%s", o);' % name)
         prnt('  Py_DECREF(o);')
-        prnt('  return res;')
+        prnt('  if (res < 0)')
+        prnt('    return -1;')
+        prnt('  return %s;' % self.chained_list_constants)
+        self.chained_list_constants = funcname + '(lib)'
         prnt('}')
         prnt()
 
@@ -384,8 +406,10 @@
                 self._generate_cpy_const(True, enumerator)
             return
         #
-        self._generate_chain_header('_cffi_enum_%s' % name)
+        funcname = '_cffi_enum_%s' % name
         prnt = self.prnt
+        prnt('static int %s(PyObject *lib)' % funcname)
+        prnt('{')
         for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
             prnt('  if (%s != %d) {' % (enumerator, enumvalue))
             prnt('    PyErr_Format(_cffi_VerificationError,')
@@ -395,7 +419,8 @@
                 name, enumerator, enumerator, enumvalue))
             prnt('    return -1;')
             prnt('  }')
-        prnt('  return 0;')
+        prnt('  return %s;' % self.chained_list_constants)
+        self.chained_list_constants = funcname + '(lib)'
         prnt('}')
         prnt()
 
@@ -529,16 +554,22 @@
 static void *_cffi_exports[_CFFI_NUM_EXPORTS];
 static PyObject *_cffi_types, *_cffi_VerificationError;
 
-static PyObject *_cffi_setup_custom(void);   /* forward */
+static int _cffi_setup_custom(PyObject *lib);   /* forward */
 
 static PyObject *_cffi_setup(PyObject *self, PyObject *args)
 {
-    if (!PyArg_ParseTuple(args, "OO", &_cffi_types, &_cffi_VerificationError))
+    PyObject *library;
+    if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
+                                       &library))
+        return NULL;
+
+    if (_cffi_setup_custom(library) < 0)
         return NULL;
     Py_INCREF(_cffi_types);
     Py_INCREF(_cffi_VerificationError);
 
-    return _cffi_setup_custom();
+    Py_INCREF(Py_None);
+    return Py_None;
 }
 
 static void _cffi_init(void)


More information about the pypy-commit mailing list