TCS*_*TCS 4 python ubuntu ctypes python-embedding
我在 ubuntu 20.04 中使用嵌入式 Python (3.9) 并尝试导入产生错误的 ctypes _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")。
我应该声明,我在网上看到了一些解决方案,但没有一个有效(例如导出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
感谢您提前提供任何帮助!
当 C 扩展在 Linux 上的 CPython 中导入时,dlopen在底层使用(默认情况下使用RTLD_LOCAL-flag)。
C 扩展通常需要 Python 库 ( libpythonX.Y.so) 中的功能,例如PyFloat_Type. 然而,在 Linux 上,C 扩展并未链接到libpythonX.Y.so(Windows 上的情况有所不同,请参阅此或此以获取更多详细信息) - 缺少的函数定义/功能将由 python 可执行文件提供。
为了能够做到这一点,可执行文件必须与 链接-Xlinker -export-dynamic,否则加载程序将无法使用可执行文件中的符号来加载用 加载的共享对象dlopen。
现在,如果嵌入的python不是可执行文件,而是一个共享对象,它加载了自身dlopen,我们需要确保它的符号被添加到动态表中。构建这个共享对象-Xlinker -export-dynamic没有多大意义(它毕竟不是可执行文件),但不会破坏任何东西 - 重要的部分是如何dlopen使用。
为了使符号text.python.so对于稍后加载的共享对象可见dlopen,应该使用 flag 打开它RTLD_GLOBAL:
RTLD_GLOBAL 此共享对象定义的符号将可用于后续加载的共享对象的符号解析。
IE
shared_lib = dlopen(path_to_so_file, RTLD_GLOBAL | RTLD_NOW);
Run Code Online (Sandbox Code Playgroud)
警告: 不RTLD_LAZY应该。
问题RTLD_LAZY是 C 扩展不依赖于libpython(可以在 的帮助下看到ldd),因此一旦加载它们并且必须查找尚未解析的符号(例如PyFloat_Type) ,动态链接器就不会'libpython我不知道它必须调查libpython。
另一方面RTLD_NOW,使用 时,所有符号都被解析并且在加载 C 扩展时可见(这与在链接步骤期间链接 libpython 时的“通常”情况相同-Xlinker -export-dynamic),因此没有问题找到例如PyFloat_Type-符号。
只要加载了嵌入式 python dlopen,主可执行文件就不需要构建/链接-Xlinker -export-dynamic。
但是,如果主可执行文件链接到嵌入式 python 共享对象,则这是必要的,否则在导入 c 扩展期间使用-Xlinker -export-dynamic时 python 符号将不可见。dlopen
有人可能会问,为什么 C 扩展不首先与 libpython 链接?
由于使用过RTLD_LOCAL,每个 C 扩展都会有自己的(未初始化的)Python 解释器版本(因为 libpython 中的符号不会被插入),并且一旦使用就会崩溃。
为了使其工作,dlopen应该使用RTLD_GLOBAL-flag 打开 - 但这不是一个合理的默认选项。
| 归档时间: |
|
| 查看次数: |
7855 次 |
| 最近记录: |