python - 嵌入式Python解释器的 undefined symbol 错误

标签 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.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)

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

最佳答案

静态链接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),则有一些 changes since version 3.8 :

On Unix, C extensions are no longer linked to libpython except on Android and Cygwin. When Python is embedded, libpython must not be loaded with RTLD_LOCAL, but RTLD_GLOBAL instead. Previously, using RTLD_LOCAL, it was already not possible to load C extensions which were not linked to libpython, like C extensions of the standard library built by the shared section of Modules/Setup. (Contributed by Victor Stinner in bpo-21536.)



另请注意(请参阅here):

To embed Python into an application, a new --embed option must be passed to python3-config --libs --embed to get -lpython3.8 (link the application to libpython). To support both 3.8 and older, try python3-config --libs --embed first and fallback to python3-config --libs (without --embed) if the previous command fails.

Add a pkg-config python-3.8-embed module to embed Python into an application: pkg-config python-3.8-embed --libs includes -lpython3.8. To support both 3.8 and older, try pkg-config python-X.Y-embed --libs first and fallback to pkg-config python-X.Y --libs (without --embed) if the previous command fails (replace X.Y with the Python version).



因此,像这样动态编译和链接现在也适用于我:
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/

关于python - 嵌入式Python解释器的 undefined symbol 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60619799/

相关文章:

c++ - 使用 xlC 13.1.2 在 AIX 7.1 上编译 boost C++ 库

python - 可以使用相同的内核参数在tensorflow或keras中重复使用Con2d吗

c - 升级到 macOS Mojave 后,MATLAB 不再卸载 MEX 文件

python - 比较python中的两个文本文件

c++ - 为什么我可以从 {} 初始化一个常规数组,而不是一个 std::array

c++ - 模板和普通函数的引用指针

c++ - 从静态函数创建类对象

python - 构建 YouCompleteMe 时出现 Libpython 错误

python - 如何修复此收敛错误? Python 3 统计模型

python - 通过网络发送图像