python - 嵌入式 Python 解释器的未定义符号错误
问题描述
最初我在使用 pybind11 嵌入 anaconda Python 解释器的较大项目中遇到此错误。只需一个简单的最小示例,我就可以将其归结并重现错误。
当我运行我的可执行文件(嵌入 python)时,我得到这个错误:
Traceback (most recent call last):
File "<string>", line 3, in <module>
File "/app/Python-3.8.2-build/lib/python3.8/struct.py", line 13, in <module>
from _struct import *
ImportError: /app/Python-3.8.2-build/lib/python3.8/lib-dynload/_struct.cpython-38-x86_64-linux-gnu.so: undefined symbol: PyByteArray_Type
起初,我从源代码构建 Python-3.8.2。然后我从以下 C 代码编译了一个可执行文件:
#include <Python.h>
int main(int argc, char *argv[])
{
Py_Initialize();
PyRun_SimpleString("import struct");
if (Py_FinalizeEx() < 0) {
exit(120);
}
return 0;
}
使用这个命令:
gcc -o execpy execpy.c \
-I/app/Python-3.8.2-build/include/python3.8 \
-Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 \
-L/app/Python-3.8.2-build/lib -lcrypt -lpthread -ldl -lutil -lm \
/app/Python-3.8.2/libpython3.8.a
然后简单地执行./execpy
从上面给出错误......有什么想法吗?
编辑:在这个例子中,我想libpython
静态链接,就像 python 解释器不依赖于任何 libpython.so。
编辑:_struct.*.so
似乎没有链接到 libpython 的依赖项(这与我的标准 anaconda python 解释器相同):
$ ldd /app/Python-3.8.2-build/lib/python3.8/lib-dynload/_struct.cpython-38-x86_64-linux-gnu.so
linux-vdso.so.1 => (0x00007fff32bf0000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f71a5634000)
libc.so.6 => /lib64/libc.so.6 (0x00007f71a5266000)
/lib64/ld-linux-x86-64.so.2 (0x00007f71a5a5c000)
我还在_struct.*.so
另一台机器上检查了我的系统 python 解释器,它有它:
linux-vdso.so.1 => (0x00007ffe2b3d9000)
libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007febe24fd000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007febe22e1000)
libc.so.6 => /lib64/libc.so.6 (0x00007febe1f13000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007febe1d0f000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007febe1b0c000)
libm.so.6 => /lib64/libm.so.6 (0x00007febe180a000)
/lib64/ld-linux-x86-64.so.2 (0x00007febe2c30000)
解决方案
静态链接 libpython
简短的回答:添加-rdynamic
到标志使它对我有用。
-rdynamic
标志文件:
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This
instructs the linker to add all symbols, not only used ones, to the dynamic symbol
table. This option is needed for some uses of dlopen or to allow obtaining
backtraces from within a program.
动态链接 libpython
我还发现:如果你想动态嵌入 Python 3.8 解释器(libpython3.8.so
),自 3.8 版以来有一些变化:
在 Unix 上,C 扩展不再链接到 libpython,除了 Android 和 Cygwin。嵌入 Python 时,libpython 不能加载 RTLD_LOCAL,而是 RTLD_GLOBAL。以前,使用 RTLD_LOCAL 已经无法加载未链接到 libpython 的 C 扩展,例如由 Modules/Setup 的共享部分构建的标准库的 C 扩展。(由 Victor Stinner 在 bpo-21536 中贡献。)
另请注意(参见此处):
要将 Python 嵌入到应用程序中,必须将新的 --embed 选项传递给 python3-config --libs --embed 以获取 -lpython3.8(将应用程序链接到 libpython)。要同时支持 3.8 和更早版本,请先尝试 python3-config --libs --embed,如果前面的命令失败,则回退到 python3-config --libs(不带 --embed)。
添加一个 pkg-config python-3.8-embed 模块以将 Python 嵌入到应用程序中:pkg-config python-3.8-embed --libs 包括 -lpython3.8。要同时支持 3.8 和更早版本,请先尝试 pkg-config python-XY-embed --libs,如果前面的命令失败(将 XY 替换为 Python 版本),则回退到 pkg-config python-XY --libs(不带 --embed) )。
所以像这样动态编译和链接现在也适用于我:
gcc -o execpy execpy.c -I/app/Python-3.8.2-build/include/python3.8 \
-Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 \
-lcrypt -lpthread -ldl -lutil -lm -lpython3.8\
-L/app/Python-3.8.2-build/lib/ -Wl,-rpath,/app/Python-3.8.2-build/lib/
推荐阅读
- javascript - 最初运行后触发功能的问题
- azure - 具有参数化架构的 Azure DataFactory DelimitedText 数据集
- r - 是否可以在 pdf 中使用 R knitr::kable 生成的表格中添加垂直线?
- java - 无法运行 Eclipse:NatureManager 类中的常量类型错误
- excel - PowerPoint 链接对象的新驱动器映射 - VBA 解决方案
- java - 如何测试 HTTP 请求
- node.js - 使用 POST 请求的 GMail API,错误代码:400,需要收件人地址
- java - 使用 feign 客户端从 Spring Boot 调用 SSL
- javascript - 获取最后一个重定向 URL 的函数(使用 javascript 进行的重定向)
- excel - 如何在 .txt 条件 VBA 中保存列