动态链接和 Python SWIG (C++) 在 C++ 中工作在 python 中失败

Posted

技术标签:

【中文标题】动态链接和 Python SWIG (C++) 在 C++ 中工作在 python 中失败【英文标题】:Dynamic linking and Python SWIG (C++) works in C++ fails in python 【发布时间】:2010-08-03 13:33:56 【问题描述】:

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

我在 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++ 测试代码运行良好。

【问题讨论】:

我对你的代码结构有点不清楚。具体来说,我假设“主程序”实际上是 Python 解释器(即,您没有嵌入它)并且您正在尝试加载一个 .so ,它是编译时动态链接到另一个 .so 的(不是通过 dlopen()) 即时加载的,但很难说。您能否更具体地说明这些组件是什么以及它们是如何链接在一起的? 对不起,我不是故意的! Python 导入一个模块,这是一个由 SWIG 包装的 C++ 库。此 C++ 库使用 dlopen 和 dlsym 从用户提供的 .so 文件中获取函数。用户提供了对作为 C++ 库一部分的函数的文件调用,以便完成它的工作。从 .so 文件到 C++ 库的函数调用是失败的部分,即它们无法调用函数并简单地返回 0。但是,这种失败仅在使用 python 编写测试代码时发生。使用该库的 C++ 测试代码运行良好。 嗯。这是一个相当不寻常的链接场景。使用dl 模块显式加载用户提供的.so 可能值得一试(请务必先设置dl.RTLD_GLOBAL 标志)。这应该会导致链接器将 C++ 库作为依赖项加载,并且希望能够确保正确处理所有符号。不过,我没想到会遇到您首先描述的问题,所以我现在纯粹是在猜测。我只能说运行时链接配置是问题所在。 我已经尝试过这个并使用 dl.open 打开主 C++ 库和用户提供的库。仅打开主库并不能解决问题。还打开用户提供的库实际上会导致原始问题返回(无法找到主库中存在的符号),即使主库在之前的行中打开为 RTLD_GLOBAL。一切都只需要加载到全局范围内,就像它没有被 SWIGed 时一样。我开始认为是 SWIG 导致了这个问题。 好吧,在找到我自己的解决方案后,结果发现它破坏了其他一些东西,所以我根据你的建议重新尝试了我正在做的事情。我在导入模块后直接使用dl.open打开.so文件。成功!这可能与我之前使用 sys.setdlopenflags 和 dl.open 一样好。谢谢你的帮助。 【参考方案1】:

解决方案是确保 python 在全局范围内预加载 C++ 主库。 这不是一个非常优雅的解决方案,我也不想这样做,但它让它暂时起作用。

在here 附近闲逛了一下,并认识到我每次启动终端时都必须设置的 LD_LIBRARY_PATH 环境变量,以便它甚至可以找到已被 SWIGed 的主 C++ 库,我注意到 LD_PRELOAD 环境变量.将此设置为主 C++ 库的文件名后,程序就可以工作了。

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

如果有人提出比设置环境变量更好的答案,那就太棒了,因为我不确定它的便携性。

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

成功了!

【讨论】:

【参考方案2】:

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

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

【讨论】:

谢谢,这确实可以消除运行时错误,但不幸的是它会导致另一个错误。代码现在无法正常运行,经过一点调试后发现 .so 文件试图调用的主程序中的函数实际上并未被调用。更改返回值甚至将控制台输出放入其中都没有任何区别。他们只是返回 0。帮助!

以上是关于动态链接和 Python SWIG (C++) 在 C++ 中工作在 python 中失败的主要内容,如果未能解决你的问题,请参考以下文章

SWIG:你能否使用 SWIG 专门使用 C++ 头文件使 C++ 在 Python 中可用?

在 Swig 中通过 ref 返回动态数组

在 SWIG 中携带自定义 Python 数据的 C++ 对象

SWIG C++ Python 多态性和多线程

Swig C++ python 包装文件解释?

将 python 函数传递给 SWIG 包装的 C++ 代码