↑ページトップへ

C++ で Python 用ライブラリーを作成する

Python 3Boost 1.67.0Ubuntu 18.04

概要

C++ で作成した処理を Python から使用するには以下を始めとした複数の方法があります。

  • Python.h
  • SWIG
  • Boost.Python
  • Shiboken
  • pybind11

どの方法を使用するかは状況によって変わりますが Boost.Python では C++ 内から Python を呼び出せる(今回の例とは逆)という利点があります。Python と C++ の間で相互に呼び出しを行えるので、C++ で作成されたアプリケーションにマクロ言語として Python を組み込む相互に呼び出しを行うといったことができるようになります。

ここでは Linux(Ubuntu 18.04)上で Boost.Python を使用して Python (Python 3)用ライブラリーを作成する方法について説明します。

Boost.Python のビルド

まず以下のコマンドで必要なパッケージをインストールします。

$sudo apt install build-essential python3-dev

また以下のコマンドで Python のインストール位置とバージョンを確認しておきます。

$which python3
/usr/bin/python3
$python3 --version
Python 3.6.5

これでインストール位置が「/usr/bin/python3」、バージョンが「3.6.5」であることがわかりました。

次に Boost ライブラリーのソースコード「boost_1_67_0.zip」を boost_1_67_0 ソースコードアーカイブからダウンロードし、適当なディレクトリに置きます(以下では$HOMEに置いたものとします)。ダウンロードが終わったらファイルのあるディレクトリに移動し、以下のコマンドを実行して Boost.Python をビルドします。

$unzip booost_1_67_0.zip
$cd booost_1_67_0
$./bootstrap.sh --with-libraries=python --with-python=python3 --with-python-version=3.6
$./b2 cxxflags=-fPIC address-model=64 threading=multi link=static runtime-link=shared variant=release -j8 --stagedir=stage/x64 

ここでは64ビット OS 用のマルチスレッド対応・静的リンク版を、C ランタイムは動的リンク設定として8並列でリリース・ビルドしています。boost_1_67_0/stage/x64/lib に「libboost_python36.a」ができていればビルドは成功しています。

Python 用ライブラリーの作成

ビルドができたら実際に C++ で Python 用ライブラリーを作成していきます。

次のような C++ ソースコード MyModule.cpp を用意します。このソースコードをコンパイルして Python から関数 add() を呼び出せるようにします。

#include <boost/python.hpp>

int add(int valueA, int valueB) {
    return valueA + valueB;
}

BOOST_PYTHON_MODULE(MyModule) {
    using namespace boost::python;
    def("add", &add);
}

まずコンパイル時に必要となるヘッダーファイル pyconfig.h がどこにあるかを確認しておきます。

$find /usr/include -name pyconfig.h
/usr/include/x86_64-linux-gnu/python3.6m/pyconfig.h
/usr/include/python3.6m/pyconfig.h

ビルド時に boost/python.hpp と pyconfig.h が参照できるように CPLUS_INCLUDE_PATH を以下のコマンドで設定しておきます。毎回、端末起動ごとに設定するのが面倒な場合は ~/.bashrc 末尾に設定しておくといいかもしれません。

$export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:$HOME/boost_1_67_0/:/usr/include/python3.6m/"

先ほどビルドした libboost_python36.a を MyModule.cpp と同じディレクトリにコピーします。その後、ファイル MyModule.cpp のあるディレクトリに移動して C++ のソースコードをビルドします。

$g++ -DPIC -shared -fPIC -o MyModule.so MyModule.cpp libboost_python36.a

コンパイルが成功すると MyModule.so が作成されます。

Python からの呼び出し

作成したライブラリーを使用する場合は、MyModule.so のあるディレクトリ内で次のような Python スクリプト CallMyModule.py を作成し、python3 で実行します。

#!/usr/bin/env python3

import MyModule

value = MyModule.add(1, 2)
print(value)

正常に実行されると「3」と表示されます。

C++ クラスの公開

次に C++ のクラスを Python から使用する場合を考えます。次のような C++ ソースコード MyClassModule.cpp を用意し、このソースコードをコンパイルして Python からクラス MyClass を呼び出せるようにします。

#include <boost/python.hpp>

class MyClass {
public:
        void add(int valueA, int valueB) {
                _result = valueA + valueB;
        }
        int value() {
                return _result;
        }
private:
        int _result;
};

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

        class_<MyClass>("MyClass")
                .def("add", &MyClass::add)
                .def("value", &MyClass::value);
}

以下のコマンドでコンパイルを行うと MyClassModule.so が作成されます(先ほどと同様 CPLUS_INCLUDE_PATH 設定、 libboost_python36.a のコピーが必要です)。

g++ -DPIC -shared -fPIC -o MyClassModule.so MyClassModule.cpp libboost_python36.a

作成したライブラリーを使用する場合は、MyClassModule.so のあるディレクトリ内で次のような Python スクリプト CallMyClassModule.py を作成し、python3 で実行します。

#!/usr/bin/env python3

import MyClassModule

my_instance = MyClassModule.MyClass()
my_instance.add(1, 2)
value = my_instance.value()

print(value)

スクリプトを実行すると「3」と表示されます。以上で Boost.Python による Python ライブラリーの基本的な作成方法を確認できました。

なお以上で紹介した C++ソースコード、Python スクリプトは「Boost.Python - サンプルソースコード」からダウンロードできます。

参照

Boost.Python の機能をざっと紹介してみる - muddy brown thang