はじめに
Python から C++ メソッドを呼び出す手段の一つとして Boost Python の利用があります。
WSL Ubuntu 上にて、Boost Python を利用するための手順を紹介します。
Boost の公式ドキュメントはこちらから参照可能です。
動作環境
- Windows 11
- WSL Ubuntu 20.04
- g++ 9.4.0
- boost 1.71.0
- python 3.8.10
Boost Python で C++ メソッドを呼び出し
事前準備
初めに、Ubuntu パッケージを最新化しておきます。
$ sudo apt update
$ sudo apt upgrade
C++ コードをコンパイルするため、Ubuntu に g++ をインストールします。
$ sudo apt install g++
また、Boost Python を利用してコンパイルするための関連パッケージをインストールします。libboost-python-dev
をインストールすることで、必要なものはまとめてインストールされます。
$ sudo apt install libboost-python-dev
おおよそ次のようなパッケージが主に関連します。
依存パッケージ | インストールされるファイル |
---|---|
libboost1.71-dev | /usr/include/boost/python.hpp |
libpython3.8-dev | /usr/include/python3.8/pyconfig.h |
libboost-python1.71.0 | /usr/lib/x86_64-linux-gnu/libboost_python38.so.1.71.0 |
C++ コードから動的リンクライブラリ生成
Python から呼び出されるソースコードです。
#include <boost/python.hpp>
void hello()
{
printf("Hello, world!\n");
}
BOOST_PYTHON_MODULE(hello_ext)
{
boost::python::def("hello", hello);
}
単純な標準出力をするのみの hello メソッドを Python へエクスポートします。BOOST_PYTHON_MODULE
のブロックは、エクスポート方法を定義するための記述になります。
ソースコードを用意したら、g++ コマンドで動的リンクファイルを生成します。
なお、BOOST_PYTHON_MODULE
で指定するモジュール名 hello_ext
と、出力ファイル名 hello_ext.so
は一致させる必要があります。
$ g++ -fPIC --shared hello.cc -o hello_ext.so -I/usr/include/python3.8 -lboost_python38
$ ls hello_ext.so
hello_ext.so
Python コードから hello 呼び出し
Python コードは簡単です。hello_ext
をインポートして、hello_ext.hello
を呼び出すのみです。
なお、先ほど生成した hello_ext.so
ファイルは、main.py と同じディレクトリに配置しておきます。
import hello_ext
hello_ext.hello()
Boost Python が多くの部分を隠蔽してくれているため、シンプルな記述で呼び出すことができます。
$ python3 main.py
Hello, world!
注意点
g++ コマンドを実行する際には、引数の順番が重要です。
インプットファイル(hello.cc)は -lboost_python38
のオプションよりも前に指定する必要があるようです。
例えば次のように、hello.cc を末尾に持ってきてしまうと、boost_python38 のリンクがスキップされてしまうようです。
$ g++ -fPIC --shared -o hello_ext.so -I/usr/include/python3.8 -lboost_python38 hello.cc
これで生成された hello_ext.so
を呼び出そうとすると、メソッドの探索エラーが発生してしまいます。
$ python3 main.py
Traceback (most recent call last):
File "main.py", line 1, in <module>
import hello_ext
ImportError: /home/***/hello_ext.so: undefined symbol: _ZNK5boost6python7objects21py_function_impl_base9max_arityEv