_ctyes.cpython-39-x86_64-linux-gnU.S.so:未定义的符号:使用dlopen加载的Embedded Python中的PyFloat_Type

_ctypes.cpython-39-x86_64-linux-gnu.so: undefined symbol: PyFloat_Type in embedded Python loaded with dlopen(_ctyes.cpython-39-x86_64-linux-gnU.S.so:未定义的符号:使用dlopen加载的Embedded Python中的PyFloat_Type)

本文介绍了_ctyes.cpython-39-x86_64-linux-gnU.S.so:未定义的符号:使用dlopen加载的Embedded Python中的PyFloat_Type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是ubuntu 20.04中的Embedded Python(3.9),尝试导入ctype时出现错误_ctypes.cpython-39-x86_64-linux-gnu.so: undefined symbol: PyFloat_Type

我正在编译共享对象,它是使用dlopen()动态加载的。

CMake用于构建共享对象。我这样说明对Python3的依赖关系: find_package(Python3 REQUIRED COMPONENTS Development Development.Embed)和使用target_link_libraries(${target_name} Boost::filesystem Python3::Python)链接

如果我理解正确的话,这会告诉CMake直接与libpython3.9.so链接(我还试图显式声明链接到libpython3.9.so,但这并没有解决问题)。 我确实看到libpython3.9.so导出PyFloat_Type,而_ctypes.cpython-39-x86_64-linux-gnu.so不导出。

导入只需PyRun_SimpleString()函数:PyRun_SimpleString("import ctypes")即可完成。

我应该声明,我在Web上看到了一些解决方案,但没有一个奏效(如导出LD_FLAGS="-rdynamic",但也没有帮助)。

我还应该指出,使用解释器(python3.9)导入效果很好。

以下是CMake生成的构建命令: /usr/bin/c++ -fPIC -g -Xlinker -export-dynamic -shared -Wl,-soname,mytest.python3.so -o mytest.python3.so CMakeFiles/mytest.python3.dir/[mydir]/[myobjects].o /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.71.0 /usr/lib/x86_64-linux-gnu/libpython3.9.so /usr/lib/x86_64-linux-gnu/libpython3.9.so

提前感谢您的帮助!

推荐答案

当在Linux上的CPython中导入C扩展时,dlopen在幕后使用(默认情况下使用RTLD_LOCAL-FLAG)。

C扩展通常需要来自Python库(libpythonX.Y.so)的功能,例如PyFloat_Type。然而,在Linux上,C扩展没有链接到libpythonX.Y.so(Windows上的情况不同,有关更多详细信息,请参阅this或this)--缺少的函数定义/功能将由python可执行文件提供。

若要执行此操作,可执行文件必须与-Xlinker -export-dynamic链接,否则加载程序将无法将可执行文件中的符号用于通过dlopen加载的共享对象。

现在,如果嵌入的python不是可执行文件,而是与dlopen本身一起加载的共享对象,我们需要确保将其符号添加到动态表中。使用-Xlinker -export-dynamic构建这个共享对象没有多大意义(它毕竟不是可执行文件),但不会破坏任何东西--重要的部分是如何使用dlopen

为了使text.python.so中的符号对以后使用dlopen加载的共享对象可见,应使用RTLD_GLOBAL标志打开它:

RTLD_GLOBAL 将制作由该共享对象定义的符号 可用于后续加载的符号解析 共享对象。

shared_lib = dlopen(path_to_so_file, RTLD_GLOBAL | RTLD_NOW);

警告:RTLD_LAZY不应使用

RTLD_LAZY的问题是,C扩展不依赖于libpython(可以通过ldd看到),因此一旦它们被加载并且来自libpython的尚未解析的符号(例如PyFloat_Type)必须被查找,动态链接器不知道它必须查找libpython

另一方面,使用RTLD_NOW时,所有符号都被解析并在加载C扩展时可见(这与在与-Xlinker -export-dynamic的链接步骤中链接libpython时的情况相同),因此不会出现查找问题,例如PyFloat_Type-符号。


只要用dlopen加载嵌入的python,就不需要用-Xlinker -export-dynamic构建/链接主可执行文件。

但是,如果主可执行文件是针对Embedded-python-Shared-Object链接的,则-Xlinker -export-dynamic是必需的,否则在导入c-扩展时使用dlopen时,希望可以看到python符号。


有人可能会问,为什么不首先将C扩展与libpython联系起来?

由于使用了RTLD_LOCAL,每个C扩展都会有自己的(未初始化的)版本的Python解释器(因为不会插入来自libpython的符号),并且一旦使用就会崩溃。

若要使其正常工作,dlopen应使用RTLD_GLOBAL标志打开-但这不是合理的默认选项。

这篇关于_ctyes.cpython-39-x86_64-linux-gnU.S.so:未定义的符号:使用dlopen加载的Embedded Python中的PyFloat_Type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:_ctyes.cpython-39-x86_64-linux-gnU.S.so:未定义的符号:使用dlopen加载的Embedded Python中的PyFloat_Type