Python ImportError - 未定义符号 - 用于自定义 C++ 模块
Posted
技术标签:
【中文标题】Python ImportError - 未定义符号 - 用于自定义 C++ 模块【英文标题】:Python ImportError - undefined symbol - for custom C++ module 【发布时间】:2012-07-23 12:38:24 【问题描述】:我一直在 Ubuntu 11.04 上使用 OpenCV 2.3 到 2.4.2 开发 C++ 中的 Python 模块。 OpenCV 是从源代码构建的。我没有使用 Ubuntu 存储库中的 OpenCV 版本。
我的 Python 模块编译没有问题,并且在 Python 中正确加载。但是,当我在 Ubuntu 11.10 或 12.04 上编译此模块时,尝试在 Python 中加载它时会收到带有消息“未定义符号”的 ImportError。
这是我编译模块的方式:
g++ -fPIC -shared `pkg-config --cflags --libs python` `pkg-config --cflags --libs opencv` -I/usr/local/include/opencv2/legacy -o mymodule.so mymodule.cpp
这是“pkg-config --cflags --libs opencv”的输出
-I/usr/local/include/opencv -I/usr/local/include /usr/local/lib/libopencv_calib3d.so /usr/local/lib/libopencv_contrib.so /usr/local/lib/libopencv_core.so /usr/local/lib/libopencv_features2d.so /usr/local/lib/libopencv_flann.so /usr/local/lib/libopencv_gpu.so /usr/local/lib/libopencv_highgui.so /usr/local/lib/libopencv_imgproc.so /usr/local/lib/libopencv_legacy.so /usr/local/lib/libopencv_ml.so /usr/local/lib/libopencv_nonfree.so /usr/local/lib/libopencv_objdetect.so /usr/local/lib/libopencv_photo.so /usr/local/lib/libopencv_stitching.so /usr/local/lib/libopencv_ts.so /usr/local/lib/libopencv_video.so /usr/local/lib/libopencv_videostab.so
我得到的错误是:
ImportError: /path/to/service/mymodule.so: undefined symbol: _ZN5CvSVMD1Ev
我的理解是“未定义的符号”通常意味着在任何链接库中都找不到给定的符号。但我知道这个符号在 libopencv_ml.so 中,因为当我运行它时:
$ nm -g /usr/local/lib/libopencv_ml.so | grep _ZN5CvSVMD1Ev
我明白了:
000000000002fd40 T _ZN5CvSVMD1Ev
/usr/local/lib 似乎在动态链接器缓存中。
$ cat /etc/ld.so.conf.d/libc.conf
# libc default configuration
/usr/local/lib
so 文件也在缓存中。
$ ldconfig -p | grep opencv | grep ml
libopencv_ml.so.2.4 (libc6,x86-64) => /usr/local/lib/libopencv_ml.so.2.4
libopencv_ml.so (libc6,x86-64) => /usr/local/lib/libopencv_ml.so
那么你能告诉我我可能做错了什么吗?在运行 Python 时加载共享库的方式在 Ubuntu 11.04 和 11.10 之间是否发生了变化?或者这是 OpenCV 的问题?
【问题讨论】:
您是否尝试将库放在g++
命令行的最后一个参数?
不,我没有。它奏效了!但是,为什么它起作用了? g++ 的选项顺序如何影响生成的二进制文件?
刚刚看到 ldd 在以旧方式编译时仅打印 6 个对生成的 .so 的依赖项。但是在最后的库中,它添加了所需的所有 75 个依赖项。谢谢塞巴斯蒂安!
参见 gcc 手册中-l
选项的描述。
"foo.o -lz bar.o 在文件 foo.o 之后但 bar.o 之前搜索库 z。如果 bar.o 引用 z 中的函数,则可能不会加载这些函数。"我完全错过了这个。谢谢!
【参考方案1】:
解决方案是将生成的模块名称放在它所依赖的其他模块之前,在 g++ 命令行中。
g++ -fPIC -shared -o mymodule.so mymodule.cpp `pkg-config --cflags --libs python` `pkg-config --cflags --libs opencv` -I/usr/local/include/opencv2/legacy
gcc 手册页提到了 -l
选项,
在命令的哪个位置编写此选项会有所不同;这 链接器按顺序搜索和处理库和目标文件 它们是指定的。因此,
foo.o -lz bar.o
在之后搜索库 z 文件 foo.o 但在 bar.o 之前。如果 bar.o 引用 z 中的函数,则那些 函数可能无法加载。
由于 mymodule.so 的名称是在它应该链接到的库之前提供的,因此它们实际上都没有链接到生成的 .so 文件。
感谢@J.F.Sebastian 指出-l
的工作原理。
【讨论】:
以上是关于Python ImportError - 未定义符号 - 用于自定义 C++ 模块的主要内容,如果未能解决你的问题,请参考以下文章
Python中ImportError: No module named request
Python 3 ImportError:没有名为“ConfigParser”的模块
Python 3:ImportError“没有名为 Setuptools 的模块”