https://github.com/python/cpython/commit/b38127f3d607e474b1299dc0bc28080288a59989
commit: b38127f3d607e474b1299dc0bc28080288a59989
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2026-03-20T15:00:10+01:00
summary:

gh-145916: Soft-deprecate ctypes.util.find_library (GH-145919)

* Put the "Loading shared libraries" section first
  * Adjust formatting at the end of the section
* In "Finding shared libraries", add more text about what's going on
* Move the stub function doc for find_library into "Finding shared libraries"
  * Also move the sister function, find_msvcrt. That's on the chopping block,
    but not removed now.

files:
M Doc/library/ctypes.rst

diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index fcbe2122d9f1a7..8b213ef1d49932 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -1360,104 +1360,6 @@ is already known, on a case by case basis.
 ctypes reference
 ----------------
 
-
-.. _ctypes-finding-shared-libraries:
-
-Finding shared libraries
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-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:`~ctypes.util.find_library` function is to locate a 
library in a way
-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.
-
-
-.. data:: find_library(name)
-   :module: ctypes.util
-   :noindex:
-
-   Try to find a library and return a pathname.  *name* is the library name 
without
-   any prefix like *lib*, suffix like ``.so``, ``.dylib`` or version number 
(this
-   is the form used for the posix linker option :option:`!-l`).  If no library 
can
-   be found, returns ``None``.
-
-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.
-
-Note that if the output of these programs does not correspond to the dynamic
-linker used by Python, the result of this function may be misleading.
-
-.. 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")
-   'libm.so.6'
-   >>> find_library("c")
-   'libc.so.6'
-   >>> find_library("bz2")
-   'libbz2.so.1.0'
-   >>>
-
-On macOS and Android, :func:`~ctypes.util.find_library` uses the system's
-standard naming schemes and paths to locate the library, and returns a full
-pathname if successful::
-
-   >>> from ctypes.util import find_library
-   >>> find_library("c")
-   '/usr/lib/libc.dylib'
-   >>> find_library("m")
-   '/usr/lib/libm.dylib'
-   >>> find_library("bz2")
-   '/usr/lib/libbz2.dylib'
-   >>> find_library("AGL")
-   '/System/Library/Frameworks/AGL.framework/AGL'
-   >>>
-
-On Windows, :func:`~ctypes.util.find_library` searches along the system search 
path, and
-returns the full pathname, but since there is no predefined naming scheme a 
call
-like ``find_library("c")`` will fail and return ``None``.
-
-If wrapping a shared library with :mod:`!ctypes`, it *may* be better to 
determine
-the shared library name at development time, and hardcode that into the wrapper
-module instead of using :func:`~ctypes.util.find_library` to locate the 
library at runtime.
-
-
-.. _ctypes-listing-loaded-shared-libraries:
-
-Listing loaded shared libraries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-When writing code that relies on code loaded from shared libraries, it can be
-useful to know which shared libraries have already been loaded into the current
-process.
-
-The :mod:`!ctypes.util` module provides the :func:`~ctypes.util.dllist` 
function,
-which calls the different APIs provided by the various platforms to help 
determine
-which shared libraries have already been loaded into the current process.
-
-The exact output of this function will be system dependent. On most platforms,
-the first entry of this list represents the current process itself, which may
-be an empty string.
-For example, on glibc-based Linux, the return may look like::
-
-   >>> from ctypes.util import dllist
-   >>> dllist()
-   ['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', 
'/lib/x86_64-linux-gnu/libc.so.6', ... ]
-
 .. _ctypes-loading-shared-libraries:
 
 Loading shared libraries
@@ -1485,13 +1387,20 @@ way is to instantiate :py:class:`CDLL` or one of its 
subclasses:
    attribute, but it may be adjusted and/or validated.
 
    If *handle* is ``None``, the underlying platform's :manpage:`dlopen(3)` or
-   :c:func:`!LoadLibrary` function is used to load the library into
+   `LoadLibraryExW`_ function is used to load the library into
    the process, and to get a handle to it.
 
    *name* is the pathname of the shared library to open.
    If *name* does not contain a path separator, the library is found
    in a platform-specific way.
 
+   On Windows, the ``.DLL`` suffix may be missing. (For details, see
+   `LoadLibraryExW`_ documentation.)
+   Other platform-specific prefixes and suffixes (for example, ``lib``,
+   ``.so``, ``.dylib``, or version numbers) must be present in *name*;
+   they are not added automatically.
+   See :ref:`ctypes-finding-shared-libraries` for more information.
+
    On non-Windows systems, *name* can  be ``None``. In this case,
    :c:func:`!dlopen` is called with ``NULL``, which opens the main program
    as a "library".
@@ -1536,7 +1445,7 @@ way is to instantiate :py:class:`CDLL` or one of its 
subclasses:
 
    The *winmode* parameter is used on Windows to specify how the library is 
loaded
    (since *mode* is ignored). It takes any value that is valid for the Win32 
API
-   ``LoadLibraryEx`` flags parameter. When omitted, the default is to use the
+   `LoadLibraryExW`_ flags parameter. When omitted, the default is to use the
    flags that result in the most secure DLL load, which avoids issues such as 
DLL
    hijacking. Passing the full path to the DLL is the safest way to ensure the
    correct library and dependencies are loaded.
@@ -1587,6 +1496,8 @@ way is to instantiate :py:class:`CDLL` or one of its 
subclasses:
 
       The name of the library passed in the constructor.
 
+.. _LoadLibraryExW: 
https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw
+
 .. class:: OleDLL
 
    See :py:class:`~ctypes.CDLL`, the superclass, for common information.
@@ -1665,39 +1576,36 @@ attribute of the loader instance.
 
 These prefabricated library loaders are available:
 
-.. data:: cdll
-
-   Creates :class:`CDLL` instances.
+   .. data:: cdll
 
+      Creates :class:`CDLL` instances.
 
-.. data:: windll
 
-   Creates :class:`WinDLL` instances.
+   .. data:: windll
 
-   .. availability:: Windows
+      Creates :class:`WinDLL` instances.
 
+      .. availability:: Windows
 
-.. data:: oledll
 
-   Creates :class:`OleDLL` instances.
+   .. data:: oledll
 
-   .. availability:: Windows
+      Creates :class:`OleDLL` instances.
 
+      .. availability:: Windows
 
-.. data:: pydll
 
-   Creates :class:`PyDLL` instances.
+   .. data:: pydll
 
+      Creates :class:`PyDLL` instances.
 
-For accessing the C Python api directly, a ready-to-use Python shared library
-object is available:
 
-.. data:: pythonapi
+   .. data:: pythonapi
 
-   An instance of :class:`PyDLL` that exposes Python C API functions as
-   attributes.  Note that all these functions are assumed to return C
-   :c:expr:`int`, which is of course not always the truth, so you have to 
assign
-   the correct :attr:`!restype` attribute to use these functions.
+      An instance of :class:`PyDLL` that exposes Python C API functions as
+      attributes.  Note that all these functions are assumed to return C
+      :c:expr:`int`, which is of course not always the truth, so you have to 
assign
+      the correct :attr:`!restype` attribute to use these functions.
 
 .. audit-event:: ctypes.dlopen name ctypes.LibraryLoader
 
@@ -1717,6 +1625,135 @@ object is available:
    accessing a function raises an auditing event ``ctypes.dlsym/handle`` with
    arguments ``handle`` (the raw library handle) and ``name``.
 
+
+.. _ctypes-finding-shared-libraries:
+
+Finding shared libraries
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When programming in a compiled language, shared libraries are accessed when
+compiling/linking a program, and when the program is run.
+The programmer specifies a short name; the C compiler, linker, and
+runtime dynamic library loader then interact in system-specific ways to find
+the filename of the library to load.
+
+While the mapping from short names to filenames is not consistently exposed
+by platforms, the :mod:`!ctypes.util` module provides a function,
+:func:`!find_library`, that attempts to match it.
+However, as backwards compatibility concerns make it difficult to adjust
+its behavior for new platforms and configurations, the function
+is :term:`soft deprecated`.
+
+If wrapping a shared library with :mod:`!ctypes`, consider determining the
+shared library name at development time, and hardcoding it into the wrapper
+module instead of using :func:`!find_library` to locate the library
+at runtime.
+Also consider addding a configuration option or environment variable to let
+users select a library to use, and then perhaps use :func:`!find_library`
+as a default or fallback.
+
+.. function:: find_library(name)
+   :module: ctypes.util
+
+   Try to find a library and return a pathname.
+
+   *name* is the "short" library name without any prefix like ``lib``,
+   suffix like ``.so``, ``.dylib`` or version number.
+   (This is the form used for the posix linker option :option:`!-l`.)
+   The result is in a format suitable for passing to :py:class:`~ctypes.CDLL`.
+
+   If no library can be found, return ``None``.
+
+   The exact functionality is system dependent, and is *not guaranteed*
+   to match the behavior of the compiler, linker, and loader used for
+   (or by) Python.
+   It is recommended to only use this function as a default or fallback,
+
+   .. deprecated:: next
+
+      This function is :term:`soft deprecated`.
+      It is kept for use in cases where it works, but not expected to be
+      updated for additional platforms and configurations.
+
+On Linux, :func:`!find_library` tries to run external
+programs (``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the
+library file.
+If the output of these programs does not correspond to the dynamic
+linker used by Python, the result of this function may be misleading.
+
+.. 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")
+   'libm.so.6'
+   >>> find_library("c")
+   'libc.so.6'
+   >>> find_library("bz2")
+   'libbz2.so.1.0'
+   >>>
+
+On macOS and Android, :func:`!find_library` uses the system's
+standard naming schemes and paths to locate the library, and returns a full
+pathname if successful::
+
+   >>> from ctypes.util import find_library
+   >>> find_library("c")
+   '/usr/lib/libc.dylib'
+   >>> find_library("m")
+   '/usr/lib/libm.dylib'
+   >>> find_library("bz2")
+   '/usr/lib/libbz2.dylib'
+   >>> find_library("AGL")
+   '/System/Library/Frameworks/AGL.framework/AGL'
+   >>>
+
+On Windows, :func:`!find_library` searches along the system search path, and
+returns the full pathname, but since there is no predefined naming scheme a 
call
+like ``find_library("c")`` will fail and return ``None``.
+
+.. function:: find_msvcrt()
+   :module: ctypes.util
+
+   Returns the filename of the VC runtime library used by Python,
+   and by the extension modules.
+
+   If the name of the library cannot be determined, ``None`` is returned.
+   Notably, this will happen for recent versions of the VC runtime library,
+   which are not directly loadable.
+
+   If you need to free memory, for example, allocated by an extension module
+   with a call to the ``free(void *)``, it is important that you use the
+   function in the same library that allocated the memory.
+
+   .. availability:: Windows
+
+
+.. _ctypes-listing-loaded-shared-libraries:
+
+Listing loaded shared libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When writing code that relies on code loaded from shared libraries, it can be
+useful to know which shared libraries have already been loaded into the current
+process.
+
+The :mod:`!ctypes.util` module provides the :func:`~ctypes.util.dllist` 
function,
+which calls the different APIs provided by the various platforms to help 
determine
+which shared libraries have already been loaded into the current process.
+
+The exact output of this function will be system dependent. On most platforms,
+the first entry of this list represents the current process itself, which may
+be an empty string.
+For example, on glibc-based Linux, the return may look like::
+
+   >>> from ctypes.util import dllist
+   >>> dllist()
+   ['', 'linux-vdso.so.1', '/lib/x86_64-linux-gnu/libm.so.6', 
'/lib/x86_64-linux-gnu/libc.so.6', ... ]
+
 .. _ctypes-foreign-functions:
 
 Foreign functions
@@ -2139,33 +2176,6 @@ Utility functions
    .. availability:: Windows
 
 
-.. function:: find_library(name)
-   :module: ctypes.util
-
-   Try to find a library and return a pathname.  *name* is the library name
-   without any prefix like ``lib``, suffix like ``.so``, ``.dylib`` or version
-   number (this is the form used for the posix linker option :option:`!-l`).  
If
-   no library can be found, returns ``None``.
-
-   The exact functionality is system dependent.
-
-   See :ref:`ctypes-finding-shared-libraries` for complete documentation.
-
-
-.. function:: find_msvcrt()
-   :module: ctypes.util
-
-   Returns the filename of the VC runtime library used by Python,
-   and by the extension modules.  If the name of the library cannot be
-   determined, ``None`` is returned.
-
-   If you need to free memory, for example, allocated by an extension module
-   with a call to the ``free(void *)``, it is important that you use the
-   function in the same library that allocated the memory.
-
-   .. availability:: Windows
-
-
 .. function:: dllist()
    :module: ctypes.util
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to