[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