[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