[pypy-commit] cffi default: Fix the issue. Tests pass but would need some review because it's

arigo noreply at buildbot.pypy.org
Sun Jun 17 11:11:51 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r397:b33e90bc3e69
Date: 2012-06-17 11:11 +0200
http://bitbucket.org/cffi/cffi/changeset/b33e90bc3e69/

Log:	Fix the issue. Tests pass but would need some review because it's
	slightly fragile... But it's enough to have the simple xclient.py
	demo work.

diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -127,6 +127,8 @@
 
     def _declare(self, name, obj):
         if name in self._declarations:
+            if self._declarations[name] is obj:
+                return
             raise api.FFIError("multiple declarations of %s" % (name,))
         assert name != '__dotdotdot__'
         self._declarations[name] = obj
@@ -292,6 +294,8 @@
             if name is not None:
                 self._declare(key, tp)
         tp.forcename = tp.forcename or force_name
+        if tp.forcename and '$' in tp.name:
+            self._declare('anonymous %s' % tp.forcename, tp)
         #
         self._structnode2type[type] = tp
         #
@@ -313,6 +317,9 @@
                 # of strings, but is sometimes just one string.  Use
                 # str.join() as a way to cope with both.
                 tp.partial = True
+                if not tp.has_c_name():
+                    raise api.CDefError("%s is partial but has no C name"
+                                        % (tp,))
                 continue
             if decl.bitsize is None:
                 bitsize = -1
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -10,6 +10,9 @@
                 % (result,))
         return result
 
+    def has_c_name(self):
+        return '$' not in self._get_c_name('')
+
     def __repr__(self):
         return '<%s>' % (self._get_c_name(''),)
 
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -123,7 +123,12 @@
     def generate(self, step_name):
         for name, tp in self.ffi._parser._declarations.iteritems():
             kind, realname = name.split(' ', 1)
-            method = getattr(self, 'generate_cpy_%s_%s' % (kind, step_name))
+            try:
+                method = getattr(self, 'generate_cpy_%s_%s' % (kind,
+                                                               step_name))
+            except AttributeError:
+                raise ffiplatform.VerificationError(
+                    "not implemented in verify(): %r" % name)
             method(tp, realname)
 
     def load(self, module, step_name, **kwds):
@@ -257,15 +262,30 @@
         setattr(library, name, getattr(module, name))
 
     # ----------
-    # struct declarations
+    # named structs
 
     def generate_cpy_struct_decl(self, tp, name):
+        assert name == tp.name
+        self._generate_struct_or_union_decl(tp, 'struct', name)
+
+    def generate_cpy_struct_method(self, tp, name):
+        self._generate_struct_or_union_method(tp, 'struct', name)
+
+    def loading_cpy_struct(self, tp, name, module):
+        self._loading_struct_or_union(tp, 'struct', name, module)
+
+    def loaded_cpy_struct(self, tp, name, module, **kwds):
+        self._loaded_struct_or_union(tp)
+
+    def _generate_struct_or_union_decl(self, tp, prefix, name):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        assert name == tp.name
+        checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        cname = ('%s %s' % (prefix, name)).strip()
+        #
         prnt = self.prnt
-        checkfuncname = '_cffi_check_%s' % (name,)
-        prnt('static void %s(struct %s *p)' % (checkfuncname, name))
+        prnt('static void %s(%s *p)' % (checkfuncname, cname))
         prnt('{')
         prnt('  /* only to generate compile-time warnings or errors */')
         for i in range(len(tp.fldnames)):
@@ -283,16 +303,16 @@
                     ftype.get_c_name('(*tmp)'), fname))
         prnt('}')
         prnt('static PyObject *')
-        prnt('_cffi_struct_%s(PyObject *self, PyObject *noarg)' % name)
+        prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
         prnt('{')
-        prnt('  struct _cffi_aligncheck { char x; struct %s y; };' % name)
+        prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
         if tp.partial:
             prnt('  static Py_ssize_t nums[] = {')
-            prnt('    sizeof(struct %s),' % name)
+            prnt('    sizeof(%s),' % cname)
             prnt('    offsetof(struct _cffi_aligncheck, y),')
             for fname in tp.fldnames:
-                prnt('    offsetof(struct %s, %s),' % (name, fname))
-                prnt('    sizeof(((struct %s *)0)->%s),' % (name, fname))
+                prnt('    offsetof(%s, %s),' % (cname, fname))
+                prnt('    sizeof(((%s *)0)->%s),' % (cname, fname))
             prnt('    -1')
             prnt('  };')
             prnt('  return _cffi_get_struct_layout(nums);')
@@ -300,16 +320,16 @@
             ffi = self.ffi
             BStruct = ffi._get_cached_btype(tp)
             conditions = [
-                'sizeof(struct %s) != %d' % (name, ffi.sizeof(BStruct)),
+                'sizeof(%s) != %d' % (cname, ffi.sizeof(BStruct)),
                 'offsetof(struct _cffi_aligncheck, y) != %d' % (
                     ffi.alignof(BStruct),)]
             for fname, ftype in zip(tp.fldnames, tp.fldtypes):
                 BField = ffi._get_cached_btype(ftype)
                 conditions += [
-                    'offsetof(struct %s, %s) != %d' % (
-                        name, fname, ffi.offsetof(BStruct, fname)),
-                    'sizeof(((struct %s *)0)->%s) != %d' % (
-                        name, fname, ffi.sizeof(BField))]
+                    'offsetof(%s, %s) != %d' % (
+                        cname, fname, ffi.offsetof(BStruct, fname)),
+                    'sizeof(((%s *)0)->%s) != %d' % (
+                        cname, fname, ffi.sizeof(BField))]
             prnt('  if (%s ||' % conditions[0])
             for i in range(1, len(conditions)-1):
                 prnt('      %s ||' % conditions[i])
@@ -326,21 +346,24 @@
         prnt('}')
         prnt()
 
-    def generate_cpy_struct_method(self, tp, name):
+    def _generate_struct_or_union_method(self, tp, prefix, name):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        self.prnt('  {"_cffi_struct_%s", _cffi_struct_%s, METH_NOARGS},' % (
-            name, name))
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        self.prnt('  {"%s", %s, METH_NOARGS},' % (layoutfuncname,
+                                                  layoutfuncname))
 
-    def loading_cpy_struct(self, tp, name, module):
+    def _loading_struct_or_union(self, tp, prefix, name, module):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
-        assert name == tp.name
-        function = getattr(module, '_cffi_struct_%s' % name)
+        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
+        cname = ('%s %s' % (prefix, name)).strip()
+        #
+        function = getattr(module, layoutfuncname)
         layout = function()
         if layout is False:
             raise ffiplatform.VerificationError(
-                "incompatible layout for struct %s" % name)
+                "incompatible layout for %s" % cname)
         elif layout is True:
             assert not tp.partial
         else:
@@ -351,12 +374,28 @@
             assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
             tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
 
-    def loaded_cpy_struct(self, tp, name, module, **kwds):
+    def _loaded_struct_or_union(self, tp):
         if tp.fldnames is None:
             return     # nothing to do with opaque structs
         self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered
 
     # ----------
+    # 'anonymous' declarations.  These are produced for anonymous structs
+    # or unions; the 'name' is obtained by a typedef.
+
+    def generate_cpy_anonymous_decl(self, tp, name):
+        self._generate_struct_or_union_decl(tp, '', name)
+
+    def generate_cpy_anonymous_method(self, tp, name):
+        self._generate_struct_or_union_method(tp, '', name)
+
+    def loading_cpy_anonymous(self, tp, name, module):
+        self._loading_struct_or_union(tp, '', name, module)
+
+    def loaded_cpy_anonymous(self, tp, name, module, **kwds):
+        self._loaded_struct_or_union(tp)
+
+    # ----------
     # constants, likely declared with '#define'
 
     def _generate_cpy_const(self, is_int, name, tp=None, category='const',
diff --git a/demo/xclient.py b/demo/xclient.py
new file mode 100644
--- /dev/null
+++ b/demo/xclient.py
@@ -0,0 +1,40 @@
+from cffi import FFI
+
+ffi = FFI()
+ffi.cdef("""
+
+typedef ... Display;
+typedef unsigned int Window;   /* 32-bit integer */
+
+typedef struct { int type; ...; } XEvent;
+
+Display *XOpenDisplay(char *display_name);
+Window DefaultRootWindow(Display *display);
+int XMapRaised(Display *display, Window w);
+Window XCreateSimpleWindow(Display *display, Window parent, int x, int y,
+                           unsigned int width, unsigned int height,
+                           unsigned int border_width, unsigned long border,
+                           unsigned long background);
+int XNextEvent(Display *display, XEvent *event_return);
+""")
+lib = ffi.verify("""
+#include <X11/Xlib.h>
+""", libraries=['X11'])
+
+globals().update(lib.__dict__)
+
+class XError(Exception):
+    pass
+
+def main():
+    display = XOpenDisplay(None)
+    if display is None:
+        raise XError("cannot open display")
+    w = XCreateSimpleWindow(display, DefaultRootWindow(display),
+                            10, 10, 500, 350, 0, 0, 0)
+    XMapRaised(display, w)
+    event = ffi.new("XEvent")
+    XNextEvent(display, event)
+
+if __name__ == '__main__':
+    main()
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -156,8 +156,7 @@
              "typedef struct { int y; } *bar_p;\n")
     assert 'typedef foo_t' in ffi._parser._declarations
     assert 'typedef bar_p' in ffi._parser._declarations
-    #assert 'structdef foo_t' in ffi._parser._declarations ...
-    #assert 'structdef bar_p' in ffi._parser._declarations
+    assert 'anonymous foo_t' in ffi._parser._declarations
     type_foo = ffi._parser.parse_type("foo_t")
     type_bar = ffi._parser.parse_type("bar_p").totype
     assert repr(type_foo) == "<foo_t>"


More information about the pypy-commit mailing list