嵌入Python解释器的未定义符号错误

嵌入Python解释器的未定义符号错误,python,c++,shared-libraries,dynamic-linking,Python,C++,Shared Libraries,Dynamic Linking,最初,我在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.

最初,我在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
然后只需执行
/execpy
即可给出上面的错误。。。有什么想法吗

EDIT:在本例中,我想静态链接
libpython
,就像python解释器不依赖任何libpython.so一样

编辑
\u struct.*。因此
似乎没有链接到libpython的依赖项(这与我的标准anaconda python解释器相同):

我还检查了另一台机器上系统python解释器的
\u 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)

我认为这是因为
execpy.c
中没有引用
PyByteArray\u Type
,因此链接器使用其默认的
--gc节
逻辑删除未使用的符号。 尝试添加以下选项之一:

-Wl,--无gc节

启用未使用输入节的垃圾收集。它被忽略了 在不支持此选项的目标上。默认行为 (指不执行此垃圾收集)可以通过 指定--命令行上没有gc节。请注意,垃圾 支持COFF和PE格式目标的集合,但 实施目前被认为是实验性的

-Wl,--gc保持导出状态

启用--gc节时,此选项可防止垃圾 包含全局符号的未使用输入节的集合 具有默认的或受保护的可见性。此选项旨在 用于可执行文件,否则未引用的节将被删除 被垃圾收集,而不考虑 包含符号。请注意,此选项在以下情况下无效: 链接共享对象,因为这已经是默认行为。 仅ELF格式目标支持此选项

静态链接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
),有一些

在Unix上,C扩展不再链接到libpython,在上除外 Android和Cygwin。嵌入Python时,不能使用libpython 已加载RTLD_本地,但改为RTLD_全局。以前,使用 RTLD_LOCAL,已经无法加载 没有链接到libpython,就像标准的C扩展一样 由模块/设置的共享部分构建的库。(贡献) Victor Stiner在bpo-21536中所作。)

另请注意(见):

要将Python嵌入到应用程序中,必须使用一个新的--embed选项 传递给python3 config--libs--embed以获取-lpython3.8(链接 应用于libpython)。要同时支持3.8和更高版本,请尝试 python3配置--libs--首先嵌入,然后回退到python3配置 --如果上一个命令失败,则使用libs(不带--embed)

添加pkg config python-3.8-embed模块以将python嵌入到 应用程序:pkg-config-python-3.8-embed--libs-includes-lpython3.8。 要同时支持3.8和更早版本,请尝试pkg config python-X.Y-embed--libs 首先返回pkg config python-X.Y--libs(不带--embed) 如果前面的命令失败(用Python版本替换X.Y)

因此,像这样动态编译和链接现在也适用于我:

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/

ldd/app/Python-3.8.2-build/lib/python3.8/lib dynload/_struct.cpython-38-x86_64-linux-gnu.so
?它是否加载了不同的libpython3.8?我在上面的问题中添加了ldd输出。您可以在python可执行文件上尝试ldd吗?我尝试了,但没有成功。据报道,“gc保持导出”对ld来说是未知的,“无gc部分”没有任何影响
    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)
-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.
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/