[Python-checkins] cpython: Closes #9998: Allowed find_library to search additional locations for libraries.
vinay.sajip
python-checkins at python.org
Wed Aug 17 11:20:38 EDT 2016
https://hg.python.org/cpython/rev/385181e809bc
changeset: 102735:385181e809bc
user: Vinay Sajip <vinay_sajip at yahoo.co.uk>
date: Wed Aug 17 16:20:07 2016 +0100
summary:
Closes #9998: Allowed find_library to search additional locations for libraries.
files:
Doc/library/ctypes.rst | 17 ++++++--
Lib/ctypes/test/test_find.py | 43 ++++++++++++++++++++++++
Lib/ctypes/util.py | 26 +++++++++++++-
Misc/NEWS | 2 +
4 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -1239,9 +1239,10 @@
compiling/linking a program, and when the program is run.
The purpose of the :func:`find_library` function is to locate a library in a way
-similar to what the compiler does (on platforms with several versions of a
-shared library the most recent should be loaded), while the ctypes library
-loaders act like when a program is run, and call the runtime loader directly.
+similar to what the compiler or runtime loader does (on platforms with several
+versions of a shared library the most recent should be loaded), while the ctypes
+library loaders act like when a program is run, and call the runtime loader
+directly.
The :mod:`ctypes.util` module provides a function which can help to determine
the library to load.
@@ -1259,8 +1260,14 @@
The exact functionality is system dependent.
On Linux, :func:`find_library` tries to run external programs
-(``/sbin/ldconfig``, ``gcc``, and ``objdump``) to find the library file. It
-returns the filename of the library file. Here are some examples::
+(``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file.
+It returns the filename of the library file.
+
+.. versionchanged:: 3.6
+ On Linux, the value of the environment variable ``LD_LIBRARY_PATH`` is used
+ when searching for libraries, if a library cannot be found by any other means.
+
+Here are some examples::
>>> from ctypes.util import find_library
>>> find_library("m")
diff --git a/Lib/ctypes/test/test_find.py b/Lib/ctypes/test/test_find.py
--- a/Lib/ctypes/test/test_find.py
+++ b/Lib/ctypes/test/test_find.py
@@ -69,6 +69,49 @@
self.assertFalse(os.path.lexists(test.support.TESTFN))
self.assertIsNone(result)
+
+ at unittest.skipUnless(sys.platform.startswith('linux'),
+ 'Test only valid for Linux')
+class LibPathFindTest(unittest.TestCase):
+ def test_find_on_libpath(self):
+ import subprocess
+ import tempfile
+
+ try:
+ p = subprocess.Popen(['gcc', '--version'], stdout=subprocess.PIPE,
+ stderr=subprocess.DEVNULL)
+ out, _ = p.communicate()
+ except OSError:
+ raise unittest.SkipTest('gcc, needed for test, not available')
+ with tempfile.TemporaryDirectory() as d:
+ # create an empty temporary file
+ srcname = os.path.join(d, 'dummy.c')
+ libname = 'py_ctypes_test_dummy'
+ dstname = os.path.join(d, 'lib%s.so' % libname)
+ with open(srcname, 'w') as f:
+ pass
+ self.assertTrue(os.path.exists(srcname))
+ # compile the file to a shared library
+ cmd = ['gcc', '-o', dstname, '--shared',
+ '-Wl,-soname,lib%s.so' % libname, srcname]
+ out = subprocess.check_output(cmd)
+ self.assertTrue(os.path.exists(dstname))
+ # now check that the .so can't be found (since not in
+ # LD_LIBRARY_PATH)
+ self.assertIsNone(find_library(libname))
+ # now add the location to LD_LIBRARY_PATH
+ with test.support.EnvironmentVarGuard() as env:
+ KEY = 'LD_LIBRARY_PATH'
+ if KEY not in env:
+ v = d
+ else:
+ v = '%s:%s' % (env[KEY], d)
+ env.set(KEY, v)
+ # now check that the .so can be found (since in
+ # LD_LIBRARY_PATH)
+ self.assertEqual(find_library(libname), 'lib%s.so' % libname)
+
+
# On platforms where the default shared library suffix is '.so',
# at least some libraries can be loaded as attributes of the cdll
# object, since ctypes now tries loading the lib again
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -285,8 +285,32 @@
except OSError:
pass
+ def _findLib_ld(name):
+ # See issue #9998 for why this is needed
+ expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
+ cmd = ['ld', '-t']
+ libpath = os.environ.get('LD_LIBRARY_PATH')
+ if libpath:
+ for d in libpath.split(':'):
+ cmd.extend(['-L', d])
+ cmd.extend(['-o', os.devnull, '-l%s' % name])
+ result = None
+ try:
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ out, _ = p.communicate()
+ res = re.search(expr, os.fsdecode(out))
+ if res:
+ result = res.group(0)
+ except Exception as e:
+ pass # result will be None
+ return result
+
def find_library(name):
- return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
+ # See issue #9998
+ return _findSoname_ldconfig(name) or \
+ _get_soname(_findLib_gcc(name) or _findLib_ld(name))
################################################################
# test code
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -13,6 +13,8 @@
Library
-------
+- Issue #9998: On Linux, ctypes.util.find_library now looks in LD_LIBRARY_PATH
+ for shared libraries.
What's New in Python 3.6.0 alpha 4
==================================
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list