私はUbuntu 11.04でOpenCV 2.3から2.4.2を使用してC++でPythonモジュールを開発しています。OpenCVはソースからビルドされました。UbuntuリポジトリのOpenCVのバージョンを使用していません。
My Pythonモジュールは問題なくコンパイルされ、Pythonに適切にロードされます。ただし、このモジュールをUbuntu 11.10または12.04でコンパイルすると、 Pythonでロードしようとすると、「undefined symbol」というメッセージが表示されます。
これは私がモジュールをコンパイルする方法です:
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
そして、そうファイルはキャッシュにもあります。
$ 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++ -fPIC -shared -o mymodule.so mymodule.cpp `pkg-config --cflags --libs python` `pkg-config --cflags --libs opencv` -I/usr/local/include/opencv2/legacy
Gccのmanページには、「-l」オプションについての説明があります。
コマンドのどこにこのオプションを記述するかによって違いが生じます。リンカは、ライブラリとオブジェクトファイルを指定された順序で検索して処理します。したがって、foo.o -lz bar.oは、ファイルfoo.oの後、ただしbar.oの前にライブラリzを検索します。 bar.oがzの関数を参照する場合、それらの関数はロードされない可能性があります。
Mymodule.soの名前は、リンクされることになっているライブラリの前に提供されていたため、生成された.soファイルに実際にリンクされたものはありません。
-lの動作を指摘してくれた@ J.F.Sebastianに感謝します。