C++/Python: Mac上の Python3.4 で setup.py を使って Boost.Python を動かす方法
バージョン
- Mac: OS X Yosemite Version 10.10.1
- Homebrew: 0.9.5
- pyenv: 20141211
- Python: 3.4.2
- gcc: Apple LLVM version 6.0 (clang-600.0.56)
- Boost: 1.57
環境構築
1. Homebrew最新化
2. pyenv環境整理
.bashrc/.bash_profile/.zshrc などに追記し実行。
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
|
$ pyenv install 2.7.9
$ pyenv install 3.4.2
$ pyenv global 3.4.2 2.7.9
$ pyenv rehash
$ pyenv versions
system
* 2.7.9 (set by PYENV_VERSION environment variable)
* 3.4.2 (set by PYENV_VERSION environment variable)
|
3. boost インストール
そのままインストールすると以下のようなエラーが出る。
$ brew install boost-python --with-python3
(snip)
==> Installing boost-python
Already downloaded: /Library/Caches/Homebrew/boost-python-1.57.0.tar.bz2
==> Patching
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar/boost-python/1.57.0/lib --with-l
==> ./b2 --build-dir=build-python --stagedir=stage-python python=3.4 --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=
...skipped <pstage-python/lib>libboost_python3.dylib for lack of <pbuild-python/boost/bin.v2/libs/python/build/darwin-4.2.1/release>libboost_python3.dylib...
...skipped <pstage-python/lib>libboost_python.dylib for lack of <pbuild-python/boost/bin.v2/libs/python/build/darwin-4.2.1/release>libboost_python.dylib...
...failed updating 4 targets...
...skipped 4 targets...
...updated 145 targets...
|
Homebrew のログは ~/Library/Logs/Homebrew/boost-python 配下に出ている。
今回のエラーの原因は、python3.4 ライブラリが見つからなかったためのようだ。
$ grep 'not found' ~/Library/Logs/Homebrew/boost-python/02.b2
ld: library not found for -lpython3.4
ld: library not found for -lpython3.4
ld: library not found for -lpython3.4
ld: library not found for -lpython3.4
|
暫定策として、libpython3.4m.a を参照する libpython3.4.a を作ったら解決した。
$ ln -s ~/.pyenv/versions/3.4.2/lib/libpython3.4m.a ~/.pyenv/versions/3.4.2/lib/libpython3.4.a
$ brew install boost-python --with-python3
Already downloaded: /Library/Caches/Homebrew/boost-python-1.57.0.tar.bz2
==> Patching
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar/boost-python/1.57.0/lib --with-libraries=python -
==> ./b2 --build-dir=build-python --stagedir=stage-python python=3.4 --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar/boost-python/1.57.0/lib --with-libraries=python -
==> ./b2 --build-dir=build-python3 --stagedir=stage-python3 python=3.4 --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cell
/usr/local/Cellar/boost-python/1.57.0: 9 files, 31M, built in 3.3 minutes
|
ちなみに、system の Python を使うように設定してからインストールすると、今度は python3 が見つからないなどの別のエラーが発生するので注意。
$ pyenv shell system
$ brew install boost-python --with-python3
pyenv: python3: command not found
The `python3' command exists in these Python versions:
3.4.2
(snip)
Already downloaded: /Library/Caches/Homebrew/boost-python-1.57.0.tar.bz2
==> Patching
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar/boost-python/1.57.0/lib --with-l
==> ./b2 --build-dir=build-python --stagedir=stage-python python=2.7 --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=
sh: python3: command not found
sh: python3: command not found
==> ./bootstrap.sh --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/usr/local/Cellar/boost-python/1.57.0/lib --with-l
==> ./b2 --build-dir=build-python3 --stagedir=stage-python3 python= --prefix=/usr/local/Cellar/boost-python/1.57.0 --libdir=/
/private/tmp/boost-python-QMqTxe/boost_1_57_0/tools/build/src/build-system.jam:583: in load from module build-system
(snip)
|
ディレクトリ構造
ファイルの配置は以下のようにした。
.
├── setup.py
├── src
│ └── chello
│ └── chello.cpp
└── tests
├── __init__.py # 空ファイル
└── chello
├── __init__.py # 空ファイル
└── test_chello.py
|
トライ & エラー
最初のバージョンのコードはこのような感じ。
chello.cpp (エラーあり)1 2 3 4 5 6 7 8 9 10 | #include <boost/python.hpp>
std::string hello() {
return "hello world" ;
}
BOOST_PYTHON_MODULE(hello) {
using namespace boost::python;
def( "hello" , &hello);
}
|
test_chello.py1 2 3 4 5 6 7 | import unittest
from chello import hello
class TestCHello(unittest.TestCase):
def test_hello( self ):
self .assertEqual(hello(), 'hello world' )
|
setup.py1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | from setuptools import setup, find_packages, Extension
setup(
name = 'example-boost-python' ,
version = '0.0.1' ,
description = 'Example for Boost.Python' ,
author = 'your-name' ,
author_email = 'your-name@example.com' ,
install_requires = [],
tests_require = [],
package_dir = {' ': ' src'},
packages = find_packages( 'src' ),
include_package_data = True ,
test_suite = 'tests' ,
entry_points = '',
ext_modules = [
Extension(
name = 'chello' ,
sources = [ 'src/chello/chello.cpp' ],
include_dirs = [ '/usr/local/include/boost' ],
library_dirs = [ '/usr/lib' , '/usr/local/lib' ],
libraries = [ 'boost_python3' ],
extra_compile_args = [ '-std=c++11' , '-Wall' ],
extra_link_args = [],
)
],
)
|
実行すると、ビルドは問題ないが、テスト実行時に以下のエラーを得る。
$ python3 ./setup.py build
(snip)
$ python3 ./setup.py test
(snip)
running build_ext
copying build/lib.macosx-10.10-x86_64-3.4/chello.so -> src
Traceback (most recent call last):
(snip)
AttributeError: 'module' object has no attribute 'test_chello'
|
手で実行すると、モジュールインポート時のエラーであることがわかる。
1 2 3 4 5 | $ python
>>> import src.chello
Traceback (most recent call last):
File "<stdin>" , line 1 , in <module>
ImportError: dynamic module does not define init function (PyInit_chello)
|
モジュールの名前を一致させる
最初の修正は、モジュールの名前を一致させること。hello を chello に修正。
chello.cpp1 2 3 4 5 6 7 8 9 10 11 12 | #include <boost/python.hpp>
using namespace std;
std::string hello() {
return "hello world" ;
}
BOOST_PYTHON_MODULE(chello) {
using namespace boost::python;
def( "hello" , &hello);
}
|
すると、今度は異なるエラーを得る。
$ python3 ./setup.py test
running test
running egg_info
writing dependency_links to src/example_boost_python.egg-info/dependency_links.txt
writing top-level names to src/example_boost_python.egg-info/top_level.txt
writing src/example_boost_python.egg-info/PKG-INFO
reading manifest file 'src/example_boost_python.egg-info/SOURCES.txt'
writing manifest file 'src/example_boost_python.egg-info/SOURCES.txt'
running build_ext
copying build/lib.macosx-10.10-x86_64-3.4/chello.so -> src
Fatal Python error: PyThreadState_Get: no current thread
zsh: abort python3 ./setup.py test
|
ビルドされたファイルの中身を見る。
$ otool -L ./src/chello.so
./src/chello.so:
/usr/local/lib/libboost_python.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
|
pyenv を system に戻して boost を再インストール
色々試行錯誤したが、結局 system の Python を指定した状態で boost (boost-python ではない) をインストールし直したら動作するようになった。
$ pyenv global system
$ brew install python3 # 必要に応じて
$ brew rm boost
$ brew install boost --build-from-source
|
$ rm -rf ./build && python3 ./setup.py test
(snip)
clang -Wno-unused-result -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/usr/local/include -I/usr/local/opt/sqlite/include -I/usr/local/include/boost -I/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/include/python3.4m -c src/chello/chello.cpp -o build/temp.macosx-10.10-x86_64-3.4/src/chello/chello.o -std=c++11 -Wall
creating build/lib.macosx-10.10-x86_64-3.4
clang++ -bundle -undefined dynamic_lookup -L/usr/local/lib -L/usr/local/opt/sqlite/lib build/temp.macosx-10.10-x86_64-3.4/src/chello/chello.o -L/usr/lib -L/usr/local/lib -lboost_python3 -o build/lib.macosx-10.10-x86_64-3.4/chello.so
copying build/lib.macosx-10.10-x86_64-3.4/chello.so -> src
test_hello (tests.chello.test_chello.TestCHello) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
|
この時、動作する環境は system の python3 のみ。
python2 で動かないのはもちろん、pyenv 経由だと先ほどと同じエラーが発生してしまう。
$ python
Python 2.7.9 (default, Jan 7 2015, 11:49:12)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import src.chello
Traceback (most recent call last):
File "<stdin>", line 1, in
ImportError: No module named src.chello
$ python3
Python 3.4.2 (default, Jan 7 2015, 11:54:58)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import src.chello
>>> src.chello.hello()
'hello world'
$ pyenv global 3.4.2 2.7.9
$ python3
Python 3.4.2 (default, Jan 18 2015, 02:00:19)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import src.chello
Fatal Python error: PyThreadState_Get: no current thread
zsh: abort python3
|
コード
まとめ
$ sudo brew update
$ brew [install | upgrade] python3
$ brew install pyenv
$ pyenv shell system
$ brew install boost --from-source
$ brew install boost-python --with-python3
$ python3 ./setup.py build
$ python3 ./setup.py test
|
Boost.Python を利用するプロジェクトでは、pyenv は system を指定する。
References
Related Posts