_ctypes.cpython-39-x86_64-linux-gnu.so:未定义符号:嵌入 Python 中的 PyFloat_Type 加载了 dlopen

问题描述

我在 ubuntu 20.04 中使用嵌入式 Python (3.9) 并尝试导入产生错误 _ctypes.cpython-39-x86_64-linux-gnu.so: undefined symbol: PyFloat_Type 的 ctypes。

我正在编译一个使用 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")

我应该声明我在网上看到了一些解决方案,但没有一个有效(比如导出 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 标志)。

C 扩展通常需要来自 Python 库 (libpythonX.Y.so) 的功能,例如 PyFloat_Type。但是,在 Linux 上,C 扩展并未与 libpythonX.Y.so 链接(Windows 上的情况有所不同,请参阅 thisthis 了解更多详细信息)- 缺少的函数定义/功能将由 python 可执行文件提供。

为了能够这样做,可执行文件必须用 -Xlinker -export-dynamic 链接,否则加载器将无法将可执行文件中的符号用于用 dlopen 加载的共享对象。>

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

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

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


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

但是,如果主可执行文件链接到嵌入式python共享对象,则需要-Xlinker -export-dynamic,否则在导入c期间使用dlopen时,python符号需要可见-扩展。


有人可能会问,为什么不首先将 C 扩展链接到 libpython?

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

为了使其工作,dlopen 应该用 RTLD_GLOBAL-flag 打开 - 但这不是一个合理的默认选项。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...