Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit