diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index ef3a9a0f5898af4..ec36d24e154e9dc 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -1317,8 +1317,9 @@ the library to load. The exact functionality is system dependent. On Linux, :func:`~ctypes.util.find_library` tries to run external programs -(``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file. -It returns the filename of the library file. +(``ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file. +Note that ``ldconfig`` falls back to using ``/sbin/ldconfig`` if it is not found on ``$PATH``. +Unlike other distributions it returns only the filename of the library file. .. versionchanged:: 3.6 On Linux, the value of the environment variable ``LD_LIBRARY_PATH`` is used diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index c550883e7c7d4b7..14c6d526dc0d47e 100644 --- a/Lib/ctypes/util.py +++ b/Lib/ctypes/util.py @@ -90,7 +90,7 @@ def find_library(name): from ctypes._aix import find_library elif os.name == "posix": - # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump + # Andreas Degert's find functions, using gcc, ldconfig, objdump import re, tempfile def _is_elf(filename): @@ -207,12 +207,13 @@ def _num_version(libname): return nums or [sys.maxsize] def find_library(name): + ldconfig_bin = shutil.which('ldconfig') or '/sbin/ldconfig' ename = re.escape(name) expr = r':-l%s\.\S+ => \S*/(lib%s\.\S+)' % (ename, ename) expr = os.fsencode(expr) try: - proc = subprocess.Popen(('/sbin/ldconfig', '-r'), + proc = subprocess.Popen((ldconfig_bin, '-r'), stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) except OSError: # E.g. command not found @@ -269,8 +270,9 @@ def find_library(name, is64 = False): return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name)) else: - + # Linux distros and any others which did not match on sys.platform def _findSoname_ldconfig(name): + ldconfig_bin = shutil.which('ldconfig') or '/sbin/ldconfig' import struct if struct.calcsize('l') == 4: machine = os.uname().machine + '-32' @@ -284,12 +286,11 @@ def _findSoname_ldconfig(name): 'ia64-64': 'libc6,IA-64', } abi_type = mach_map.get(machine, 'libc6') - # XXX assuming GLIBC's ldconfig (with option -p) regex = r'\s+(lib%s\.[^\s]+)\s+\(%s' regex = os.fsencode(regex % (re.escape(name), abi_type)) try: - with subprocess.Popen(['/sbin/ldconfig', '-p'], + with subprocess.Popen([ldconfig_bin, '-p'], stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdout=subprocess.PIPE, diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-11-27-01-07-27.gh-issue-112417.6UU0jx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-11-27-01-07-27.gh-issue-112417.6UU0jx.rst new file mode 100644 index 000000000000000..cdf52e1e22640c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-11-27-01-07-27.gh-issue-112417.6UU0jx.rst @@ -0,0 +1 @@ +For compatibility across Linux distros ``ctypes.util.find_library`` has been modified to favour a version of ``ldconfig`` on the current ``$PATH``, falling back to ``/sbin/ldconfig`` if there isn't another version available.