由于缺少符号,Python C 扩展的动态加载失败
Dynamic loading of Python C extension fails due to missing symbols
我的情况是我有一个可执行文件 (main.c
) 动态加载一个共享对象 (py_plugin.c
),然后 linked 到 python.
但是,当 python 插件试图导入一个模块,其依赖项 not linked to libpython 我得到了以下错误:
ImportError: /usr/lib/python2.7/lib-dynload/bz2.x86_64-linux-gnu.so: undefined symbol: PyExc_SystemError
据我所知,这意味着库 bz2.x86_64-linux-gnu.so
无法访问 python 符号。
请注意,该错误特定于 "bz2" 包,因为我在问题末尾使用最小工作示例强制它浮出水面。在那里,我正在执行 "bz2" 的显式导入,它在 python 插件 (py_plugin.c
).
中加载库 bz2.x86_64-linux-gnu.so
查看依赖项我确认:
库 bz2.x86_64-linux-gnu.so
不是 linked 到 python
usr@cmptr $ ldd /usr/lib/python2.7/lib-dynload/bz2.x86_64-linux-gnu.so
linux-vdso.so.1 => (0x00007ffd511fb000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8c63a0a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c6362a000)
libbz2.so.1.0 => /lib/x86_64-linux-gnu/libbz2.so.1.0 (0x00007f8c6341a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8c63e33000)
但是我的python插件是:
usr@cmptr $ ldd py_plugin.so
linux-vdso.so.1 => (0x00007ffc1ef5c000)
libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f56ac01c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f56abc3c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f56aba1d000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f56ab800000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f56ab5fc000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f56ab3f8000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f56ab0a2000)
/lib64/ld-linux-x86-64.so.2 (0x00007f56ac79a000)
我的问题如下:
问题本身很明显,但是为什么我的插件明明是linked到libpython时python符号不可用?
当我可以 not link python 到主可执行文件时,有没有人知道如何解决这个问题(它是一个预编译的二进制文件)?
来自this e-mail thread I understand that the source of the error may be because differences in the distribution philosophy of python (I am running a Ubuntu-based distro). This bug report也强调了这个问题。
产生错误的例子
生成libs/execs
gcc $(pkg-config --cflags python) -shared -o py_plugin.so py_plugin.c $(pkg-config --libs python)
gcc -o main main.c -lltdl
我系统上 pkg-config 的输入是:
pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7
pkg-config --libs python
-lpython
文件: main.c
#include <ltdl.h>
#include <stdio.h>
typedef int(*dyn_fptr)();
int main()
{
if(lt_dlinit()) {
return -1;
}
lt_dlhandle handle = lt_dlopen("./py_plugin.so");
dyn_fptr func = (dyn_fptr)lt_dlsym(handle, "func");
int a = func(); // <----------------------------------- Call "func" in py_plugin
lt_dlclose(handle);
return 0;
}
文件: py_plugin.c
#include <Python.h>
int func()
{
Py_Initialize();
PyObject *pName = PyString_FromString("bz2");
PyObject *pModule = PyImport_Import(pName); // <--------------------- ERROR
Py_DECREF(pName);
if(!pModule) {
PyErr_Print();
}
Py_Finalize();
return 0;
}
关闭线程以供将来参考。
正如在对我的问题的评论中所指出的,这里的问题是 Python(当前)在不同的 Linux 发行版上以不同的方式打包。
为了解决这个问题,必须确保 Python 符号对 在 python 插件 中加载的库可见。
据我所知,有三种处理方法:
- Link 主可执行文件到 Python.
- 设置
RTDL_GLOBAL
选项(仅在使用dlopen时可用,dlopen("lib.so", RTDL_NOW | RTDL_LAZY | RTDL_GLOBAL)
,不保证所有系统都支持)。
- 设置环境变量
LD_PRELOAD
、export LD_PRELOAD="/path/to/libpython2.7.so.1.0"
,以强制某些库在 任何其他库之前加载。对我来说,这适用于我的小示例插件,但在处理更大的软件框架时会造成有害的交互。
我的情况是我有一个可执行文件 (main.c
) 动态加载一个共享对象 (py_plugin.c
),然后 linked 到 python.
但是,当 python 插件试图导入一个模块,其依赖项 not linked to libpython 我得到了以下错误:
ImportError: /usr/lib/python2.7/lib-dynload/bz2.x86_64-linux-gnu.so: undefined symbol: PyExc_SystemError
据我所知,这意味着库 bz2.x86_64-linux-gnu.so
无法访问 python 符号。
请注意,该错误特定于 "bz2" 包,因为我在问题末尾使用最小工作示例强制它浮出水面。在那里,我正在执行 "bz2" 的显式导入,它在 python 插件 (py_plugin.c
).
bz2.x86_64-linux-gnu.so
查看依赖项我确认:
库
bz2.x86_64-linux-gnu.so
不是 linked 到 pythonusr@cmptr $ ldd /usr/lib/python2.7/lib-dynload/bz2.x86_64-linux-gnu.so linux-vdso.so.1 => (0x00007ffd511fb000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f8c63a0a000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c6362a000) libbz2.so.1.0 => /lib/x86_64-linux-gnu/libbz2.so.1.0 (0x00007f8c6341a000) /lib64/ld-linux-x86-64.so.2 (0x00007f8c63e33000)
但是我的python插件是:
usr@cmptr $ ldd py_plugin.so linux-vdso.so.1 => (0x00007ffc1ef5c000) libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f56ac01c000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f56abc3c000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f56aba1d000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f56ab800000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f56ab5fc000) libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f56ab3f8000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f56ab0a2000) /lib64/ld-linux-x86-64.so.2 (0x00007f56ac79a000)
我的问题如下:
问题本身很明显,但是为什么我的插件明明是linked到libpython时python符号不可用?
当我可以 not link python 到主可执行文件时,有没有人知道如何解决这个问题(它是一个预编译的二进制文件)?
来自this e-mail thread I understand that the source of the error may be because differences in the distribution philosophy of python (I am running a Ubuntu-based distro). This bug report也强调了这个问题。
产生错误的例子
生成libs/execs
gcc $(pkg-config --cflags python) -shared -o py_plugin.so py_plugin.c $(pkg-config --libs python)
gcc -o main main.c -lltdl
我系统上 pkg-config 的输入是:
pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7
pkg-config --libs python
-lpython
文件: main.c
#include <ltdl.h>
#include <stdio.h>
typedef int(*dyn_fptr)();
int main()
{
if(lt_dlinit()) {
return -1;
}
lt_dlhandle handle = lt_dlopen("./py_plugin.so");
dyn_fptr func = (dyn_fptr)lt_dlsym(handle, "func");
int a = func(); // <----------------------------------- Call "func" in py_plugin
lt_dlclose(handle);
return 0;
}
文件: py_plugin.c
#include <Python.h>
int func()
{
Py_Initialize();
PyObject *pName = PyString_FromString("bz2");
PyObject *pModule = PyImport_Import(pName); // <--------------------- ERROR
Py_DECREF(pName);
if(!pModule) {
PyErr_Print();
}
Py_Finalize();
return 0;
}
关闭线程以供将来参考。
正如在对我的问题的评论中所指出的,这里的问题是 Python(当前)在不同的 Linux 发行版上以不同的方式打包。
为了解决这个问题,必须确保 Python 符号对 在 python 插件 中加载的库可见。
据我所知,有三种处理方法:
- Link 主可执行文件到 Python.
- 设置
RTDL_GLOBAL
选项(仅在使用dlopen时可用,dlopen("lib.so", RTDL_NOW | RTDL_LAZY | RTDL_GLOBAL)
,不保证所有系统都支持)。 - 设置环境变量
LD_PRELOAD
、export LD_PRELOAD="/path/to/libpython2.7.so.1.0"
,以强制某些库在 任何其他库之前加载。对我来说,这适用于我的小示例插件,但在处理更大的软件框架时会造成有害的交互。