[pypy-commit] cffi cffi-1.0: look in ffi.included modules for global functions/variables/consts

arigo noreply at buildbot.pypy.org
Mon Apr 27 23:48:56 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1865:42497db90079
Date: 2015-04-27 22:56 +0200
http://bitbucket.org/cffi/cffi/changeset/42497db90079/

Log:	look in ffi.included modules for global functions/variables/consts

diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c
--- a/_cffi1/cffi1_module.c
+++ b/_cffi1/cffi1_module.c
@@ -45,6 +45,59 @@
     return 0;
 }
 
+static int make_included_tuples(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 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 error;
+
+        if (!FFIObject_Check(included_ffi) ||
+            !LibObject_Check(included_lib)) {
+            PyErr_Format(PyExc_TypeError,
+                         "expected FFI/Lib objects in %.200s.ffi/lib",
+                         *p_include);
+            goto error;
+        }
+        num++;
+    }
+    return 0;
+
+ error:
+    Py_XDECREF(*included_ffis); *included_ffis = NULL;
+    Py_XDECREF(*included_libs); *included_libs = NULL;
+    return -1;
+}
+
 static int _cffi_init_module(char *module_name,
                              const struct _cffi_type_context_s *ctx)
 {
@@ -61,5 +114,9 @@
     if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0)
         return -1;
 
+    if (make_included_tuples(ctx->includes, &ffi->included_ffis,
+                             &lib->l_includes) < 0)
+        return -1;
+
     return 0;
 }
diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c
--- a/_cffi1/ffi_obj.c
+++ b/_cffi1/ffi_obj.c
@@ -18,12 +18,15 @@
 
 #define FFI_COMPLEXITY_OUTPUT   1200     /* xxx should grow as needed */
 
+#define FFIObject_Check(op) PyObject_TypeCheck(op, &FFI_Type)
+
 struct FFIObject_s {
     PyObject_HEAD
     PyObject *gc_wrefs;
     struct _cffi_parse_info_s info;
     int ctx_is_static;
     builder_c_t *types_builder;
+    PyObject *included_ffis;
 };
 
 static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
@@ -53,6 +56,7 @@
     ffi->info.output = internal_output;
     ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
     ffi->ctx_is_static = (static_ctx != NULL);
+    ffi->included_ffis = NULL;
 #if 0
     ffi->dynamic_types = NULL;
 #endif
@@ -70,6 +74,7 @@
     if (!ffi->ctx_is_static)
         free_builder_c(ffi->types_builder);
 
+    Py_XDECREF(ffi->included_ffis);
     Py_TYPE(ffi)->tp_free((PyObject *)ffi);
 }
 
@@ -77,6 +82,7 @@
 {
     Py_VISIT(ffi->types_builder->types_dict);
     Py_VISIT(ffi->gc_wrefs);
+    Py_VISIT(ffi->included_ffis);
     return 0;
 }
 
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -23,6 +23,7 @@
     builder_c_t *l_types_builder; /* same as the one on the ffi object */
     PyObject *l_dict;           /* content, built lazily */
     PyObject *l_libname;        /* some string that gives the name of the lib */
+    PyObject *l_includes;       /* tuple of LibObjects included here */
 };
 
 #define LibObject_Check(ob)  ((Py_TYPE(ob) == &Lib_Type))
@@ -64,6 +65,7 @@
 {
     Py_DECREF(lib->l_dict);
     Py_DECREF(lib->l_libname);
+    Py_XDECREF(lib->l_includes);
     PyObject_Del(lib);
 }
 
@@ -128,9 +130,11 @@
     return NULL;
 }
 
-static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name)
+static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name,
+                                          int recursion)
 {
     /* does not return a new reference! */
+    PyObject *x;
 
     char *s = PyText_AsUTF8(name);
     if (s == NULL)
@@ -138,15 +142,45 @@
 
     int index = search_in_globals(&lib->l_types_builder->ctx, s, strlen(s));
     if (index < 0) {
+
+        if (lib->l_includes != NULL) {
+
+            if (recursion > 100) {
+                PyErr_SetString(PyExc_RuntimeError,
+                    "recursion overflow in ffi.include() delegations");
+                return NULL;
+            }
+
+            Py_ssize_t i;
+            for (i = 0; i < PyTuple_GET_SIZE(lib->l_includes); i++) {
+                LibObject *lib1;
+                lib1 = (LibObject *)PyTuple_GET_ITEM(lib->l_includes, i);
+                x = PyDict_GetItem(lib1->l_dict, name);
+                if (x != NULL) {
+                    Py_INCREF(x);
+                    goto found;
+                }
+                x = lib_build_and_cache_attr(lib1, name, recursion + 1);
+                if (x != NULL) {
+                    Py_INCREF(x);
+                    goto found;
+                }
+                if (PyErr_Occurred())
+                    return NULL;
+            }
+        }
+
+        if (recursion > 0)
+            return NULL;  /* no error set, continue looking elsewhere */
+
         PyErr_Format(PyExc_AttributeError,
-                     "lib '%.200s' has no function,"
+                     "cffi lib '%.200s' has no function,"
                      " global variable or constant named '%.200s'",
                      PyText_AS_UTF8(lib->l_libname), s);
         return NULL;
     }
 
     const struct _cffi_global_s *g = &lib->l_types_builder->ctx.globals[index];
-    PyObject *x;
     CTypeDescrObject *ct;
 
     switch (_CFFI_GETOP(g->type_op)) {
@@ -217,6 +251,7 @@
         return NULL;
     }
 
+ found:
     if (x != NULL) {
         int err = PyDict_SetItem(lib->l_dict, name, x);
         Py_DECREF(x);
@@ -230,7 +265,7 @@
 {
     PyObject *x = PyDict_GetItem(lib->l_dict, name);
     if (x == NULL) {
-        x = lib_build_and_cache_attr(lib, name);
+        x = lib_build_and_cache_attr(lib, name, 0);
         if (x == NULL)
             return NULL;
     }
@@ -246,7 +281,7 @@
 {
     PyObject *x = PyDict_GetItem(lib->l_dict, name);
     if (x == NULL) {
-        x = lib_build_and_cache_attr(lib, name);
+        x = lib_build_and_cache_attr(lib, name, 0);
         if (x == NULL)
             return -1;
     }
@@ -351,5 +386,6 @@
     lib->l_types_builder = types_builder;
     lib->l_dict = dict;
     lib->l_libname = libname;
+    lib->l_includes = NULL;
     return lib;
 }
diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h
--- a/_cffi1/parse_c_type.h
+++ b/_cffi1/parse_c_type.h
@@ -113,7 +113,7 @@
     int num_struct_unions;
     int num_enums;
     int num_typenames;
-    const char * const *includes;
+    const char *const *includes;
 };
 
 struct _cffi_parse_info_s {
diff --git a/_cffi1/test_recompiler.py b/_cffi1/test_recompiler.py
--- a/_cffi1/test_recompiler.py
+++ b/_cffi1/test_recompiler.py
@@ -465,6 +465,17 @@
     lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }")
     assert lib.ff1(0) == 42.5
 
+def test_include_1b():
+    ffi1 = FFI()
+    ffi1.cdef("int foo1(int);")
+    verify(ffi1, "test_include_1b_parent", "int foo1(int x) { return x + 10; }")
+    ffi = FFI()
+    ffi.include(ffi1)
+    ffi.cdef("int foo2(int);")
+    lib = verify(ffi, "test_include_1b", "int foo2(int x) { return x - 5; }")
+    assert lib.foo2(42) == 37
+    assert lib.foo1(42) == 52
+
 def test_include_2():
     ffi1 = FFI()
     ffi1.cdef("struct foo_s { int x, y; };")


More information about the pypy-commit mailing list