[pypy-commit] cffi cpy-extension: _cffi_to_c_char_p(). Use the technique documented in

arigo noreply at buildbot.pypy.org
Tue Jun 12 16:03:44 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: cpy-extension
Changeset: r289:e210108bc5d9
Date: 2012-06-12 16:03 +0200
http://bitbucket.org/cffi/cffi/changeset/e210108bc5d9/

Log:	_cffi_to_c_char_p(). Use the technique documented in
	http://docs.python.org/release/2.5.3/ext/using-cobjects.html to
	access a function defined in _ffi_backend from the C code in the
	generated module _cffi_N.

diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -3236,6 +3236,32 @@
     {NULL,     NULL}	/* Sentinel */
 };
 
+/************************************************************/
+/* Functions used by '_cffi_N.so', the generated modules    */
+
+static char *_cffi_to_c_char_p(PyObject *obj)
+{
+    if (PyString_Check(obj)) {
+        return PyString_AS_STRING(obj);
+    }
+    if (obj == Py_None) {
+        return NULL;
+    }
+    if (CData_Check(obj)) {
+        return ((CDataObject *)obj)->c_data;
+    }
+    PyErr_Format(PyExc_TypeError,
+                "initializer for ctype 'char *' must be a compatible pointer, "
+                 "not %.200s", Py_TYPE(obj)->tp_name);
+    return NULL;
+}
+
+static void *cffi_exports[] = {
+    _cffi_to_c_char_p,
+};
+
+/************************************************************/
+
 void init_ffi_backend(void)
 {
     PyObject *m, *v;
@@ -3264,4 +3290,8 @@
         return;
     if (PyType_Ready(&CDataWithDestructor_Type) < 0)
         return;
+
+    v = PyCObject_FromVoidPtr((void *)cffi_exports, NULL);
+    if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
+        return;
 }
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -20,14 +20,9 @@
         modname = ffiplatform.undercffi_module_name()
         filebase = os.path.join(ffiplatform.tmpdir(), modname)
         
-        with open(filebase + 'module.c', 'w') as f:
+        with open(filebase + '.c', 'w') as f:
             self.f = f
-            self.prnt("#include <Python.h>")
-            self.prnt()
-            self.prnt('#define _cffi_from_c_double PyFloat_FromDouble')
-            self.prnt('#define _cffi_to_c_double PyFloat_AsDouble')
-            self.prnt('#define _cffi_from_c_float PyFloat_FromDouble')
-            self.prnt('#define _cffi_to_c_float PyFloat_AsDouble')
+            self.prnt(cffimod_header)
             self.prnt()
             self.prnt(preamble)
             self.prnt()
@@ -43,7 +38,7 @@
             self.prnt('void init%s()' % modname)
             self.prnt('{')
             self.prnt('  Py_InitModule("%s", _cffi_methods);' % modname)
-            self.prnt('  if (PyErr_Occurred()) return;')
+            self.prnt('  if (PyErr_Occurred() || _cffi_init()) return;')
             self.generate("init")
             self.prnt('}')
             #
@@ -52,11 +47,11 @@
         # XXX use more distutils?
         import distutils.sysconfig
         python_h = distutils.sysconfig.get_python_inc()
-        err = os.system("gcc -I'%s' -O2 -shared %smodule.c -o %s.so" %
+        err = os.system("gcc -I'%s' -O2 -shared %s.c -o %s.so" %
                         (python_h, filebase, filebase))
         if err:
             raise ffiplatform.VerificationError(
-                '%smodule.c: see compilation errors above' % (filebase,))
+                '%s.c: see compilation errors above' % (filebase,))
         #
         import imp
         try:
@@ -75,15 +70,27 @@
 
     # ----------
 
-    def convert_to_c(self, tp, fromvar, tovar, errcode):
+    def convert_to_c(self, tp, fromvar, tovar, errcode, is_funcarg=False):
         if isinstance(tp, model.PrimitiveType):
-            self.prnt('  %s = _cffi_to_c_%s(%s);' % (
-                tovar, tp.name.replace(' ', '_'), fromvar))
-            self.prnt('  if (%s == (%s)-1 && PyErr_Occurred())' % (
-                tovar, tp.name))
-            self.prnt('    %s;' % errcode)
+            converter = '_cffi_to_c_%s' % tp.name.replace(' ', '_')
+            errvalue = '-1'
+        #
+        elif isinstance(tp, model.PointerType):
+            if (is_funcarg and
+                    isinstance(tp.totype, model.PrimitiveType) and
+                    tp.totype.name == 'char'):
+                converter = '_cffi_to_c_char_p'
+            else:
+                converter = '_cffi_to_c_pointer'
+            errvalue = 'NULL'
+        #
         else:
             raise NotImplementedError(tp)
+        #
+        self.prnt('  %s = %s(%s);' % (tovar, converter, fromvar))
+        self.prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
+            tovar, tp.get_c_name(''), errvalue))
+        self.prnt('    %s;' % errcode)
 
     def get_converter_from_c(self, tp):
         if isinstance(tp, model.PrimitiveType):
@@ -134,7 +141,8 @@
         prnt()
         #
         for i, type in enumerate(tp.args):
-            self.convert_to_c(type, 'arg%d' % i, 'x%d' % i, 'return NULL')
+            self.convert_to_c(type, 'arg%d' % i, 'x%d' % i, 'return NULL',
+                              is_funcarg=True)
             prnt()
         #
         prnt('  { %s%s(%s); }' % (
@@ -161,3 +169,39 @@
         self.prnt('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
 
     generate_cpy_function_init = generate_nothing
+
+
+cffimod_header = r'''
+#include <Python.h>
+
+#define _cffi_from_c_double PyFloat_FromDouble
+#define _cffi_to_c_double PyFloat_AsDouble
+#define _cffi_from_c_float PyFloat_FromDouble
+#define _cffi_to_c_float PyFloat_AsDouble
+
+#define _cffi_to_c_char_p ((char *(*)(PyObject *))_cffi_exports[0])
+
+
+static void **_cffi_exports;
+
+static int _cffi_init(void)
+{
+    PyObject *module = PyImport_ImportModule("_ffi_backend");
+    PyObject *c_api_object;
+
+    if (module == NULL)
+        return -1;
+
+    c_api_object = PyObject_GetAttrString(module, "_C_API");
+    if (c_api_object == NULL)
+        return -1;
+    if (!PyCObject_Check(c_api_object)) {
+        PyErr_SetNone(PyExc_ImportError);
+        return -1;
+    }
+    _cffi_exports = (void **)PyCObject_AsVoidPtr(c_api_object);
+    return 0;
+}
+
+/**********/
+'''


More information about the pypy-commit mailing list