2010-08-03 38 views
2

我有一个库,我已经使用SWIG创建了一个python包装器。库本身接受用户提供的功能,这些功能位于动态链接的.so文件中。目前我正在处理一个我自己创建的并且已经设法使用C++来动态链接的工作。当我尝试在python中运行它时,出现未定义的符号错误。这些符号是所提供的.so文件中不存在但是存在于主程序中的符号(实质上它们是允许提供的模块从主程序访问数据的功能)。动态链接和Python SWIG(C++)在C++中工作失败python

我没有在C++中运行一个简短的测试程序时出现任何错误,但是用这个包装器(以前的工作方式)在Python中做了一个简短的测试程序失败了。我想不出一个解释,为什么它会在C++而不是在python中失败。令我担心的是,C++不能正常工作,但并没有告诉我,Python正在拾取C++没有的错误。然而,C++返回的结果是准确的,所以这似乎不大可能。

任何想法如何这是可能的,因此我怎么能解决它?

谢谢。

更新: 我加入这个代码到程序的顶部:

import dl 
sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL) 

这摆脱了运行时错误的,但不幸的是允许出现第二个问题(还由于连接)。作为主程序一部分的动态链接库中调用的函数未返回正确的值。他们返回0.更重要的是,显然他们甚至都没有运行。问题变成了实际运行的内容,为什么它与C++不同,我该如何解决这个问题?

再次感谢。

更新 - 一个潜在更清晰的说明 Python导入一个模块,它是我的C++库已被SWIG包装。这个C++库使用dlopen和dlsym从用户提供的.so文件中获取函数。用户提供了对作为C++库一部分的函数的文件调用,以完成它的工作。从.so文件到C++库的函数调用是失败的部分,也就是说它们无法调用该函数并简单地返回0.但是,只有当测试代码用python编写时才会发生这种失败。使用该库的C++测试代码正常工作。

+0

我对你的代码结构有点不清楚。具体来说,我假设“主程序”实际上是Python解释器(即,您并未嵌入它),并且您正在尝试加载.so,这是编译时动态链接到另一个.so没有通过dlopen()载入),但很难说。您能否更具体地了解组件是什么以及它们如何链接在一起? – Rakis 2010-08-04 12:30:57

+0

对不起,我不是不清楚! Python导入一个模块,该模块是由SWIG包装的C++库。这个C++库使用dlopen和dlsym从用户提供的.so文件中获取函数。用户提供了对作为C++库一部分的函数的文件调用,以完成它的工作。从.so文件到C++库的函数调用是失败的部分,也就是它们无法调用该函数并返回0. 但是,只有当测试代码是用python编写时,才会发生此故障。使用该库的C++测试代码正常工作。 – VolatileStorm 2010-08-04 12:43:01

+1

嗯。这是一种非常不寻常的联动情景。可能值得尝试使用'dl'模块来显式加载用户提供的.so(确保首先设置dl.RTLD_GLOBAL标志)。这应该会导致链接器将C++库作为依赖项加载,并希望能够确保所有符号都得到适当的处理。尽管我在这一点上纯粹猜测,但我不会预料到你会首先描述的问题。我可以肯定地说,运行时间连接配置就是问题所在。 – Rakis 2010-08-04 19:02:44

回答

2

一种解决方案是确保Python是预加载C++库主要在全球范围内。 这不是一个非常优雅的解决方案,我不想这样做,但它使它暂时有效。

here周围稍微戳了一下之后,我发现LD_LIBRARY_PATH环境变量每次启动终端时都要设置,以便它甚至能够找到SWIGed的主C++库,我注意到了LD_PRELOAD环境变量。将此设置为主C++库的文件名后,该程序就可以工作。

我怀疑这是因为它“可以用来有选择地覆盖其他共享库中的函数”。

如果有人提出比设置环境变量更好的答案,它会很棒,因为我不确定这是多么便携。

编辑:最初的问题是用户提供的库所寻找的功能不在全局范围内。为了解决这个问题,只需使用python的“dl.open”打开主库的.so文件,使用dl.RTLD_NOW和dl.RTLD_GLOBAL。

成功!

1

python解释器可能正在加载你的包装器.so,而不会将其符号提供给其他动态链接库(以避免符号冲突)。尝试只导入您的包装之前添加以下行:

import dl 
sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL) 
+0

Thankyou,这可以解决运行时错误,但不幸的是它会导致另一个错误。 代码现在无法正常运行,经过一些调试后,事实证明,主程序中.so文件试图调用的函数实际上并未被调用。更改返回值或者甚至将控制台输出放入它们中都没有任何区别。他们只是返回0. 帮助! – VolatileStorm 2010-08-04 08:40:52