読者です 読者をやめる 読者になる 読者になる

n-yoda's blog

主にUnity3Dに関するあんまり技術的じゃないメモ的な何かを書いています。

Boost.NumPyをMac OS Xで使おうとして躓いたメモ

OS XBoost.NumPyを使ったときのメモです。PythonC++モジュールを作るには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)

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)