Python から C++ のメソッドを呼び出すためには、いくつかの手段があります。
本記事では swig を利用して C++ メソッドを呼び出す手法を紹介します。
swig とは、C++ のヘッダファイルを解析して、これに基づいてラッパーとなるコードを自動生成するための仕組みになります。
おおよそ次のような流れになります。
- C++ ソースファイル、ヘッダファイルを用意する。
- swig のインタフェースファイルを用意する。
- swig を実行して、C++ ラッパーコード、Python ラッパーコードを生成する。
- g++ を実行して、C++ ソースファイル、C++ ラッパーコードから動的リンクライブラリを生成する。
- Python ラッパーコードを介して、C++ メソッドを呼び出す。
動作環境
- Windows 11
- WSL Ubuntu 22.04
- g++ 11.3.0
- swig 4.0.1
- python 3.10.6
事前準備
パッケージ最新化
初めに、Ubuntu パッケージを最新化しておきます。
$ sudo apt update
$ sudo apt upgrade
swig インストール
swig をインストールします。
$ sudo apt install swig
-veresion
オプションを指定して swig を実行するとバージョンを確認することができます。
4.0.1 の swig がインストールされました。
$ swig -version
SWIG Version 4.0.2
Compiled with g++ [x86_64-pc-linux-gnu]
Configured options: +pcre
Please see http://www.swig.org for reporting bugs and further information
その他パッケージのインストール
以下の要否は環境によりますので、必要に応じて実施します。
C++ コードのコンパイルのため、g++ もインストールしておきます。
$ sudo apt install g++
Python.h が必要になりますので、python3-dev もインストールします。
$ sudo apt install python3-dev
C++ メソッドを呼び出すための手順
① C++ ソースコード / ヘッダーファイルを準備する
Python から呼び出すための C++ ソースコードを準備します。
以下のファイルをそれぞれ、hello.h
, hello.cc
として保存します。
#ifndef HELLO_H_
#define HELLO_H_
void hello();
#endif // HELLO_H_
#include "hello.h"
#include <iostream>
void hello()
{
std::cout << "Hello World" << std::endl;
}
② swig インタフェースファイルを作成する
ラッパーコードを生成するための swig インタフェースファイル hello.i
も用意します。
%module hello_ext
%{
#include "hello.h"
%}
%include "hello.h"
③ swig でラッパーコードを生成する
hello.i
をインプットに swig を実行することで、ラッパーファイルが2つ hello_ext.py
, hello_wrap.cc
生成されます。
$ swig -c++ -python -cppext cc hello.i
$ ls hello_ext.py hello_wrap.cc
hello_ext.py hello_wrap.cc
④ 動的リンクライブラリを生成する
hello.cc
と hello_wrap.cc
をインプットとして、動的リンクライブラリを生成します。
$ g++ -fPIC -shared hello.cc hello_wrap.cc -o _hello_ext.so -I/usr/include/python3.10
$ ls _hello_ext.so
_hello_ext.so
.so ファイルは hello_ext.py
を介して呼び出されます。
今回のケースでは動的リンクライブラリのファイル名を _hello_ext.so
とする必要があります。
Python.h が見つからない場合
環境によっては、次のように Python.h
が見つからないエラーが発生します。
hello_wrap.cc:178:11: fatal error: Python.h: No such file or directory
178 | # include <Python.h>
| ^~~~~~~~~~
compilation terminated.
g++ の -I/usr/include/python3.10
指定のパスに Python.h
が存在しない可能性があります。
その場合は、find
コマンドで Python.h
を探して、-I
の指定を修正すると良いです。
例えば、次のように python3.8
配下にファイルが存在する場合は -I/usr/include/python3.8
とすると解決するはずです。
$ find /usr -name Python.h
/usr/include/python3.8/Python.h
そもそも find
コマンドで見つからない場合は、事前準備に記載の通り、python3-dev
のインストールを試みるのが良いです。
⑤ Python から hello メソッドを呼び出す
ここまでできたら Python からの呼び出しは簡単です。hello_ext
をインポートして、hello
メソッドを実行します。
import hello_ext
hello_ext.hello()
$ python3 main.py
Hello, world!
なお、hello_ext.py
と _hello_ext.so
の2ファイルは、main.py
と同じディレクトリに配置する必要があります。
コメント