Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r1974:56fc30b8d7e1 Date: 2015-05-11 15:59 +0200 http://bitbucket.org/cffi/cffi/changeset/56fc30b8d7e1/
Log: merge heads diff --git a/TODO b/TODO --- a/TODO +++ b/TODO @@ -13,3 +13,6 @@ * mention todo: ffi.new("xyz") makes {"xyz": <ctype>} always immortal * mention todo: dlopen(), by "compiling" a cdef()-only FFI into a .py module + +* ffi.set_source() produces a C file that is entirely independent on + the OS, what is installed, and the current Python version diff --git a/_cffi1/cdlopen.c b/_cffi1/cdlopen.c new file mode 100644 --- /dev/null +++ b/_cffi1/cdlopen.c @@ -0,0 +1,58 @@ +/* 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 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_dlclose(PyObject *self, PyObject *args) +{ + LibObject *lib; + if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib)) + return NULL; + + if (lib->l_libhandle == NULL) { + PyErr_Format(FFIError, "library '%s' is already closed " + "or was not created with ffi.dlopen()", + PyText_AS_UTF8(lib->l_libhandle)); + return NULL; + } + + if (cdlopen_close(lib->l_libname, lib->l_libhandle) < 0) + 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); + + Py_INCREF(Py_None); + return Py_None; +} diff --git a/_cffi1/cffi1_module.c b/_cffi1/cffi1_module.c --- a/_cffi1/cffi1_module.c +++ b/_cffi1/cffi1_module.c @@ -12,6 +12,7 @@ #include "cglob.c" #include "cgc.c" #include "lib_obj.c" +#include "cdlopen.c" static int init_ffi_lib(PyObject *m) @@ -169,7 +170,7 @@ if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0) return NULL; - lib = lib_internal_new(ffi, module_name); + lib = lib_internal_new(ffi, module_name, NULL); if (lib == NULL || PyModule_AddObject(m, "lib", (PyObject *)lib) < 0) return NULL; diff --git a/_cffi1/cffi_opcode.py b/_cffi1/cffi_opcode.py --- a/_cffi1/cffi_opcode.py +++ b/_cffi1/cffi_opcode.py @@ -30,6 +30,7 @@ OP_CONSTANT = 29 OP_CONSTANT_INT = 31 OP_GLOBAL_VAR = 33 +OP_DLOPEN = 35 PRIM_VOID = 0 PRIM_BOOL = 1 diff --git a/_cffi1/ffi_obj.c b/_cffi1/ffi_obj.c --- a/_cffi1/ffi_obj.c +++ b/_cffi1/ffi_obj.c @@ -25,7 +25,7 @@ PyObject_HEAD PyObject *gc_wrefs; struct _cffi_parse_info_s info; - int ctx_is_static; + char ctx_is_static, ctx_is_nonempty; builder_c_t types_builder; }; @@ -55,9 +55,7 @@ ffi->info.output = internal_output; ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; ffi->ctx_is_static = (static_ctx != NULL); -#if 0 - ffi->dynamic_types = NULL; -#endif + ffi->ctx_is_nonempty = (static_ctx != NULL); return ffi; } @@ -65,12 +63,8 @@ { PyObject_GC_UnTrack(ffi); Py_XDECREF(ffi->gc_wrefs); -#if 0 - Py_XDECREF(ffi->dynamic_types); -#endif - if (!ffi->ctx_is_static) - free_dynamic_builder_c(&ffi->types_builder); + free_builder_c(&ffi->types_builder, ffi->ctx_is_static); Py_TYPE(ffi)->tp_free((PyObject *)ffi); } @@ -91,9 +85,31 @@ static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds) { - static char *keywords[] = {NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, ":FFI", keywords)) + FFIObject *ffi; + static char *keywords[] = {"module_name", "_version", "_types", + "_globals", "_struct_unions", "_enums", + "_typenames", "_consts", NULL}; + char *ffiname = NULL, *types = NULL; + Py_ssize_t version = -1; + Py_ssize_t types_len = 0; + PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL; + PyObject *typenames = NULL, *consts = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#OOOOO:FFI", keywords, + &ffiname, &version, &types, &types_len, + &globals, &struct_unions, &enums, + &typenames, &consts)) 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; return 0; } @@ -688,6 +704,23 @@ return 0; } +PyDoc_STRVAR(ffi_dlopen_doc, +"Load and return a dynamic library identified by 'name'. The standard\n" +"C library can be loaded by passing None.\n" +"\n" +"Note that functions and types declared with 'ffi.cdef()' are not\n" +"linked to a particular library, just like C headers. In the library\n" +"we only look for the actual (untyped) symbols at the time of their\n" +"first access."); + +PyDoc_STRVAR(ffi_dlclose_doc, +"Close a library obtained with ffi.dlopen(). After this call, access to\n" +"functions or variables from the library will fail (possibly with a\n" +"segmentation fault)."); + +static PyObject *ffi_dlopen(PyObject *self, PyObject *args); /* forward */ +static PyObject *ffi_dlclose(PyObject *self, PyObject *args); /* forward */ + #if 0 static PyObject *ffi__set_types(FFIObject *self, PyObject *args) { @@ -784,6 +817,8 @@ {"buffer", (PyCFunction)ffi_buffer, METH_VARARGS, ffi_buffer_doc}, {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, + {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc}, + {"dlopen", (PyCFunction)ffi_dlopen, METH_VARARGS, ffi_dlopen_doc}, {"from_buffer",(PyCFunction)ffi_from_buffer,METH_O, ffi_from_buffer_doc}, {"from_handle",(PyCFunction)ffi_from_handle,METH_O, ffi_from_handle_doc}, {"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc}, diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c --- a/_cffi1/lib_obj.c +++ b/_cffi1/lib_obj.c @@ -25,6 +25,7 @@ PyObject *l_libname; /* some string that gives the name of the lib */ PyObject *l_includes; /* tuple of LibObjects included here */ FFIObject *l_ffi; /* reference back to the ffi object */ + void *l_libhandle; /* the dlopen()ed handle, if any */ }; static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) @@ -71,8 +72,15 @@ return result; } +static int cdlopen_close(PyObject *libname, void *libhandle); /* forward */ +static void *cdlopen_fetch(PyObject *libname, void *libhandle, char *symbol); + static void lib_dealloc(LibObject *lib) { + if (cdlopen_close(lib->l_libname, lib->l_libhandle) < 0) { + PyErr_WriteUnraisable((PyObject *)lib); + PyErr_Clear(); + } Py_DECREF(lib->l_dict); Py_DECREF(lib->l_libname); Py_XDECREF(lib->l_includes); @@ -161,6 +169,14 @@ index = search_in_globals(&lib->l_types_builder->ctx, s, strlen(s)); if (index < 0) { + if (lib->l_types_builder->known_constants != NULL) { + x = PyDict_GetItem(lib->l_types_builder->known_constants, name); + if (x != NULL) { + Py_INCREF(x); + goto found; + } + } + if (lib->l_includes != NULL) { Py_ssize_t i; @@ -261,6 +277,36 @@ Py_DECREF(ct); break; + case _CFFI_OP_DLOPEN: + { + /* For dlopen(): the function or global variable of the given + 'name'. We use dlsym() to get the address of something in + the dynamic library, which we interpret as being exactly of + the specified type. If this type is a function (not a + function pointer), then we assume it is a regular function + in the dynamic library; otherwise, we assume it is a global + variable. + */ + PyObject *ct1; + void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (address == NULL) + return NULL; + + ct1 = realize_c_type_or_func(lib->l_types_builder, + lib->l_types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct1 == NULL) + return NULL; + + if (CTypeDescr_Check(ct1)) + x = make_global_var((CTypeDescrObject *)ct1, address); + else + x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); + + Py_DECREF(ct1); + break; + } + default: PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", (int)_CFFI_GETOP(g->type_op)); @@ -382,7 +428,8 @@ offsetof(LibObject, l_dict), /* tp_dictoffset */ }; -static LibObject *lib_internal_new(FFIObject *ffi, char *module_name) +static LibObject *lib_internal_new(FFIObject *ffi, char *module_name, + void *dlopen_libhandle) { LibObject *lib; PyObject *libname, *dict; @@ -405,6 +452,7 @@ lib->l_includes = NULL; Py_INCREF(ffi); lib->l_ffi = ffi; + lib->l_libhandle = dlopen_libhandle; 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 @@ -22,6 +22,7 @@ #define _CFFI_OP_CONSTANT 29 #define _CFFI_OP_CONSTANT_INT 31 #define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN 35 #define _CFFI_PRIM_VOID 0 #define _CFFI_PRIM_BOOL 1 diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c --- a/_cffi1/realize_c_type.c +++ b/_cffi1/realize_c_type.c @@ -3,6 +3,7 @@ struct _cffi_type_context_s ctx; /* inlined substructure */ PyObject *types_dict; PyObject *included_ffis; + PyObject *known_constants; } builder_c_t; @@ -53,22 +54,24 @@ return err; } -static void free_dynamic_builder_c(builder_c_t *builder) +static void free_builder_c(builder_c_t *builder, int ctx_is_static) { - int i; - const void *mem[] = {builder->ctx.types, - builder->ctx.globals, - builder->ctx.struct_unions, - builder->ctx.fields, - builder->ctx.enums, - builder->ctx.typenames}; - for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { - if (mem[i] != NULL) - PyMem_Free((void *)mem[i]); + if (!ctx_is_static) { + int i; + const void *mem[] = {builder->ctx.types, + builder->ctx.globals, + builder->ctx.struct_unions, + builder->ctx.fields, + builder->ctx.enums, + builder->ctx.typenames}; + for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { + if (mem[i] != NULL) + PyMem_Free((void *)mem[i]); + } } - Py_XDECREF(builder->included_ffis); Py_XDECREF(builder->types_dict); + Py_XDECREF(builder->known_constants); } static int init_builder_c(builder_c_t *builder, @@ -85,6 +88,7 @@ builder->types_dict = ldict; builder->included_ffis = NULL; + builder->known_constants = NULL; return 0; } _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit