らんだむな記憶

blogというものを体験してみようか!的なー

Boost.Python

さて、わざわざあのboooooooost様を導入した目的を実行しようか。
とりあえず、夢を見過ぎないための戒めを冒頭に貼り付けて、boooooooost様という高嶺の花とのお付き合いには相応の忍耐力が必要であることを認識しておく。

$ make
g++ -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -I/opt/boost_1_58_0/include -fPIC -c myboostpy.cpp
In file included from /opt/boost_1_58_0/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:47:0,
                 from /opt/boost_1_58_0/include/boost/python/detail/invoke.hpp:63,
                 from /opt/boost_1_58_0/include/boost/python/detail/caller.hpp:16,
                 from /opt/boost_1_58_0/include/boost/python/object/function_handle.hpp:8,
                 from /opt/boost_1_58_0/include/boost/python/converter/arg_to_python.hpp:19,
                 from /opt/boost_1_58_0/include/boost/python/call.hpp:15,
                 from /opt/boost_1_58_0/include/boost/python/object_core.hpp:14,
                 from /opt/boost_1_58_0/include/boost/python/args.hpp:25,
                 from /opt/boost_1_58_0/include/boost/python.hpp:11,
                 from myboostpy.cpp:1:
/opt/boost_1_58_0/include/boost/python/detail/invoke.hpp: In instantiation of ‘PyObject* boost::python::detail::invoke(boost::python::detail::invoke_tag_<false, true>, const RC&, F&, TC&) [with RC = boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<SubCalculator&>; F = SubCalculator& (Calculator::*)(); TC = boost::python::arg_from_python<Calculator&>; PyObject = _object]’:
/opt/boost_1_58_0/include/boost/python/detail/caller.hpp:223:13:   required from ‘PyObject* boost::python::detail::caller_arity<1u>::impl<F, Policies, Sig>::operator()(PyObject*, PyObject*) [with F = SubCalculator& (Calculator::*)(); Policies = boost::python::default_call_policies; Sig = boost::mpl::vector2<SubCalculator&, Calculator&>; PyObject = _object]’
/opt/boost_1_58_0/include/boost/python/object/py_function.hpp:38:33:   required from ‘PyObject* boost::python::objects::caller_py_function_impl<Caller>::operator()(PyObject*, PyObject*) [with Caller = boost::python::detail::caller<SubCalculator& (Calculator::*)(), boost::python::default_call_policies, boost::mpl::vector2<SubCalculator&, Calculator&> >; PyObject = _object]’
myboostpy.cpp:41:1:   required from here
/opt/boost_1_58_0/include/boost/python/detail/invoke.hpp:88:90: error: no match for call to ‘(const boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<SubCalculator&>) (SubCalculator&)return rc( (tc().*f)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT)) );
                                                                                          ^
etc. etc. (まだまだ続くっ!)

このようにコンソールを埋め尽くす文字が風景に見えるようになり、心地よい一陣の風を感じるようになった頃に、boostは我々に手を差し伸べてくれるだろう(絶対ムリ!)

readmeとか読む気ないので、またggってみる。

優しい先人が多いので色々と手が抜けて良い。
「若者に人気の大型掲示板」とかかつて紹介されていたところで問おうものなら、"ggrks" の5バイトの文字列が返ってきたらまだマシなほうだろうな。まぁ、とにかくksなので、先にggrことにした。

ついでに、色々悪夢はあるので、以下のようなリンクも張っておく。

その上で、なんかあたかも素晴らしいことが手軽にできるように見える結果だけを記載。

[Makefile] (いまだによく分からん)

TARGET=myboostpy.so

OBJS = myboostpy.o

# /usr/include/python2.7
CXXFLAGS += -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'`

INC += -I/opt/boost_1_58_0/include

CXXFLAGS += $(INC) -fPIC
LIBS += -L/opt/boost_1_58_0/lib -lboost_python
LDFLAGS += -shared $(LIBS)

################################################################################

.PHONY: all
all: $(TARGET)

.PHONY: run
run: ./$(TARGET)

$(TARGET): $(OBJS)
    $(CXX) -Wall -o $(TARGET) $(OBJS) $(LDFLAGS)

.cpp.o:
    $(CXX) $(CXXFLAGS) -c $<

.PHONY: clean
clean:
    rm -rf $(TARGET) $(OBJS)

[myboostpy.cpp] (いきなりクラス作るとかやっちゃダメ!)

#include <boost/python.hpp>

class SubCalculator {
 public:
     int multiply(int a, int b)
     {
         return a * b;
     }
};

class Calculator {
 public:
    int add(int a, int b)
    {
        return a + b;
    }

    // SubCalculator* get_sub() とか SubCalculator& get_sub() だと、
    // booooOOOOSTなんだけど...
    SubCalculator get_sub()
    {
        return m_sub;
    }
// for test
//    int get_sub() { return 0; }

 private:
    SubCalculator m_sub;
};

BOOST_PYTHON_MODULE(myboostpy)
{
    using namespace boost::python;

    class_<SubCalculator>("SubCalculator")
        .def("multiply", &SubCalculator::multiply)
    ;

    class_<Calculator>("Calculator")
        .def("add", &Calculator::add)
        .def("get_sub", &Calculator::get_sub)
    ;
}

んで、make (タターンッ)
俺のターン!俺はこの二匹を生け贄にしブルーアイズホ●イトドラゴンを召喚!
→ 召喚されたのは In file included from /opt/boost_1_58_0/include/boost/preprocessor/iteration/detail/iter/forward1.hpp:47:0 でした... (´Д`;;;

そもそもreadmeとか読んでないから、クラスインスタンスの返し方とか分からんし。なんかポインタや参照を返すのはダメっぽい。ダメっぽいっていうか言語の境界越えていくんだからアドレスとかC++の意味での参照とか返すなやというというjk的なもんはあるかもしれないが、なんかあんまりにもBoost.Pythonが神だとか書いてあったので夢を見てしまった。
class_<>で教えてあげた物体しかやっぱ返せないよな。

しかし、旧式のC拡張ならpython2.x/3.x系の実装を同じファイル内でifdefで切り替えられるけど、Boost.Pythonだとどうなんだ?boostをビルドした時にpython2.7を検出だぜ!みたいなログが見えたけど、python2.7専用になってるんじゃ?3.x系も使いたい場合は、boostを別ビルドして別のとこにインストールとかなのかなぁ。なんか邪悪な現実が待っている気がする。

さて、soができたので評価。

[test.py]

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from myboostpy import Calculator

c = Calculator()
print c.add(3, 5)

sub =c.get_sub()
print sub.multiply( c.add(2, 5), 9 )

で、実行。

$ ./test.py 
8
63

おっ、素晴らしい!(ここまで辿りつくまでの悪夢を見なければ、な)

勿論、boostを勝手なとこにインストールしている以上、boostの共有ライブラリをdlopenしてシンボル引っ張ってこれるように事前に

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/boost_1_58_0/lib

はやっている。というか、.bashrc に書いている。書かないと無事死亡。

―――・・・

とりあえず、Boost.Pythonすげー!ってのは分かった。

  • もう全部バッチシ!の環境が準備された状態で目の前に置かれて、
  • 隣にboostの先生がいてくれて「それはコンパイルエラーになるからこう書かないとダメだよ」という優しい世界

があればPython使いにも優しい世界だろうな。さもなくば、C++の醜悪な現実のまえに地獄の釜が咢を開き、灼熱の業火で焼かれること幾千とな。(asio~ asio~)

scipy/numpyのBoost.Pythonによる高速化 - Risky Dune

・Boost.Python : 神

って書いてあるから誘惑されてみたけど、pythonの高速化のためにboostを使おう!と思えて、かつboostは神器だと思えるためには、その時点で既に(自覚があろうとなかろうと)スーパーエンジニアになってないと無理だなぁ。

取りあえず、メンテナが自分だけになっても文句言わずに頑張れるとかいう状況じゃないと安易にboostを導入したくないな。自己責任で個人プロジェクトに適用する分には面白いんだが。
C++ってNだけ楽しむためにはexp(N)くらい実力が要るイメージだよなぁ...。
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms ホント、非expertにはnot friendlyだゎ...。