mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
Closes #9998: Allowed find_library to search additional locations for libraries.
This commit is contained in:
parent
48e4bd6a02
commit
82df3b3071
4 changed files with 82 additions and 6 deletions
|
@ -1239,9 +1239,10 @@ When programming in a compiled language, shared libraries are accessed when
|
|||
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 library to load.
|
|||
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")
|
||||
|
|
|
@ -69,6 +69,49 @@ class Test_OpenGL_libs(unittest.TestCase):
|
|||
self.assertFalse(os.path.lexists(test.support.TESTFN))
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
@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
|
||||
|
|
|
@ -285,8 +285,32 @@ elif os.name == "posix":
|
|||
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
|
||||
|
|
|
@ -13,6 +13,8 @@ Core and Builtins
|
|||
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
|
||||
==================================
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue