[pypy-commit] pypy cffi-1.0: Tweaks to end up in _cffi_backend when loading C extension modules

arigo noreply at buildbot.pypy.org
Thu May 7 16:48:46 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77179:90b0f73648e7
Date: 2015-05-07 16:48 +0200
http://bitbucket.org/pypy/pypy/changeset/90b0f73648e7/

Log:	Tweaks to end up in _cffi_backend when loading C extension modules
	that declare "_cffi_pypyinit_%s()" instead of "init%s()".

diff --git a/pypy/module/_cffi_backend/cffi1_module.py b/pypy/module/_cffi_backend/cffi1_module.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cffi1_module.py
@@ -0,0 +1,4 @@
+
+def load_cffi1_module(space, name, dll, initptr):
+    xxxx
+
diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -44,7 +44,7 @@
             raise oefmt(w_errorcls or space.w_TypeError,
                         "'%s' is opaque or not completed yet", self.name)
 
-    def force_lazy_struct(self, w_errorcls=None):
+    def force_lazy_struct(self):
         # Force a "lazy" struct to become "forced"; complain if we are "opaque".
         if self._fields_list is None:
             self.check_complete()
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1113,30 +1113,66 @@
 initfunctype = lltype.Ptr(lltype.FuncType([], lltype.Void))
 @unwrap_spec(path=str, name=str)
 def load_extension_module(space, path, name):
+    # note: this is used both to load CPython-API-style C extension
+    # modules (cpyext) and to load CFFI-style extension modules
+    # (_cffi_backend).  Any of the two can be disabled at translation
+    # time, though.  For this reason, we need to be careful about the
+    # order of things here.
+    from rpython.rlib import rdynload
+
     if os.sep not in path:
         path = os.curdir + os.sep + path      # force a '/' in the path
+    basename = name.split('.')[-1]
+    try:
+        ll_libname = rffi.str2charp(path)
+        try:
+            dll = rdynload.dlopen(ll_libname)
+        finally:
+            lltype.free(ll_libname, flavor='raw')
+    except rdynload.DLOpenError, e:
+        raise oefmt(space.w_ImportError,
+                    "unable to load extension module '%s': %s",
+                    path, e.msg)
+    look_for = None
+    #
+    if space.config.objspace.usemodules._cffi_backend:
+        look_for = '_cffi_pypyinit_%s' % (basename,)
+        try:
+            initptr = rdynload.dlsym(dll, look_for)
+        except KeyError:
+            pass
+        else:
+            from pypy.module._cffi_backend.cffi1_module import load_cffi1_module
+            return load_cffi1_module(space, name, dll, initptr)
+    #
+    if space.config.objspace.usemodules.cpyext:
+        also_look_for = 'init%s' % (basename,)
+        try:
+            initptr = rdynload.dlsym(dll, also_look_for)
+        except KeyError:
+            pass
+        else:
+            return load_cpyext_module(space, name, dll, initptr)
+        if look_for is not None:
+            look_for += ' or ' + also_look_for
+        else:
+            look_for = also_look_for
+    #
+    raise oefmt(space.w_ImportError,
+                "function %s not found in library %s", look_for, path)
+
+
+def load_cpyext_module(space, name, dll, initptr):
+    from rpython.rlib import rdynload
+
+    space.getbuiltinmodule("cpyext")    # mandatory to init cpyext
     state = space.fromcache(State)
     if state.find_extension(name, path) is not None:
+        rdynload.dlclose(dll)
         return
     old_context = state.package_context
     state.package_context = name, path
     try:
-        from rpython.rlib import rdynload
-        try:
-            ll_libname = rffi.str2charp(path)
-            try:
-                dll = rdynload.dlopen(ll_libname)
-            finally:
-                lltype.free(ll_libname, flavor='raw')
-        except rdynload.DLOpenError, e:
-            raise oefmt(space.w_ImportError,
-                        "unable to load extension module '%s': %s",
-                        path, e.msg)
-        try:
-            initptr = rdynload.dlsym(dll, 'init%s' % (name.split('.')[-1],))
-        except KeyError:
-            raise oefmt(space.w_ImportError,
-                        "function init%s not found in library %s", name, path)
         initfunc = rffi.cast(initfunctype, initptr)
         generic_cpy_call(space, initfunc)
         state.check_and_raise_exception()
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -51,6 +51,10 @@
     """Tests whether the given path is an existing regular file."""
     return os.path.isfile(path) and case_ok(path)
 
+def has_so_extension(space):
+    return (space.config.objspace.usemodules.cpyext or
+            space.config.objspace.usemodules._cffi_backend)
+
 def find_modtype(space, filepart):
     """Check which kind of module to import for the given filepart,
     which is a path without extension.  Returns PY_SOURCE, PY_COMPILED or
@@ -79,7 +83,7 @@
             # existing .pyc file
             return PY_COMPILED, ".pyc", "rb"
 
-    if space.config.objspace.usemodules.cpyext:
+    if has_so_extension(space):
         so_extension = get_so_extension(space)
         pydfile = filepart + so_extension
         if file_exists(pydfile):
@@ -565,10 +569,9 @@
     return w_mod
 
 def load_c_extension(space, filename, modulename):
-    # the next line is mandatory to init cpyext
-    space.getbuiltinmodule("cpyext")
     from pypy.module.cpyext.api import load_extension_module
     load_extension_module(space, filename, modulename)
+    # NB. cpyext.api.load_extension_module() can also delegate to _cffi_backend
 
 @jit.dont_look_inside
 def load_module(space, w_modulename, find_info, reuse=False):
@@ -628,7 +631,7 @@
                 # fetch the module again, in case of "substitution"
                 w_mod = check_sys_modules(space, w_modulename)
                 return w_mod
-            elif find_info.modtype == C_EXTENSION and space.config.objspace.usemodules.cpyext:
+            elif find_info.modtype == C_EXTENSION and has_so_extension(space):
                 load_c_extension(space, find_info.filename, space.str_w(w_modulename))
                 return check_sys_modules(space, w_modulename)
         except OperationError:
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -11,7 +11,7 @@
 def get_suffixes(space):
     w = space.wrap
     suffixes_w = []
-    if space.config.objspace.usemodules.cpyext:
+    if importing.has_so_extension(space):
         suffixes_w.append(
             space.newtuple([w(importing.get_so_extension(space)),
                             w('rb'), w(importing.C_EXTENSION)]))
@@ -128,7 +128,7 @@
 
 @unwrap_spec(filename=str)
 def load_dynamic(space, w_modulename, filename, w_file=None):
-    if not space.config.objspace.usemodules.cpyext:
+    if not importing.has_so_extension(space):
         raise OperationError(space.w_ImportError, space.wrap(
             "Not implemented"))
     importing.load_c_extension(space, filename, space.str_w(w_modulename))


More information about the pypy-commit mailing list