Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r2049:c870763046a6
Date: 2015-05-18 18:22 +0200
http://bitbucket.org/cffi/cffi/changeset/c870763046a6/

Log:    hg merge cffi-1.0

diff too long, truncating to 2000 out of 19486 lines

diff --git a/MANIFEST.in b/MANIFEST.in
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,6 @@
-recursive-include cffi *.py
+recursive-include cffi *.py *.h
 recursive-include c *.c *.h *.asm *.py win64.obj
 recursive-include testing *.py
 recursive-include doc *.py *.rst Makefile *.bat
-recursive-include demo py.cleanup *.py
-include LICENSE setup_base.py
+recursive-include demo py.cleanup *.py manual.c
+include AUTHORS LICENSE setup.py setup_base.py
diff --git a/TODO b/TODO
deleted file mode 100644
--- a/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-Add other required types from stdint.h
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -72,6 +72,7 @@
 # define PyText_FromString PyUnicode_FromString
 # define PyText_FromStringAndSize PyUnicode_FromStringAndSize
 # define PyText_InternInPlace PyUnicode_InternInPlace
+# define PyText_InternFromString PyUnicode_InternFromString
 # define PyIntOrLong_Check PyLong_Check
 #else
 # define STR_OR_BYTES "str"
@@ -85,6 +86,7 @@
 # define PyText_FromString PyString_FromString
 # define PyText_FromStringAndSize PyString_FromStringAndSize
 # define PyText_InternInPlace PyString_InternInPlace
+# define PyText_InternFromString PyString_InternFromString
 # define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op))
 #endif
 
@@ -92,6 +94,7 @@
 # define PyInt_FromLong PyLong_FromLong
 # define PyInt_FromSsize_t PyLong_FromSsize_t
 # define PyInt_AsSsize_t PyLong_AsSsize_t
+# define PyInt_AsLong PyLong_AsLong
 #endif
 
 #if PY_MAJOR_VERSION >= 3
@@ -131,6 +134,7 @@
 #define CT_IS_VOID_PTR         524288
 #define CT_WITH_VAR_ARRAY     1048576
 #define CT_IS_UNSIZED_CHAR_A  2097152
+#define CT_LAZY_FIELD_LIST    4194304
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
@@ -270,6 +274,8 @@
 # include "wchar_helper.h"
 #endif
 
+static PyObject *FFIError;
+
 /************************************************************/
 
 static CTypeDescrObject *
@@ -420,12 +426,21 @@
 static PyObject *
 get_field_name(CTypeDescrObject *ct, CFieldObject *cf);   /* forward */
 
+#define force_lazy_struct(ct)                                           \
+    ((ct)->ct_stuff != NULL ? 1 : do_realize_lazy_struct(ct))
+
+static int do_realize_lazy_struct(CTypeDescrObject *ct);
+/* forward, implemented in realize_c_type.c */
+
 static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context)
 {
     if (ct->ct_flags & (CT_STRUCT | CT_UNION)) {
         if (!(ct->ct_flags & CT_IS_OPAQUE)) {
             CFieldObject *cf;
-            PyObject *res = PyList_New(0);
+            PyObject *res;
+            if (force_lazy_struct(ct) < 0)
+                return NULL;
+            res = PyList_New(0);
             if (res == NULL)
                 return NULL;
             for (cf = (CFieldObject *)ct->ct_extra;
@@ -1217,6 +1232,9 @@
 {
     const char *expected;
 
+    if (force_lazy_struct(ct) < 0)
+        return -1;
+
     if (ct->ct_flags & CT_UNION) {
         Py_ssize_t n = PyObject_Size(init);
         if (n < 0)
@@ -1478,6 +1496,10 @@
     if ((ct->ct_flags & (CT_PRIMITIVE_ANY|CT_STRUCT|CT_UNION)) &&
         !(ct->ct_flags & CT_IS_OPAQUE)) {
         align = ct->ct_length;
+        if (align == -1 && (ct->ct_flags & CT_LAZY_FIELD_LIST)) {
+            force_lazy_struct(ct);
+            align = ct->ct_length;
+        }
     }
     else if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR)) {
         struct aligncheck_ptr { char x; char *y; };
@@ -1903,7 +1925,7 @@
 }
 
 static PyObject *
-new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj);   /* forward */
+new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length);   /* forward */
 
 static CTypeDescrObject *
 _cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[])
@@ -1968,7 +1990,7 @@
         return NULL;
 
     if (ct->ct_stuff == NULL) {
-        ct->ct_stuff = new_array_type(ct, Py_None);
+        ct->ct_stuff = new_array_type(ct, -1);
         if (ct->ct_stuff == NULL)
             return NULL;
     }
@@ -2220,18 +2242,26 @@
     if (ct->ct_flags & CT_POINTER)
         ct = ct->ct_itemdescr;
 
-    if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
-        cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
-        if (cf != NULL) {
-            /* read the field 'cf' */
-            char *data = cd->c_data + cf->cf_offset;
-            if (cf->cf_bitshift == BS_REGULAR)
-                return convert_to_object(data, cf->cf_type);
-            else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
-                return new_simple_cdata(data,
-                    (CTypeDescrObject *)cf->cf_type->ct_stuff);
-            else
-                return convert_to_object_bitfield(data, cf);
+    if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+        switch (force_lazy_struct(ct)) {
+        case 1:
+            cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+            if (cf != NULL) {
+                /* read the field 'cf' */
+                char *data = cd->c_data + cf->cf_offset;
+                if (cf->cf_bitshift == BS_REGULAR)
+                    return convert_to_object(data, cf->cf_type);
+                else if (cf->cf_bitshift == BS_EMPTY_ARRAY)
+                    return new_simple_cdata(data,
+                        (CTypeDescrObject *)cf->cf_type->ct_stuff);
+                else
+                    return convert_to_object_bitfield(data, cf);
+            }
+            break;
+        case -1:
+            return NULL;
+        default:
+            break;
         }
     }
     return PyObject_GenericGetAttr((PyObject *)cd, attr);
@@ -2246,18 +2276,26 @@
     if (ct->ct_flags & CT_POINTER)
         ct = ct->ct_itemdescr;
 
-    if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) {
-        cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
-        if (cf != NULL) {
-            /* write the field 'cf' */
-            if (value != NULL) {
-                return convert_field_from_object(cd->c_data, cf, value);
+    if (ct->ct_flags & (CT_STRUCT|CT_UNION)) {
+        switch (force_lazy_struct(ct)) {
+        case 1:
+            cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr);
+            if (cf != NULL) {
+                /* write the field 'cf' */
+                if (value != NULL) {
+                    return convert_field_from_object(cd->c_data, cf, value);
+                }
+                else {
+                    PyErr_SetString(PyExc_AttributeError,
+                                    "cannot delete struct field");
+                    return -1;
+                }
             }
-            else {
-                PyErr_SetString(PyExc_AttributeError,
-                                "cannot delete struct field");
-                return -1;
-            }
+            break;
+        case -1:
+            return -1;
+        default:
+            break;
         }
     }
     return PyObject_GenericSetAttr((PyObject *)cd, attr, value);
@@ -2269,18 +2307,13 @@
 static cif_description_t *
 fb_prepare_cif(PyObject *fargs, CTypeDescrObject *, ffi_abi);      /*forward*/
 
-static PyObject *
-b_new_primitive_type(PyObject *self, PyObject *args);              /*forward*/
+static PyObject *new_primitive_type(const char *name);             /*forward*/
 
 static CTypeDescrObject *_get_ct_int(void)
 {
     static CTypeDescrObject *ct_int = NULL;
     if (ct_int == NULL) {
-        PyObject *args = Py_BuildValue("(s)", "int");
-        if (args == NULL)
-            return NULL;
-        ct_int = (CTypeDescrObject *)b_new_primitive_type(NULL, args);
-        Py_DECREF(args);
+        ct_int = (CTypeDescrObject *)new_primitive_type("int");
     }
     return ct_int;
 }
@@ -2801,14 +2834,11 @@
     return (PyObject *)cd;
 }
 
-static PyObject *b_newp(PyObject *self, PyObject *args)
-{
-    CTypeDescrObject *ct, *ctitem;
+static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init)
+{
+    CTypeDescrObject *ctitem;
     CDataObject *cd;
-    PyObject *init = Py_None;
     Py_ssize_t dataoffset, datasize, explicitlength;
-    if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
-        return NULL;
 
     explicitlength = -1;
     if (ct->ct_flags & CT_POINTER) {
@@ -2824,11 +2854,16 @@
         if (ctitem->ct_flags & CT_PRIMITIVE_CHAR)
             datasize *= 2;   /* forcefully add another character: a null */
 
-        if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) {
-            Py_ssize_t optvarsize = datasize;
-            if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0)
+        if ((ctitem->ct_flags & (CT_STRUCT | CT_UNION)) && init != Py_None) {
+            if (force_lazy_struct(ctitem) < 0)   /* for CT_WITH_VAR_ARRAY */
                 return NULL;
-            datasize = optvarsize;
+            if (ctitem->ct_flags & CT_WITH_VAR_ARRAY) {
+                Py_ssize_t optvarsize = datasize;
+                if (convert_struct_from_object(NULL,ctitem, init,
+                                               &optvarsize) < 0)
+                    return NULL;
+                datasize = optvarsize;
+            }
         }
     }
     else if (ct->ct_flags & CT_ARRAY) {
@@ -2899,6 +2934,15 @@
     return (PyObject *)cd;
 }
 
+static PyObject *b_newp(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ct;
+    PyObject *init = Py_None;
+    if (!PyArg_ParseTuple(args, "O!|O:newp", &CTypeDescr_Type, &ct, &init))
+        return NULL;
+    return direct_newp(ct, init);
+}
+
 static int
 _my_PyObject_AsBool(PyObject *ob)
 {
@@ -3029,13 +3073,9 @@
     return cd;
 }
 
-static PyObject *b_cast(PyObject *self, PyObject *args)
-{
-    CTypeDescrObject *ct;
+static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob)
+{
     CDataObject *cd;
-    PyObject *ob;
-    if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob))
-        return NULL;
 
     if (ct->ct_flags & (CT_POINTER|CT_FUNCTIONPTR|CT_ARRAY) &&
         ct->ct_size >= 0) {
@@ -3152,6 +3192,16 @@
     return NULL;
 }
 
+static PyObject *b_cast(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ct;
+    PyObject *ob;
+    if (!PyArg_ParseTuple(args, "O!O:cast", &CTypeDescr_Type, &ct, &ob))
+        return NULL;
+
+    return do_cast(ct, ob);
+}
+
 /************************************************************/
 
 typedef struct {
@@ -3338,7 +3388,58 @@
 
 /************************************************************/
 
-static PyObject *b_new_primitive_type(PyObject *self, PyObject *args)
+static PyObject *unique_cache;
+
+static PyObject *get_unique_type(CTypeDescrObject *x,
+                                 const void *unique_key[], long keylength)
+{
+    /* Replace the CTypeDescrObject 'x' with a standardized one.
+       This either just returns x, or x is decrefed and a new reference
+       to the already-existing equivalent is returned.
+
+       In this function, 'x' always contains a reference that must be
+       either decrefed or returned.
+
+       Keys:
+           void       ["void"]
+           primitive  [&static_struct]
+           pointer    [ctype]
+           array      [ctype, length]
+           funcptr    [ctresult, ellipsis+abi, num_args, ctargs...]
+    */
+    long i;
+    PyObject *key, *y;
+    const void **pkey;
+    int err;
+
+    key = PyBytes_FromStringAndSize(NULL, keylength * sizeof(void *));
+    if (key == NULL)
+        goto error;
+
+    pkey = (const void **)PyBytes_AS_STRING(key);
+    for (i = 0; i < keylength; i++)
+        pkey[i] = unique_key[i];
+
+    y = PyDict_GetItem(unique_cache, key);
+    if (y != NULL) {
+        Py_DECREF(key);
+        Py_INCREF(y);
+        Py_DECREF(x);
+        return y;
+    }
+    err = PyDict_SetItem(unique_cache, key, (PyObject *)x);
+    Py_DECREF(key);
+    if (err < 0)
+        goto error;
+
+    return (PyObject *)x;
+
+ error:
+    Py_DECREF(x);
+    return NULL;
+}
+
+static PyObject *new_primitive_type(const char *name)
 {
 #define ENUM_PRIMITIVE_TYPES                                    \
        EPTYPE(c, char, CT_PRIMITIVE_CHAR)                       \
@@ -3403,7 +3504,6 @@
 #undef EPTYPE
 
     CTypeDescrObject *td;
-    const char *name;
     static const struct descr_s { const char *name; int size, align, flags; }
     types[] = {
 #define EPTYPE(code, typename, flags)                   \
@@ -3419,12 +3519,10 @@
         { NULL }
     };
     const struct descr_s *ptypes;
+    const void *unique_key[1];
     int name_size;
     ffi_type *ffitype;
 
-    if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name))
-        return NULL;
-
     for (ptypes=types; ; ptypes++) {
         if (ptypes->name == NULL) {
 #ifndef HAVE_WCHAR_H
@@ -3487,7 +3585,8 @@
             td->ct_flags |= CT_PRIMITIVE_FITS_LONG;
     }
     td->ct_name_position = strlen(td->ct_name);
-    return (PyObject *)td;
+    unique_key[0] = ptypes;
+    return get_unique_type(td, unique_key, 1);
 
  bad_ffi_type:
     PyErr_Format(PyExc_NotImplementedError,
@@ -3497,14 +3596,19 @@
     return NULL;
 }
 
-static PyObject *b_new_pointer_type(PyObject *self, PyObject *args)
-{
-    CTypeDescrObject *td, *ctitem;
+static PyObject *b_new_primitive_type(PyObject *self, PyObject *args)
+{
+    char *name;
+    if (!PyArg_ParseTuple(args, "s:new_primitive_type", &name))
+        return NULL;
+    return new_primitive_type(name);
+}
+
+static PyObject *new_pointer_type(CTypeDescrObject *ctitem)
+{
+    CTypeDescrObject *td;
     const char *extra;
-
-    if (!PyArg_ParseTuple(args, "O!:new_pointer_type",
-                          &CTypeDescr_Type, &ctitem))
-        return NULL;
+    const void *unique_key[1];
 
     if (ctitem->ct_flags & CT_ARRAY)
         extra = "(*)";   /* obscure case: see test_array_add */
@@ -3525,47 +3629,31 @@
         ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
          ctitem->ct_size == sizeof(char)))
         td->ct_flags |= CT_CAST_ANYTHING;   /* 'void *' or 'char *' only */
-    return (PyObject *)td;
+    unique_key[0] = ctitem;
+    return get_unique_type(td, unique_key, 1);
+}
+
+static PyObject *b_new_pointer_type(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ctitem;
+    if (!PyArg_ParseTuple(args, "O!:new_pointer_type",
+                          &CTypeDescr_Type, &ctitem))
+        return NULL;
+    return new_pointer_type(ctitem);
 }
 
 static PyObject *b_new_array_type(PyObject *self, PyObject *args)
 {
     PyObject *lengthobj;
+    Py_ssize_t length;
     CTypeDescrObject *ctptr;
 
     if (!PyArg_ParseTuple(args, "O!O:new_array_type",
                           &CTypeDescr_Type, &ctptr, &lengthobj))
         return NULL;
 
-    return new_array_type(ctptr, lengthobj);
-}
-
-static PyObject *
-new_array_type(CTypeDescrObject *ctptr, PyObject *lengthobj)
-{
-    CTypeDescrObject *td, *ctitem;
-    char extra_text[32];
-    Py_ssize_t length, arraysize;
-    int flags = CT_ARRAY;
-
-    if (!(ctptr->ct_flags & CT_POINTER)) {
-        PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype");
-        return NULL;
-    }
-    ctitem = ctptr->ct_itemdescr;
-    if (ctitem->ct_size < 0) {
-        PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'",
-                     ctitem->ct_name);
-        return NULL;
-    }
-
     if (lengthobj == Py_None) {
-        sprintf(extra_text, "[]");
         length = -1;
-        arraysize = -1;
-        if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
-                ctitem->ct_size == sizeof(char))
-            flags |= CT_IS_UNSIZED_CHAR_A;
     }
     else {
         length = PyNumber_AsSsize_t(lengthobj, PyExc_OverflowError);
@@ -3574,6 +3662,39 @@
                 PyErr_SetString(PyExc_ValueError, "negative array length");
             return NULL;
         }
+    }
+    return new_array_type(ctptr, length);
+}
+
+static PyObject *
+new_array_type(CTypeDescrObject *ctptr, Py_ssize_t length)
+{
+    CTypeDescrObject *td, *ctitem;
+    char extra_text[32];
+    Py_ssize_t arraysize;
+    int flags = CT_ARRAY;
+    const void *unique_key[2];
+
+    if (!(ctptr->ct_flags & CT_POINTER)) {
+        PyErr_SetString(PyExc_TypeError, "first arg must be a pointer ctype");
+        return NULL;
+    }
+    ctitem = ctptr->ct_itemdescr;
+    if (ctitem->ct_size < 0) {
+        PyErr_Format(PyExc_ValueError, "array item of unknown size: '%s'",
+                     ctitem->ct_name);
+        return NULL;
+    }
+
+    if (length < 0) {
+        sprintf(extra_text, "[]");
+        length = -1;
+        arraysize = -1;
+        if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
+                ctitem->ct_size == sizeof(char))
+            flags |= CT_IS_UNSIZED_CHAR_A;
+    }
+    else {
         sprintf(extra_text, "[%llu]", (unsigned PY_LONG_LONG)length);
         arraysize = length * ctitem->ct_size;
         if (length > 0 && (arraysize / length) != ctitem->ct_size) {
@@ -3591,12 +3712,15 @@
     td->ct_size = arraysize;
     td->ct_length = length;
     td->ct_flags = flags;
-    return (PyObject *)td;
-}
-
-static PyObject *b_new_void_type(PyObject *self, PyObject *args)
+    unique_key[0] = ctptr;
+    unique_key[1] = (void *)length;
+    return get_unique_type(td, unique_key, 2);
+}
+
+static PyObject *new_void_type(void)
 {
     int name_size = strlen("void") + 1;
+    const void *unique_key[1];
     CTypeDescrObject *td = ctypedescr_new(name_size);
     if (td == NULL)
         return NULL;
@@ -3605,10 +3729,16 @@
     td->ct_size = -1;
     td->ct_flags = CT_VOID | CT_IS_OPAQUE;
     td->ct_name_position = strlen("void");
-    return (PyObject *)td;
-}
-
-static PyObject *_b_struct_or_union_type(const char *name, int flag)
+    unique_key[0] = "void";
+    return get_unique_type(td, unique_key, 1);
+}
+
+static PyObject *b_new_void_type(PyObject *self, PyObject *args)
+{
+    return new_void_type();
+}
+
+static PyObject *new_struct_or_union_type(const char *name, int flag)
 {
     int namelen = strlen(name);
     CTypeDescrObject *td = ctypedescr_new(namelen + 1);
@@ -3618,6 +3748,7 @@
     td->ct_size = -1;
     td->ct_length = -1;
     td->ct_flags = flag | CT_IS_OPAQUE;
+    td->ct_extra = NULL;
     memcpy(td->ct_name, name, namelen + 1);
     td->ct_name_position = namelen;
     return (PyObject *)td;
@@ -3633,7 +3764,7 @@
     flag = CT_STRUCT;
     if (strcmp(name, "struct _IO_FILE") == 0 || strcmp(name, "FILE") == 0)
         flag |= CT_IS_FILE;
-    return _b_struct_or_union_type(name, flag);
+    return new_struct_or_union_type(name, flag);
 }
 
 static PyObject *b_new_union_type(PyObject *self, PyObject *args)
@@ -3641,7 +3772,7 @@
     char *name;
     if (!PyArg_ParseTuple(args, "s:new_union_type", &name))
         return NULL;
-    return _b_struct_or_union_type(name, CT_UNION);
+    return new_struct_or_union_type(name, CT_UNION);
 }
 
 static CFieldObject *
@@ -3685,6 +3816,7 @@
 #define SF_GCC_LITTLE_ENDIAN  0x40
 
 #define SF_PACKED             0x08
+#define SF_STD_FIELD_POS      0x80
 
 static int complete_sflags(int sflags)
 {
@@ -3712,12 +3844,34 @@
     return sflags;
 }
 
+static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
+                                Py_ssize_t cdef_value,
+                                Py_ssize_t compiler_value,
+                                const char *msg1, const char *txt,
+                                const char *msg2)
+{
+    if (compiler_value != cdef_value) {
+        if (sflags & SF_STD_FIELD_POS) {
+            PyErr_Format(FFIError,
+                         "%s: %s%s%s (cdef says %zd, but C compiler says %zd)."
+                         " fix it or use \"...;\" in the cdef for %s to "
+                         "make it flexible",
+                         ct->ct_name, msg1, txt, msg2,
+                         cdef_value, compiler_value,
+                         ct->ct_name);
+            return -1;
+        }
+        ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+    }
+    return 0;
+}
+
 static PyObject *b_complete_struct_or_union(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct;
     PyObject *fields, *interned_fields, *ignored;
     int is_union, alignment;
-    Py_ssize_t boffset, i, nb_fields, boffsetmax;
+    Py_ssize_t boffset, i, nb_fields, boffsetmax, alignedsize;
     Py_ssize_t totalsize = -1;
     int totalalignment = -1;
     CFieldObject **previous;
@@ -3745,6 +3899,7 @@
                   "first arg must be a non-initialized struct or union ctype");
         return NULL;
     }
+    ct->ct_flags &= ~CT_CUSTOM_FIELD_POS;
 
     alignment = 1;
     boffset = 0;         /* this number is in *bits*, not bytes! */
@@ -3822,8 +3977,10 @@
             if (foffset >= 0) {
                 /* a forced field position: ignore the offset just computed,
                    except to know if we must set CT_CUSTOM_FIELD_POS */
-                if (boffset != foffset * 8)
-                    ct->ct_flags |= CT_CUSTOM_FIELD_POS;
+                if (detect_custom_layout(ct, sflags, boffset / 8, foffset,
+                                         "wrong offset for field '",
+                                         PyText_AS_UTF8(fname), "'") < 0)
+                    goto error;
                 boffset = foffset * 8;
             }
 
@@ -3996,19 +4153,35 @@
        as 1 instead.  But for ctypes support, we allow the manually-
        specified totalsize to be zero in this case. */
     boffsetmax = (boffsetmax + 7) / 8;        /* bits -> bytes */
+    alignedsize = (boffsetmax + alignment - 1) & ~(alignment-1);
+    if (alignedsize == 0)
+        alignedsize = 1;
+
     if (totalsize < 0) {
-        totalsize = (boffsetmax + alignment - 1) & ~(alignment-1);
-        if (totalsize == 0)
-            totalsize = 1;
-    }
-    else if (totalsize < boffsetmax) {
-        PyErr_Format(PyExc_TypeError,
-                     "%s cannot be of size %zd: there are fields at least "
-                     "up to %zd", ct->ct_name, totalsize, boffsetmax);
-        goto error;
-    }
+        totalsize = alignedsize;
+    }
+    else {
+        if (detect_custom_layout(ct, sflags, alignedsize,
+                                 totalsize, "wrong total size", "", "") < 0)
+            goto error;
+        if (totalsize < boffsetmax) {
+            PyErr_Format(PyExc_TypeError,
+                         "%s cannot be of size %zd: there are fields at least "
+                         "up to %zd", ct->ct_name, totalsize, boffsetmax);
+            goto error;
+        }
+    }
+    if (totalalignment < 0) {
+        totalalignment = alignment;
+    }
+    else {
+        if (detect_custom_layout(ct, sflags, alignment, totalalignment,
+                                 "wrong total alignment", "", "") < 0)
+            goto error;
+    }
+
     ct->ct_size = totalsize;
-    ct->ct_length = totalalignment < 0 ? alignment : totalalignment;
+    ct->ct_length = totalalignment;
     ct->ct_stuff = interned_fields;
     ct->ct_flags &= ~CT_IS_OPAQUE;
 
@@ -4016,6 +4189,7 @@
     return Py_None;
 
  error:
+    ct->ct_extra = NULL;
     Py_DECREF(interned_fields);
     return NULL;
 }
@@ -4045,6 +4219,8 @@
 static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
                               int is_result_type)
 {
+    const char *place = is_result_type ? "return value" : "argument";
+
     if (ct->ct_flags & CT_PRIMITIVE_ANY) {
         return (ffi_type *)ct->ct_extra;
     }
@@ -4081,10 +4257,15 @@
            here, so better safe (and forbid it) than sorry (and maybe
            crash).
         */
+        if (force_lazy_struct(ct) < 0)
+            return NULL;
         if (ct->ct_flags & CT_CUSTOM_FIELD_POS) {
-            PyErr_SetString(PyExc_TypeError,
-                "cannot pass as an argument a struct that was completed "
-                "with verify() (see _cffi_backend.c for details of why)");
+            /* these NotImplementedErrors may be caught and ignored until
+               a real call is made to a function of this type */
+            PyErr_Format(PyExc_NotImplementedError,
+                "ctype '%s' not supported as %s (it is a struct declared "
+                "with \"...;\", but the C calling convention may depend "
+                "on the missing fields)", ct->ct_name, place);
             return NULL;
         }
 
@@ -4100,9 +4281,9 @@
             assert(cf != NULL);
             if (cf->cf_bitshift >= 0) {
                 PyErr_Format(PyExc_NotImplementedError,
-                     "ctype '%s' not supported as argument or return value"
+                     "ctype '%s' not supported as %s"
                      " (it is a struct with bit fields)",
-                     ct->ct_name);
+                     ct->ct_name, place);
                 return NULL;
             }
             flat = 1;
@@ -4113,9 +4294,9 @@
             }
             if (flat <= 0) {
                 PyErr_Format(PyExc_NotImplementedError,
-                     "ctype '%s' not supported as argument or return value"
+                     "ctype '%s' not supported as %s"
                      " (it is a struct with a zero-length array)",
-                     ct->ct_name);
+                     ct->ct_name, place);
                 return NULL;
             }
             nflat += flat;
@@ -4154,7 +4335,6 @@
         return ffistruct;
     }
     else {
-        const char *place = is_result_type ? "return value" : "argument";
         PyErr_Format(PyExc_NotImplementedError,
                      "ctype '%s' (size %zd) not supported as %s",
                      ct->ct_name, ct->ct_size, place);
@@ -4370,21 +4550,15 @@
     return NULL;
 }
 
-static PyObject *b_new_function_type(PyObject *self, PyObject *args)
-{
-    PyObject *fargs, *fabiobj;
-    CTypeDescrObject *fresult;
+static PyObject *new_function_type(PyObject *fargs,   /* tuple */
+                                   CTypeDescrObject *fresult,
+                                   int ellipsis, int fabi)
+{
+    PyObject *fabiobj;
     CTypeDescrObject *fct;
-    int ellipsis = 0, fabi = FFI_DEFAULT_ABI;
     struct funcbuilder_s funcbuilder;
     Py_ssize_t i;
-
-    if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type",
-                          &PyTuple_Type, &fargs,
-                          &CTypeDescr_Type, &fresult,
-                          &ellipsis,
-                          &fabi))
-        return NULL;
+    const void **unique_key;
 
     if ((fresult->ct_size < 0 && !(fresult->ct_flags & CT_VOID)) ||
         (fresult->ct_flags & CT_ARRAY)) {
@@ -4440,15 +4614,37 @@
         Py_INCREF(o);
         PyTuple_SET_ITEM(fct->ct_stuff, 2 + i, o);
     }
-    fct->ct_size = sizeof(void(*)(void));
-    fct->ct_flags = CT_FUNCTIONPTR;
-    return (PyObject *)fct;
+
+    /* [ctresult, ellipsis+abi, num_args, ctargs...] */
+    unique_key = alloca((3 + funcbuilder.nargs) * sizeof(void *));
+    unique_key[0] = fresult;
+    unique_key[1] = (const void *)(Py_ssize_t)((fabi << 1) | !!ellipsis);
+    unique_key[2] = (const void *)(Py_ssize_t)(funcbuilder.nargs);
+    for (i=0; i<funcbuilder.nargs; i++)
+        unique_key[3 + i] = PyTuple_GET_ITEM(fct->ct_stuff, 2 + i);
+    return get_unique_type(fct, unique_key, 3 + funcbuilder.nargs);
 
  error:
     Py_DECREF(fct);
     return NULL;
 }
 
+static PyObject *b_new_function_type(PyObject *self, PyObject *args)
+{
+    PyObject *fargs;
+    CTypeDescrObject *fresult;
+    int ellipsis = 0, fabi = FFI_DEFAULT_ABI;
+
+    if (!PyArg_ParseTuple(args, "O!O!|ii:new_function_type",
+                          &PyTuple_Type, &fargs,
+                          &CTypeDescr_Type, &fresult,
+                          &ellipsis,
+                          &fabi))
+        return NULL;
+
+    return new_function_type(fargs, fresult, ellipsis, fabi);
+}
+
 static int convert_from_object_fficallback(char *result,
                                            CTypeDescrObject *ctype,
                                            PyObject *pyobj)
@@ -4831,25 +5027,26 @@
     return res;
 }
 
-static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
-{
-    PyObject *res, *fieldname;
-    CTypeDescrObject *ct;
+static CTypeDescrObject *direct_typeoffsetof(CTypeDescrObject *ct,
+                                             PyObject *fieldname,
+                                             int following, Py_ssize_t *offset)
+{
+    /* Does not return a new reference! */
+    CTypeDescrObject *res;
     CFieldObject *cf;
-    Py_ssize_t offset;
-    int following = 0;
-
-    if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
-                          &CTypeDescr_Type, &ct, &fieldname, &following))
-        return NULL;
 
     if (PyTextAny_Check(fieldname)) {
         if (!following && (ct->ct_flags & CT_POINTER))
             ct = ct->ct_itemdescr;
-        if (!(ct->ct_flags & (CT_STRUCT|CT_UNION)) || ct->ct_stuff == NULL) {
+        if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) {
             PyErr_SetString(PyExc_TypeError,
-                            "with a field name argument, expected an "
-                            "initialized struct or union ctype");
+                            "with a field name argument, expected a "
+                            "struct or union ctype");
+            return NULL;
+        }
+        if (force_lazy_struct(ct) <= 0) {
+            if (!PyErr_Occurred())
+                PyErr_SetString(PyExc_TypeError, "struct/union is opaque");
             return NULL;
         }
         cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, fieldname);
@@ -4861,8 +5058,8 @@
             PyErr_SetString(PyExc_TypeError, "not supported for bitfields");
             return NULL;
         }
-        res = (PyObject *)cf->cf_type;
-        offset = cf->cf_offset;
+        res = cf->cf_type;
+        *offset = cf->cf_offset;
     }
     else {
         ssize_t index = PyInt_AsSsize_t(fieldname);
@@ -4879,14 +5076,32 @@
                                              "pointer to non-opaque");
             return NULL;
         }
-        res = (PyObject *)ct->ct_itemdescr;
-        offset = index * ct->ct_itemdescr->ct_size;
-        if ((offset / ct->ct_itemdescr->ct_size) != index) {
+        res = ct->ct_itemdescr;
+        *offset = index * ct->ct_itemdescr->ct_size;
+        if ((*offset / ct->ct_itemdescr->ct_size) != index) {
             PyErr_SetString(PyExc_OverflowError,
                             "array offset would overflow a Py_ssize_t");
             return NULL;
         }
     }
+    return res;
+}
+
+static PyObject *b_typeoffsetof(PyObject *self, PyObject *args)
+{
+    PyObject *res, *fieldname;
+    CTypeDescrObject *ct;
+    Py_ssize_t offset;
+    int following = 0;
+
+    if (!PyArg_ParseTuple(args, "O!O|i:typeoffsetof",
+                          &CTypeDescr_Type, &ct, &fieldname, &following))
+        return NULL;
+
+    res = (PyObject *)direct_typeoffsetof(ct, fieldname, following, &offset);
+    if (res == NULL)
+        return NULL;
+
     return Py_BuildValue("(On)", res, offset);
 }
 
@@ -5069,12 +5284,16 @@
     return PyInt_FromLong(err);
 }
 
-static PyObject *b_set_errno(PyObject *self, PyObject *args)
-{
-    int i;
-    if (!PyArg_ParseTuple(args, "i:set_errno", &i))
+static PyObject *b_set_errno(PyObject *self, PyObject *arg)
+{
+    long ival = PyInt_AsLong(arg);
+    if (ival == -1 && PyErr_Occurred())
         return NULL;
-    errno = i;
+    else if (ival < INT_MIN || ival > INT_MAX) {
+        PyErr_SetString(PyExc_OverflowError, "errno value too large");
+        return NULL;
+    }
+    errno = (int)ival;
     save_errno_only();
     errno = 0;
     Py_INCREF(Py_None);
@@ -5211,21 +5430,11 @@
     return 0;
 }
 
-static PyObject *b_from_buffer(PyObject *self, PyObject *args)
-{
-    CTypeDescrObject *ct;
+static PyObject *direct_from_buffer(CTypeDescrObject *ct, PyObject *x)
+{
     CDataObject *cd;
-    PyObject *x;
     Py_buffer *view;
 
-    if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
-        return NULL;
-
-    if (!(ct->ct_flags & CT_IS_UNSIZED_CHAR_A)) {
-        PyErr_Format(PyExc_TypeError, "needs 'char[]', got '%s'", ct->ct_name);
-        return NULL;
-    }
-
     if (invalid_input_buffer_type(x)) {
         PyErr_SetString(PyExc_TypeError,
                         "from_buffer() cannot return the address of the "
@@ -5259,6 +5468,21 @@
     return NULL;
 }
 
+static PyObject *b_from_buffer(PyObject *self, PyObject *args)
+{
+    CTypeDescrObject *ct;
+    PyObject *x;
+
+    if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x))
+        return NULL;
+
+    if (!(ct->ct_flags & CT_IS_UNSIZED_CHAR_A)) {
+        PyErr_Format(PyExc_TypeError, "needs 'char[]', got '%s'", ct->ct_name);
+        return NULL;
+    }
+    return direct_from_buffer(ct, x);
+}
+
 static PyObject *b__get_types(PyObject *self, PyObject *noarg)
 {
     return PyTuple_Pack(2, (PyObject *)&CData_Type,
@@ -5539,6 +5763,10 @@
     return Py_None;
 }
 
+static PyObject *b_init_cffi_1_0_external_module(PyObject *, PyObject *);
+/* forward, see cffi1_module.c */
+
+
 static PyMethodDef FFIBackendMethods[] = {
     {"load_library", b_load_library, METH_VARARGS},
     {"new_primitive_type", b_new_primitive_type, METH_VARARGS},
@@ -5562,7 +5790,7 @@
     {"string", b_string, METH_VARARGS},
     {"buffer", b_buffer, METH_VARARGS},
     {"get_errno", b_get_errno, METH_NOARGS},
-    {"set_errno", b_set_errno, METH_VARARGS},
+    {"set_errno", b_set_errno, METH_O},
     {"newp_handle", b_newp_handle, METH_VARARGS},
     {"from_handle", b_from_handle, METH_O},
     {"from_buffer", b_from_buffer, METH_VARARGS},
@@ -5572,6 +5800,7 @@
     {"_get_types", b__get_types, METH_NOARGS},
     {"_testfunc", b__testfunc, METH_VARARGS},
     {"_testbuff", b__testbuff, METH_VARARGS},
+    {"_init_cffi_1_0_external_module", b_init_cffi_1_0_external_module, 
METH_O},
     {NULL,     NULL}    /* Sentinel */
 };
 
@@ -5685,7 +5914,7 @@
 #endif
 
 static void *cffi_exports[] = {
-    0,
+    NULL,
     _cffi_to_c_i8,
     _cffi_to_c_u8,
     _cffi_to_c_i16,
@@ -5717,6 +5946,32 @@
     convert_array_from_object,
 };
 
+static struct { const char *name; int value; } all_dlopen_flags[] = {
+    { "RTLD_LAZY",     RTLD_LAZY     },
+    { "RTLD_NOW",      RTLD_NOW      },
+    { "RTLD_GLOBAL",   RTLD_GLOBAL   },
+#ifdef RTLD_LOCAL
+    { "RTLD_LOCAL",    RTLD_LOCAL    },
+#else
+    { "RTLD_LOCAL",    0             },
+#endif
+#ifdef RTLD_NODELETE
+    { "RTLD_NODELETE", RTLD_NODELETE },
+#endif
+#ifdef RTLD_NOLOAD
+    { "RTLD_NOLOAD",   RTLD_NOLOAD   },
+#endif
+#ifdef RTLD_DEEPBIND
+    { "RTLD_DEEPBIND", RTLD_DEEPBIND },
+#endif
+    { NULL, 0 }
+};
+
+
+/************************************************************/
+
+#include "cffi1_module.c"
+
 /************************************************************/
 
 #if PY_MAJOR_VERSION >= 3
@@ -5740,6 +5995,7 @@
 #endif
 {
     PyObject *m, *v;
+    int i;
 
     v = PySys_GetObject("version");
     if (v == NULL || !PyText_Check(v) ||
@@ -5758,6 +6014,11 @@
 
     if (m == NULL)
         INITERROR;
+
+    unique_cache = PyDict_New();
+    if (unique_cache == NULL)
+        INITERROR;
+
     if (PyType_Ready(&dl_type) < 0)
         INITERROR;
     if (PyType_Ready(&CTypeDescr_Type) < 0)
@@ -5784,11 +6045,12 @@
                                           "__name__", v) < 0)
         INITERROR;
 
+    /* this is for backward compatibility only */
     v = PyCapsule_New((void *)cffi_exports, "cffi", NULL);
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
         INITERROR;
 
-    v = PyText_FromString("0.9.2");
+    v = PyText_FromString("1.0.0");
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
@@ -5809,29 +6071,21 @@
         PyModule_AddIntConstant(m, "_WIN", 32) < 0 ||   /* win32 */
 #  endif
 #endif
-
-        PyModule_AddIntConstant(m, "RTLD_LAZY",   RTLD_LAZY) < 0 ||
-        PyModule_AddIntConstant(m, "RTLD_NOW",    RTLD_NOW) < 0 ||
-        PyModule_AddIntConstant(m, "RTLD_GLOBAL", RTLD_GLOBAL) < 0 ||
-#ifdef RTLD_LOCAL
-        PyModule_AddIntConstant(m, "RTLD_LOCAL",  RTLD_LOCAL) < 0 ||
-#else
-        PyModule_AddIntConstant(m, "RTLD_LOCAL",  0) < 0 ||
-#endif
-#ifdef RTLD_NODELETE
-        PyModule_AddIntConstant(m, "RTLD_NODELETE",  RTLD_NODELETE) < 0 ||
-#endif
-#ifdef RTLD_NOLOAD
-        PyModule_AddIntConstant(m, "RTLD_NOLOAD",  RTLD_NOLOAD) < 0 ||
-#endif
-#ifdef RTLD_DEEPBIND
-        PyModule_AddIntConstant(m, "RTLD_DEEPBIND",  RTLD_DEEPBIND) < 0 ||
-#endif
         0)
       INITERROR;
 
+    for (i = 0; all_dlopen_flags[i].name != NULL; i++) {
+        if (PyModule_AddIntConstant(m,
+                                    all_dlopen_flags[i].name,
+                                    all_dlopen_flags[i].value) < 0)
+            INITERROR;
+    }
+
     init_errno();
 
+    if (init_ffi_lib(m) < 0)
+        INITERROR;
+
 #if PY_MAJOR_VERSION >= 3
     if (init_file_emulator() < 0)
         INITERROR;
diff --git a/c/cdlopen.c b/c/cdlopen.c
new file mode 100644
--- /dev/null
+++ b/c/cdlopen.c
@@ -0,0 +1,382 @@
+/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
+
+static void *cdlopen_fetch(PyObject *libname, void *libhandle, char *symbol)
+{
+    void *address;
+
+    if (libhandle == NULL) {
+        PyErr_Format(FFIError, "library '%s' has been closed",
+                     PyText_AS_UTF8(libname));
+        return NULL;
+    }
+
+    dlerror();   /* clear error condition */
+    address = dlsym(libhandle, symbol);
+    if (address == NULL) {
+        const char *error = dlerror();
+        PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s",
+                     symbol, PyText_AS_UTF8(libname), error);
+    }
+    return address;
+}
+
+static void cdlopen_close_ignore_errors(void *libhandle)
+{
+    if (libhandle != NULL)
+        dlclose(libhandle);
+}
+
+static int cdlopen_close(PyObject *libname, void *libhandle)
+{
+    if (libhandle != NULL && dlclose(libhandle) != 0) {
+        const char *error = dlerror();
+        PyErr_Format(FFIError, "closing library '%s': %s",
+                     PyText_AS_UTF8(libname), error);
+        return -1;
+    }
+    return 0;
+}
+
+static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
+{
+    char *filename_or_null, *printable_filename;
+    void *handle;
+    int flags = 0;
+
+    if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
+        PyObject *dummy;
+        if (!PyArg_ParseTuple(args, "|Oi:load_library",
+                              &dummy, &flags))
+            return NULL;
+        filename_or_null = NULL;
+    }
+    else if (!PyArg_ParseTuple(args, "et|i:load_library",
+                          Py_FileSystemDefaultEncoding, &filename_or_null,
+                          &flags))
+        return NULL;
+
+    if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
+        flags |= RTLD_NOW;
+    printable_filename = filename_or_null ? filename_or_null : "<None>";
+
+    handle = dlopen(filename_or_null, flags);
+    if (handle == NULL) {
+        const char *error = dlerror();
+        PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
+                     printable_filename, error);
+        return NULL;
+    }
+    return (PyObject *)lib_internal_new((FFIObject *)self,
+                                        printable_filename, handle);
+}
+
+static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
+{
+    LibObject *lib;
+    void *libhandle;
+    if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
+        return NULL;
+
+    libhandle = lib->l_libhandle;
+    lib->l_libhandle = NULL;
+
+    if (libhandle == NULL) {
+        PyErr_Format(FFIError, "library '%s' is already closed "
+                     "or was not created with ffi.dlopen()",
+                     PyText_AS_UTF8(lib->l_libname));
+        return NULL;
+    }
+
+    /* Clear the dict to force further accesses to do cdlopen_fetch()
+       again, and fail because the library was closed. */
+    PyDict_Clear(lib->l_dict);
+
+    if (cdlopen_close(lib->l_libname, libhandle) < 0)
+        return NULL;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+static Py_ssize_t cdl_4bytes(char *src)
+{
+    /* read 4 bytes in little-endian order; return it as a signed integer */
+    signed char *ssrc = (signed char *)src;
+    unsigned char *usrc = (unsigned char *)src;
+    return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
+}
+
+static _cffi_opcode_t cdl_opcode(char *src)
+{
+    return (_cffi_opcode_t)cdl_4bytes(src);
+}
+
+typedef struct {
+    unsigned long long value;
+    int neg;
+} cdl_intconst_t;
+
+static int _cdl_realize_global_int(struct _cffi_getconst_s *gc)
+{
+    /* The 'address' field of 'struct _cffi_global_s' is set to point
+       to this function in case ffiobj_init() sees constant integers.
+       This fishes around after the 'ctx->globals' array, which is
+       initialized to contain another array, this time of
+       'cdl_intconst_t' structures.  We get the nth one and it tells
+       us what to return.
+    */
+    cdl_intconst_t *ic;
+    ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals);
+    ic += gc->gindex;
+    gc->value = ic->value;
+    return ic->neg;
+}
+
+static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    FFIObject *ffi;
+    static char *keywords[] = {"module_name", "_version", "_types",
+                               "_globals", "_struct_unions", "_enums",
+                               "_typenames", "_includes", NULL};
+    char *ffiname = "?", *types = NULL, *building = NULL;
+    Py_ssize_t version = -1;
+    Py_ssize_t types_len = 0;
+    PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
+    PyObject *typenames = NULL, *includes = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds,
+                                     "|sns#O!O!O!O!O!:FFI", keywords,
+                                     &ffiname, &version, &types, &types_len,
+                                     &PyTuple_Type, &globals,
+                                     &PyTuple_Type, &struct_unions,
+                                     &PyTuple_Type, &enums,
+                                     &PyTuple_Type, &typenames,
+                                     &PyTuple_Type, &includes))
+        return -1;
+
+    ffi = (FFIObject *)self;
+    if (ffi->ctx_is_nonempty) {
+        PyErr_SetString(PyExc_ValueError,
+                        "cannot call FFI.__init__() more than once");
+        return -1;
+    }
+    ffi->ctx_is_nonempty = 1;
+
+    if (version == -1 && types_len == 0)
+        return 0;
+    if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
+        PyErr_Format(PyExc_ImportError,
+                     "cffi out-of-line Python module '%s' has unknown "
+                     "version %p", ffiname, (void *)version);
+        return -1;
+    }
+
+    if (types_len > 0) {
+        /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */
+        _cffi_opcode_t *ntypes;
+        Py_ssize_t i, n = types_len / 4;
+
+        building = PyMem_Malloc(n * sizeof(_cffi_opcode_t));
+        if (building == NULL)
+            goto error;
+        ntypes = (_cffi_opcode_t *)building;
+
+        for (i = 0; i < n; i++) {
+            ntypes[i] = cdl_opcode(types);
+            types += 4;
+        }
+        ffi->types_builder.ctx.types = ntypes;
+        ffi->types_builder.ctx.num_types = n;
+        building = NULL;
+    }
+
+    if (globals != NULL) {
+        /* unpack a tuple alternating strings and ints, each two together
+           describing one global_s entry with no specified address or size.
+           The int is only used with integer constants. */
+        struct _cffi_global_s *nglobs;
+        cdl_intconst_t *nintconsts;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
+
+        i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t));
+        building = PyMem_Malloc(i);
+        if (building == NULL)
+            goto error;
+        memset(building, 0, i);
+        nglobs = (struct _cffi_global_s *)building;
+        nintconsts = (cdl_intconst_t *)(nglobs + n);
+
+        for (i = 0; i < n; i++) {
+            char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2));
+            nglobs[i].type_op = cdl_opcode(g); g += 4;
+            nglobs[i].name = g;
+            if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT ||
+                _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) {
+                PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1);
+                nglobs[i].address = &_cdl_realize_global_int;
+#if PY_MAJOR_VERSION < 3
+                if (PyInt_Check(o)) {
+                    nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
+                    nintconsts[i].value = (long long)PyInt_AS_LONG(o);
+                }
+                else
+#endif
+                {
+                    nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False,
+                                                                 Py_LE);
+                    nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o);
+                    if (PyErr_Occurred())
+                        goto error;
+                }
+            }
+        }
+        ffi->types_builder.ctx.globals = nglobs;
+        ffi->types_builder.ctx.num_globals = n;
+        building = NULL;
+    }
+
+    if (struct_unions != NULL) {
+        /* unpack a tuple of struct/unions, each described as a sub-tuple;
+           the item 0 of each sub-tuple describes the struct/union, and
+           the items 1..N-1 describe the fields, if any */
+        struct _cffi_struct_union_s *nstructs;
+        struct _cffi_field_s *nfields;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions);
+        Py_ssize_t nf = 0;   /* total number of fields */
+
+        for (i = 0; i < n; i++) {
+            nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1;
+        }
+        i = (n * sizeof(struct _cffi_struct_union_s) +
+             nf * sizeof(struct _cffi_field_s));
+        building = PyMem_Malloc(i);
+        if (building == NULL)
+            goto error;
+        memset(building, 0, i);
+        nstructs = (struct _cffi_struct_union_s *)building;
+        nfields = (struct _cffi_field_s *)(nstructs + n);
+        nf = 0;
+
+        for (i = 0; i < n; i++) {
+            /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) 
*/
+            PyObject *desc = PyTuple_GET_ITEM(struct_unions, i);
+            Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
+            char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0));
+            /* 's' is the first string, describing the struct/union */
+            nstructs[i].type_index = cdl_4bytes(s); s += 4;
+            nstructs[i].flags = cdl_4bytes(s); s += 4;
+            nstructs[i].name = s;
+            if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) {
+                nstructs[i].size = (size_t)-1;
+                nstructs[i].alignment = -1;
+                nstructs[i].first_field_index = -1;
+                nstructs[i].num_fields = 0;
+                assert(nf1 == 0);
+            }
+            else {
+                nstructs[i].size = (size_t)-2;
+                nstructs[i].alignment = -2;
+                nstructs[i].first_field_index = nf;
+                nstructs[i].num_fields = nf1;
+            }
+            for (j = 0; j < nf1; j++) {
+                char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1));
+                /* 'f' is one of the other strings beyond the first one,
+                   describing one field each */
+                nfields[nf].field_type_op = cdl_opcode(f); f += 4;
+                nfields[nf].field_offset = (size_t)-1;
+                if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) {
+                    nfields[nf].field_size = cdl_4bytes(f); f += 4;
+                }
+                else {
+                    nfields[nf].field_size = (size_t)-1;
+                }
+                nfields[nf].name = f;
+                nf++;
+            }
+        }
+        ffi->types_builder.ctx.struct_unions = nstructs;
+        ffi->types_builder.ctx.fields = nfields;
+        ffi->types_builder.ctx.num_struct_unions = n;
+        building = NULL;
+    }
+
+    if (enums != NULL) {
+        /* unpack a tuple of strings, each of which describes one enum_s
+           entry */
+        struct _cffi_enum_s *nenums;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(enums);
+
+        i = n * sizeof(struct _cffi_enum_s);
+        building = PyMem_Malloc(i);
+        if (building == NULL)
+            goto error;
+        memset(building, 0, i);
+        nenums = (struct _cffi_enum_s *)building;
+
+        for (i = 0; i < n; i++) {
+            char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i));
+            /* 'e' is a string describing the enum */
+            nenums[i].type_index = cdl_4bytes(e); e += 4;
+            nenums[i].type_prim = cdl_4bytes(e); e += 4;
+            nenums[i].name = e; e += strlen(e) + 1;
+            nenums[i].enumerators = e;
+        }
+        ffi->types_builder.ctx.enums = nenums;
+        ffi->types_builder.ctx.num_enums = n;
+        building = NULL;
+    }
+
+    if (typenames != NULL) {
+        /* unpack a tuple of strings, each of which describes one typename_s
+           entry */
+        struct _cffi_typename_s *ntypenames;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(typenames);
+
+        i = n * sizeof(struct _cffi_typename_s);
+        building = PyMem_Malloc(i);
+        if (building == NULL)
+            goto error;
+        memset(building, 0, i);
+        ntypenames = (struct _cffi_typename_s *)building;
+
+        for (i = 0; i < n; i++) {
+            char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i));
+            /* 't' is a string describing the typename */
+            ntypenames[i].type_index = cdl_4bytes(t); t += 4;
+            ntypenames[i].name = t;
+        }
+        ffi->types_builder.ctx.typenames = ntypenames;
+        ffi->types_builder.ctx.num_typenames = n;
+        building = NULL;
+    }
+
+    if (includes != NULL) {
+        PyObject *included_libs;
+
+        included_libs = PyTuple_New(PyTuple_GET_SIZE(includes));
+        if (included_libs == NULL)
+            return -1;
+
+        Py_INCREF(includes);
+        ffi->types_builder.included_ffis = includes;
+        ffi->types_builder.included_libs = included_libs;
+    }
+
+    /* Above, we took directly some "char *" strings out of the strings,
+       typically from somewhere inside tuples.  Keep them alive by
+       incref'ing the whole input arguments. */
+    Py_INCREF(args);
+    Py_XINCREF(kwds);
+    ffi->types_builder._keepalive1 = args;
+    ffi->types_builder._keepalive2 = kwds;
+    return 0;
+
+ error:
+    if (building != NULL)
+        PyMem_Free(building);
+    if (!PyErr_Occurred())
+        PyErr_NoMemory();
+    return -1;
+}
diff --git a/c/cffi1_module.c b/c/cffi1_module.c
new file mode 100644
--- /dev/null
+++ b/c/cffi1_module.c
@@ -0,0 +1,193 @@
+
+#include "parse_c_type.c"
+#include "realize_c_type.c"
+
+#define CFFI_VERSION_MIN    0x2601
+#define CFFI_VERSION_MAX    0x26FF
+
+typedef struct FFIObject_s FFIObject;
+typedef struct LibObject_s LibObject;
+
+static PyTypeObject FFI_Type;   /* forward */
+static PyTypeObject Lib_Type;   /* forward */
+
+#include "ffi_obj.c"
+#include "cglob.c"
+#include "cgc.c"
+#include "lib_obj.c"
+#include "cdlopen.c"
+
+
+static int init_ffi_lib(PyObject *m)
+{
+    PyObject *x;
+    int i;
+
+    if (PyType_Ready(&FFI_Type) < 0)
+        return -1;
+    if (PyType_Ready(&Lib_Type) < 0)
+        return -1;
+    if (init_global_types_dict(FFI_Type.tp_dict) < 0)
+        return -1;
+
+    FFIError = PyErr_NewException("ffi.error", NULL, NULL);
+    if (FFIError == NULL)
+        return -1;
+    if (PyDict_SetItemString(FFI_Type.tp_dict, "error", FFIError) < 0)
+        return -1;
+    if (PyDict_SetItemString(FFI_Type.tp_dict, "CType",
+                             (PyObject *)&CTypeDescr_Type) < 0)
+        return -1;
+    if (PyDict_SetItemString(FFI_Type.tp_dict, "CData",
+                             (PyObject *)&CData_Type) < 0)
+        return -1;
+
+    for (i = 0; all_dlopen_flags[i].name != NULL; i++) {
+        x = PyInt_FromLong(all_dlopen_flags[i].value);
+        if (x == NULL || PyDict_SetItemString(FFI_Type.tp_dict,
+                                              all_dlopen_flags[i].name,
+                                              x) < 0)
+            return -1;
+        Py_DECREF(x);
+    }
+
+    x = (PyObject *)&FFI_Type;
+    Py_INCREF(x);
+    if (PyModule_AddObject(m, "FFI", x) < 0)
+        return -1;
+    x = (PyObject *)&Lib_Type;
+    Py_INCREF(x);
+    if (PyModule_AddObject(m, "Lib", x) < 0)
+        return -1;
+
+    return 0;
+}
+
+static int make_included_tuples(char *module_name,
+                                const char *const *ctx_includes,
+                                PyObject **included_ffis,
+                                PyObject **included_libs)
+{
+    Py_ssize_t num = 0;
+    const char *const *p_include;
+
+    if (ctx_includes == NULL)
+        return 0;
+
+    for (p_include = ctx_includes; *p_include; p_include++) {
+        num++;
+    }
+    *included_ffis = PyTuple_New(num);
+    *included_libs = PyTuple_New(num);
+    if (*included_ffis == NULL || *included_libs == NULL)
+        goto error;
+
+    num = 0;
+    for (p_include = ctx_includes; *p_include; p_include++) {
+        PyObject *included_ffi, *included_lib;
+        PyObject *m = PyImport_ImportModule(*p_include);
+        if (m == NULL)
+            goto import_error;
+
+        included_ffi = PyObject_GetAttrString(m, "ffi");
+        PyTuple_SET_ITEM(*included_ffis, num, included_ffi);
+
+        included_lib = (included_ffi == NULL) ? NULL :
+                       PyObject_GetAttrString(m, "lib");
+        PyTuple_SET_ITEM(*included_libs, num, included_lib);
+
+        Py_DECREF(m);
+        if (included_lib == NULL)
+            goto import_error;
+
+        if (!FFIObject_Check(included_ffi) ||
+            !LibObject_Check(included_lib))
+            goto import_error;
+        num++;
+    }
+    return 0;
+
+ import_error:
+    PyErr_Format(PyExc_ImportError,
+                 "while loading %.200s: failed to import ffi, lib from %.200s",
+                 module_name, *p_include);
+ error:
+    Py_XDECREF(*included_ffis); *included_ffis = NULL;
+    Py_XDECREF(*included_libs); *included_libs = NULL;
+    return -1;
+}
+
+static PyObject *_my_Py_InitModule(char *module_name)
+{
+#if PY_MAJOR_VERSION >= 3
+    struct PyModuleDef *module_def, local_module_def = {
+        PyModuleDef_HEAD_INIT,
+        module_name,
+        NULL,
+        -1,
+        NULL, NULL, NULL, NULL, NULL
+    };
+    /* note: the 'module_def' is allocated dynamically and leaks,
+       but anyway the C extension module can never be unloaded */
+    module_def = PyMem_Malloc(sizeof(struct PyModuleDef));
+    if (module_def == NULL)
+        return PyErr_NoMemory();
+    *module_def = local_module_def;
+    return PyModule_Create(module_def);
+#else
+    return Py_InitModule(module_name, NULL);
+#endif
+}
+
+static PyObject *b_init_cffi_1_0_external_module(PyObject *self, PyObject *arg)
+{
+    PyObject *m;
+    FFIObject *ffi;
+    LibObject *lib;
+    Py_ssize_t version;
+    char *module_name, *exports;
+    void **raw;
+    const struct _cffi_type_context_s *ctx;
+
+    raw = (void **)PyLong_AsVoidPtr(arg);
+    if (raw == NULL)
+        return NULL;
+
+    module_name = (char *)raw[0];
+    version = (Py_ssize_t)raw[1];
+    exports = (char *)raw[2];
+    ctx = (const struct _cffi_type_context_s *)raw[3];
+
+    if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
+        if (!PyErr_Occurred())
+            PyErr_Format(PyExc_ImportError,
+                         "cffi extension module '%s' has unknown version %p",
+                         module_name, (void *)version);
+        return NULL;
+    }
+
+    /* initialize the exports array */
+    memcpy(exports, (char *)cffi_exports, sizeof(cffi_exports));
+
+    /* make the module object */
+    m = _my_Py_InitModule(module_name);
+    if (m == NULL)
+        return NULL;
+
+    /* build the FFI and Lib object inside this new module */
+    ffi = ffi_internal_new(&FFI_Type, ctx);
+    Py_XINCREF(ffi);    /* make the ffi object really immortal */
+    if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
+        return NULL;
+
+    lib = lib_internal_new(ffi, module_name, NULL);
+    if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
+        return NULL;
+
+    if (make_included_tuples(module_name, ctx->includes,
+                             &ffi->types_builder.included_ffis,
+                             &lib->l_types_builder->included_libs) < 0)
+        return NULL;
+
+    return m;
+}
diff --git a/c/cgc.c b/c/cgc.c
new file mode 100644
--- /dev/null
+++ b/c/cgc.c
@@ -0,0 +1,80 @@
+
+/* translated to C from cffi/gc_weakref.py */
+
+
+static PyObject *const_name_pop;
+
+static PyObject *gc_wref_remove(PyObject *ffi_wref_data, PyObject *arg)
+{
+    PyObject *destructor, *cdata, *x;
+    PyObject *res = PyObject_CallMethodObjArgs(ffi_wref_data,
+                                               const_name_pop, arg, NULL);
+    if (res == NULL)
+        return NULL;
+
+    assert(PyTuple_Check(res));
+    destructor = PyTuple_GET_ITEM(res, 0);
+    cdata = PyTuple_GET_ITEM(res, 1);
+    x = PyObject_CallFunctionObjArgs(destructor, cdata, NULL);
+    Py_DECREF(res);
+    if (x == NULL)
+        return NULL;
+    Py_DECREF(x);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMethodDef remove_callback = {
+    "gc_wref_remove", (PyCFunction)gc_wref_remove, METH_O
+};
+
+static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cd,
+                                   PyObject *destructor)
+{
+    PyObject *new_cdata, *ref = NULL, *tup = NULL;
+
+    if (ffi->gc_wrefs == NULL) {
+        /* initialize */
+        PyObject *data;
+
+        if (const_name_pop == NULL) {
+            const_name_pop = PyText_InternFromString("pop");
+            if (const_name_pop == NULL)
+                return NULL;
+        }
+        data = PyDict_New();
+        if (data == NULL)
+            return NULL;
+        ffi->gc_wrefs = PyCFunction_New(&remove_callback, data);
+        Py_DECREF(data);
+        if (ffi->gc_wrefs == NULL)
+            return NULL;
+    }
+
+    new_cdata = do_cast(cd->c_type, (PyObject *)cd);
+    if (new_cdata == NULL)
+        goto error;
+
+    ref = PyWeakref_NewRef(new_cdata, ffi->gc_wrefs);
+    if (ref == NULL)
+        goto error;
+
+    tup = PyTuple_Pack(2, destructor, cd);
+    if (tup == NULL)
+        goto error;
+
+    /* the 'self' of the function 'gc_wrefs' is actually the data dict */
+    if (PyDict_SetItem(PyCFunction_GET_SELF(ffi->gc_wrefs), ref, tup) < 0)
+        goto error;
+
+    Py_DECREF(tup);
+    Py_DECREF(ref);
+    return new_cdata;
+
+ error:
+    Py_XDECREF(new_cdata);
+    Py_XDECREF(ref);
+    Py_XDECREF(tup);
+    return NULL;
+}
diff --git a/c/cglob.c b/c/cglob.c
new file mode 100644
--- /dev/null
+++ b/c/cglob.c
@@ -0,0 +1,72 @@
+
+typedef struct {
+    PyObject_HEAD
+
+    CTypeDescrObject *gs_type;
+    char             *gs_data;
+
+} GlobSupportObject;
+
+static void glob_support_dealloc(GlobSupportObject *gs)
+{
+    Py_DECREF(gs->gs_type);
+    PyObject_Del(gs);
+}
+
+static PyTypeObject GlobSupport_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "FFIGlobSupport",
+    sizeof(GlobSupportObject),
+    0,
+    (destructor)glob_support_dealloc,           /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    0,                                          /* tp_repr */
+    0,                                          /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,                                          /* tp_as_mapping */
+    0,                                          /* tp_hash */
+    0,                                          /* tp_call */
+    0,                                          /* tp_str */
+    PyObject_GenericGetAttr,                    /* tp_getattro */
+    0,                                          /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
+};
+
+#define GlobSupport_Check(ob)  (Py_TYPE(ob) == &GlobSupport_Type)
+
+static PyObject *make_global_var(CTypeDescrObject *type, char *addr)
+{
+    GlobSupportObject *gs = PyObject_New(GlobSupportObject, &GlobSupport_Type);
+    if (gs == NULL)
+        return NULL;
+
+    Py_INCREF(type);
+    gs->gs_type = type;
+    gs->gs_data = addr;
+    return (PyObject *)gs;
+}
+
+static PyObject *read_global_var(GlobSupportObject *gs)
+{
+    return convert_to_object(gs->gs_data, gs->gs_type);
+}
+
+static int write_global_var(GlobSupportObject *gs, PyObject *obj)
+{
+    return convert_from_object(gs->gs_data, gs->gs_type, obj);
+}
+
+static PyObject *cg_addressof_global_var(GlobSupportObject *gs)
+{
+    PyObject *x, *ptrtype = new_pointer_type(gs->gs_type);
+    if (ptrtype == NULL)
+        return NULL;
+
+    x = new_simple_cdata(gs->gs_data, (CTypeDescrObject *)ptrtype);
+    Py_DECREF(ptrtype);
+    return x;
+}
diff --git a/c/ffi_obj.c b/c/ffi_obj.c
new file mode 100644
--- /dev/null
+++ b/c/ffi_obj.c
@@ -0,0 +1,887 @@
+
+/* An FFI object has methods like ffi.new().  It is also a container
+   for the type declarations (typedefs and structs) that you can use,
+   say in ffi.new().
+
+   CTypeDescrObjects are internally stored in the dict 'types_dict'.
+   The types_dict is lazily filled with CTypeDescrObjects made from
+   reading a _cffi_type_context_s structure.
+
+   In "modern" mode, the FFI instance is made by the C extension
+   module originally created by recompile().  The _cffi_type_context_s
+   structure comes from global data in the C extension module.
+
+   In "compatibility" mode, an FFI instance is created explicitly by
+   the user, and its _cffi_type_context_s is initially empty.  You
+   need to call ffi.cdef() to add more information to it.
+*/
+
+#define FFI_COMPLEXITY_OUTPUT   1200     /* xxx should grow as needed */
+
+#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type)
+#define LibObject_Check(ob)  ((Py_TYPE(ob) == &Lib_Type))
+
+struct FFIObject_s {
+    PyObject_HEAD
+    PyObject *gc_wrefs;
+    struct _cffi_parse_info_s info;
+    char ctx_is_static, ctx_is_nonempty;
+    builder_c_t types_builder;
+};
+
+static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
+                                 const struct _cffi_type_context_s *static_ctx)
+{
+    static _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT];
+
+    FFIObject *ffi;
+    if (static_ctx != NULL) {
+        ffi = (FFIObject *)PyObject_GC_New(FFIObject, ffitype);
+        /* we don't call PyObject_GC_Track() here: from _cffi_init_module()
+           it is not needed, because in this case the ffi object is immortal */
+    }
+    else {
+        ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0);
+    }
+    if (ffi == NULL)
+        return NULL;
+
+    if (init_builder_c(&ffi->types_builder, static_ctx) < 0) {
+        Py_DECREF(ffi);
+        return NULL;
+    }
+    ffi->gc_wrefs = NULL;
+    ffi->info.ctx = &ffi->types_builder.ctx;
+    ffi->info.output = internal_output;
+    ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
+    ffi->ctx_is_static = (static_ctx != NULL);
+    ffi->ctx_is_nonempty = (static_ctx != NULL);
+    return ffi;
+}
+
+static void ffi_dealloc(FFIObject *ffi)
+{
+    PyObject_GC_UnTrack(ffi);
+    Py_XDECREF(ffi->gc_wrefs);
+
+    free_builder_c(&ffi->types_builder, ffi->ctx_is_static);
+
+    Py_TYPE(ffi)->tp_free((PyObject *)ffi);
+}
+
+static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg)
+{
+    Py_VISIT(ffi->types_builder.types_dict);
+    Py_VISIT(ffi->types_builder.included_ffis);
+    Py_VISIT(ffi->types_builder.included_libs);
+    Py_VISIT(ffi->gc_wrefs);
+    return 0;
+}
+
+static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    /* user-facing initialization code, for explicit FFI() calls */
+    return (PyObject *)ffi_internal_new(type, NULL);
+}
+
+/* forward, declared in cdlopen.c because it's mostly useful for this case */
+static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds);
+
+static PyObject *ffi_fetch_int_constant(FFIObject *ffi, char *name,
+                                        int recursion)
+{
+    int index;
+
+    index = search_in_globals(&ffi->types_builder.ctx, name, strlen(name));
+    if (index >= 0) {
+        const struct _cffi_global_s *g;
+        g = &ffi->types_builder.ctx.globals[index];
+
+        switch (_CFFI_GETOP(g->type_op)) {
+        case _CFFI_OP_CONSTANT_INT:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to