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

Reply via email to