来自https://docs.python.org/3/library/ctypes.html#loading-shared-libraries
也可以使用预制的其中一个来加载共享库 对象,它们是LibraryLoader类的实例, by 通过检索库来调用LoadLibrary()方法或 加载程序实例的属性。
我找到了第一种方式的例子Free the opened ctypes library in Python
我想知道如何使用第二种方式?特别是,如何创建加载器实例cdll
的属性?我的问题来自Why does loading the libc shared library have "'LibraryLoader' object is not callable" error?
LibraryLoader的重点在于,当您访问它时,它会为您创建库。而
cdll.LoadLibrary("foo")
并未创建cdll.foo
。
我的实验有问题吗?为什么cdll.libc
永远不存在?
>>> 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'>}
答案 0 :(得分:1)
示例(发生了什么):
>>> import sys >>> import ctypes >>> print("Python {:s} on {:s}".format(sys.version, sys.platform)) Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 >>> >>> [item for item in dir(ctypes.windll) if "__" not in item] ['LoadLibrary', '_dlltype', 'kernel32'] >>> >>> user32_dll = ctypes.windll.LoadLibrary("user32") >>> user32_dll <WinDLL 'user32', handle 7ff882810000 at 0x2434399b4e0> >>> [item for item in dir(ctypes.windll) if "__" not in item] ['LoadLibrary', '_dlltype', 'kernel32'] >>> >>> user32_dll = ctypes.WinDLL("user32") >>> user32_dll <WinDLL 'user32', handle 7ff882810000 at 0x2434399b4a8> >>> [item for item in dir(ctypes.windll) if "__" not in item] ['LoadLibrary', '_dlltype', 'kernel32'] >>> >>> user32_dll = ctypes.windll.user32 >>> user32_dll <WinDLL 'user32', handle 7ff882810000 at 0x24343984d68> >>> [item for item in dir(ctypes.windll) if "__" not in item] ['LoadLibrary', '_dlltype', 'kernel32', 'user32'] >>> >>> ctypes.windll.user32 <WinDLL 'user32', handle 7ff882810000 at 0x24343984d68> >>> >>> ctypes.windll.user321 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "c:\install\x64\python\python\3.5\Lib\ctypes\__init__.py", line 421, in __getattr__ dll = self._dlltype(name) File "c:\install\x64\python\python\3.5\Lib\ctypes\__init__.py", line 351, in __init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 126] The specified module could not be found >>> >>> dir(ctypes.windll) ['LoadLibrary', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_dlltype', 'kernel32', 'user32']
如何它发生 - 它全部在“$ {PYTHON_SRC_DIR} / Lib / ctypes / __ init __。py”
([GitHub]: python/cpython - (master) cpython/Lib/ctypes/__init__.py)。我正在粘贴cdll
的代码,因为windll
(我在上面的示例中使用的)只是它的包装(并且需要更多的代码):
# ...
class CDLL(object):
# ...
class LibraryLoader(object):
def __init__(self, dlltype):
self._dlltype = dlltype
def __getattr__(self, name):
if name[0] == '_':
raise AttributeError(name)
dll = self._dlltype(name)
setattr(self, name, dll) # @TODO - cfati: This is the key for always returning the same instance.
return dll
# ...
cdll = LibraryLoader(CDLL)
# ...
<强> @ EDIT0 强>:
嗯,在 Ux (至少 Lnx )上,事情并不是那么好看:
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> ls libcapi.so [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> LD_LIBRARY_PATH=$(pwd) python3 -c "import ctypes; ctypes.cdll.LoadLibrary('libcapi.so')" [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> LD_LIBRARY_PATH=$(pwd) python3 -c "import ctypes; ctypes.cdll.LoadLibrary('libcapi')" Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/lib/python3.5/ctypes/__init__.py", line 425, in LoadLibrary return self._dlltype(name) File "/usr/lib/python3.5/ctypes/__init__.py", line 347, in __init__ self._handle = _dlopen(self._name, mode) OSError: libcapi: cannot open shared object file: No such file or directory
这是因为显然(与[MSDN]: LoadLibrary function相反),[man7]: DLOPEN(3)不会将(默认)库扩展名( .so )附加到文件名(如果它不包含它。)
code.c :
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[]) {
if (argc == 1) {
printf("Dll name required\n");
return 1;
}
void *handle = dlopen(argv[1], RTLD_NOW);
if (handle == NULL) {
printf("Could not load [%s]\n", argv[1]);
return 2;
} else {
printf("Successfully loaded [%s]\n", argv[1]);
dlclose(handle);
return 0;
}
}
<强>输出强>:
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> gcc code.c -Wl,-ldl [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> ./a.out "libcapi.so" Could not load [libcapi.so] [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> LD_LIBRARY_PATH=$(pwd) ./a.out "libcapi.so" Successfully loaded [libcapi.so] [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q050838633]> LD_LIBRARY_PATH=$(pwd) ./a.out "libcapi" Could not load [libcapi]
因此,无法在 Ux 上复制 Win 行为(遗憾的是,.
( dot )无法复制成为属性名称的一部分,以克服这一点)。或者,链接器是否可以配置为隐式搜索 .so 文件?但这只会部分解决问题,因为许多库看起来像 libc.so.6 (或 AFAIK , OSX 。所以和 .dylib 确定)。