Python – swig で C++ メソッドを呼び出す

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.cchello_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 と同じディレクトリに配置する必要があります。

  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次