Boost.NumPyをMac OS Xで使おうとして躓いたメモ
OS XでBoost.NumPyを使ったときのメモです。PythonのC++モジュールを作るにはBoost.Pythonを使うととても簡単らしく、さらにnumpyの扱いも簡単にしてくれるのがBoost.NumPyとのこと。install_nameという物を知らなくて少し躓きました。何か知見の得られる読み物ではなくメモです。OS Xでのdynamic link libraryの扱い方を知りませんでした、というだけの話です。
環境
失敗編
まずC++でpythonを拡張する(Boost.NumPy) - Qiitaの通りにやったが最後のところでエラーでた。 URLの通りと言うのは少し嘘で、最後のnumpy.cppのビルドにはcmakeを使っていない。
$ brew install boost-python $ git clone https://github.com/ndarray/Boost.NumPy.git $ cd Boost.NumPy $ mkdir build $ cd build $ cmake .. $ make install $ cat > numpy.cpp #上記URL参照 $ clang++ -I/usr/include/python2.7 -lpython2.7 -lboost_python -lboost_numpy -shared numpy.cpp -o mymodule.so $ python >>> import mymodule ImportError: dlopen(./mymodule.so, 2): Library not loaded: libboost_numpy.dylib Referenced from: ?/mymodule.so Reason: unsafe use of relative rpath libboost_numpy.dylib in ./mymodule.so with restricted binary
検索用に置いておくと以下のエラーの場合もあるかも。
ImportError: dlopen(./mymodule.so, 2): Library not loaded: @rpath/libboost_numpy.dylib Referenced from: ?/mymodule.so Reason: image not found
これを直すためにいろいろ調べたら
otool -L mymodule.so
を実行してlibboost_numpy.dylibの正しいパスが表示されてないやつやダメとのこと。 パスが正しくないのであれば書き換えてあげれば良いので
$ DYLIB_PATH=/usr/local/lib64/libboost_numpy.dylib $ install_name_tool mymodule.so -change libboost_numpy.dylib $DYLIB_PATH $ install_name_tool $DYLIB_PATH -id $DYLIB_PATH
みたいなことをやれば良い。が、ビルドするたびにinstall_name_toolでsoを弄るのもおかしい気がするのでもう少し調べたら以下のやり方が正解っぽい。
成功編
$ git clone https://github.com/ndarray/Boost.NumPy.git $ cd Boost.NumPy $ mkdir build $ cd build $ cmake .. -DCMAKE_INSTALL_NAME_DIR=/usr/local/lib -DLIB_SUFFIX= $ make install $ #あとはさっきと同じ
- CMAKE_INSTALL_NAME_DIRはlibboost_numpy.dylibに正しいinstall_nameを指定するために必要。
- 参考:dynamic library の OS Xの補足 - Qiita
- ビルド時に指定しなくても前述の通り
install_name_tool -id
で書き換えられる。 - CMakeListsに書き加えるならこんな感じ:Specify install_name of shared library for MacOSX. · n-yoda/Boost.NumPy@1351a40 · GitHub
- dylibをinstallしない人は
cmake .. --DCMAKE_MACOSX_RPATH=ON
にすると良さそうだけどよく知らない。 - .aを吐いて静的リンクしたい人はCMakeListsのSHAREDを指定してる部分をSTATICにする。
- LIB_SUFFIXに空文字列を指定したのはデフォルトで
/usr/local/lib64
にinstallするのを/usr/local/lib
に変えたかったから。
おまけ(cmakeとinstall_name)
brewでCGALをインストールするときは、CGALのCMakeListsにINSTALL_NAME_DIRの記述が無いから、cmakeするときに-DCMAKE_INSTALL_NAME_DIR=#{HOMEBREW_PREFIX}/lib
を渡している、という例が見つかった。
https://github.com/Homebrew/homebrew-core/blob/33df5f8322616e6155b10a0732af89996aa66345/Formula/cgal.rb#L43
cmakeでdylibを作ってinstallする際のベストプラクティスがわからないので誰か教えてください。↓はダメでしょうか。
if(APPLE) set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib) endif(APPLE)