Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
300 changes: 155 additions & 145 deletions Doc/library/ctypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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".
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
Loading