Author: Armin Rigo <ar...@tunes.org> Branch: cffi-1.0 Changeset: r77360:284fd2b1e81c Date: 2015-05-17 20:18 +0200 http://bitbucket.org/pypy/pypy/changeset/284fd2b1e81c/
Log: test_global_var diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py --- a/pypy/module/_cffi_backend/cdlopen.py +++ b/pypy/module/_cffi_backend/cdlopen.py @@ -7,7 +7,8 @@ _CFFI_OPCODE_T, GLOBAL_S, CDL_INTCONST_S, ll_set_cdl_realize_global_int) from pypy.module._cffi_backend.realize_c_type import getop -from pypy.module._cffi_backend import cffi_opcode, lib_obj +from pypy.module._cffi_backend.lib_obj import W_LibObject +from pypy.module._cffi_backend import cffi_opcode class StringDecoder: @@ -95,15 +96,28 @@ # ... -def ffi_dlopen(ffi, filename, flags): - with rffi.scoped_str2charp(filename) as ll_libname: - if filename is None: - filename = "<None>" +class W_DlOpenLibObject(W_LibObject): + + def __init__(self, ffi, filename, flags): + with rffi.scoped_str2charp(filename) as ll_libname: + if filename is None: + filename = "<None>" + try: + handle = dlopen(ll_libname, flags) + except DLOpenError, e: + raise wrap_dlopenerror(space, e, filename) + W_LibObject.__init__(self, ffi, filename) + self.libhandle = handle + + def __del__(self): + if self.libhandle: + dlclose(self.libhandle) + + def cdlopen_fetch(self, name): try: - handle = dlopen(ll_libname, flags) + cdata = dlsym(self.libhandle, name) except DLOpenError, e: - raise wrap_dlopenerror(space, e, filename) - return lib_obj.W_LibObject(ffi, filename, handle) - -def ffi_dlclose(xxx): - yyyy + raise oefmt(self.ffi.w_FFIError, + "symbol '%s' not found in library '%s': %s", + name, self.libname, e.msg) + return rffi.cast(rffi.CCHARP, cdata) diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py --- a/pypy/module/_cffi_backend/ffi_obj.py +++ b/pypy/module/_cffi_backend/ffi_obj.py @@ -55,8 +55,10 @@ else: self.cached_types = None self.w_FFIError = get_ffi_error(space) - self.included_ffis = [] # list of W_FFIObject's included here - self.included_libs = [] # list of W_LibObject's included here + # + # list of (W_FFIObject, W_LibObject) included in this ffi, + # where the lib object may be None + self.included_ffis_libs = [] def fetch_int_constant(self, name): index = parse_c_type.search_in_globals(self.ctxobj.ctx, name) @@ -71,7 +73,7 @@ "'%s' must be fetched from its original 'lib' " "object", name) - for ffi1 in self.included_ffis: + for ffi1, _ in self.included_ffis_libs: w_result = ffi1.ffi_fetch_int_constant(name) if w_result is not None: return w_result @@ -489,7 +491,7 @@ first access.""" # from pypy.module._cffi_backend import cdlopen - return cdlopen.ffi_dlopen(self, filename, flags) + return cdlopen.W_DlOpenLibObject(self, filename, flags) def descr_dlclose(self, w_lib): diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py --- a/pypy/module/_cffi_backend/lib_obj.py +++ b/pypy/module/_cffi_backend/lib_obj.py @@ -16,14 +16,14 @@ class W_LibObject(W_Root): + libhandle = rffi.cast(DLLHANDLE, 0) # the dlopen()ed handle, if any - def __init__(self, ffi, libname, libhandle=rffi.cast(DLLHANDLE, 0)): + def __init__(self, ffi, libname): self.space = ffi.space self.ctx = ffi.ctxobj.ctx self.ffi = ffi self.dict_w = {} # content, built lazily self.libname = libname # some string that gives the name of the lib - self.libhandle = libhandle # the dlopen()ed handle, if any def descr_repr(self): return self.space.wrap("<Lib object for '%s'>" % self.libname) @@ -45,9 +45,9 @@ raise oefmt(space.w_ImportError, "while loading %s: failed to import ffi, lib from %s", self.libname, include_name) - includes.append(lib1) + includes.append((lib1.ffi, lib1)) num += 1 - self.ffi.included_libs = includes[:] + self.ffi.included_ffis_libs = includes[:] def _build_cpython_func(self, g): # Build a function: in the PyPy version, these are all equivalent @@ -63,6 +63,7 @@ w_ct, locs = rawfunctype.unwrap_as_nostruct_fnptr(self.ffi) # ptr = rffi.cast(rffi.CCHARP, g.c_address) + assert ptr w_cdata = W_CData(self.space, ptr, w_ct) if locs is not None: w_cdata = W_StructWrapper(w_cdata, locs, rawfunctype) @@ -76,14 +77,19 @@ def _build_attr(self, attr): index = parse_c_type.search_in_globals(self.ctx, attr) if index < 0: - for lib1 in self.ffi.included_libs: - try: - w_result = lib1._get_attr_elidable(attr) - except KeyError: - w_result = lib1._build_attr(attr) - if w_result is None: - continue - break # found, break out of this loop + for ffi1, lib1 in self.ffi.included_ffis_libs: + if lib1 is not None: + try: + w_result = lib1._get_attr_elidable(attr) + break # found, break out of this loop + except KeyError: + w_result = lib1._build_attr(attr) + if w_result is not None: + break # found, break out of this loop + else: + w_result = ffi1.fetch_int_constant(attr) + if w_result is not None: + break # found, break out of this loop else: return None # not found at all else: @@ -107,6 +113,8 @@ "according to the cdef, but is actually %d", attr, w_ct.size, g_size) ptr = rffi.cast(rffi.CCHARP, g.c_address) + if not ptr: # for dlopen() style + ptr = self.cdlopen_fetch(attr) w_result = cglob.W_GlobSupport(space, w_ct, ptr) # elif (op == cffi_opcode.OP_CONSTANT_INT or @@ -123,6 +131,7 @@ fetch_funcptr = rffi.cast( realize_c_type.FUNCPTR_FETCH_CHARP, g.c_address) + assert fetch_funcptr assert w_ct.size > 0 with lltype.scoped_alloc(rffi.CCHARP.TO, w_ct.size) as ptr: fetch_funcptr(ptr) @@ -144,8 +153,8 @@ w_value = self._build_attr(attr) if w_value is None: raise oefmt(self.space.w_AttributeError, - "cffi lib '%s' has no function," - " global variable or constant named '%s'", + "cffi library '%s' has no function, constant " + "or global variable named '%s'", self.libname, attr) return w_value @@ -195,6 +204,9 @@ raise oefmt(space.w_AttributeError, "cannot take the address of the constant '%s'", varname) + def cdlopen_fetch(self, name): + raise NotImplementedError + W_LibObject.typedef = TypeDef( 'CompiledLib', diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py --- a/pypy/module/_cffi_backend/realize_c_type.py +++ b/pypy/module/_cffi_backend/realize_c_type.py @@ -258,7 +258,7 @@ assert c_first_field_index < 0 else: assert c_first_field_index < 0 - x = _fetch_external_struct_or_union(s, ffi.included_libs) + x = _fetch_external_struct_or_union(s, ffi.included_ffis_libs) if x is None: raise oefmt(ffi.w_FFIError, "'%s %s' should come from ffi.include() but was not found", @@ -472,25 +472,26 @@ w_ctype._lazy_s = lltype.nullptr(parse_c_type.STRUCT_UNION_S) -def _fetch_external_struct_or_union(s, included_libs): +def _fetch_external_struct_or_union(s, included_ffis_libs): name = rffi.charp2str(s.c_name) # - for lib1 in included_libs: - sindex = parse_c_type.search_in_struct_unions(lib1.ctx, name) + for ffi1, _ in included_ffis_libs: + ctx1 = ffi1.ctxobj.ctx + sindex = parse_c_type.search_in_struct_unions(ctx1, name) if sindex < 0: # not found at all continue - s1 = lib1.ctx.c_struct_unions[sindex] + s1 = ctx1.c_struct_unions[sindex] s1_flags = rffi.getintfield(s1, 'c_flags') s_flags = rffi.getintfield(s, 'c_flags') if ((s1_flags & (cffi_opcode.F_EXTERNAL | cffi_opcode.F_UNION)) == (s_flags & cffi_opcode.F_UNION)): # s1 is not external, and the same kind (struct or union) as s - return _realize_c_struct_or_union(lib1.ffi, sindex) + return _realize_c_struct_or_union(ffi1, sindex) # not found, look more recursively - if len(lib1.ffi.included_libs) > 0: - w_res = _fetch_external_struct_or_union(s, lib1.ffi.included_libs) + if len(ffi1.included_ffis_libs) > 0: + w_res = _fetch_external_struct_or_union(s, ffi1.included_ffis_libs) if w_res is not None: return w_res return None diff --git a/pypy/module/_cffi_backend/test/test_re_python.py b/pypy/module/_cffi_backend/test/test_re_python.py --- a/pypy/module/_cffi_backend/test/test_re_python.py +++ b/pypy/module/_cffi_backend/test/test_re_python.py @@ -94,7 +94,7 @@ from re_python_pysrc import ffi lib = ffi.dlopen(self.extmod) ffi.dlclose(lib) - e = py.test.raises(ffi.error, ffi.dlclose, lib) + e = raises(ffi.error, ffi.dlclose, lib) assert str(e.value) == ( "library '%s' is already closed or was not created with ffi.dlopen()" % (self.extmod,)) @@ -108,7 +108,7 @@ def test_opaque_struct(self): from re_python_pysrc import ffi ffi.cast("struct foo_s *", 0) - py.test.raises(TypeError, ffi.new, "struct foo_s *") + raises(TypeError, ffi.new, "struct foo_s *") def test_nonopaque_struct(self): from re_python_pysrc import ffi @@ -160,3 +160,13 @@ ffi.RTLD_NOW # check that we have the attributes ffi.RTLD_LAZY ffi.RTLD_GLOBAL + + def test_no_such_function_or_global_var(self): + from re_python_pysrc import ffi + lib = ffi.dlopen(extmod) + e = raises(ffi.error, getattr, lib, 'no_such_function') + assert str(e.value).startswith( + "symbol 'no_such_function' not found in library '") + e = raises(ffi.error, getattr, lib, 'no_such_globalvar') + assert str(e.value).startswith( + "symbol 'no_such_globalvar' not found in library '") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit