#概要
ctypesでextern "C"する http://qiita.com/tibigame/items/da0e50f59fb0b9fac540
のは単純な関数ならいいが、
クラスを拡張していくには不安がある。
そこでpybind11というのを試してみる。
#環境
- Windows7(64bit)
- Anaconda (Python3.6 64bit)
- Microsoft Visual C++ 2015 Community
#準備
- pybind11をgitCloneしてくる。 https://github.com/pybind/pybind11
- includeの中にあるpybind11をフォルダごとAnacondaのincludeにコピーする。
- Visual Studioの追加のインクルード ディレクトリにAnacondaのincludeディレクトリを追加する。
- Visual Studioのリンカ―の追加の依存ファイルにAnaconda3\libs\python36.libを追加する。
- ビルドはx64, Releaseに設定する。
C++コード
ClassTestLib.cpp
#define NOMINMAX
#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include <pybind11/pybind11.h>
namespace py = pybind11;
class ClassTest {
public:
int a;
int *b;
ClassTest() {
}
ClassTest(int X) {
a = X;
b = new int;
*b = X * 2;
}
~ClassTest() {
delete b;
}
int calcA(int add) {
return a + add;
}
int getB() {
return *b;
}
};
PYBIND11_PLUGIN(ClassTestLib) {
py::module m("ClassTestLib", "pybind11 example plugin");
py::class_<ClassTest>(m, "ClassTest")
.def(py::init<const int>())
.def("calcA", &ClassTest::calcA)
.def("getB", &ClassTest::getB);
return m.ptr();
}
###ポイント
この二行を定義しておかないとビルドが止まる。
- #define NOMINMAX
- #define _CRT_SECURE_NO_WARNINGS
共有DLLでMFCを使用するにしないとcmathとかの関数使うと落ちる。
スタティックよりは共有のが若干速い。
class部分は前のコードをそのままコピペしてきた。
Cでexternしてた部分がPYBIND11_PLUGIN('ファイル名')に置き換わった。
ビルド後に「ClassTestLib.dll」を「ClassTestLib.pyd」にリネームして
pythonコードがあるディレクトリにコピーする。
#Pythonコード
classTest.py
import ClassTestLib
x = ClassTestLib.ClassTest(100)
print (x.calcA(10))
print (x.getB())
#結果
110
200
PYBIND11_PLUGINの書き方はイマイチわかっていない。
デストラクタがどうなるのかとか、
複雑な引数、返り値の時にうまく書けるんだろうかという心配はあるが、
ずいぶんとクラスっぽく使えるようになったのでよしとする。