[pypy-commit] cffi default: Change the default dlopen() flags from RTLD_LAZY to RTLD_NOW.

arigo noreply at buildbot.pypy.org
Mon Sep 24 11:00:23 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r968:0c8581ea7507
Date: 2012-09-24 11:00 +0200
http://bitbucket.org/cffi/cffi/changeset/0c8581ea7507/

Log:	Change the default dlopen() flags from RTLD_LAZY to RTLD_NOW. Give
	access to all flags, for more precise control.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2691,20 +2691,24 @@
     char *filename_or_null, *printable_filename;
     void *handle;
     DynLibObject *dlobj;
-    int is_global = 0;
+    int flags = 0;
 
     if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
-        filename_or_null = NULL;
-        is_global = 1;
+        PyObject *dummy;
+        if (!PyArg_ParseTuple(args, "|Oi:load_library",
+                              &dummy, &flags))
+            return NULL;
     }
     else if (!PyArg_ParseTuple(args, "et|i:load_library",
                           Py_FileSystemDefaultEncoding, &filename_or_null,
-                          &is_global))
+                          &flags))
         return NULL;
 
+    if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
+        flags |= RTLD_NOW;
+
     printable_filename = filename_or_null ? filename_or_null : "<None>";
-    handle = dlopen(filename_or_null,
-                    RTLD_LAZY | (is_global?RTLD_GLOBAL:RTLD_LOCAL));
+    handle = dlopen(filename_or_null, flags);
     if (handle == NULL) {
         PyErr_Format(PyExc_OSError, "cannot load library %s: %s",
                      printable_filename, dlerror());
@@ -4723,17 +4727,35 @@
     if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0)
         INITERROR;
 
+    if (PyModule_AddIntConstant(m, "FFI_DEFAULT_ABI", FFI_DEFAULT_ABI) < 0 ||
 #if defined(MS_WIN32) && !defined(_WIN64)
-    v = PyInt_FromLong(FFI_STDCALL);
-    if (v == NULL || PyModule_AddObject(m, "FFI_STDCALL", v) < 0)
-        INITERROR;
+        PyModule_AddIntConstant(m, "FFI_STDCALL", FFI_STDCALL) < 0 ||
 #endif
-    v = PyInt_FromLong(FFI_DEFAULT_ABI);
-    if (v == NULL || PyModule_AddObject(m, "FFI_DEFAULT_ABI", v) < 0)
-        INITERROR;
-    Py_INCREF(v);
-    if (PyModule_AddObject(m, "FFI_CDECL", v) < 0)  /* win32 name */
-        INITERROR;
+#ifdef FFI_CDECL
+        PyModule_AddIntConstant(m, "FFI_CDECL", FFI_CDECL) < 0 ||   /* win32 */
+#else
+        PyModule_AddIntConstant(m, "FFI_CDECL", FFI_DEFAULT_ABI) < 0 ||
+#endif
+
+        PyModule_AddIntConstant(m, "RTLD_LAZY",   RTLD_LAZY) < 0 ||
+        PyModule_AddIntConstant(m, "RTLD_NOW",    RTLD_NOW) < 0 ||
+        PyModule_AddIntConstant(m, "RTLD_GLOBAL", RTLD_GLOBAL) < 0 ||
+#ifdef RTLD_LOCAL
+        PyModule_AddIntConstant(m, "RTLD_LOCAL",  RTLD_LOCAL) < 0 ||
+#else
+        PyModule_AddIntConstant(m, "RTLD_LOCAL",  0) < 0 ||
+#endif
+#ifdef RTLD_NODELETE
+        PyModule_AddIntConstant(m, "RTLD_NODELETE",  RTLD_NODELETE) < 0 ||
+#endif
+#ifdef RTLD_NOLOAD
+        PyModule_AddIntConstant(m, "RTLD_NOLOAD",  RTLD_NOLOAD) < 0 ||
+#endif
+#ifdef RTLD_DEEPBIND
+        PyModule_AddIntConstant(m, "RTLD_DEEPBIND",  RTLD_DEEPBIND) < 0 ||
+#endif
+        0)
+      INITERROR;
 
     init_errno();
 
diff --git a/c/misc_win32.h b/c/misc_win32.h
--- a/c/misc_win32.h
+++ b/c/misc_win32.h
@@ -84,6 +84,7 @@
 /* Emulate dlopen()&co. from the Windows API */
 
 #define RTLD_LAZY   0
+#define RTLD_NOW    0
 #define RTLD_GLOBAL 0
 #define RTLD_LOCAL  0
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -46,19 +46,34 @@
     return sizeof(BPtr)
 
 
-def find_and_load_library(name, is_global=0):
+def find_and_load_library(name, flags=RTLD_NOW):
     import ctypes.util
     if name is None:
         path = None
     else:
         path = ctypes.util.find_library(name)
-    return load_library(path, is_global)
+    return load_library(path, flags)
 
 def test_load_library():
     x = find_and_load_library('c')
     assert repr(x).startswith("<clibrary '")
-    x = find_and_load_library('c', 1)
+    x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL)
     assert repr(x).startswith("<clibrary '")
+    x = find_and_load_library('c', RTLD_LAZY)
+    assert repr(x).startswith("<clibrary '")
+
+def test_all_rtld_symbols():
+    import sys
+    FFI_DEFAULT_ABI        # these symbols must be defined
+    FFI_CDECL
+    RTLD_LAZY
+    RTLD_NOW
+    RTLD_GLOBAL
+    RTLD_LOCAL
+    if sys.platform.startswith("linux"):
+        RTLD_NODELETE
+        RTLD_NOLOAD
+        RTLD_DEEPBIND
 
 def test_nonstandard_integer_types():
     d = nonstandard_integer_types()
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -54,6 +54,9 @@
         self._pointer_type_cache = {}
         if hasattr(backend, 'set_ffi'):
             backend.set_ffi(self)
+        for name in backend.__dict__:
+            if name.startswith('RTLD_'):
+                setattr(self, name, getattr(backend, name))
         #
         lines = []
         by_size = {}
@@ -84,7 +87,7 @@
             for cache in self._function_caches:
                 cache.clear()
 
-    def dlopen(self, name):
+    def dlopen(self, name, flags=0):
         """Load and return a dynamic library identified by 'name'.
         The standard C library can be loaded by passing None.
         Note that functions and types declared by 'ffi.cdef()' are not
@@ -92,7 +95,7 @@
         library we only look for the actual (untyped) symbols.
         """
         assert isinstance(name, str) or name is None
-        lib, function_cache = _make_ffi_library(self, name)
+        lib, function_cache = _make_ffi_library(self, name, flags)
         self._function_caches.append(function_cache)
         return lib
 
@@ -301,11 +304,13 @@
         return self._backend.rawaddressof(ctypeptr, cdata, offset)
 
 
-def _make_ffi_library(ffi, libname):
+def _make_ffi_library(ffi, libname, flags):
+    import os
     name = libname
     if name is None:
         name = 'c'    # on Posix only
-    if '/' in name:
+    if os.path.sep in name or (
+            os.path.altsep is not None and os.path.altsep in name):
         path = name
     else:
         import ctypes.util
@@ -314,7 +319,7 @@
             raise OSError("library not found: %r" % (name,))
     #
     backend = ffi._backend
-    backendlib = backend.load_library(path)
+    backendlib = backend.load_library(path, flags)
     #
     def make_accessor(name):
         key = 'function ' + name
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -287,6 +287,12 @@
         '_Bool': ctypes.c_bool,
     }
 
+    def __init__(self):
+        self.RTLD_LAZY = 0   # not supported anyway by ctypes
+        self.RTLD_NOW  = 0
+        self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL
+        self.RTLD_LOCAL = ctypes.RTLD_LOCAL
+
     def set_ffi(self, ffi):
         self.ffi = ffi
 
@@ -309,8 +315,8 @@
                 result['ssize_t'] = size
         return result
 
-    def load_library(self, path):
-        cdll = ctypes.CDLL(path)
+    def load_library(self, path, flags=0):
+        cdll = ctypes.CDLL(path, flags)
         return CTypesLibrary(self, cdll)
 
     def new_void_type(self):
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -404,7 +404,7 @@
 Loading libraries
 -----------------
 
-``ffi.dlopen(libpath)``: this function opens a shared library and
+``ffi.dlopen(libpath, [flags])``: this function opens a shared library and
 returns a module-like library object.  You need to use *either*
 ``ffi.dlopen()`` *or* ``ffi.verify()``, documented below_.
 
@@ -432,6 +432,9 @@
 cannot call functions from a library without linking it in your program,
 as ``dlopen()`` does dynamically in C.
 
+For the optional ``flags`` argument, see ``man dlopen`` (ignored on
+Windows).  It defaults to ``ffi.RTLD_NOW``.
+
 .. _below:
 
 
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -68,6 +68,15 @@
         x = m.sin(1.23)
         assert x is None
 
+    def test_dlopen_flags(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            double cos(double x);
+        """)
+        m = ffi.dlopen("m", ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
+        x = m.cos(1.23)
+        assert x == math.cos(1.23)
+
     def test_tlsalloc(self):
         if sys.platform != 'win32':
             py.test.skip("win32 only")
diff --git a/testing/test_parsing.py b/testing/test_parsing.py
--- a/testing/test_parsing.py
+++ b/testing/test_parsing.py
@@ -9,7 +9,7 @@
     def sizeof(self, name):
         return 1
 
-    def load_library(self, name):
+    def load_library(self, name, flags):
         if sys.platform == 'win32':
             assert "msvcr" in name
         else:


More information about the pypy-commit mailing list