From https://docs.python.org/3/library/ctypes.html#loading-shared-libraries
Shared libraries can also be loaded by using one of the prefabricated objects, which are instances of the LibraryLoader class, either by calling the LoadLibrary() method, or by retrieving the library as attribute of the loader instance.
I found an example for the first way Free the opened ctypes library in Python
I was wondering how to use the second way? In particular, how is the attribute of the loader instance cdll
created? My question comes from Why does loading the libc shared library have "'LibraryLoader' object is not callable" error?
The whole point of the LibraryLoader is that it creates the library for you when you access it. And
cdll.LoadLibrary("foo")
doesn't createcdll.foo
.
Is there something wrong with my experiment? Why does cdll.libc
never exist?
>>> from ctypes import *
>>> cdll.libc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/ctypes/__init__.py", line 418, in __getattr__
dll = self._dlltype(name)
File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libc: cannot open shared object file: No such file or directory
>>> cdll.LoadLibrary("libc.so.6")
<CDLL 'libc.so.6', handle 7f6afe03a000 at 0x7f6afc1afac8>
>>> cdll.libc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/ctypes/__init__.py", line 418, in __getattr__
dll = self._dlltype(name)
File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libc: cannot open shared object file: No such file or directory
>>> libc=cdll.LoadLibrary("libc.so.6")
>>> cdll.libc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/ctypes/__init__.py", line 418, in __getattr__
dll = self._dlltype(name)
File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libc: cannot open shared object file: No such file or directory
>>> CDLL("libc.so.6")
<CDLL 'libc.so.6', handle 7f6afe03a000 at 0x7f6afc1af978>
>>> cdll.libc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/ctypes/__init__.py", line 418, in __getattr__
dll = self._dlltype(name)
File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libc: cannot open shared object file: No such file or directory
>>> libc=CDLL("libc.so.6")
>>> cdll.libc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/ctypes/__init__.py", line 418, in __getattr__
dll = self._dlltype(name)
File "/usr/lib/python3.6/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libc: cannot open shared object file: No such file or directory
>>> cdll.__dict__
{'_dlltype': <class 'ctypes.CDLL'>}
Answer
The confusion you're encountering stems from a misunderstanding of how the cdll
object works in the ctypes
library, particularly how the LibraryLoader
class is used to load shared libraries and how attributes like cdll.libc
are accessed.
Let me break it down and clarify:
1. The cdll
Object
The cdll
object is an instance of the LibraryLoader
class in ctypes
. The purpose of LibraryLoader
is to provide a convenient way to load shared libraries and interact with them. The cdll
instance itself is not a direct interface to any specific library by name (like libc
), but rather it provides the method LoadLibrary()
to load shared libraries dynamically.
2. Accessing Libraries as Attributes of cdll
When you use cdll.libc
directly, Python will try to access an attribute libc
of cdll
. If that attribute doesn’t exist, Python will attempt to resolve it dynamically. In the case of ctypes
, this dynamic lookup will attempt to load a shared library named libc
. This is not how cdll
is designed to work for specific libraries like libc.so.6
.
To make this clearer:
cdll.LoadLibrary("libc.so.6")
: This loads thelibc.so.6
shared library and returns aCDLL
object representing that library.cdll.libc
: This causes an error becausecdll
does not automatically have an attributelibc
, and it does not create it when you try to access it.
3. Why cdll.libc
doesn't work
When you do cdll.libc
, Python looks for an attribute libc
in cdll
, which doesn't exist by default. Therefore, it tries to load libc
as a library, which results in the error:
OSError: libc: cannot open shared object file: No such file or directory
The LibraryLoader
class doesn't automatically create attributes like libc
for specific libraries; you need to explicitly load libraries using LoadLibrary()
.
4. Proper Usage of cdll
for Loading Libraries
Instead of accessing libraries like cdll.libc
, you should explicitly load the library with LoadLibrary()
, which returns a CDLL
object for that specific library.
Correct approach:
from ctypes import cdll
# Load the library using LoadLibrary
libc = cdll.LoadLibrary("libc.so.6")
# Now you can use the `libc` object to call functions from libc
print(libc)
This will load the libc.so.6
shared library, and you'll be able to interact with it via the libc
object returned by cdll.LoadLibrary()
.
Understanding cdll.__dict__
:
If you check cdll.__dict__
, you'll see that it contains an attribute _dlltype
, which is the CDLL
class used by cdll
to create instances for loaded libraries. But it does not contain attributes for individual libraries like libc
.
Conclusion
To summarize:
cdll.libc
doesn’t work becausecdll
doesn’t automatically create alibc
attribute.- You should explicitly load libraries using
cdll.LoadLibrary("libc.so.6")
orCDLL("libc.so.6")
to interact with shared libraries inctypes
. cdll
itself is not designed to automatically load specific libraries when accessed as attributes. You need to manually load libraries usingLoadLibrary()
.
So, the following should work:
from ctypes import cdll
# Load the library explicitly
libc = cdll.LoadLibrary("libc.so.6")
# Now, `libc` is a CDLL object for interacting with the libc shared library
This way, you can access the shared library directly and interact with its functions.