Skip to content

Commit d64f83d

Browse files
authored
gh-78773: Improve ctypes dynamic library loading docs (GH-145313)
1 parent 39aa415 commit d64f83d

File tree

1 file changed

+133
-117
lines changed

1 file changed

+133
-117
lines changed

Doc/library/ctypes.rst

Lines changed: 133 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ used to wrap these libraries in pure Python.
2020
ctypes tutorial
2121
---------------
2222

23-
Note: The code samples in this tutorial use :mod:`doctest` to make sure that
24-
they actually work. Since some code samples behave differently under Linux,
25-
Windows, or macOS, they contain doctest directives in comments.
26-
2723
Note: Some code samples reference the ctypes :class:`c_int` type. On platforms
2824
where ``sizeof(long) == sizeof(int)`` it is an alias to :class:`c_long`.
2925
So, you should not be confused if :class:`c_long` is printed if you would expect
@@ -34,13 +30,16 @@ So, you should not be confused if :class:`c_long` is printed if you would expect
3430
Loading dynamic link libraries
3531
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3632

37-
:mod:`!ctypes` exports the *cdll*, and on Windows *windll* and *oledll*
33+
:mod:`!ctypes` exports the :py:data:`~ctypes.cdll`, and on Windows
34+
:py:data:`~ctypes.windll` and :py:data:`~ctypes.oledll`
3835
objects, for loading dynamic link libraries.
3936

40-
You load libraries by accessing them as attributes of these objects. *cdll*
41-
loads libraries which export functions using the standard ``cdecl`` calling
42-
convention, while *windll* libraries call functions using the ``stdcall``
43-
calling convention. *oledll* also uses the ``stdcall`` calling convention, and
37+
You load libraries by accessing them as attributes of these objects.
38+
:py:data:`!cdll` loads libraries which export functions using the
39+
standard ``cdecl`` calling convention, while :py:data:`!windll`
40+
libraries call functions using the ``stdcall``
41+
calling convention.
42+
:py:data:`~oledll` also uses the ``stdcall`` calling convention, and
4443
assumes the functions return a Windows :c:type:`!HRESULT` error code. The error
4544
code is used to automatically raise an :class:`OSError` exception when the
4645
function call fails.
@@ -70,11 +69,13 @@ Windows appends the usual ``.dll`` file suffix automatically.
7069
being used by Python. Where possible, use native Python functionality,
7170
or else import and use the ``msvcrt`` module.
7271

73-
On Linux, it is required to specify the filename *including* the extension to
72+
Other systems require the filename *including* the extension to
7473
load a library, so attribute access can not be used to load libraries. Either the
7574
:meth:`~LibraryLoader.LoadLibrary` method of the dll loaders should be used,
76-
or you should load the library by creating an instance of CDLL by calling
77-
the constructor::
75+
or you should load the library by creating an instance of :py:class:`CDLL`
76+
by calling the constructor.
77+
78+
For example, on Linux::
7879

7980
>>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX
8081
<CDLL 'libc.so.6', handle ... at ...>
@@ -83,7 +84,14 @@ the constructor::
8384
<CDLL 'libc.so.6', handle ... at ...>
8485
>>>
8586

86-
.. XXX Add section for macOS.
87+
On macOS::
88+
89+
>>> cdll.LoadLibrary("libc.dylib") # doctest: +MACOS
90+
<CDLL 'libc.dylib', handle ... at ...>
91+
>>> libc = CDLL("libc.dylib") # doctest: +MACOS
92+
>>> libc # doctest: +MACOS
93+
<CDLL 'libc.dylib', handle ... at ...>
94+
8795

8896

8997
.. _ctypes-accessing-functions-from-loaded-dlls:
@@ -1456,14 +1464,82 @@ Loading shared libraries
14561464
^^^^^^^^^^^^^^^^^^^^^^^^
14571465

14581466
There are several ways to load shared libraries into the Python process. One
1459-
way is to instantiate one of the following classes:
1467+
way is to instantiate :py:class:`CDLL` or one of its subclasses:
14601468

14611469

14621470
.. class:: CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)
14631471

1464-
Instances of this class represent loaded shared libraries. Functions in these
1465-
libraries use the standard C calling convention, and are assumed to return
1466-
:c:expr:`int`.
1472+
Represents a loaded shared library.
1473+
1474+
Functions in this library use the standard C calling convention, and are
1475+
assumed to return :c:expr:`int`.
1476+
The Python :term:`global interpreter lock` is released before calling any
1477+
function exported by these libraries, and reacquired afterwards.
1478+
For different function behavior, use a subclass: :py:class:`~ctypes.OleDLL`,
1479+
:py:class:`~ctypes.WinDLL`, or :py:class:`~ctypes.PyDLL`.
1480+
1481+
If you have an existing :py:attr:`handle <ctypes.CDLL._handle>` to an already
1482+
loaded shared library, it can be passed as the *handle* argument to wrap
1483+
the opened library in a new :py:class:`!CDLL` object.
1484+
In this case, *name* is only used to set the :py:attr:`~ctypes.CDLL._name`
1485+
attribute, but it may be adjusted and/or validated.
1486+
1487+
If *handle* is ``None``, the underlying platform's :manpage:`dlopen(3)` or
1488+
:c:func:`!LoadLibrary` function is used to load the library into
1489+
the process, and to get a handle to it.
1490+
1491+
*name* is the pathname of the shared library to open.
1492+
If *name* does not contain a path separator, the library is found
1493+
in a platform-specific way.
1494+
1495+
On non-Windows systems, *name* can be ``None``. In this case,
1496+
:c:func:`!dlopen` is called with ``NULL``, which opens the main program
1497+
as a "library".
1498+
(Some systems do the same is *name* is empty; ``None``/``NULL`` is more
1499+
portable.)
1500+
1501+
.. admonition:: CPython implementation detail
1502+
1503+
Since CPython is linked to ``libc``, a ``None`` *name* is often used
1504+
to access the C standard library::
1505+
1506+
>>> printf = ctypes.CDLL(None).printf
1507+
>>> printf.argtypes = [ctypes.c_char_p]
1508+
>>> printf(b"hello\n")
1509+
hello
1510+
6
1511+
1512+
To access the Python C API, prefer :py:data:`ctypes.pythonapi` which
1513+
works across platforms.
1514+
1515+
The *mode* parameter can be used to specify how the library is loaded. For
1516+
details, consult the :manpage:`dlopen(3)` manpage. On Windows, *mode* is
1517+
ignored. On posix systems, RTLD_NOW is always added, and is not
1518+
configurable.
1519+
1520+
The *use_errno* parameter, when set to true, enables a ctypes mechanism that
1521+
allows accessing the system :data:`errno` error number in a safe way.
1522+
:mod:`!ctypes` maintains a thread-local copy of the system's :data:`errno`
1523+
variable; if you call foreign functions created with ``use_errno=True`` then the
1524+
:data:`errno` value before the function call is swapped with the ctypes private
1525+
copy, the same happens immediately after the function call.
1526+
1527+
The function :func:`ctypes.get_errno` returns the value of the ctypes private
1528+
copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy
1529+
to a new value and returns the former value.
1530+
1531+
The *use_last_error* parameter, when set to true, enables the same mechanism for
1532+
the Windows error code which is managed by the :func:`GetLastError` and
1533+
:func:`!SetLastError` Windows API functions; :func:`ctypes.get_last_error` and
1534+
:func:`ctypes.set_last_error` are used to request and change the ctypes private
1535+
copy of the windows error code.
1536+
1537+
The *winmode* parameter is used on Windows to specify how the library is loaded
1538+
(since *mode* is ignored). It takes any value that is valid for the Win32 API
1539+
``LoadLibraryEx`` flags parameter. When omitted, the default is to use the
1540+
flags that result in the most secure DLL load, which avoids issues such as DLL
1541+
hijacking. Passing the full path to the DLL is the safest way to ensure the
1542+
correct library and dependencies are loaded.
14671543

14681544
On Windows creating a :class:`CDLL` instance may fail even if the DLL name
14691545
exists. When a dependent DLL of the loaded DLL is not found, a
@@ -1475,20 +1551,47 @@ way is to instantiate one of the following classes:
14751551
DLLs and determine which one is not found using Windows debugging and
14761552
tracing tools.
14771553

1554+
.. seealso::
1555+
1556+
`Microsoft DUMPBIN tool <https://learn.microsoft.com/en-us/cpp/build/reference/dumpbin-reference?view=msvc-170>`_
1557+
-- A tool to find DLL dependents.
1558+
1559+
.. versionchanged:: 3.8
1560+
Added *winmode* parameter.
1561+
14781562
.. versionchanged:: 3.12
14791563

14801564
The *name* parameter can now be a :term:`path-like object`.
14811565

1482-
.. seealso::
1566+
Instances of this class have no public methods. Functions exported by the
1567+
shared library can be accessed as attributes or by index. Please note that
1568+
accessing the function through an attribute caches the result and therefore
1569+
accessing it repeatedly returns the same object each time. On the other hand,
1570+
accessing it through an index returns a new object each time::
1571+
1572+
>>> from ctypes import CDLL
1573+
>>> libc = CDLL("libc.so.6") # On Linux
1574+
>>> libc.time == libc.time
1575+
True
1576+
>>> libc['time'] == libc['time']
1577+
False
1578+
1579+
The following public attributes are available. Their name starts with an
1580+
underscore to not clash with exported function names:
1581+
1582+
.. attribute:: _handle
1583+
1584+
The system handle used to access the library.
14831585

1484-
`Microsoft DUMPBIN tool <https://docs.microsoft.com/cpp/build/reference/dependents>`_
1485-
-- A tool to find DLL dependents.
1586+
.. attribute:: _name
14861587

1588+
The name of the library passed in the constructor.
14871589

1488-
.. class:: OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)
1590+
.. class:: OleDLL
14891591

1490-
Instances of this class represent loaded shared libraries,
1491-
functions in these libraries use the ``stdcall`` calling convention, and are
1592+
See :py:class:`~ctypes.CDLL`, the superclass, for common information.
1593+
1594+
Functions in this library use the ``stdcall`` calling convention, and are
14921595
assumed to return the windows specific :class:`HRESULT` code. :class:`HRESULT`
14931596
values contain information specifying whether the function call failed or
14941597
succeeded, together with additional error code. If the return value signals a
@@ -1500,133 +1603,51 @@ way is to instantiate one of the following classes:
15001603
:exc:`WindowsError` used to be raised,
15011604
which is now an alias of :exc:`OSError`.
15021605

1503-
.. versionchanged:: 3.12
1504-
1505-
The *name* parameter can now be a :term:`path-like object`.
15061606

1607+
.. class:: WinDLL
15071608

1508-
.. class:: WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)
1609+
See :py:class:`~ctypes.CDLL`, the superclass, for common information.
15091610

1510-
Instances of this class represent loaded shared libraries,
1511-
functions in these libraries use the ``stdcall`` calling convention, and are
1611+
Functions in these libraries use the ``stdcall`` calling convention, and are
15121612
assumed to return :c:expr:`int` by default.
15131613

15141614
.. availability:: Windows
15151615

1516-
.. versionchanged:: 3.12
1616+
.. class:: PyDLL
15171617

1518-
The *name* parameter can now be a :term:`path-like object`.
1618+
See :py:class:`~ctypes.CDLL`, the superclass, for common information.
15191619

1520-
1521-
The Python :term:`global interpreter lock` is released before calling any
1522-
function exported by these libraries, and reacquired afterwards.
1523-
1524-
1525-
.. class:: PyDLL(name, mode=DEFAULT_MODE, handle=None)
1526-
1527-
Instances of this class behave like :class:`CDLL` instances, except that the
1620+
When functions in this library are called, the
15281621
Python GIL is *not* released during the function call, and after the function
15291622
execution the Python error flag is checked. If the error flag is set, a Python
15301623
exception is raised.
15311624

1532-
Thus, this is only useful to call Python C api functions directly.
1533-
1534-
.. versionchanged:: 3.12
1535-
1536-
The *name* parameter can now be a :term:`path-like object`.
1537-
1538-
All these classes can be instantiated by calling them with at least one
1539-
argument, the pathname of the shared library. If you have an existing handle to
1540-
an already loaded shared library, it can be passed as the ``handle`` named
1541-
parameter, otherwise the underlying platform's :c:func:`!dlopen` or
1542-
:c:func:`!LoadLibrary` function is used to load the library into
1543-
the process, and to get a handle to it.
1544-
1545-
The *mode* parameter can be used to specify how the library is loaded. For
1546-
details, consult the :manpage:`dlopen(3)` manpage. On Windows, *mode* is
1547-
ignored. On posix systems, RTLD_NOW is always added, and is not
1548-
configurable.
1549-
1550-
The *use_errno* parameter, when set to true, enables a ctypes mechanism that
1551-
allows accessing the system :data:`errno` error number in a safe way.
1552-
:mod:`!ctypes` maintains a thread-local copy of the system's :data:`errno`
1553-
variable; if you call foreign functions created with ``use_errno=True`` then the
1554-
:data:`errno` value before the function call is swapped with the ctypes private
1555-
copy, the same happens immediately after the function call.
1556-
1557-
The function :func:`ctypes.get_errno` returns the value of the ctypes private
1558-
copy, and the function :func:`ctypes.set_errno` changes the ctypes private copy
1559-
to a new value and returns the former value.
1560-
1561-
The *use_last_error* parameter, when set to true, enables the same mechanism for
1562-
the Windows error code which is managed by the :func:`GetLastError` and
1563-
:func:`!SetLastError` Windows API functions; :func:`ctypes.get_last_error` and
1564-
:func:`ctypes.set_last_error` are used to request and change the ctypes private
1565-
copy of the windows error code.
1566-
1567-
The *winmode* parameter is used on Windows to specify how the library is loaded
1568-
(since *mode* is ignored). It takes any value that is valid for the Win32 API
1569-
``LoadLibraryEx`` flags parameter. When omitted, the default is to use the
1570-
flags that result in the most secure DLL load, which avoids issues such as DLL
1571-
hijacking. Passing the full path to the DLL is the safest way to ensure the
1572-
correct library and dependencies are loaded.
1573-
1574-
.. versionchanged:: 3.8
1575-
Added *winmode* parameter.
1625+
Thus, this is only useful to call Python C API functions directly.
15761626

15771627

15781628
.. data:: RTLD_GLOBAL
1579-
:noindex:
15801629

15811630
Flag to use as *mode* parameter. On platforms where this flag is not available,
15821631
it is defined as the integer zero.
15831632

15841633

15851634
.. data:: RTLD_LOCAL
1586-
:noindex:
15871635

15881636
Flag to use as *mode* parameter. On platforms where this is not available, it
15891637
is the same as *RTLD_GLOBAL*.
15901638

15911639

15921640
.. data:: DEFAULT_MODE
1593-
:noindex:
15941641

15951642
The default mode which is used to load shared libraries. On OSX 10.3, this is
15961643
*RTLD_GLOBAL*, otherwise it is the same as *RTLD_LOCAL*.
15971644

1598-
Instances of these classes have no public methods. Functions exported by the
1599-
shared library can be accessed as attributes or by index. Please note that
1600-
accessing the function through an attribute caches the result and therefore
1601-
accessing it repeatedly returns the same object each time. On the other hand,
1602-
accessing it through an index returns a new object each time::
1603-
1604-
>>> from ctypes import CDLL
1605-
>>> libc = CDLL("libc.so.6") # On Linux
1606-
>>> libc.time == libc.time
1607-
True
1608-
>>> libc['time'] == libc['time']
1609-
False
1610-
1611-
The following public attributes are available, their name starts with an
1612-
underscore to not clash with exported function names:
1613-
1614-
1615-
.. attribute:: PyDLL._handle
1616-
1617-
The system handle used to access the library.
1618-
1619-
1620-
.. attribute:: PyDLL._name
1621-
1622-
The name of the library passed in the constructor.
16231645

16241646
Shared libraries can also be loaded by using one of the prefabricated objects,
16251647
which are instances of the :class:`LibraryLoader` class, either by calling the
16261648
:meth:`~LibraryLoader.LoadLibrary` method, or by retrieving the library as
16271649
attribute of the loader instance.
16281650

1629-
16301651
.. class:: LibraryLoader(dlltype)
16311652

16321653
Class which loads shared libraries. *dlltype* should be one of the
@@ -1645,29 +1666,25 @@ attribute of the loader instance.
16451666
These prefabricated library loaders are available:
16461667

16471668
.. data:: cdll
1648-
:noindex:
16491669

16501670
Creates :class:`CDLL` instances.
16511671

16521672

16531673
.. data:: windll
1654-
:noindex:
16551674

16561675
Creates :class:`WinDLL` instances.
16571676

16581677
.. availability:: Windows
16591678

16601679

16611680
.. data:: oledll
1662-
:noindex:
16631681

16641682
Creates :class:`OleDLL` instances.
16651683

16661684
.. availability:: Windows
16671685

16681686

16691687
.. data:: pydll
1670-
:noindex:
16711688

16721689
Creates :class:`PyDLL` instances.
16731690

@@ -1676,7 +1693,6 @@ For accessing the C Python api directly, a ready-to-use Python shared library
16761693
object is available:
16771694

16781695
.. data:: pythonapi
1679-
:noindex:
16801696

16811697
An instance of :class:`PyDLL` that exposes Python C API functions as
16821698
attributes. Note that all these functions are assumed to return C

0 commit comments

Comments
 (0)