最初,我在使用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
从上面给出错误...有什么想法吗?
EDIT:在此示例中,我想静态链接libpython
,就像python解释器不依赖于任何libpython.so。
EDIT:_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)
我还在另一台机器上检查了我的系统python解释器的_struct.*.so
,它具有它:
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)
-Wl,--no-gc-sections
:启用未使用的输入节的垃圾回收。被忽略在不支持此选项的目标上。默认行为(不执行此垃圾收集的)可以通过以下方式恢复在命令行上指定--no-gc-sections。注意垃圾支持COFF和PE格式目标的收集,但是目前认为实施是实验性的。
-Wl,--gc-keep-exported
:启用--gc-sections时,此选项可防止垃圾包含全局符号的未使用输入节的集合具有默认或受保护的可见性。此选项旨在用于可执行文件,否则未引用节将不管外部可见性如何,都被垃圾收集包含符号。请注意,此选项在以下情况下无效链接共享对象,因为它已经是默认行为。仅ELF格式目标支持此选项。