$ brew install boost-python --with-python3

なのだが、すこしハマりどころがある。

brew install boost-python のオプション

brew install にはオプションを指定できる場合がある。
boost-python の場合は --with-python3 オプションが使える。

brew options で使用可能なオプションをすべて表示することができる。

$ brew options boost-python
--c++11
	Build using C++11 mode
--with-python3
	Build with python3 support
--without-python
	Build without python 2 support
--HEAD
	Install HEAD version

--with-python3 を指定した場合、boost-python はソースコードからビルドされる。

インストール手順

Homebrew の formula はオプションのあり・なしに関わらず重複インストールできないので、 すでにインストールしている場合ははじめにアンインストールする。

$ # macOS Sierra (10.12) + Homebrew
$ # おこられる
$ brew install boost-python --with-python3
Warning: boost-python 1.65.1 is already installed
$
$ # はじめにアンインストール
$ brew uninstall boost-python
Uninstalling /usr/local/Cellar/boost-python/1.65.1... (457 files, 16MB)
$
$ # ---------------------------------------------------------------------------
$ # * この処理は実際は不要です
$ # オプションなしインストール(参考)。ビルド済みバイナリがインストールされる。
$ brew install boost-python
==> Downloading https://homebrew.bintray.com/bottles/boost-python-1.65.1.sierra.bottle.tar.gz
==> Pouring boost-python-1.65.1.sierra.bottle.tar.gz
🍺  /usr/local/Cellar/boost-python/1.65.1: 457 files, 16MB
$
$ # ふたたびアンインストール
$ brew uninstall boost-python
Uninstalling /usr/local/Cellar/boost-python/1.65.1... (457 files, 16MB)
$ # ---------------------------------------------------------------------------
$
$ # python3 版をビルドしてインストールする
$ brew install boost-python --with-python3
==> Downloading https://dl.bintray.com/boostorg/release/1.65.1/source/boost_1_65_1.tar.bz2
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.65.1 --libdir=/usr/local/Cellar/boost-python/1.65.1/lib --with-libraries=python --with-python=python --with-python-root=/System/Library/Frameworks/Python.framework/Versions/2.7
==> ./b2 --build-dir=build-python --stagedir=stage-python python=2.7 --prefix=/usr/local/Cellar/boost-python/1.65.1 --libdir=/usr/local/Cellar/boost-python/1.65.1/lib -d2 -j4 --layout=tagged --user-config=user-config.jam threading=multi,single link=shared,static
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.65.1 --libdir=/usr/local/Cellar/boost-python/1.65.1/lib --with-libraries=python --with-python=python3 --with-python-root=/usr/local/Cellar/python3/3.6.2/Frameworks/Python.framework/Versions/3.6
==> ./b2 --build-dir=build-python3 --stagedir=stage-python3 python=3.6 --prefix=/usr/local/Cellar/boost-python/1.65.1 --libdir=/usr/local/Cellar/boost-python/1.65.1/lib -d2 -j4 --layout=tagged --user-config=user-config.jam threading=multi,single link=shared,static
🍺  /usr/local/Cellar/boost-python/1.65.1: 465 files, 28.4MB, built in 7 minutes 21 seconds

Python 2 用と Python 3 用のバイナリが両方ビルドされています。バッチリです。

Python 3 用のライブラリにリンクする(重要)

  • Python 2 用の場合は -lboost_python, -lboost_numpy を指定する。
  • Python 3 用の場合は -lboost_python3, -lboost_numpy3 を指定する。

Python 2 用と Python 3 用のライブラリは名前がことなるため注意が必要です。

$ ls /usr/local/lib | grep libboost_python
libboost_python-mt.a
libboost_python-mt.dylib
libboost_python.a
libboost_python.dylib
libboost_python3-mt.a
libboost_python3-mt.dylib
libboost_python3.a
libboost_python3.dylib

テストとして python-multi-array ライブラリをビルドします。 ビルドスクリプトは setup.py です。
https://github.com/yokaze/python-multi-array

$ # -lboost_python3, -lboost_numpy3 だとちゃんと動く
$ python3
>>> import multi_array
>>>

ここを間違えると結局 Python 2 用のライブラリにリンクされてしまい、拡張モジュールがうまく動きません。

$ # -lboost_python, -lboost_numpy
$ python3
>>> import multi_array
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dlopen(multi_array.cpython-36m-darwin.so, 2): Symbol not found: _PyClass_Type
  Referenced from: /usr/local/opt/boost-python/lib/libboost_python.dylib
  Expected in: flat namespace
 in /usr/local/opt/boost-python/lib/libboost_python.dylib
>>>

参考資料