[pypy-commit] cffi default: hg merge cpy-extension

arigo noreply at buildbot.pypy.org
Thu Jun 14 13:39:25 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r334:57830003252d
Date: 2012-06-14 13:39 +0200
http://bitbucket.org/cffi/cffi/changeset/57830003252d/

Log:	hg merge cpy-extension

diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -22,28 +22,11 @@
 Next steps
 ----------
 
-the verify() step, which should handle:
+the verify() step, which is missing:
 
-* completing "...;" structs
+* global variables
 
-* checking the other structs, and the arguments to functions, using the real C compiler
+* typedef ... some_integer_type;
 
-* simple "#define FOO value" macros
-
-* macros of the kind "#define funcname otherfuncname"
-
-* more complicated macros "#define foo(a, b, c) ..."
-
-* checking and correcting the value of the enum {} declarations
-
-* probably also fixing the array lengths, e.g. declared as a field "int foo[...];"
-
-generating C extensions:
-
-* this is needed anyway to call macros
-
-* faster, libffi-free way to call C code
-
-* partial blockers: callbacks (probably still use libffi)
 
 _ffi backend for PyPy
diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -579,10 +579,55 @@
     return 0;
 }
 
+static int _convert_overflow(PyObject *init, const char *ct_name)
+{
+    PyObject *s;
+    if (PyErr_Occurred())   /* already an exception pending */
+        return -1;
+    s = PyObject_Str(init);
+    if (s == NULL)
+        return -1;
+    PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'",
+                 PyString_AS_STRING(s), ct_name);
+    Py_DECREF(s);
+    return -1;
+}
+
+static int _convert_to_char(PyObject *init)
+{
+    if (PyString_Check(init) && PyString_GET_SIZE(init) == 1) {
+        return (unsigned char)(PyString_AS_STRING(init)[0]);
+    }
+    if (CData_Check(init) &&
+           (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR)) {
+        return (unsigned char)(((CDataObject *)init)->c_data[0]);
+    }
+    PyErr_Format(PyExc_TypeError,
+                 "initializer for ctype 'char' must be a string of length 1, "
+                 "not %.200s", Py_TYPE(init)->tp_name);
+    return -1;
+}
+
+static int _convert_error(PyObject *init, const char *ct_name,
+                          const char *expected)
+{
+    if (CData_Check(init))
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not cdata '%s'",
+                     ct_name, expected,
+                     ((CDataObject *)init)->c_type->ct_name);
+    else
+        PyErr_Format(PyExc_TypeError,
+                     "initializer for ctype '%s' must be a %s, "
+                     "not %.200s",
+                     ct_name, expected, Py_TYPE(init)->tp_name);
+    return -1;
+}
+
 static int
 convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init)
 {
-    PyObject *s;
     const char *expected;
     char buf[sizeof(PY_LONG_LONG)];
 
@@ -695,17 +740,11 @@
         return 0;
     }
     if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
-        if (PyString_Check(init) && PyString_GET_SIZE(init) == 1) {
-            data[0] = PyString_AS_STRING(init)[0];
-            return 0;
-        }
-        if (CData_Check(init) &&
-               (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR)) {
-            data[0] = ((CDataObject *)init)->c_data[0];
-            return 0;
-        }
-        expected = "string of length 1";
-        goto cannot_convert;
+        int res = _convert_to_char(init);
+        if (res < 0)
+            return -1;
+        data[0] = res;
+        return 0;
     }
     if (ct->ct_flags & CT_STRUCT) {
 
@@ -773,27 +812,10 @@
     return -1;
 
  overflow:
-    s = PyObject_Str(init);
-    if (s == NULL)
-        return -1;
-    PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'",
-                 PyString_AS_STRING(s), ct->ct_name);
-    Py_DECREF(s);
-    return -1;
+    return _convert_overflow(init, ct->ct_name);
 
  cannot_convert:
-    if (CData_Check(init))
-        PyErr_Format(PyExc_TypeError,
-                     "initializer for ctype '%s' must be a %s, "
-                     "not cdata '%s'",
-                     ct->ct_name, expected,
-                     ((CDataObject *)init)->c_type->ct_name);
-    else
-        PyErr_Format(PyExc_TypeError,
-                     "initializer for ctype '%s' must be a %s, "
-                     "not %.200s",
-                     ct->ct_name, expected, Py_TYPE(init)->tp_name);
-    return -1;
+    return _convert_error(init, ct->ct_name, expected);
 }
 
 static int
@@ -1210,8 +1232,8 @@
                             ctptr);
 
  not_implemented:
-    Py_INCREF(Py_NotImplemented);               \
-    return Py_NotImplemented;                   \
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
 }
 
 static PyObject *
@@ -1988,7 +2010,7 @@
         { "ptrdiff_t",     sizeof(ptrdiff_t) },
         { "size_t",        sizeof(size_t) | UNSIGNED },
         { "ssize_t",       sizeof(ssize_t) },
-        { "wchar_t",       sizeof(wchar_t) | UNSIGNED },
+        /*{ "wchar_t",       sizeof(wchar_t) | UNSIGNED },*/
         { NULL }
     };
 #undef UNSIGNED
@@ -2127,12 +2149,17 @@
 static PyObject *b_new_pointer_type(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *td, *ctitem;
+    const char *extra;
 
     if (!PyArg_ParseTuple(args, "O!:new_pointer_type",
                           &CTypeDescr_Type, &ctitem))
         return NULL;
 
-    td = ctypedescr_new_on_top(ctitem, " *", 2);
+    if (ctitem->ct_flags & CT_ARRAY)
+        extra = "(*)";   /* obscure case: see test_array_add */
+    else
+        extra = " *";
+    td = ctypedescr_new_on_top(ctitem, extra, 2);
     if (td == NULL)
         return NULL;
 
@@ -2249,12 +2276,14 @@
     PyObject *fields, *interned_fields, *ignored;
     int is_union, alignment;
     Py_ssize_t offset, i, nb_fields, maxsize, prev_bit_position;
+    Py_ssize_t totalsize = -1;
+    int totalalignment = -1;
     CFieldObject **previous, *prev_field;
 
-    if (!PyArg_ParseTuple(args, "O!O!|O:complete_struct_or_union",
+    if (!PyArg_ParseTuple(args, "O!O!|Oni:complete_struct_or_union",
                           &CTypeDescr_Type, &ct,
                           &PyList_Type, &fields,
-                          &ignored))
+                          &ignored, &totalsize, &totalalignment))
         return NULL;
 
     if ((ct->ct_flags & (CT_STRUCT|CT_IS_OPAQUE)) ==
@@ -2286,19 +2315,19 @@
     for (i=0; i<nb_fields; i++) {
         PyObject *fname;
         CTypeDescrObject *ftype;
-        int fbitsize, falign, err, bitshift;
+        int fbitsize, falign, err, bitshift, foffset = -1;
         CFieldObject *cf;
 
-        if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!i:list item",
+        if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!i|i:list item",
                               &PyString_Type, &fname,
                               &CTypeDescr_Type, &ftype,
-                              &fbitsize))
+                              &fbitsize, &foffset))
             goto error;
 
         if (ftype->ct_size < 0) {
             PyErr_Format(PyExc_TypeError,
-                         "field '%s' has ctype '%s' of unknown size",
-                         PyString_AS_STRING(fname),
+                         "field '%s.%s' has ctype '%s' of unknown size",
+                         ct->ct_name, PyString_AS_STRING(fname),
                          ftype->ct_name);
             goto error;
         }
@@ -2309,8 +2338,12 @@
         if (alignment < falign)
             alignment = falign;
 
-        /* align this field to its own 'falign' by inserting padding */
-        offset = (offset + falign - 1) & ~(falign-1);
+        if (foffset < 0) {
+            /* align this field to its own 'falign' by inserting padding */
+            offset = (offset + falign - 1) & ~(falign-1);
+        }
+        else
+            offset = foffset;
 
         if (fbitsize < 0 || (fbitsize == 8 * ftype->ct_size &&
                              !(ftype->ct_flags & CT_PRIMITIVE_CHAR))) {
@@ -2385,15 +2418,23 @@
 
     if (is_union) {
         assert(offset == 0);
-        ct->ct_size = maxsize;
+        offset = maxsize;
     }
     else {
         if (offset == 0)
             offset = 1;
         offset = (offset + alignment - 1) & ~(alignment-1);
-        ct->ct_size = offset;
     }
-    ct->ct_length = alignment;
+    if (totalsize < 0)
+        totalsize = offset;
+    else if (totalsize < offset) {
+        PyErr_Format(PyExc_TypeError,
+                     "%s cannot be of size %zd: there are fields at least "
+                     "up to %zd", ct->ct_name, totalsize, offset);
+        goto error;
+    }
+    ct->ct_size = totalsize;
+    ct->ct_length = totalalignment < 0 ? alignment : totalalignment;
     ct->ct_stuff = interned_fields;
     ct->ct_flags &= ~CT_IS_OPAQUE;
 
@@ -3005,40 +3046,35 @@
     return PyInt_FromLong(align);
 }
 
-static PyObject *b_sizeof_type(PyObject *self, PyObject *arg)
+static PyObject *b_sizeof(PyObject *self, PyObject *arg)
 {
-    if (!CTypeDescr_Check(arg)) {
-        PyErr_SetString(PyExc_TypeError, "expected a 'ctype' object");
+    Py_ssize_t size;
+
+    if (CData_Check(arg)) {
+        CDataObject *cd = (CDataObject *)arg;
+
+        if (cd->c_type->ct_flags & CT_ARRAY)
+            size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+        else
+            size = cd->c_type->ct_size;
+    }
+    else if (CTypeDescr_Check(arg)) {
+        if (((CTypeDescrObject *)arg)->ct_size < 0) {
+            PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size",
+                         ((CTypeDescrObject *)arg)->ct_name);
+            return NULL;
+        }
+        size = ((CTypeDescrObject *)arg)->ct_size;
+    }
+    else {
+        PyErr_SetString(PyExc_TypeError,
+                        "expected a 'cdata' or 'ctype' object");
         return NULL;
     }
-    if (((CTypeDescrObject *)arg)->ct_size < 0) {
-        PyErr_Format(PyExc_ValueError, "ctype '%s' is of unknown size",
-                     ((CTypeDescrObject *)arg)->ct_name);
-        return NULL;
-    }
-    return PyInt_FromSsize_t(((CTypeDescrObject *)arg)->ct_size);
-}
-
-static PyObject *b_sizeof_instance(PyObject *self, PyObject *arg)
-{
-    CDataObject *cd;
-    Py_ssize_t size;
-
-    if (!CData_Check(arg)) {
-        PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object");
-        return NULL;
-    }
-    cd = (CDataObject *)arg;
-
-    if (cd->c_type->ct_flags & CT_ARRAY)
-        size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
-    else
-        size = cd->c_type->ct_size;
-
     return PyInt_FromSsize_t(size);
 }
 
-static PyObject *b_typeof_instance(PyObject *self, PyObject *arg)
+static PyObject *b_typeof(PyObject *self, PyObject *arg)
 {
     PyObject *res;
 
@@ -3230,9 +3266,8 @@
     {"cast", b_cast, METH_VARARGS},
     {"callback", b_callback, METH_VARARGS},
     {"alignof", b_alignof, METH_O},
-    {"sizeof_type", b_sizeof_type, METH_O},
-    {"sizeof_instance", b_sizeof_instance, METH_O},
-    {"typeof_instance", b_typeof_instance, METH_O},
+    {"sizeof", b_sizeof, METH_O},
+    {"typeof", b_typeof, METH_O},
     {"offsetof", b_offsetof, METH_VARARGS},
     {"string", b_string, METH_VARARGS},
     {"get_errno", b_get_errno, METH_NOARGS},
@@ -3242,6 +3277,121 @@
     {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;
+    }
+    _convert_error(obj, "char *", "compatible pointer");
+    return NULL;
+}
+
+#define _cffi_to_c_PRIMITIVE(TARGETNAME, TARGET)        \
+static TARGET _cffi_to_c_##TARGETNAME(PyObject *obj) {  \
+    long tmp = PyInt_AsLong(obj);                       \
+    if (tmp != (TARGET)tmp)                             \
+        return (TARGET)_convert_overflow(obj, #TARGET); \
+    return (TARGET)tmp;                                 \
+}
+
+_cffi_to_c_PRIMITIVE(signed_char,    signed char)
+_cffi_to_c_PRIMITIVE(unsigned_char,  unsigned char)
+_cffi_to_c_PRIMITIVE(short,          short)
+_cffi_to_c_PRIMITIVE(unsigned_short, unsigned short)
+#if SIZEOF_INT < SIZEOF_LONG
+_cffi_to_c_PRIMITIVE(int,            int)
+_cffi_to_c_PRIMITIVE(unsigned_int,   unsigned int)
+#endif
+
+#if SIZEOF_LONG < SIZEOF_LONG_LONG
+static unsigned long _cffi_to_c_unsigned_long(PyObject *obj)
+{
+    unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(obj, 1);
+    if (value != (unsigned long)value)
+        return (unsigned long)_convert_overflow(obj, "unsigned long");
+    return (unsigned long)value;
+}
+#else
+#  define _cffi_to_c_unsigned_long _cffi_to_c_unsigned_long_long
+#endif
+
+static unsigned PY_LONG_LONG _cffi_to_c_unsigned_long_long(PyObject *obj)
+{
+    return _my_PyLong_AsUnsignedLongLong(obj, 1);
+}
+
+static char _cffi_to_c_char(PyObject *obj)
+{
+    return (char)_convert_to_char(obj);
+}
+
+static PyObject *_cffi_from_c_pointer(char *ptr, CTypeDescrObject *ct)
+{
+    return convert_to_object((char *)&ptr, ct);
+}
+
+static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct)
+{
+    char *result;
+    if (convert_from_object((char *)&result, ct, obj) < 0)
+        return NULL;
+    return result;
+}
+
+static PyObject *_cffi_get_struct_layout(Py_ssize_t nums[])
+{
+    PyObject *result;
+    int count = 0;
+    while (nums[count] >= 0)
+        count++;
+
+    result = PyList_New(count);
+    if (result == NULL)
+        return NULL;
+
+    while (--count >= 0) {
+        PyObject *o = PyInt_FromSsize_t(nums[count]);
+        if (o == NULL) {
+            Py_DECREF(result);
+            return NULL;
+        }
+        PyList_SET_ITEM(result, count, o);
+    }
+    return result;
+}
+
+static void *cffi_exports[] = {
+    _cffi_to_c_char_p,
+    _cffi_to_c_signed_char,
+    _cffi_to_c_unsigned_char,
+    _cffi_to_c_short,
+    _cffi_to_c_unsigned_short,
+#if SIZEOF_INT < SIZEOF_LONG
+    _cffi_to_c_int,
+    _cffi_to_c_unsigned_int,
+#else
+    0,
+    0,
+#endif
+    _cffi_to_c_unsigned_long,
+    _cffi_to_c_unsigned_long_long,
+    _cffi_to_c_char,
+    _cffi_from_c_pointer,
+    _cffi_to_c_pointer,
+    _cffi_get_struct_layout,
+};
+
+/************************************************************/
+
 void init_ffi_backend(void)
 {
     PyObject *m, *v;
@@ -3270,4 +3420,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/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -11,16 +11,16 @@
 
 def size_of_int():
     BInt = new_primitive_type("int")
-    return sizeof_type(BInt)
+    return sizeof(BInt)
 
 def size_of_long():
     BLong = new_primitive_type("long")
-    return sizeof_type(BLong)
+    return sizeof(BLong)
 
 def size_of_ptr():
     BInt = new_primitive_type("int")
     BPtr = new_pointer_type(BInt)
-    return sizeof_type(BPtr)
+    return sizeof(BPtr)
 
 
 def test_load_library():
@@ -55,14 +55,14 @@
     assert (x != cast(q, -66)) is True
 
 def test_sizeof_type():
-    py.test.raises(TypeError, sizeof_type, 42.5)
+    py.test.raises(TypeError, sizeof, 42.5)
     p = new_primitive_type("short")
-    assert sizeof_type(p) == 2
+    assert sizeof(p) == 2
 
 def test_integer_types():
     for name in ['signed char', 'short', 'int', 'long', 'long long']:
         p = new_primitive_type(name)
-        size = sizeof_type(p)
+        size = sizeof(p)
         min = -(1 << (8*size-1))
         max = (1 << (8*size-1)) - 1
         assert int(cast(p, min)) == min
@@ -72,7 +72,7 @@
         assert long(cast(p, min - 1)) == max
     for name in ['char', 'short', 'int', 'long', 'long long']:
         p = new_primitive_type('unsigned ' + name)
-        size = sizeof_type(p)
+        size = sizeof(p)
         max = (1 << (8*size)) - 1
         assert int(cast(p, 0)) == 0
         assert int(cast(p, max)) == max
@@ -268,6 +268,20 @@
         assert a[i] == 100 + i
     assert a[42] == 0      # extra uninitialized item
 
+def test_array_add():
+    p = new_primitive_type("int")
+    p1 = new_array_type(new_pointer_type(p), 5)    # int[5]
+    p2 = new_array_type(new_pointer_type(p1), 3)   # int[3][5]
+    a = newp(p2, [range(n, n+5) for n in [100, 200, 300]])
+    assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
+        3*5*size_of_int(),)
+    assert repr(a + 0) == "<cdata 'int(*)[5]'>"
+    assert repr(a[0]) == "<cdata 'int[5]'>"
+    assert repr((a + 0)[0]) == "<cdata 'int[5]'>"
+    assert repr(a[0] + 0) == "<cdata 'int *'>"
+    assert type(a[0][0]) is int
+    assert type((a[0] + 0)[0]) is int
+
 def test_cast_primitive_from_cdata():
     p = new_primitive_type("int")
     n = cast(p, cast(p, -42))
@@ -338,9 +352,9 @@
 
 def test_alignof():
     BInt = new_primitive_type("int")
-    assert alignof(BInt) == sizeof_type(BInt)
+    assert alignof(BInt) == sizeof(BInt)
     BPtr = new_pointer_type(BInt)
-    assert alignof(BPtr) == sizeof_type(BPtr)
+    assert alignof(BPtr) == sizeof(BPtr)
     BArray = new_array_type(BPtr, None)
     assert alignof(BArray) == alignof(BInt)
 
@@ -374,15 +388,15 @@
     assert d[0][1].bitsize == -1
     assert d[1][0] == 'a2'
     assert d[1][1].type is BChar
-    assert d[1][1].offset == sizeof_type(BLong)
+    assert d[1][1].offset == sizeof(BLong)
     assert d[1][1].bitshift == -1
     assert d[1][1].bitsize == -1
     assert d[2][0] == 'a3'
     assert d[2][1].type is BShort
-    assert d[2][1].offset == sizeof_type(BLong) + sizeof_type(BShort)
+    assert d[2][1].offset == sizeof(BLong) + sizeof(BShort)
     assert d[2][1].bitshift == -1
     assert d[2][1].bitsize == -1
-    assert sizeof_type(BStruct) == 2 * sizeof_type(BLong)
+    assert sizeof(BStruct) == 2 * sizeof(BLong)
     assert alignof(BStruct) == alignof(BLong)
 
 def test_complete_union():
@@ -400,7 +414,7 @@
     assert d[1][0] == 'a2'
     assert d[1][1].type is BChar
     assert d[1][1].offset == 0
-    assert sizeof_type(BUnion) == sizeof_type(BLong)
+    assert sizeof(BUnion) == sizeof(BLong)
     assert alignof(BUnion) == alignof(BLong)
 
 def test_struct_instance():
@@ -446,6 +460,15 @@
     assert s.a2 == 456
     assert s.a3 == 0
 
+def test_array_in_struct():
+    BInt = new_primitive_type("int")
+    BStruct = new_struct_type("foo")
+    BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
+    complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
+    s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
+    assert s.a1[2] == 27
+    assert repr(s.a1) == "<cdata 'int[5]'>"
+
 def test_offsetof():
     BInt = new_primitive_type("int")
     BStruct = new_struct_type("foo")
@@ -505,7 +528,7 @@
     BLongLong = new_primitive_type("long long")
     BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False)
     f = cast(BFunc2, _testfunc(2))
-    longlong_max = (1 << (8*sizeof_type(BLongLong)-1)) - 1
+    longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1
     assert f(longlong_max - 42, 42) == longlong_max
     assert f(43, longlong_max - 42) == - longlong_max - 1
 
@@ -539,7 +562,7 @@
     f = cast(BFunc6, _testfunc(6))
     x = newp(BIntPtr, 42)
     res = f(x)
-    assert typeof_instance(res) is BIntPtr
+    assert typeof(res) is BIntPtr
     assert res[0] == 42 - 1000
     #
     BIntArray = new_array_type(BIntPtr, None)
@@ -550,7 +573,7 @@
     #
     x = newp(BIntArray, [242])
     res = f(x)
-    assert typeof_instance(res) is BIntPtr
+    assert typeof(res) is BIntPtr
     assert res[0] == 242 - 1000
 
 def test_call_function_7():
@@ -660,14 +683,14 @@
 def test_struct_with_bitfields():
     BLong = new_primitive_type("long")
     BStruct = new_struct_type("foo")
-    LONGBITS = 8 * sizeof_type(BLong)
+    LONGBITS = 8 * sizeof(BLong)
     complete_struct_or_union(BStruct, [('a1', BLong, 1),
                                        ('a2', BLong, 2),
                                        ('a3', BLong, 3),
                                        ('a4', BLong, LONGBITS - 5)])
     d = _getfields(BStruct)
     assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
-    assert d[3][1].offset == sizeof_type(BLong)
+    assert d[3][1].offset == sizeof(BLong)
     assert d[0][1].bitshift == 0
     assert d[0][1].bitsize == 1
     assert d[1][1].bitshift == 1
@@ -676,7 +699,7 @@
     assert d[2][1].bitsize == 3
     assert d[3][1].bitshift == 0
     assert d[3][1].bitsize == LONGBITS - 5
-    assert sizeof_type(BStruct) == 2 * sizeof_type(BLong)
+    assert sizeof(BStruct) == 2 * sizeof(BLong)
     assert alignof(BStruct) == alignof(BLong)
 
 def test_bitfield_instance():
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -22,7 +22,12 @@
         ffi.cdef("""
             int printf(const char *, ...);
         """)
-        ffi.C.printf("hello, %s!\n", ffi.new("char[]", "world"))
+
+        C = ffi.rawload(name=None)   # standard library
+        -or-
+        C = ffi.verify()  # use a C compiler: verify the decl above is right
+
+        C.printf("hello, %s!\n", ffi.new("char[]", "world"))
     '''
 
     def __init__(self, backend=None):
@@ -46,7 +51,6 @@
         self._new_types = new.module('new_types').__dict__
         if hasattr(backend, 'set_ffi'):
             backend.set_ffi(self)
-        self.C = _make_ffi_library(self, None)
         #
         lines = []
         by_size = {}
@@ -64,19 +68,19 @@
     def cdef(self, csource):
         """Parse the given C source.  This registers all declared functions,
         types, and global variables.  The functions and global variables can
-        then be accessed via 'ffi.C' or 'ffi.load()'.  The types can be used
+        then be accessed via 'ffi.rawload()'.  The types can be used
         in 'ffi.new()' and other functions.
         """
         self._parser.parse(csource)
 
-    def load(self, name):
+    def rawload(self, name):
         """Load and return a dynamic library identified by 'name'.
-        The standard C library is preloaded into 'ffi.C'.
+        The standard C library can be loaded by passing None.
         Note that functions and types declared by 'ffi.cdef()' are not
         linked to a particular library, just like C headers; in the
         library we only look for the actual (untyped) symbols.
         """
-        assert isinstance(name, str)
+        assert isinstance(name, str) or name is None
         return _make_ffi_library(self, name)
 
     def typeof(self, cdecl):
@@ -89,11 +93,11 @@
                 return self._parsed_types[cdecl]
             except KeyError:
                 type = self._parser.parse_type(cdecl)
-                btype = type.get_backend_type(self)
+                btype = self._get_cached_btype(type)
                 self._parsed_types[cdecl] = btype
                 return btype
         else:
-            return self._backend.typeof_instance(cdecl)
+            return self._backend.typeof(cdecl)
 
     def sizeof(self, cdecl):
         """Return the size in bytes of the argument.  It can be a
@@ -101,23 +105,25 @@
         """
         if isinstance(cdecl, basestring):
             BType = self.typeof(cdecl)
-            return self._backend.sizeof_type(BType)
+            return self._backend.sizeof(BType)
         else:
-            return self._backend.sizeof_instance(cdecl)
+            return self._backend.sizeof(cdecl)
 
     def alignof(self, cdecl):
         """Return the natural alignment size in bytes of the C type
         given as a string.
         """
-        BType = self.typeof(cdecl)
-        return self._backend.alignof(BType)
+        if isinstance(cdecl, basestring):
+            cdecl = self.typeof(cdecl)
+        return self._backend.alignof(cdecl)
 
     def offsetof(self, cdecl, fieldname):
         """Return the offset of the named field inside the given
         structure, which must be given as a C type name.
         """
-        BType = self.typeof(cdecl)
-        return self._backend.offsetof(BType, fieldname)
+        if isinstance(cdecl, basestring):
+            cdecl = self.typeof(cdecl)
+        return self._backend.offsetof(cdecl, fieldname)
 
     def new(self, cdecl, init=None):
         """Allocate an instance 'x' of the named C type, and return a
@@ -141,7 +147,7 @@
             BType = self._new_types[cdecl]
         except KeyError:
             type = self._parser.parse_type(cdecl, force_pointer=True)
-            BType = type.get_backend_type(self)
+            BType = self._get_cached_btype(type)
             self._new_types[cdecl] = BType
         #
         return self._backend.newp(BType, init)
@@ -179,10 +185,16 @@
         return BType
 
     def verify(self, preamble='', **kwargs):
-        """ Verify that the current ffi signatures compile on this machine
+        """Verify that the current ffi signatures compile on this
+        machine, and return a dynamic library object.  The dynamic
+        library can be used to call functions and access global
+        variables declared in this 'ffi'.  The library is compiled
+        by the C compiler: it gives you C-level API compatibility
+        (including calling macros).  This is unlike 'ffi.rawload()',
+        which requires binary compatibility in the signatures.
         """
         from .verifier import Verifier
-        return Verifier().verify(self, preamble, **kwargs)
+        return Verifier(self).verify(preamble, **kwargs)
 
 def _make_ffi_library(ffi, libname):
     name = libname
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -77,6 +77,10 @@
     __slots__ = []
 
 
+class CTypesGenericArray(CTypesData):
+    __slots__ = []
+
+
 class CTypesGenericPtr(CTypesData):
     __slots__ = ['_address', '_as_ctype_ptr']
     _automatic_casts = False
@@ -208,8 +212,8 @@
             if size == ctypes.sizeof(ctypes.c_size_t):
                 result['size_t'] = size | UNSIGNED
                 result['ssize_t'] = size
-            if size == ctypes.sizeof(ctypes.c_wchar):
-                result['wchar_t'] = size | UNSIGNED
+            #if size == ctypes.sizeof(ctypes.c_wchar):
+            #    result['wchar_t'] = size | UNSIGNED
         return result
 
     def load_library(self, path):
@@ -366,7 +370,10 @@
                 _bitem_size = ctypes.sizeof(BItem._ctype)
             else:
                 _ctype = ctypes.c_void_p
-            _reftypename = BItem._get_c_name(' * &')
+            if issubclass(BItem, CTypesGenericArray):
+                _reftypename = BItem._get_c_name('(* &)')
+            else:
+                _reftypename = BItem._get_c_name(' * &')
 
             def __init__(self, init):
                 ctypeobj = BItem._create_ctype_obj(init)
@@ -436,7 +443,7 @@
         else:
             kind = 'generic'
         #
-        class CTypesArray(CTypesData):
+        class CTypesArray(CTypesGenericArray):
             __slots__ = ['_blob', '_own']
             if length is not None:
                 _ctype = BItem._ctype * length
@@ -760,13 +767,12 @@
         p = ctypes.cast(bptr._as_ctype_ptr, ctypes.POINTER(ctypes.c_char))
         return ''.join([p[i] for i in range(length)])
 
-    def sizeof_type(self, BType):
-        assert issubclass(BType, CTypesData)
-        return BType._get_size()
-
-    def sizeof_instance(self, cdata):
-        assert isinstance(cdata, CTypesData)
-        return cdata._get_size_of_instance()
+    def sizeof(self, cdata_or_BType):
+        if isinstance(cdata_or_BType, CTypesData):
+            return cdata_or_BType._get_size_of_instance()
+        else:
+            assert issubclass(cdata_or_BType, CTypesData)
+            return cdata_or_BType._get_size()
 
     def alignof(self, BType):
         assert issubclass(BType, CTypesData)
@@ -785,7 +791,7 @@
     def callback(self, BType, source):
         return BType(source)
 
-    typeof_instance = type
+    typeof = type
 
 
 class CTypesLibrary(object):
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -1,7 +1,10 @@
 
 from . import api, model
-import pycparser, weakref
+import pycparser, weakref, re
 
+_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE)
+_r_partial_enum = re.compile(r"\.\.\.\s*\}")
+_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
 _parser_cache = None
 
 def _get_parser():
@@ -10,26 +13,66 @@
         _parser_cache = pycparser.CParser()
     return _parser_cache
 
+def _preprocess(csource):
+    # Remove comments.  NOTE: this only work because the cdef() section
+    # should not contain any string literal!
+    csource = _r_comment.sub(' ', csource)
+    # Replace "...}" with "__dotdotdotNUM__}".  This construction should
+    # occur only at the end of enums; at the end of structs we have "...;}"
+    # and at the end of vararg functions "...);"
+    matches = list(_r_partial_enum.finditer(csource))
+    for number, match in enumerate(reversed(matches)):
+        p = match.start()
+        assert csource[p:p+3] == '...'
+        csource = '%s __dotdotdot%d__ %s' % (csource[:p], number,
+                                             csource[p+3:])
+    # Replace all remaining "..." with the same name, "__dotdotdot__",
+    # which is declared with a typedef for the purpose of C parsing.
+    return csource.replace('...', ' __dotdotdot__ ')
+
 class Parser(object):
     def __init__(self):
         self._declarations = {}
         self._anonymous_counter = 0
         self._structnode2type = weakref.WeakKeyDictionary()
 
+    def _parse(self, csource):
+        # XXX: for more efficiency we would need to poke into the
+        # internals of CParser...  the following registers the
+        # typedefs, because their presence or absence influences the
+        # parsing itself (but what they are typedef'ed to plays no role)
+        csourcelines = []
+        for name in sorted(self._declarations):
+            if name.startswith('typedef '):
+                csourcelines.append('typedef int %s;' % (name[8:],))
+        csourcelines.append('typedef int __dotdotdot__;')
+        csourcelines.append(_preprocess(csource))
+        csource = '\n'.join(csourcelines)
+        ast = _get_parser().parse(csource)
+        return ast
+
     def parse(self, csource):
-        csource = ("typedef int __dotdotdot__;\n" +
-                   csource.replace('...', '__dotdotdot__'))
-        ast = _get_parser().parse(csource)
-        for decl in ast.ext:
+        ast = self._parse(csource)
+        # find the first "__dotdotdot__" and use that as a separator
+        # between the repeated typedefs and the real csource
+        iterator = iter(ast.ext)
+        for decl in iterator:
+            if decl.name == '__dotdotdot__':
+                break
+        #
+        for decl in iterator:
             if isinstance(decl, pycparser.c_ast.Decl):
                 self._parse_decl(decl)
             elif isinstance(decl, pycparser.c_ast.Typedef):
                 if not decl.name:
                     raise api.CDefError("typedef does not declare any name",
                                         decl)
-                if decl.name != '__dotdotdot__':
-                    self._declare('typedef ' + decl.name,
-                                  self._get_type(decl.type))
+                if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
+                        and decl.type.type.names == ['__dotdotdot__']):
+                    realtype = model.OpaqueType(decl.name)
+                else:
+                    realtype = self._get_type(decl.type)
+                self._declare('typedef ' + decl.name, realtype)
             else:
                 raise api.CDefError("unrecognized construct", decl)
 
@@ -54,33 +97,28 @@
                                     decl)
             #
             if decl.name:
-                self._declare('variable ' + decl.name, self._get_type(node))
+                tp = self._get_type(node)
+                if 'const' in decl.quals:
+                    self._declare('constant ' + decl.name, tp)
+                else:
+                    self._declare('variable ' + decl.name, tp)
 
-    def parse_type(self, cdecl, force_pointer=False,
-                   convert_array_to_pointer=False):
-        # XXX: for more efficiency we would need to poke into the
-        # internals of CParser...  the following registers the
-        # typedefs, because their presence or absence influences the
-        # parsing itself (but what they are typedef'ed to plays no role)
-        csourcelines = []
-        for name in sorted(self._declarations):
-            if name.startswith('typedef '):
-                csourcelines.append('typedef int %s;' % (name[8:],))
-        #
-        csourcelines.append('void __dummy(%s);' % cdecl)
-        ast = _get_parser().parse('\n'.join(csourcelines))
+    def parse_type(self, cdecl, force_pointer=False):
+        ast = self._parse('void __dummy(%s);' % cdecl)
         typenode = ast.ext[-1].type.args.params[0].type
-        return self._get_type(typenode, force_pointer=force_pointer,
-                              convert_array_to_pointer=convert_array_to_pointer)
+        return self._get_type(typenode, force_pointer=force_pointer)
 
     def _declare(self, name, obj):
         if name in self._declarations:
             raise api.FFIError("multiple declarations of %s" % (name,))
+        assert name != '__dotdotdot__'
         self._declarations[name] = obj
 
-    def _get_type_pointer(self, type):
+    def _get_type_pointer(self, type, const=False):
         if isinstance(type, model.FunctionType):
             return type # "pointer-to-function" ~== "function"
+        if const:
+            return model.ConstPointerType(type)
         return model.PointerType(type)
 
     def _get_type(self, typenode, convert_array_to_pointer=False,
@@ -114,7 +152,10 @@
         #
         if isinstance(typenode, pycparser.c_ast.PtrDecl):
             # pointer type
-            return self._get_type_pointer(self._get_type(typenode.type))
+            const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl)
+                     and 'const' in typenode.type.quals)
+            return self._get_type_pointer(self._get_type(typenode.type), const)
+                                          
         #
         if isinstance(typenode, pycparser.c_ast.TypeDecl):
             type = typenode.type
@@ -132,6 +173,8 @@
                 ident = ' '.join(names)
                 if ident == 'void':
                     return model.void_type
+                if ident == '__dotdotdot__':
+                    raise api.FFIError('bad usage of "..."')
                 return model.PrimitiveType(ident)
             #
             if isinstance(type, pycparser.c_ast.Struct):
@@ -152,7 +195,7 @@
         #
         raise api.FFIError("bad or unsupported type declaration")
 
-    def _parse_function_type(self, typenode, name=None):
+    def _parse_function_type(self, typenode, funcname=None):
         params = list(getattr(typenode.args, 'params', []))
         ellipsis = (
             len(params) > 0 and
@@ -171,7 +214,7 @@
                                convert_array_to_pointer=True)
                 for argdeclnode in params]
         result = self._get_type(typenode.type)
-        return model.FunctionType(name, tuple(args), result, ellipsis)
+        return model.FunctionType(tuple(args), result, ellipsis)
 
     def _get_struct_or_union_type(self, kind, type, typenode=None):
         # First, a level of caching on the exact 'type' node of the AST.
@@ -238,10 +281,11 @@
         for decl in type.decls:
             if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
                     ''.join(decl.type.names) == '__dotdotdot__'):
-                xxxx
                 # XXX pycparser is inconsistent: 'names' should be a list
                 # of strings, but is sometimes just one string.  Use
                 # str.join() as a way to cope with both.
+                tp.partial = True
+                continue
             if decl.bitsize is None:
                 bitsize = -1
             else:
@@ -274,17 +318,23 @@
         if key in self._declarations:
             return self._declarations[key]
         if decls is not None:
-            enumerators = tuple([enum.name for enum in decls.enumerators])
+            enumerators = [enum.name for enum in decls.enumerators]
+            partial = False
+            if enumerators and _r_enum_dotdotdot.match(enumerators[-1]):
+                enumerators.pop()
+                partial = True
+            enumerators = tuple(enumerators)
             enumvalues = []
             nextenumvalue = 0
-            for enum in decls.enumerators:
+            for enum in decls.enumerators[:len(enumerators)]:
                 if enum.value is not None:
                     nextenumvalue = self._parse_constant(enum.value)
                 enumvalues.append(nextenumvalue)
                 nextenumvalue += 1
             enumvalues = tuple(enumvalues) 
             tp = model.EnumType(name, enumerators, enumvalues)
-            self._declarations[key] = tp
+            tp.partial = partial
+            self._declare(key, tp)
         else:   # opaque enum
             enumerators = ()
             enumvalues = ()
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -1,5 +1,5 @@
+import os
 
-from platformer import udir
 
 class VerificationError(Exception):
     """ An error raised when verification fails
@@ -10,11 +10,22 @@
     cdef, but no verification has been done
     """
 
-def _get_test_file():
-    tst_file = udir.join('test.c')
-    i = 0
-    # XXX we want to put typedefs here
-    while tst_file.check():
-        tst_file = udir.join('test%d.c' % i)
-        i += 1
-    return tst_file
+_file_counter = 0
+_tmpdir = None
+
+def undercffi_module_name():
+    global _file_counter
+    modname = '_cffi_%d' % _file_counter
+    _file_counter += 1
+    return modname
+
+def tmpdir():
+    # for now, living in the __pycache__ subdirectory
+    global _tmpdir
+    if _tmpdir is None:
+        try:
+            os.mkdir('__pycache__')
+        except OSError:
+            pass
+        _tmpdir = os.path.abspath('__pycache__')
+    return _tmpdir
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -1,5 +1,9 @@
 
 class BaseType(object):
+
+    def __repr__(self):
+        return '<%s>' % (self.get_c_name(),)
+
     def __eq__(self, other):
         return (self.__class__ == other.__class__ and
                 self._get_items() == other._get_items())
@@ -22,24 +26,18 @@
         except KeyError:
             return self.new_backend_type(ffi, *args)
 
-    def get_backend_type(self, ffi):
-        return ffi._get_cached_btype(self)
-
-    def verifier_declare(self, verifier, f):
-        # nothing to see here
-        pass
 
 class VoidType(BaseType):
     _attrs_ = ()
-    name = 'void'
-    
+
+    def get_c_name(self, replace_with=''):
+        return 'void' + replace_with
+
     def new_backend_type(self, ffi):
         return ffi._backend.new_void_type()
 
-    def __repr__(self):
-        return '<void>'
+void_type = VoidType()
 
-void_type = VoidType()
 
 class PrimitiveType(BaseType):
     _attrs_ = ('name',)
@@ -47,26 +45,39 @@
     def __init__(self, name):
         self.name = name
 
+    def get_c_name(self, replace_with=''):
+        return self.name + replace_with
+
+    def is_char_type(self):
+        return self.name == 'char'
+    def is_signed_type(self):
+        return self.is_integer_type() and not self.is_unsigned_type()
+    def is_unsigned_type(self):
+        return self.name.startswith('unsigned ')
+    def is_integer_type(self):
+        return not self.is_float_type() and not self.is_char_type()
+    def is_float_type(self):
+        return self.name in ('double', 'float')
+
     def new_backend_type(self, ffi):
         return ffi._backend.new_primitive_type(self.name)
 
-    def __repr__(self):
-        return '<%s>' % (self.name,)
 
 class FunctionType(BaseType):
     _attrs_ = ('args', 'result', 'ellipsis')
 
-    def __init__(self, name, args, result, ellipsis):
-        self.name = name # can be None in case it's an empty type
+    def __init__(self, args, result, ellipsis):
         self.args = args
         self.result = result
         self.ellipsis = ellipsis
 
-    def __repr__(self):
-        args = ', '.join([repr(x) for x in self.args])
+    def get_c_name(self, replace_with=''):
+        reprargs = [arg.get_c_name() for arg in self.args]
         if self.ellipsis:
-            return '<(%s, ...) -> %r>' % (args, self.result)
-        return '<(%s) -> %r>' % (args, self.result)
+            reprargs.append('...')
+        reprargs = reprargs or ['void']
+        replace_with = '(*%s)(%s)' % (replace_with, ', '.join(reprargs))
+        return self.result.get_c_name(replace_with)
 
     def prepare_backend_type(self, ffi):
         args = [ffi._get_cached_btype(self.result)]
@@ -77,15 +88,6 @@
     def new_backend_type(self, ffi, result, *args):
         return ffi._backend.new_function_type(args, result, self.ellipsis)
 
-    def verifier_declare(self, verifier, f):
-        restype = self.result.name
-        args = []
-        for arg in self.args:
-            args.append(arg.name)
-        args = ', '.join(args)
-        f.write('  %s(* res%d)(%s) = %s;\n' % (restype, verifier.rescount,
-                                               args, self.name))
-        verifier.rescount += 1
 
 class PointerType(BaseType):
     _attrs_ = ('totype',)
@@ -93,86 +95,172 @@
     def __init__(self, totype):
         self.totype = totype
 
+    def get_c_name(self, replace_with=''):
+        return self.totype.get_c_name('* ' + replace_with)
+
     def prepare_backend_type(self, ffi):
         return (ffi._get_cached_btype(self.totype),)
 
     def new_backend_type(self, ffi, BItem):
         return ffi._backend.new_pointer_type(BItem)
 
-    def __repr__(self):
-        return '<*%r>' % (self.totype,)
+
+class ConstPointerType(PointerType):
+
+    def get_c_name(self, replace_with=''):
+        return self.totype.get_c_name(' const * ' + replace_with)
+
+    def prepare_backend_type(self, ffi):
+        return (ffi._get_cached_btype(PointerType(self.totype)),)
+
+    def new_backend_type(self, ffi, BPtr):
+        return BPtr
+
 
 class ArrayType(BaseType):
     _attrs_ = ('item', 'length')
 
     def __init__(self, item, length):
-        self.item = PointerType(item) # XXX why is this pointer?
+        self.item = item
         self.length = length
 
-    def __repr__(self):
+    def resolve_length(self, newlength):
+        return ArrayType(self.item, newlength)
+
+    def get_c_name(self, replace_with=''):
         if self.length is None:
-            return '<%r[]>' % (self.item,)
-        return '<%r[%s]>' % (self.item, self.length)
+            brackets = '[]'
+        else:
+            brackets = '[%d]' % self.length
+        return self.item.get_c_name(replace_with + brackets)
 
     def prepare_backend_type(self, ffi):
-        return (ffi._get_cached_btype(self.item),)
+        return (ffi._get_cached_btype(PointerType(self.item)),)
 
-    def new_backend_type(self, ffi, BItem):
-        return ffi._backend.new_array_type(BItem, self.length)
+    def new_backend_type(self, ffi, BPtrItem):
+        return ffi._backend.new_array_type(BPtrItem, self.length)
+
 
 class StructOrUnion(BaseType):
     _attrs_ = ('name',)
-        
+    fixedlayout = None
+
     def __init__(self, name, fldnames, fldtypes, fldbitsize):
         self.name = name
         self.fldnames = fldnames
         self.fldtypes = fldtypes
         self.fldbitsize = fldbitsize
 
-    def __repr__(self):
-        if self.fldnames is None:
-            return '<struct %s>' % (self.name,)
-        fldrepr = ', '.join(['%s: %r' % (name, tp) for name, tp in
-                             zip(self.fldnames, self.fldtypes)])
-        return '<struct %s {%s}>' % (self.name, fldrepr)
+    def get_c_name(self, replace_with=''):
+        return '%s %s%s' % (self.kind, self.name, replace_with)
 
     def prepare_backend_type(self, ffi):
         BType = self.get_btype(ffi)
         ffi._cached_btypes[self] = BType
         args = [BType]
-        for tp in self.fldtypes:
-            args.append(ffi._get_cached_btype(tp))
+        if self.fldtypes is not None:
+            for tp in self.fldtypes:
+                args.append(ffi._get_cached_btype(tp))
         return args
 
     def finish_backend_type(self, ffi, BType, *fldtypes):
-        lst = zip(self.fldnames, fldtypes, self.fldbitsize)
-        ffi._backend.complete_struct_or_union(BType, lst, self)
+        if self.fldnames is None:
+            return BType   # not completing it: it's an opaque struct
+        #
+        if self.fixedlayout is None:
+            lst = zip(self.fldnames, fldtypes, self.fldbitsize)
+            ffi._backend.complete_struct_or_union(BType, lst, self)
+            #
+        else:
+            fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout
+            for i in range(len(self.fldnames)):
+                fsize = fieldsize[i]
+                ftype = self.fldtypes[i]
+                #
+                if isinstance(ftype, ArrayType) and ftype.length is None:
+                    # fix the length to match the total size
+                    BItemType = ffi._get_cached_btype(ftype.item)
+                    nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
+                    if nrest != 0:
+                        self._verification_error(
+                            "field '%s.%s' has a bogus size?" % (
+                            self.name, self.fldnames[i]))
+                    ftype = ftype.resolve_length(nlen)
+                    self.fldtypes = (self.fldtypes[:i] + (ftype,) +
+                                     self.fldtypes[i+1:])
+                    BArrayType = ffi._get_cached_btype(ftype)
+                    fldtypes = (fldtypes[:i] + (BArrayType,) +
+                                fldtypes[i+1:])
+                    continue
+                #
+                bitemsize = ffi.sizeof(fldtypes[i])
+                if bitemsize != fsize:
+                    self._verification_error(
+                        "field '%s.%s' is declared as %d bytes, but is "
+                        "really %d bytes" % (self.name, self.fldnames[i],
+                                             bitemsize, fsize))
+            lst = zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)
+            ffi._backend.complete_struct_or_union(BType, lst, self,
+                                                  totalsize, totalalignment)
         return BType
 
+    def _verification_error(self, msg):
+        from .ffiplatform import VerificationError
+        raise VerificationError(msg)
+
+
 class StructType(StructOrUnion):
+    kind = 'struct'
+    partial = False
+
+    def check_not_partial(self):
+        if self.partial and self.fixedlayout is None:
+            from . import ffiplatform
+            raise ffiplatform.VerificationMissing(self.get_c_name())
+
     def get_btype(self, ffi):
+        self.check_not_partial()
         return ffi._backend.new_struct_type(self.name)
 
-    def verifier_declare(self, verifier, f):
-        verifier._write_printf(f, 'BEGIN struct %s size(%%ld)' % self.name,
-                      'sizeof(struct %s)' % self.name)
-        for decl in decl.decls:
-            pass
-            #_write_printf(f, 'FIELD ofs(%s) size(%s)')
-        verifier._write_printf(f, 'END struct %s' % self.name)
 
 class UnionType(StructOrUnion):
+    kind = 'union'
+
     def get_btype(self, ffi):
         return ffi._backend.new_union_type(self.name)
-    
+
+
 class EnumType(BaseType):
     _attrs_ = ('name',)
+    partial = False
 
     def __init__(self, name, enumerators, enumvalues):
         self.name = name
         self.enumerators = enumerators
         self.enumvalues = enumvalues
 
+    def get_c_name(self, replace_with=''):
+        return 'enum %s%s' % (self.name, replace_with)
+
+    def check_not_partial(self):
+        if self.partial:
+            from . import ffiplatform
+            raise ffiplatform.VerificationMissing(self.get_c_name())
+
     def new_backend_type(self, ffi):
+        self.check_not_partial()
         return ffi._backend.new_enum_type(self.name, self.enumerators,
                                           self.enumvalues)
+
+
+class OpaqueType(BaseType):
+    _attrs_ = ('name',)
+
+    def __init__(self, name):
+        self.name = name
+
+    def get_c_name(self, replace_with=''):
+        return self.name + replace_with
+
+    def new_backend_type(self, ffi):
+        return ffi._backend.new_struct_type('$' + self.name)
diff --git a/cffi/verifier.py b/cffi/verifier.py
--- a/cffi/verifier.py
+++ b/cffi/verifier.py
@@ -1,30 +1,520 @@
-
-from platformer import platform, ExternalCompilationInfo
-from . import ffiplatform
+import os
+from . import model, ffiplatform
 
 class Verifier(object):
-    def __init__(self):
-        self.rescount = 0
 
-    def _write_printf(f, what, *args):
-        if not args:
-            f.write('  printf("%s\\n");\n' % (what,))
+    def __init__(self, ffi):
+        self.ffi = ffi
+        self.typesdict = {}
+
+    def prnt(self, what=''):
+        print >> self.f, what
+
+    def gettypenum(self, type):
+        try:
+            return self.typesdict[type]
+        except KeyError:
+            num = len(self.typesdict)
+            self.typesdict[type] = num
+            return num
+
+    def verify(self, preamble, stop_on_warnings=True):
+        modname = ffiplatform.undercffi_module_name()
+        filebase = os.path.join(ffiplatform.tmpdir(), modname)
+        self.chained_list_constants = None
+        
+        with open(filebase + '.c', 'w') as f:
+            self.f = f
+            self.prnt(cffimod_header)
+            self.prnt()
+            self.prnt(preamble)
+            self.prnt()
+            #
+            self.generate("decl")
+            #
+            self.prnt('static PyObject *_cffi_setup_custom(void)')
+            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('}')
+            self.prnt()
+            #
+            self.prnt('static PyMethodDef _cffi_methods[] = {')
+            self.generate("method")
+            self.prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS},')
+            self.prnt('  {NULL, NULL}    /* Sentinel */')
+            self.prnt('};')
+            self.prnt()
+            #
+            self.prnt('void init%s()' % modname)
+            self.prnt('{')
+            self.prnt('  Py_InitModule("%s", _cffi_methods);' % modname)
+            self.prnt('  _cffi_init();')
+            self.prnt('}')
+            #
+            del self.f
+
+        # XXX use more distutils?
+        import distutils.sysconfig
+        python_h = distutils.sysconfig.get_python_inc()
+        cmdline = "gcc -I'%s' -O2 -shared -fPIC %s.c -o %s.so" % (
+            python_h, filebase, filebase)
+        if stop_on_warnings:
+            cmdline += " -Werror"
+        err = os.system(cmdline)
+        if err:
+            raise ffiplatform.VerificationError(
+                '%s.c: see compilation errors above' % (filebase,))
+        #
+        import imp
+        try:
+            module = imp.load_dynamic(modname, '%s.so' % filebase)
+        except ImportError, e:
+            raise ffiplatform.VerificationError(str(e))
+        #
+        self.load(module, 'loading')
+        #
+        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)
+        del module._cffi_setup
+        module.__dict__.update(dct)
+        #
+        self.load(module, 'loaded')
+        #
+        return module
+
+    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))
+            method(tp, realname)
+
+    def load(self, module, step_name):
+        for name, tp in self.ffi._parser._declarations.iteritems():
+            kind, realname = name.split(' ', 1)
+            method = getattr(self, '%s_cpy_%s' % (step_name, kind))
+            method(tp, realname, module)
+
+    def generate_nothing(self, tp, name):
+        pass
+
+    def loaded_noop(self, tp, name, module):
+        pass
+
+    # ----------
+
+    def convert_to_c(self, tp, fromvar, tovar, errcode, is_funcarg=False):
+        extraarg = ''
+        if isinstance(tp, model.PrimitiveType):
+            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 = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
+                extraarg = ', _cffi_type(%d)' % self.gettypenum(tp)
+            errvalue = 'NULL'
+        #
         else:
-            f.write('  printf("%s\\n", %s);\n' % (what, ', '.join(args)))
+            raise NotImplementedError(tp)
+        #
+        self.prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
+        self.prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
+            tovar, tp.get_c_name(''), errvalue))
+        self.prnt('    %s;' % errcode)
 
-    def verify(self, ffi, preamble, **kwargs):
-        tst_file = ffiplatform._get_test_file()
-        with tst_file.open('w') as f:
-            f.write('#include <stdio.h>\n')
-            f.write(preamble + "\n\n")
-            f.write('int main() {\n')
-            for name, tp in ffi._parser._declarations.iteritems():
-                tp.verifier_declare(self, f)
-            f.write('  return 0;\n')
-            f.write('}\n')
-        f.close()
-        exe_name = platform.compile([str(tst_file)],
-                                    ExternalCompilationInfo(**kwargs))
-        out = platform.execute(exe_name)
-        assert out.returncode == 0
-        outlines = out.out.splitlines()
+    def convert_expr_from_c(self, tp, var):
+        if isinstance(tp, model.PrimitiveType):
+            return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
+        elif isinstance(tp, model.PointerType):
+            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
+                var, self.gettypenum(tp))
+        else:
+            raise NotImplementedError(tp)
+
+    # ----------
+    # typedefs: generates no code so far
+
+    generate_cpy_typedef_decl   = generate_nothing
+    generate_cpy_typedef_method = generate_nothing
+    loading_cpy_typedef         = loaded_noop
+    loaded_cpy_typedef          = loaded_noop
+
+    # ----------
+    # function declarations
+
+    def generate_cpy_function_decl(self, tp, name):
+        assert isinstance(tp, model.FunctionType)
+        prnt = self.prnt
+        numargs = len(tp.args)
+        if numargs == 0:
+            argname = 'no_arg'
+        elif numargs == 1:
+            argname = 'arg0'
+        else:
+            argname = 'args'
+        prnt('static PyObject *')
+        prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
+        prnt('{')
+        assert not tp.ellipsis  # XXX later
+        #
+        for i, type in enumerate(tp.args):
+            prnt('  %s;' % type.get_c_name(' x%d' % i))
+        if not isinstance(tp.result, model.VoidType):
+            result_code = 'result = '
+            prnt('  %s;' % tp.result.get_c_name(' result'))
+        else:
+            result_code = ''
+        #
+        if len(tp.args) > 1:
+            rng = range(len(tp.args))
+            for i in rng:
+                prnt('  PyObject *arg%d;' % i)
+            prnt()
+            prnt('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
+                'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
+            prnt('    return NULL;')
+        prnt()
+        #
+        for i, type in enumerate(tp.args):
+            self.convert_to_c(type, 'arg%d' % i, 'x%d' % i, 'return NULL',
+                              is_funcarg=True)
+            prnt()
+        #
+        prnt('  { %s%s(%s); }' % (
+            result_code, name,
+            ', '.join(['x%d' % i for i in range(len(tp.args))])))
+        prnt()
+        #
+        if result_code:
+            prnt('  return %s;' %
+                 self.convert_expr_from_c(tp.result, 'result'))
+        else:
+            prnt('  Py_INCREF(Py_None);')
+            prnt('  return Py_None;')
+        prnt('}')
+        prnt()
+
+    def generate_cpy_function_method(self, tp, name):
+        numargs = len(tp.args)
+        if numargs == 0:
+            meth = 'METH_NOARGS'
+        elif numargs == 1:
+            meth = 'METH_O'
+        else:
+            meth = 'METH_VARARGS'
+        self.prnt('  {"%s", _cffi_f_%s, %s},' % (name, name, meth))
+
+    loading_cpy_function       = loaded_noop
+    loaded_cpy_function        = loaded_noop
+
+    # ----------
+    # struct declarations
+
+    def generate_cpy_struct_decl(self, tp, name):
+        if tp.fldnames is None:
+            return     # nothing to do with opaque structs
+        assert name == tp.name
+        prnt = self.prnt
+        prnt('static PyObject *')
+        prnt('_cffi_struct_%s(PyObject *self, PyObject *noarg)' % name)
+        prnt('{')
+        prnt('  struct _cffi_aligncheck { char x; struct %s y; };' % name)
+        if tp.partial:
+            prnt('  static Py_ssize_t nums[] = {')
+            prnt('    sizeof(struct %s),' % name)
+            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('    -1')
+            prnt('  };')
+            prnt('  return _cffi_get_struct_layout(nums);')
+        else:
+            ffi = self.ffi
+            BStruct = ffi._get_cached_btype(tp)
+            conditions = [
+                'sizeof(struct %s) != %d' % (name, 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))]
+            prnt('  if (%s ||' % conditions[0])
+            for i in range(1, len(conditions)-1):
+                prnt('      %s ||' % conditions[i])
+            prnt('      %s) {' % conditions[-1])
+            prnt('    Py_INCREF(Py_False);')
+            prnt('    return Py_False;')
+            prnt('  }')
+            prnt('  else {')
+            prnt('    Py_INCREF(Py_True);')
+            prnt('    return Py_True;')
+            prnt('  }')
+        prnt('}')
+        prnt('static void _cffi_check_%s(struct %s *p)' % (name, name))
+        prnt('{')
+        prnt('  /* only to generate compile-time warnings or errors */')
+        for i in range(len(tp.fldnames)):
+            fname = tp.fldnames[i]
+            ftype = tp.fldtypes[i]
+            if (isinstance(ftype, model.PrimitiveType)
+                and ftype.is_integer_type()):
+                # accept all integers, but complain on float or double
+                prnt('  (p->%s) << 1;' % fname)
+            else:
+                # only accept exactly the type declared.  Note the parentheses
+                # around the '*tmp' below.  In most cases they are not needed
+                # but don't hurt --- except test_struct_array_field.
+                prnt('  { %s = &p->%s; }' % (
+                    ftype.get_c_name('(*tmp)'), fname))
+        prnt('}')
+        prnt()
+
+    def generate_cpy_struct_method(self, tp, 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))
+
+    def loading_cpy_struct(self, tp, 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)
+        layout = function()
+        if layout is False:
+            raise ffiplatform.VerificationError(
+                "incompatible layout for struct %s" % name)
+        elif layout is True:
+            assert not tp.partial
+        else:
+            totalsize = layout[0]
+            totalalignment = layout[1]
+            fieldofs = layout[2::2]
+            fieldsize = layout[3::2]
+            assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
+            tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
+
+    def loaded_cpy_struct(self, tp, name, module):
+        if tp.fldnames is None:
+            return     # nothing to do with opaque structs
+        self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered
+
+    # ----------
+    # constants, likely declared with '#define'
+
+    def _generate_chain_header(self, funcname, *vardecls):
+        prnt = self.prnt
+        prnt('static int %s(PyObject *dct)' % 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):
+        vardecls = ['PyObject *o;',
+                    'int res;']
+        if not is_int:
+            vardecls.append('%s;' % tp.get_c_name(' i'))
+        self._generate_chain_header('_cffi_const_%s' % name, *vardecls)
+        #
+        prnt = self.prnt
+        if not is_int:
+            prnt('  i = (%s);' % (name,))
+            prnt('  o = %s;' % (self.convert_expr_from_c(tp, 'i'),))
+        else:
+            prnt('  if (LONG_MIN <= (%s) && (%s) <= LONG_MAX)' % (name, name))
+            prnt('    o = PyInt_FromLong((long)(%s));' % (name,))
+            prnt('  else if ((%s) <= 0)' % (name,))
+            prnt('    o = PyLong_FromLongLong((long long)(%s));' % (name,))
+            prnt('  else')
+            prnt('    o = PyLong_FromUnsignedLongLong('
+                 '(unsigned long long)(%s));' % (name,))
+        prnt('  if (o == NULL)')
+        prnt('    return -1;')
+        prnt('  res = PyDict_SetItemString(dct, "%s", o);' % name)
+        prnt('  Py_DECREF(o);')
+        prnt('  return res;')
+        prnt('}')
+        prnt()
+
+    def generate_cpy_constant_decl(self, tp, name):
+        is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
+        self._generate_cpy_const(is_int, name, tp)
+
+    generate_cpy_constant_method = generate_nothing
+    loading_cpy_constant = loaded_noop
+    loaded_cpy_constant  = loaded_noop
+
+    # ----------
+    # enums
+
+    def generate_cpy_enum_decl(self, tp, name):
+        if tp.partial:
+            for enumerator in tp.enumerators:
+                self._generate_cpy_const(True, enumerator)
+            return
+        #
+        self._generate_chain_header('_cffi_enum_%s' % name)
+        prnt = self.prnt
+        for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
+            prnt('  if (%s != %d) {' % (enumerator, enumvalue))
+            prnt('    PyErr_Format(_cffi_VerificationError,')
+            prnt('                 "in enum %s: %s has the real value %d, '
+                 'not %d",')
+            prnt('                 "%s", "%s", (int)%s, %d);' % (
+                name, enumerator, enumerator, enumvalue))
+            prnt('    return -1;')
+            prnt('  }')
+        prnt('  return 0;')
+        prnt('}')
+        prnt()
+
+    generate_cpy_enum_method = generate_nothing
+    loading_cpy_enum = loaded_noop
+
+    def loaded_cpy_enum(self, tp, name, module):
+        if tp.partial:
+            enumvalues = [getattr(module, enumerator)
+                          for enumerator in tp.enumerators]
+            tp.enumvalues = tuple(enumvalues)
+            tp.partial = False
+
+    # ----------
+
+cffimod_header = r'''
+#include <Python.h>
+#include <stddef.h>
+
+#define _cffi_from_c_double PyFloat_FromDouble
+#define _cffi_from_c_float PyFloat_FromDouble
+#define _cffi_from_c_signed_char PyInt_FromLong
+#define _cffi_from_c_short PyInt_FromLong
+#define _cffi_from_c_int PyInt_FromLong
+#define _cffi_from_c_long PyInt_FromLong
+#define _cffi_from_c_unsigned_char PyInt_FromLong
+#define _cffi_from_c_unsigned_short PyInt_FromLong
+#define _cffi_from_c_unsigned_long PyLong_FromUnsignedLong
+#define _cffi_from_c_unsigned_long_long PyLong_FromUnsignedLongLong
+
+#if SIZEOF_INT < SIZEOF_LONG
+#  define _cffi_from_c_unsigned_int PyInt_FromLong
+#else
+#  define _cffi_from_c_unsigned_int PyLong_FromUnsignedLong
+#endif
+
+#if SIZEOF_LONG < SIZEOF_LONG_LONG
+#  define _cffi_from_c_long_long PyLong_FromLongLong
+#else
+#  define _cffi_from_c_long_long PyInt_FromLong
+#endif
+
+static PyObject *_cffi_from_c_char(char x) {
+    return PyString_FromStringAndSize(&x, 1);
+}
+
+#define _cffi_to_c_long PyInt_AsLong
+#define _cffi_to_c_double PyFloat_AsDouble
+#define _cffi_to_c_float PyFloat_AsDouble
+
+#define _cffi_to_c_char_p                                                \
+                 ((char *(*)(PyObject *))_cffi_exports[0])
+#define _cffi_to_c_signed_char                                           \
+                 ((signed char(*)(PyObject *))_cffi_exports[1])
+#define _cffi_to_c_unsigned_char                                         \
+                 ((unsigned char(*)(PyObject *))_cffi_exports[2])
+#define _cffi_to_c_short                                                 \
+                 ((short(*)(PyObject *))_cffi_exports[3])
+#define _cffi_to_c_unsigned_short                                        \
+                 ((unsigned short(*)(PyObject *))_cffi_exports[4])
+
+#if SIZEOF_INT < SIZEOF_LONG
+#  define _cffi_to_c_int                                                 \
+                   ((int(*)(PyObject *))_cffi_exports[5])
+#  define _cffi_to_c_unsigned_int                                        \
+                   ((unsigned int(*)(PyObject *))_cffi_exports[6])
+#else
+#  define _cffi_to_c_int          _cffi_to_c_long
+#  define _cffi_to_c_unsigned_int _cffi_to_c_unsigned_long
+#endif
+
+#define _cffi_to_c_unsigned_long                                         \
+                 ((unsigned long(*)(PyObject *))_cffi_exports[7])
+#define _cffi_to_c_unsigned_long_long                                    \
+                 ((unsigned long long(*)(PyObject *))_cffi_exports[8])
+#define _cffi_to_c_char                                                  \
+                 ((char(*)(PyObject *))_cffi_exports[9])
+#define _cffi_from_c_pointer                                             \
+    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
+#define _cffi_to_c_pointer                                               \
+    ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
+#define _cffi_get_struct_layout                                          \
+    ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
+
+#if SIZEOF_LONG < SIZEOF_LONG_LONG
+#  define _cffi_to_c_long_long PyLong_AsLongLong
+#else
+#  define _cffi_to_c_long_long _cffi_to_c_long
+#endif
+
+typedef struct _ctypedescr CTypeDescrObject;
+
+static void **_cffi_exports;
+static PyObject *_cffi_types, *_cffi_VerificationError;
+
+static PyObject *_cffi_setup_custom(void);   /* forward */
+
+static PyObject *_cffi_setup(PyObject *self, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, "OO", &_cffi_types, &_cffi_VerificationError))
+        return NULL;
+    Py_INCREF(_cffi_types);
+    Py_INCREF(_cffi_VerificationError);
+
+    return _cffi_setup_custom();
+}
+
+static void _cffi_init(void)
+{
+    PyObject *module = PyImport_ImportModule("_ffi_backend");
+    PyObject *c_api_object;
+
+    if (module == NULL)
+        return;
+
+    c_api_object = PyObject_GetAttrString(module, "_C_API");
+    if (c_api_object == NULL)
+        return;
+    if (!PyCObject_Check(c_api_object)) {
+        PyErr_SetNone(PyExc_ImportError);
+        return;
+    }
+    _cffi_exports = (void **)PyCObject_AsVoidPtr(c_api_object);
+}
+
+#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))
+
+/**********/
+'''
diff --git a/demo/readdir.py b/demo/readdir.py
--- a/demo/readdir.py
+++ b/demo/readdir.py
@@ -11,11 +11,12 @@
     typedef long off_t;
 
     struct dirent {
-        ino_t          d_ino;       
-        off_t          d_off;       
-        unsigned short d_reclen;    
-        unsigned char  d_type;      
-        char           d_name[256]; 
+        ino_t          d_ino;       /* inode number */
+        off_t          d_off;       /* offset to the next dirent */
+        unsigned short d_reclen;    /* length of this record */
+        unsigned char  d_type;      /* type of file; not supported
+                                       by all file system types */
+        char           d_name[256]; /* filename */
     };
 
     int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
@@ -24,6 +25,7 @@
     int closedir(DIR *dirp);
 
 """)
+ffi.C = ffi.rawload(None)
 
 
 
diff --git a/demo/readdir2.py b/demo/readdir2.py
new file mode 100644
--- /dev/null
+++ b/demo/readdir2.py
@@ -0,0 +1,62 @@
+# A Linux-only demo, using verify() instead of hard-coding the exact layouts
+#
+from cffi import FFI
+
+
+ffi = FFI()
+ffi.cdef("""
+
+    typedef ... DIR;
+
+    struct dirent {
+        unsigned char  d_type;      /* type of file; not supported
+                                       by all file system types */
+        char           d_name[256]; /* filename */
+        ...;
+    };
+
+    int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+    int openat(int dirfd, const char *pathname, int flags);
+    DIR *fdopendir(int fd);
+    int closedir(DIR *dirp);
+
+    static const int DT_DIR;
+
+""")
+ffi.C = ffi.verify("""
+#ifndef _ATFILE_SOURCE
+#  define _ATFILE_SOURCE
+#endif
+#ifndef _BSD_SOURCE
+#  define _BSD_SOURCE
+#endif
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+""")
+
+
+def walk(basefd, path):
+    print '{', path
+    dirfd = ffi.C.openat(basefd, path, 0)
+    if dirfd < 0:
+        # error in openat()
+        return
+    dir = ffi.C.fdopendir(dirfd)
+    dirent = ffi.new("struct dirent")
+    result = ffi.new("struct dirent *")
+    while True:
+        if ffi.C.readdir_r(dir, dirent, result):
+            # error in readdir_r()
+            break
+        if result[0] is None:
+            break
+        name = str(dirent.d_name)
+        print '%3d %s' % (dirent.d_type, name)
+        if dirent.d_type == ffi.C.DT_DIR and name != '.' and name != '..':
+            walk(dirfd, name)
+    ffi.C.closedir(dir)
+    print '}'
+
+
+walk(-1, "/tmp")
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -6,7 +6,7 @@
 SIZE_OF_LONG  = ctypes.sizeof(ctypes.c_long)
 SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
 SIZE_OF_PTR   = ctypes.sizeof(ctypes.c_void_p)
-SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
+#SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
 
 
 class BackendTests:
@@ -41,7 +41,7 @@
         self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
         self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
         self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)
-        self._test_int_type(ffi, 'wchar_t', SIZE_OF_WCHAR, True)
+        #self._test_int_type(ffi, 'wchar_t', SIZE_OF_WCHAR, True)
 
     def _test_int_type(self, ffi, c_decl, size, unsigned):
         if unsigned:
@@ -50,6 +50,8 @@
         else:
             min = -(1 << (8*size-1))
             max = (1 << (8*size-1)) - 1
+        min = int(min)
+        max = int(max)
         p = ffi.cast(c_decl, min)
         assert p != min       # no __eq__(int)
         assert bool(p) is True
@@ -68,6 +70,10 @@
         py.test.raises(OverflowError, ffi.new, c_decl, max + 1)
         py.test.raises(OverflowError, ffi.new, c_decl, long(min - 1))
         py.test.raises(OverflowError, ffi.new, c_decl, long(max + 1))
+        assert ffi.new(c_decl, min)[0] == min
+        assert ffi.new(c_decl, max)[0] == max
+        assert ffi.new(c_decl, long(min))[0] == min
+        assert ffi.new(c_decl, long(max))[0] == max
 
     def test_new_single_integer(self):
         ffi = FFI(backend=self.Backend())
@@ -680,6 +686,11 @@
         assert s[0].b == 412
         py.test.raises(IndexError, 's[1]')
 
+    def test_pointer_to_array(self):
+        ffi = FFI(backend=self.Backend())
+        p = ffi.new("int(*)[5]")
+        assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_INT
+
     def test_offsetof(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo { int a, b, c; };")
@@ -755,3 +766,12 @@
             assert s == '\x64\x00\x00\x00\x65\x00\x00\x00'
         else:
             assert s == '\x00\x00\x00\x64\x00\x00\x00\x65'
+
+    def test_new_struct_containing_array_varsize(self):
+        py.test.skip("later?")
+        ffi = FFI(backend=_ffi_backend)
+        ffi.cdef("struct foo_s { int len; short data[]; };")
+        p = ffi.new("struct foo_s", 10)     # a single integer is the length
+        assert p.len == 0
+        assert p.data[9] == 0
+        py.test.raises(IndexError, "p.data[10]")
diff --git a/testing/test_cdata.py b/testing/test_cdata.py
--- a/testing/test_cdata.py
+++ b/testing/test_cdata.py
@@ -6,7 +6,7 @@
     def nonstandard_integer_types(self):
         return {}
 
-    def sizeof_type(self, name):
+    def sizeof(self, name):
         return 1
 
     def load_library(self, path):
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -36,7 +36,7 @@
         ffi.cdef("""
             double sin(double x);
         """)
-        m = ffi.load("m")
+        m = ffi.rawload("m")
         x = m.sin(1.23)
         assert x == math.sin(1.23)
 
@@ -45,7 +45,7 @@
         ffi.cdef("""
             float sinf(float x);
         """)
-        m = ffi.load("m")
+        m = ffi.rawload("m")
         x = m.sinf(1.23)
         assert type(x) is float
         assert x != math.sin(1.23)    # rounding effects
@@ -57,6 +57,7 @@
             int puts(const char *);
             int fflush(void *);
         """)
+        ffi.C = ffi.rawload(None)
         ffi.C.puts   # fetch before capturing, for easier debugging
         with FdWriteCapture() as fd:
             ffi.C.puts("hello")
@@ -71,6 +72,7 @@
             int puts(char *);
             int fflush(void *);
         """)
+        ffi.C = ffi.rawload(None)
         ffi.C.puts   # fetch before capturing, for easier debugging
         with FdWriteCapture() as fd:
             ffi.C.puts("hello")
@@ -85,6 +87,7 @@
             int fputs(const char *, void *);
             void *stdout, *stderr;
         """)
+        ffi.C = ffi.rawload(None)
         with FdWriteCapture(2) as fd:
             ffi.C.fputs("hello from stderr\n", ffi.C.stderr)
         res = fd.getvalue()
@@ -96,6 +99,7 @@
            int printf(const char *format, ...);
            int fflush(void *);
         """)
+        ffi.C = ffi.rawload(None)
         with FdWriteCapture() as fd:
             ffi.C.printf("hello with no arguments\n")
             ffi.C.printf("hello, %s!\n", ffi.new("char[]", "world"))
@@ -119,6 +123,7 @@
         ffi.cdef("""
            int printf(const char *format, ...);
         """)
+        ffi.C = ffi.rawload(None)
         e = py.test.raises(TypeError, ffi.C.printf, "hello %d\n", 42)
         assert str(e.value) == ("argument 2 passed in the variadic part "
                                 "needs to be a cdata object (got int)")
@@ -128,6 +133,7 @@
         ffi.cdef("""
             int puts(const char *);
         """)
+        ffi.C = ffi.rawload(None)
         fptr = ffi.C.puts
         assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)")
         if self.Backend is CTypesBackend:
@@ -148,6 +154,7 @@
             int puts(const char *);
             int fflush(void *);
         """)
+        ffi.C = ffi.rawload(None)
         fptr = ffi.cast("int(*)(const char *txt)", ffi.C.puts)
         assert fptr == ffi.C.puts
         assert repr(fptr) == "<cdata 'int(*)(char *)'>"
@@ -162,6 +169,7 @@
         ffi.cdef("""
             int strlen(char[]);
         """)
+        ffi.C = ffi.rawload(None)
         p = ffi.new("char[]", "hello")
         res = ffi.C.strlen(p)
         assert res == 5
@@ -172,6 +180,7 @@
             int puts(const char *);
             void *stdout, *stderr;
         """)
+        ffi.C = ffi.rawload(None)
         pout = ffi.C.stdout
         perr = ffi.C.stderr
         assert repr(pout) == "<cdata 'void *'>"
@@ -190,6 +199,7 @@
         ffi.cdef("""
             char *strchr(const char *s, int c);
         """)
+        ffi.C = ffi.rawload(None)
         p = ffi.new("char[]", "hello world!")
         q = ffi.C.strchr(p, ord('w'))
         assert str(q) == "world!"
@@ -200,6 +210,7 @@
             struct in_addr { unsigned int s_addr; };
             char *inet_ntoa(struct in_addr in);
         """)
+        ffi.C = ffi.rawload(None)
         ina = ffi.new("struct in_addr", [0x04040404])
         a = ffi.C.inet_ntoa(ina[0])
         assert str(a) == '4.4.4.4'
diff --git a/testing/test_ownlib.py b/testing/test_ownlib.py
--- a/testing/test_ownlib.py
+++ b/testing/test_ownlib.py
@@ -33,10 +33,11 @@
         ffi.cdef("""
             int test_getting_errno(void);
         """)
-        ownlib = ffi.load(self.module)
+        ownlib = ffi.rawload(self.module)
+        C = ffi.rawload(None)
         res = ownlib.test_getting_errno()
         assert res == -1
-        assert ffi.C.errno == 123
+        assert C.errno == 123
 
     def test_setting_errno(self):
         if self.Backend is CTypesBackend and '__pypy__' in sys.modules:
@@ -45,8 +46,9 @@
         ffi.cdef("""
             int test_setting_errno(void);
         """)
-        ownlib = ffi.load(self.module)
-        ffi.C.errno = 42
+        ownlib = ffi.rawload(self.module)
+        C = ffi.rawload(None)
+        C.errno = 42
         res = ownlib.test_setting_errno()
         assert res == 42
-        assert ffi.C.errno == 42
+        assert C.errno == 42
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -5,7 +5,7 @@
     def nonstandard_integer_types(self):
         return {}
 
-    def sizeof_type(self, name):
+    def sizeof(self, name):
         return 1
 
     def load_library(self, name):
@@ -53,7 +53,7 @@
 def test_simple():
     ffi = FFI(backend=FakeBackend())
     ffi.cdef("double sin(double x);")
-    m = ffi.load("m")
+    m = ffi.rawload("m")
     func = m.sin    # should be a callable on real backends
     assert func.name == 'sin'
     assert func.BType == '<func (<double>), <double>, False>'
@@ -61,14 +61,16 @@
 def test_pipe():
     ffi = FFI(backend=FakeBackend())
     ffi.cdef("int pipe(int pipefd[2]);")
-    func = ffi.C.pipe
+    C = ffi.rawload(None)
+    func = C.pipe
     assert func.name == 'pipe'
     assert func.BType == '<func (<pointer to <int>>), <int>, False>'
 
 def test_vararg():
     ffi = FFI(backend=FakeBackend())
     ffi.cdef("short foo(int, ...);")
-    func = ffi.C.foo
+    C = ffi.rawload(None)
+    func = C.foo
     assert func.name == 'foo'
     assert func.BType == '<func (<int>), <short>, True>'
 
@@ -77,7 +79,8 @@
     ffi.cdef("""
         int foo(void);
         """)
-    assert ffi.C.foo.BType == '<func (), <int>, False>'
+    C = ffi.rawload(None)
+    assert C.foo.BType == '<func (), <int>, False>'
 
 def test_typedef():
     ffi = FFI(backend=FakeBackend())
@@ -86,8 +89,9 @@
         typedef UInt UIntReally;
         UInt foo(void);
         """)
+    C = ffi.rawload(None)
     assert ffi.typeof("UIntReally") == '<unsigned int>'
-    assert ffi.C.foo.BType == '<func (), <unsigned int>, False>'
+    assert C.foo.BType == '<func (), <unsigned int>, False>'
 
 def test_typedef_more_complex():
     ffi = FFI(backend=FakeBackend())
@@ -95,10 +99,11 @@
         typedef struct { int a, b; } foo_t, *foo_p;
         int foo(foo_p[]);
         """)
+    C = ffi.rawload(None)
     assert str(ffi.typeof("foo_t")) == '<int>a, <int>b'
     assert ffi.typeof("foo_p") == '<pointer to <int>a, <int>b>'
-    assert ffi.C.foo.BType == ('<func (<pointer to <pointer to '
-                               '<int>a, <int>b>>), <int>, False>')
+    assert C.foo.BType == ('<func (<pointer to <pointer to '
+                           '<int>a, <int>b>>), <int>, False>')
 
 def test_typedef_array_force_pointer():
     ffi = FFI(backend=FakeBackend())
@@ -106,14 +111,31 @@
         typedef int array_t[5];
         """)
     type = ffi._parser.parse_type("array_t", force_pointer=True)
-    BType = type.get_backend_type(ffi)
+    BType = ffi._get_cached_btype(type)
     assert BType == '<array <pointer to <int>> x 5>'
 
 def test_typedef_array_convert_array_to_pointer():
     ffi = FFI(backend=FakeBackend())
     ffi.cdef("""
-        typedef int array_t[5];
+        typedef int (*fn_t)(int[5]);
         """)
-    type = ffi._parser.parse_type("array_t", convert_array_to_pointer=True)
-    BType = type.get_backend_type(ffi)
-    assert BType == '<pointer to <int>>'
+    type = ffi._parser.parse_type("fn_t")
+    BType = ffi._get_cached_btype(type)
+    assert BType == '<func (<pointer to <int>>), <int>, False>'
+
+def test_remove_comments():
+    ffi = FFI(backend=FakeBackend())
+    ffi.cdef("""
+        double /*comment here*/ sin   // blah blah
+        /* multi-
+           line-
+           //comment */  (
+        // foo
+        double // bar      /* <- ignored, because it's in a comment itself
+        x, double/*several*//*comment*/y) /*on the same line*/
+        ;
+    """)
+    m = ffi.rawload("m")
+    func = m.sin
+    assert func.name == 'sin'
+    assert func.BType == '<func (<double>, <double>), <double>, False>'
diff --git a/testing/test_platform.py b/testing/test_platform.py
deleted file mode 100644
--- a/testing/test_platform.py
+++ /dev/null
@@ -1,19 +0,0 @@
-
-import py
-from cffi import FFI, VerificationMissing
-
-def test_ffi_nonfull_struct():
-    py.test.skip("XXX")
-    ffi = FFI()
-    ffi.cdef("""
-    struct sockaddr {
-       int sa_family;
-       ...;
-    };
-    """)
-    py.test.raises(VerificationMissing, ffi.sizeof, 'struct sockaddr')
-    ffi.verify('''
-    #include <sys/types.h>
-    #include <sys/socket.h>
-    ''')
-    assert ffi.sizeof('struct sockaddr') == 14 + ffi.sizeof(int)
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -1,21 +1,321 @@
+import py
+import math
+from cffi import FFI, VerificationError, VerificationMissing, model
 
-import py
-from cffi import FFI
-from platformer import CompilationError
 
-def test_simple_verify():
+def test_missing_function():
     ffi = FFI()
     ffi.cdef("void some_completely_unknown_function();")
-    py.test.raises(CompilationError, ffi.verify)
+    py.test.raises(VerificationError, ffi.verify)
+
+def test_simple_case():
     ffi = FFI()
     ffi.cdef("double sin(double x);")
-    # omission of math.h
-    py.test.raises(CompilationError, ffi.verify)
-    assert ffi.verify('#include <math.h>') is None
-    #
+    lib = ffi.verify('#include <math.h>')
+    assert lib.sin(1.23) == math.sin(1.23)
+
+def test_rounding_1():
     ffi = FFI()
     ffi.cdef("float sin(double x);")
-    py.test.raises(CompilationError, ffi.verify, '#include <math.h>')
+    lib = ffi.verify('#include <math.h>')
+    res = lib.sin(1.23)
+    assert res != math.sin(1.23)     # not exact, because of double->float
+    assert abs(res - math.sin(1.23)) < 1E-5
+
+def test_rounding_2():
     ffi = FFI()
     ffi.cdef("double sin(float x);")
-    py.test.raises(CompilationError, ffi.verify, '#include <math.h>')
+    lib = ffi.verify('#include <math.h>')
+    res = lib.sin(1.23)
+    assert res != math.sin(1.23)     # not exact, because of double->float
+    assert abs(res - math.sin(1.23)) < 1E-5
+
+def test_strlen_exact():
+    ffi = FFI()
+    ffi.cdef("size_t strlen(const char *s);")
+    lib = ffi.verify("#include <string.h>")
+    assert lib.strlen("hi there!") == 9
+
+def test_strlen_approximate():
+    ffi = FFI()
+    ffi.cdef("int strlen(char *s);")
+    lib = ffi.verify("#include <string.h>")
+    assert lib.strlen("hi there!") == 9
+
+
+all_integer_types = ['short', 'int', 'long', 'long long',
+                     'signed char', 'unsigned char',
+                     'unsigned short', 'unsigned int',
+                     'unsigned long', 'unsigned long long']
+all_signed_integer_types = [_typename for _typename in all_integer_types
+                                      if not _typename.startswith('unsigned ')]
+all_unsigned_integer_types = [_typename for _typename in all_integer_types
+                                        if _typename.startswith('unsigned ')]
+all_float_types = ['float', 'double']
+
+def test_primitive_category():
+    for typename in all_integer_types + all_float_types + ['char']:
+        tp = model.PrimitiveType(typename)
+        assert tp.is_char_type() == (typename == 'char')
+        assert tp.is_signed_type() == (typename in all_signed_integer_types)
+        assert tp.is_unsigned_type()== (typename in all_unsigned_integer_types)
+        assert tp.is_integer_type() == (typename in all_integer_types)
+        assert tp.is_float_type() == (typename in all_float_types)
+
+def test_all_integer_and_float_types():
+    for typename in all_integer_types + all_float_types:
+        ffi = FFI()
+        ffi.cdef("%s foo(%s);" % (typename, typename))
+        lib = ffi.verify("%s foo(%s x) { return x+1; }" % (typename, typename))
+        assert lib.foo(42) == 43
+        assert lib.foo(44L) == 45
+        assert lib.foo(ffi.cast(typename, 46)) == 47
+        py.test.raises(TypeError, lib.foo, None)
+        #
+        # check for overflow cases
+        if typename in all_float_types:
+            continue
+        for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
+                      2**5, 2**10, 2**20, 2**40, 2**80]:
+            overflows = int(ffi.cast(typename, value)) != value
+            if overflows:
+                py.test.raises(OverflowError, lib.foo, value)
+            else:
+                assert lib.foo(value) == value + 1
+
+def test_char_type():
+    ffi = FFI()
+    ffi.cdef("char foo(char);")
+    lib = ffi.verify("char foo(char x) { return x+1; }")
+    assert lib.foo("A") == "B"
+    py.test.raises(TypeError, lib.foo, "bar")
+
+def test_no_argument():
+    ffi = FFI()
+    ffi.cdef("int foo(void);")
+    lib = ffi.verify("int foo() { return 42; }")
+    assert lib.foo() == 42
+
+def test_two_arguments():
+    ffi = FFI()
+    ffi.cdef("int foo(int, int);")
+    lib = ffi.verify("int foo(int a, int b) { return a - b; }")
+    assert lib.foo(40, -2) == 42
+
+def test_macro():
+    ffi = FFI()
+    ffi.cdef("int foo(int, int);")
+    lib = ffi.verify("#define foo(a, b) ((a) * (b))")
+    assert lib.foo(-6, -7) == 42
+
+def test_ptr():
+    ffi = FFI()
+    ffi.cdef("int *foo(int *);")
+    lib = ffi.verify("int *foo(int *a) { return a; }")
+    assert lib.foo(None) is None
+    p = ffi.new("int", 42)
+    q = ffi.new("int", 42)
+    assert lib.foo(p) == p
+    assert lib.foo(q) != p
+
+def test_bogus_ptr():
+    ffi = FFI()
+    ffi.cdef("int *foo(int *);")
+    lib = ffi.verify("int *foo(int *a) { return a; }")
+    py.test.raises(TypeError, lib.foo, ffi.new("short", 42))
+
+
+def test_verify_typedefs():
+    py.test.skip("ignored so far")
+    types = ['signed char', 'unsigned char', 'int', 'long']
+    for cdefed in types:
+        for real in types:
+            ffi = FFI()
+            ffi.cdef("typedef %s foo_t;" % cdefed)
+            if cdefed == real:
+                ffi.verify("typedef %s foo_t;" % real)
+            else:
+                py.test.raises(VerificationError, ffi.verify,
+                               "typedef %s foo_t;" % real)
+
+def test_nondecl_struct():
+    ffi = FFI()
+    ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);")
+    lib = ffi.verify("typedef struct foo_s foo_t;\n"
+                     "int bar(foo_t *f) { return 42; }\n")
+    assert lib.bar(None) == 42
+
+def test_missing_typedef():
+    ffi = FFI()
+    ffi.cdef("typedef...foo_t; int bar(foo_t *);")
+    py.test.raises(TypeError, ffi.new, "foo_t")
+    lib = ffi.verify("typedef struct foo_s { int x; } foo_t;\n"
+                     "int bar(foo_t *f) { return 42; }\n")
+    py.test.raises(TypeError, ffi.new, "foo_t")
+    f = ffi.cast("foo_t*", 0)
+    assert lib.bar(f) == 42
+
+
+def test_ffi_full_struct():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { char x; int y; long *z; };")
+    ffi.verify("struct foo_s { char x; int y; long *z; };")
+    #
+    for real in [
+        "struct foo_s { char x; int y; int *z; };",
+        "struct foo_s { char x; long *z; int y; };",
+        "struct foo_s { int y; long *z; };",
+        "struct foo_s { char x; int y; long *z; char extra; };",
+        ]:
+        py.test.raises(VerificationError, ffi.verify, real)
+    #
+    # a corner case that we cannot really detect, but where it has no
+    # bad consequences: the size is the same, but there is an extra field
+    # that replaces what is just padding in our declaration above
+    ffi.verify("struct foo_s { char x, extra; int y; long *z; };")
+
+
+def test_ffi_nonfull_struct():
+    ffi = FFI()
+    ffi.cdef("""
+    struct foo_s {
+       int x;
+       ...;
+    };
+    """)
+    py.test.raises(VerificationMissing, ffi.sizeof, 'struct foo_s')
+    py.test.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x')
+    py.test.raises(VerificationMissing, ffi.new, 'struct foo_s')
+    ffi.verify("""
+    struct foo_s {
+       int a, b, x, c, d, e;
+    };
+    """)
+    assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
+    assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')
+
+def test_ffi_nonfull_alignment():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { char x; ...; };")
+    ffi.verify("struct foo_s { int a, b; char x; };")
+    assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int')
+    assert ffi.alignof('struct foo_s') == ffi.sizeof('int')
+
+def _check_field_match(typename, real, expect_mismatch):
+    ffi = FFI()
+    if expect_mismatch == 'by_size':
+        expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real)
+    ffi.cdef("struct foo_s { %s x; ...; };" % typename)
+    try:
+        ffi.verify("struct foo_s { %s x; };" % real)
+    except VerificationError:
+        if not expect_mismatch:
+            raise AssertionError("unexpected mismatch: %s should be accepted "
+                                 "as equal to %s" % (typename, real))
+    else:
+        if expect_mismatch:
+            raise AssertionError("mismatch not detected: "
+                                 "%s != %s" % (typename, real))
+
+def test_struct_bad_sized_integer():
+    for typename in all_signed_integer_types:
+        for real in all_signed_integer_types:
+            _check_field_match(typename, real, "by_size")
+
+def test_struct_bad_sized_float():
+    for typename in all_float_types:
+        for real in all_float_types:
+            _check_field_match(typename, real, "by_size")
+
+def test_struct_signedness_ignored():
+    _check_field_match("int", "unsigned int", expect_mismatch=False)
+    _check_field_match("unsigned short", "signed short", expect_mismatch=False)
+
+def test_struct_float_vs_int():
+    for typename in all_signed_integer_types:
+        for real in all_float_types:
+            _check_field_match(typename, real, expect_mismatch=True)
+    for typename in all_float_types:
+        for real in all_signed_integer_types:
+            _check_field_match(typename, real, expect_mismatch=True)
+
+def test_struct_array_field():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int a[17]; ...; };")
+    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
+    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
+    s = ffi.new("struct foo_s")
+    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
+
+def test_struct_array_guess_length():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int a[]; ...; };")    # <= no declared length
+    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
+    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
+    s = ffi.new("struct foo_s")
+    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
+
+def test_struct_array_guess_length_2():
+    ffi = FFI()
+    ffi.cdef("struct foo_s { int a[]; ...; };\n"    # <= no declared length
+             "int bar(struct foo_s *);\n")
+    lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n"
+                     "int bar(struct foo_s *f) { return f->a[14]; }\n")
+    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
+    s = ffi.new("struct foo_s")
+    s.a[14] = 4242
+    assert lib.bar(s) == 4242
+
+def test_global_constants():
+    ffi = FFI()
+    # use 'static const int', as generally documented, although in this
+    # case the 'static' is completely ignored.
+    ffi.cdef("static const int AA, BB, CC, DD;")
+    lib = ffi.verify("#define AA 42\n"
+                     "#define BB (-43)\n"
+                     "#define CC (22*2)\n"
+                     "#define DD ((unsigned int)142)\n")
+    assert lib.AA == 42
+    assert lib.BB == -43
+    assert lib.CC == 44
+    assert lib.DD == 142
+
+def test_global_const_int_size():
+    # integer constants: ignore the declared type, always just use the value
+    for value in [-2**63, -2**31, -2**15,
+                  2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32,
+                  2**63-1, 2**63, 2**64-1]:
+        ffi = FFI()
+        if value == int(ffi.cast("long long", value)):
+            if value < 0:
+                vstr = '(-%dLL-1)' % (~value,)
+            else:
+                vstr = '%dLL' % value
+        elif value == int(ffi.cast("unsigned long long", value)):
+            vstr = '%dULL' % value
+        else:
+            raise AssertionError(value)
+        ffi.cdef("static const unsigned short AA;")
+        lib = ffi.verify("#define AA %s\n" % vstr)
+        assert lib.AA == value
+        assert type(lib.AA) is type(int(lib.AA))
+
+def test_nonfull_enum():
+    ffi = FFI()
+    ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };")
+    py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2')
+    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
+    assert int(ffi.cast('enum ee', 'EE2')) == 11
+    assert int(ffi.cast('enum ee', 'EE3')) == -10
+    py.test.raises(ValueError, ffi.cast, 'enum ee', '__dotdotdot0__')
+
+def test_full_enum():
+    ffi = FFI()
+    ffi.cdef("enum ee { EE1, EE2, EE3 };")
+    ffi.verify("enum ee { EE1, EE2, EE3 };")
+    py.test.raises(VerificationError, ffi.verify, "enum ee { EE1, EE2 };")
+    e = py.test.raises(VerificationError, ffi.verify,
+                       "enum ee { EE1, EE3, EE2 };")
+    assert str(e.value) == 'in enum ee: EE2 has the real value 2, not 1'
+    # extra items cannot be seen and have no bad consequence anyway
+    ffi.verify("enum ee { EE1, EE2, EE3, EE4 };")


More information about the pypy-commit mailing list