Help us understand the problem. What is going on with this article?

Boost.pythonをhomebrewで導入

More than 3 years have passed since last update.

Boost.pythonを試してみようとhomebrewで導入してみたところ、少々ハマりましたのでメモっておきます。

環境

  • OS X El Capitan(10.11.3)
  • Python 2.7.11 (homebrew)
  • boost 1.59 (homebrew)
  • boost-python 1.59 (homebrew)

使用例(C++)

c++の自乗を返す関数をpythonから呼んでみます。

hello_ext.cpp
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>

int square(int a)
{
    return a*a;
}

BOOST_PYTHON_MODULE(hello_ext)
{
    using namespace boost::python;
    def("square",square);
}

hello_ext.soをビルドするためのMakefileです。

all: hello_ext.so

CC = g++

FRAMEWORK_PATH=/usr/local/opt/python/Frameworks
INCLUDE_PATH=$(FRAMEWORK_PATH)/Python.framework/Versions/2.7/include/python2.7

hello_ext.o: hello_ext.cpp
    $(CC) -Wall -O2 -fPIC -c $< -I$(INCLUDE_PATH)

hello_ext.so: hello_ext.o
    $(CC) -shared  -o $@ $< -lboost_python -F$(FRAMEWORK_PATH) -framework Python

pythonの呼び出し側です。

hello.py
#!/usr/bin/env python
import hello_ext
print hello_ext.square(2)

ビルドと実行結果です。

$ make
g++ -shared  -o hello_ext.so -I/usr/local/opt/python/Frameworks/Python.framework/Versions/2.7/include/python2.7 hello_ext.o -lboost_python -F/usr/local/opt/python/Frameworks -framework Python
$ python hello.py
4

なるほど、昔ながらのPython拡張に比べてコードがすっきりしてよいですね。

使用例(Objective-C++)

既存のフレームワークを使いたいなどの理由で、Objective-Cを混在させるにはObjective-C++を使うといけますね。下記をhello_ext.mmとして作成します。

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>

#import <Foundation/Foundation.h>

int square(int a)
{
    return a*a;
}

void nslog(void)
{
    NSLog(@"Hello");
}

BOOST_PYTHON_MODULE(hello_ext)
{
    using namespace boost::python;
    def("square",square);
    def("nslog",nslog);
}

Makefileは下記です。コンパイル時には-x objective-c++をつけ、リンク時にはフレームワークのパスとフレームワーク名をつけます。

all: hello_ext.so

CC =clang++

FRAMEWORK_PATH=/usr/local/opt/python/Frameworks
INCLUDE_PATH=$(FRAMEWORK_PATH)/Python.framework/Versions/2.7/include/python2.7
FRAMEWORK_PATH2=/System/Library/Frameworks

STD_CPP_PATH = /usr/include/c++/4.2.1/

FRAMEWORK_OPTIONS=-F$(FRAMEWORK_PATH) -framework Python -F$(FRAMEWORK_PATH2) -framework Foundation

hello_ext.o: hello_ext.mm
    $(CC) -x objective-c++ -Wall -O2 -fPIC -c $< -I$(INCLUDE_PATH) -I$(STD_CPP_PATH)

hello_ext.so: hello_ext.o
    $(CC) -shared -o $@  $< -lboost_python $(FRAMEWORK_OPTIONS)

.PHONY: clean
clean:
    rm *.so *.o

下記で呼び出せます。

import hello_ext

hello_ext.nslog()
print hello_ext.square(2)

実行結果は下記です。

2017-04-09 11:45:29.818 Python[7710:333116] Hello
4

ハマった点と解決までの経緯

まず公式チュートリアルはbjamを使えと書いてあります。bjamはhomebrewの boost-buildを入れるとインストールできますが、Jamfileとやらのパスを指定せよといわれ、homebrewでのインストール先がわからず断念しました。

次にBoost.Python の機能をざっと紹介してみるなどの先人に習ってg++でビルドをしてみましたが、引数の受け渡しをしようとした時点で、

Segmentation fault: 11

だの、

Fatal Python error: PyEval_SaveThread: NULL tstate

だのいわれて散々でした。

後者のエラーメッセージが検索に引っ掛かり、StackOverFlowの記事にたどり着きました。

だいたいこういうのは複数のバージョンの python が混在してるときじゃね?
otool -Lとかで依存関係を見てみたら;)

とのコメントがまさにビンゴ。確かにOSXネイティブなパスとhomebrewのパスが混在していました。

ということで、-F オプションをつけてフレームワークのパスを OSX ネイティブのものではなく homebrew のものに置き換えることで解決しました。

-Fオプションには man ld でたどり着きました。恥ずかしながら -framework オプションも理解しておらず。勉強不足でしたがどうにかたどり着きました。

参考リンク

ashitani
趣味で機械学習をやっている者です。
http://ashitani.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away