Edited at

Boost.pythonをhomebrewで導入

More than 1 year has 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 オプションも理解しておらず。勉強不足でしたがどうにかたどり着きました。


参考リンク