swigでpythonからc++コードを使う
c++とpythonの連携はどうやるのか、ずっと気になってたのでメモ。
もともとはpythonのsubprocessモジュールを使って無理矢理連携させてたりしていたのですが、色々難しい&結局満足にできないのでオススメしません…
■どうやれば連携できるの?
こちら(http://d.hatena.ne.jp/niitsuma/20080209/1203184397)に色々書かれています。
今回はswigを使ってみます。
■swigを使ってみる
まずはswigをインストール。特に問題なくインストールできました。
本家ページ:http://www.swig.org/
次に、本家のpython用マニュアルに従ってサンプルを動かしてみる。(http://www.swig.org/Doc1.3/Python.html)
そのまんまコピペで………あれ、いかない。
$ swig -python example.i $ python setup.py build_ext --inplace running build_ext building '_example' extension /usr/bin/gcc-4.2 -fno-strict-aliasing -fno-common -dynamic -pipe -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/opt/local/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 -c example_wrap.c -o build/temp.macosx-10.6-x86_64-2.7/example_wrap.o unable to execute /usr/bin/gcc-4.2: No such file or directory error: command '/usr/bin/gcc-4.2' failed with exit status 1
使ってるgccは4.6なので、コンパイラ選びが間違ってるみたいです。CC=g++とか書けばいいのかな…?
$ CC=g++ CXX=CC python setup.py build_ext --inplace ~略(さっきより進んだ) unable to execute /usr/bin/gcc-4.2: No such file or directory error: command '/usr/bin/gcc-4.2' failed with exit status 1
途中からgcc-4.2をみにいってるorz
どういうことだ………
色々やってみるも、なかなか上手くいかず、挫折しそうになる…………
最初はswig周りを頑張って調べていたものの、考えてみればこの段階ではpythonのdistutilsを使ってモジュールをインストールしようとしてるだけなので、distutils周りを調べればいいことに気付く。
正直未だにしっかり理解はしてないけど、なんかsetup.pyに以下のように追記すればいいことを発見。(雑すぎる…
from distutils import sysconfig print sysconfig.get_config_var("LDSHARED") sysconfig._config_vars["LDSHARED"] = "/opt/local/bin/g++ -bundle -undefined dynamic_lookup -isysroot / -L/opt/local/lib" print sysconfig.get_config_var("LDSHARED") from distutils.core import setup, Extension #以下サンプルと同じ
print文はデバッグのためもありますが、最初のprintをいれないと、LDSHAREDなんてねーよって怒られるので必要です。
この状態で、上のコマンドを実行…うむ、できた。
pythonからもモジュールを呼び出せました。
速度的なところが気になったので一応テスト。
・10^9回x++するだけのコードをcppで書いて、swigを使ってpythonから呼び出してみる
→実行時間は約3秒
・同じコードをpythonで書いて、pythonで呼び出してみる
→実行時間は300秒以上。当然だけど早くなってます。
・同じコードを、普通にcppで呼び出してみる
→実行時間は約5秒。あれ、pythonで呼びだした時より長い…………なぜ?
・入力を2倍して返すコードをcppで書いてみて、pythonから10^7回呼び出してみる
→実行時間は9秒ほど
・入力を2倍して返すコードをpythonで書いてみて、pythonから10^7回呼び出してみる
→実行時間は8秒ほど。何度もc++のコードを呼び出すよりも、ネイティブなコードを呼んだ方が早くなる場合もあるみたいですね。(参考:http://python.matrix.jp/tips/cpp_extension/)
■コンパイラ・リンカのフラグを弄る
c++の方でmecabを使わせて、それをごにょごにょしたのをpythonに渡したいので、フラグを弄ってc++側でmecabが使えるようにします。
http://www.python.jp/doc/2.5/inst/tweak-flags.html#SECTION000610000000000000000
ここにそれっぽいこと書いてあるんですが、よくわからん…
pythonで、help(Extension)とすると、それっぽいことが書いてあるので、これを参考にsetup.pyを書き直すとします。
geho_module = Extension('_geho', sources=['geho_wrap.cxx', 'geho.cpp'], include_dirs=['/opt/local/include'], library_dirs=['/opt/local/lib'], libraries=['mecab', 'stdc++'], )
これでよし…と思ったけど、できないヽ(´o`;
ImportError: dlopen(./_geho.so, 2): Symbol not found: __ZN5MeCab12createTaggerEPKc   Referenced from: /Users/katsuma/src/geho/_geho.so   Expected in: flat namespace  in /Users/katsuma/src/geho/_geho.so
ううむ……。
tagger->parseをしなければ(つまり、include
ってこの症状、前にも経験した気がする。何をすれば直ったのだっけ……