ctypes 加载具有依赖关系的 c 共享库
Posted
技术标签:
【中文标题】ctypes 加载具有依赖关系的 c 共享库【英文标题】:ctypes loading a c shared library that has dependencies 【发布时间】:2011-01-20 14:31:02 【问题描述】:在 Linux 上,我有一个依赖于其他库的 c 共享库。 LD_LIBRARY_PATH 已正确设置以允许链接器加载所有库。当我这样做时:
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
我收到以下错误:
Traceback (most recent call last):
File "libwfm_test.py", line 12, in <module>
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
File "/usr/lib/python2.5/ctypes/__init__.py", line 431, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python2.5/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: path-to-my-lib/libwav.so: undefined symbol: ODBCGeneralQuery
似乎 LD_LIBRARY_PATH 在这里不起作用。 有没有办法让这些依赖库“可加载”?
提前感谢您的帮助。
【问题讨论】:
您使用的是什么操作系统?请参阅tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html——在 HpUx 中是SHLIB_PATH
,在 Aix 中是 LIBPATH
,在 Mac 上是 DYLD_lotsofthings
……语义也有细微的不同。即使是 Linux,请澄清版本并适当标记您的 Q,谢谢!
我在Linux上,所以我使用LD_LIBRARY_PATH,但ctypes似乎没有使用它
【参考方案1】:
似乎 libwav.so 没有声明它依赖于定义 ODBCGeneralQuery 的库。尝试运行ldd path-to-my-lib/libwav.so
并查看是否缺少某些内容。如果这是您正在构建的共享库,您应该将-llibname
添加到库代码使用的每个库的链接命令(类似于gcc -shared -o libwav.so a.o b.o c.o
)中。以这种方式被原始共享库引用的任何其他库也应自动加载。
【讨论】:
如果您能详细说明“缺少的东西”,我将不胜感激。我在我的 .so 上运行 ldd - 但我应该看到什么? 我想我的意思不清楚。我的意思是 ldd 将显示 libwav.so 引用的库,并且应该检查是否存在应该列出但没有列出的库。 非常感谢您真正澄清这个四年前的答案。我发现ldd
的输出有点令人困惑,但您的回答有助于澄清它。谢谢。【参考方案2】:
您应该使用RTLD_GLOBAL。我有一个混合平台系统,所以我的代码如下所示:
import numpy, ctypes
try:
if "Linux" in esmfos:
_ESMF = ctypes.CDLL(libsdir+'/libesmf.so',mode=ctypes.RTLD_GLOBAL)
else:
_ESMF = numpy.ctypeslib.load_library('libesmf',libsdir)
except:
traceback.print_exc(file=sys.stdout)
sys.exit(ESMP_ERROR_SHAREDLIB)
【讨论】:
【参考方案3】:我发现我必须使用 RTLD_LAZY
,因为未定义的符号未链接,因为它没有被使用。由于我的 ctypes 中没有 ctypes.RTLD_LAZY
,我不得不使用:
ctypes.CDLL(libidcwf_path, mode=1)
我通过检查/usr/include/bits/dlfcn.h
发现了这种模式,这可能不是标准的。向 ctypes 邮件列表上的这个 2006 thread 致敬。
【讨论】:
在 Python 3 中使用from posix import RTLD_LAZY
或 os.RTLD_LAZY
,正如 Rookie 在另一个答案中提到的那样。我还没有在 Python 2 中找到这个常量。【参考方案4】:
编译共享对象的时候,一定要把所有的-lsomething
放在字符串命令的最后。对我来说,它解决了问题。
【讨论】:
【参考方案5】:我遇到了同样的问题。 为了解决这个问题,需要做两件事:
-
如其他用户所说,使用
RTLD_GLOBAL
您需要加载您的库使用的每个库。所以如果ODBCGeneralQuery
定义在libIDCodbc
中,你需要先运行这一行:
ctypes.CDLL("libIDCodbc.so", mode = ctypes.RTLD_GLOBAL)
【讨论】:
RTLD_GLOBAL
到底是做什么的?是不是说“如果你加载一堆 .so 文件,把所有的符号放到一个巨大的命名空间中”?【参考方案6】:
基于上面Walter Nissen的answer,可以修改代码为:
import os
ctypes.CDLL(libidcwf_path, mode=os.RTLD_LAZY)
【讨论】:
以上是关于ctypes 加载具有依赖关系的 c 共享库的主要内容,如果未能解决你的问题,请参考以下文章