[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