SWIGを使ってPythonラッパーを生成する
このエントリではSWIGを使ったPythonラッパーの生成をautomakeでおこなう方法を紹介する。
例えば自然言語処理でよく使われているMeCabやCRFsuiteなどのC++実装にはPythonラッパーが付属していることがある。C++実装を呼び出せるPythonラッパーがあれば、計算量が多くなりやすい機械学習部分だけC++で実装して、他の処理部分はPythonで手軽に書いて運用する、であるとかC++には不慣れであってもPythonなら使ったことがある、というユーザにも利用してもらう、といったことができるようになる。C++ではSWIGを用いて他の言語へのラッパーを生成することができ、MeCabやCRFsuiteなども、SWIGを使ってPythonラッパーを生成している。
またSWIGによるラッパーの生成の手続きは設定が面倒であったりするため、MeCabやCRFsuiteがおこなっているような、automakeで出来るだけ簡略化する作業も調べてまとめる。
目次
利用するツールおよび環境
このエントリでは以下のツールを利用する:
- SWIG (3.0.8)
- gcc-c++ (4.4.7)
- autoconf (2.63)
- automake (1.11.1)
- libtool (2.2.6b)
- Python (3.5.0)
またOSはCentOS release 6.8 (さくらのVPS) を利用する。
C++の実装を作成する
このエントリはC++の実装そのものではなく、C++実装をPythonから使えるようにするための手順に焦点を当てているので、実装はなんでも良いのだけど、ここでは 平均化パーセプトロンの実装を用いる。
SWIGのインターフェースファイルを作成する
インターフェースファイルはSWIGへの入力になる。
インターフェースファイル (例: onlineml.swigcxx) を以下のようにする:
%module onlineml
%include "std_pair.i"
%include "std_string.i"
%include "std_map.i"
%include "std_vector.i"
%{
#define SWIG_FILE_WITH_INIT
#include <onlineml/learner/learner.hpp>
#include <onlineml/learner/perceptron.hpp>
#include <onlineml/common/classifier.hpp>
#include <onlineml/learner/averaged_perceptron.hpp>
%}
%template() std::pair<std::string, float>;
%template(PairVector) std::vector<std::pair<std::string, float> >;
%template(PairVectors) std::vector< std::vector<std::pair<std::string, float> > >;
%template(StringVectors) std::vector<std::string>;
%include <onlineml/learner/learner.hpp>
%include <onlineml/learner/perceptron.hpp>
%include <onlineml/learner/averaged_perceptron.hpp>
%include <onlineml/common/classifier.hpp>
#define SWIG_FILE_WITH_INIT
は出力されるラッパーファイルがPython用の拡張としてビルドされることを指定するマクロ (Running SWIG)%template
はC++で定義されている型をPythonでどう記述するかを指定する (C++ templates)%include
は指定したファイルに記述された関数をインターフェースファイルに挿入する (The %include directive)%{...%}
は生成されるラッパーにそのままコピーされる (Input format)。
生成されるラッパーファイル (例: onlineml_wrap.cxx) の中には以下の様な記述ができる:
#define SWIG_FILE_WITH_INIT
#include <onlineml/learner/learner.h>
#include <onlineml/learner/perceptron.h>
#include <onlineml/learner/averaged_perceptron.h>
#include <onlineml/common/classifier.h>
setup.pyを用意する
setup.pyは以下の様な目的で使うスクリプト (2. setup スクリプトを書く Python 3.5.2 ドキュメント)。
setup スクリプトは、Distutils を使ってモジュールをビルドし、配布し、インストールする際の全ての動作の中心になります。 setup スクリプトの主な目的は、モジュール配布物について Distutils に伝え、モジュール配布を操作するための様々なコマンドを正しく動作させることにあります。
次のようにする:
#!/usr/bin/env python
from distutils.core import setup, Extension
module = Extension('_onlineml',
sources=['onlineml_wrap.cxx'],
extra_compile_args=["-O3"],
language="c++",
)
setup(
name = 'onlineml',
version = "0.1",
author = "Takuya Makino",
description = """online machine learning algorithms""",
ext_modules = [module],
py_modules = ['onlineml'],
)
Makefile.amを作成する
プロジェクトを以下のディレクトリ構成とする:
onlineml
├── Makefile.am
├── configure.ac
├── onlineml
│ ├── common
│ │ ├── classifier.hpp
│ │ ...
│ ├── learner
│ │ ├── learner.hpp
│ │ ...
└── swig
├── Makefile.am
├── onlineml.swigcxx
├── sample.py
└── setup.py
confiugre
時に、--prefix
でインストール場所を指定した場合を想定する。onlineml/Makefile.am
のswigに関わる部分は以下のようにする:
SUBDIRS = swig
python:
cd swig && \
swig -c++ -I../ -python onlineml.swigcxx && \
python setup.py build_ext --inplace --include-dirs=@prefix@/include \
--library-dirs=@prefix@/lib && \
python setup.install && \
cd -
またmake dist
で生成されるパッケージにswigも含まれるように、onlineml/swig/Makefile.am
中で以下のようにEXTRA_DIST
に配布したいスクリプトを含める:
EXTRA_DIST = \
onlineml.swigcxx \
sample.py \
setup.py
インストールする
以上のことを準備すれば、あとは以下のとおりに実行するだけでよい:
./configure
make
make install
make python