gymnoの自由談

音楽系、プログラミング系の内容 方針はいずれ

swigで pythonとc++連携

pythonjavaが遅いのなら その部分だけ別の言語で書けばよいではないか という拡張の話

参考にしたページは以下
SWIG and Python
http://www.swig.org/Doc1.3/Python.html

distutils with boost.python - おびなたん☆
http://d.hatena.ne.jp/earth2001y/20070611/p1

C++Pythonのコラボレーション ― PythonMatrixJp
http://python.matrix.jp/tips/cpp_extension/

nesugi.net - swigの使い方のメモ書き
http://www.nesugi.net/hiki/?swig%A4%CE%BB%C8%A4%A4%CA%FD%A4%CE%A5%E1%A5%E2%BD%F1%A4%AD


手順は以下
hello.cpp, hello.h hello.i setup.pyを用意する

swig -c++ -python hello.i


hello_wrap.cxx とhello.pyが生成される

python setup.py build_ext --inplace

c++プログラムがビルドされ 
カレントディレクトリに_hello.soが 
また build/temp.macosx-10.6-universal-2.6/以下に
hello.oとhello_wrap.o
が生成される

>>> import hello
>>> dir(hello)
['MyClass', 'MyClass_swigregister', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_hello', '_newclass', '_object', '_swig_getattr', '_swig_property', '_swig_repr', '_swig_setattr', '_swig_setattr_nondynamic', 'get_sine', 'hello', 'new', 'new_instancemethod', 'sum']
>>> hello.hello()
Hello World!!
>>> a=hello.sum(5)
>>> a
10
>>> a=hello.MyClass("this is a class.")
>>> a
<hello.MyClass; proxy of <Swig Object of type 'MyClass *' at 0x21efa0> >
>>> dir(a)
['__class__', '__del__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattr__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__swig_destroy__', '__swig_getmethods__', '__swig_setmethods__', '__weakref__', 'a', 'clear', 'name', 'set_a', 'set_name', 'size', 'this']
>>> a.name()
'this is a class.'
>>> a.set_name("we are the world")
>>> a.name()
'we are the world'

ということで クラスやSTLもきちんと使える
hello.cppをいじったらリビルドするだけでなくpythonは再起動しなければならない
reloadしても中身が更新されないので注意


hello.cpp

#include "hello.h"
#include <cstdio>
#include <cmath>

void hello(void)
{
  printf("Hello World!!\n");
}

int sum(int d) {
  int ret=0;
  for (int i=0;i<d;++i) {
    ret += i;
  }
  return ret;
}

double get_sine(int size) {
  const double width = 2 * M_PI/(double)size;
  printf("size = %d, width = %e\n",size,width);
  double sum = 0.0;
  for (int i=0;i<size;++i) {
    double x = i * width;
    sum += sin(x);
  }
  return sum;
}


MyClass::MyClass(const std::string& name) : a_(0),name_(name) 
{
}

void MyClass::set_a(int a) {
  a_.push_back(a);
}

int MyClass::a(int d) const {
  if (d>=a_.size()) {
    return 0;
  }
  return a_[d];
}

void MyClass::clear() {
  a_.clear();
}

int MyClass::size() const {
  return a_.size();
}

hello.h

#include <vector>
#include <string>

class MyClass {
 public:
  MyClass(const std::string& name);
  void set_a(int a);
  int a(int d) const;
  void clear();
  int size() const;
  void set_name(const std::string& name) { name_= name;}
  const char*  name() const {return name_.c_str();}
 private:
  std::vector<int> a_;
  std::string name_;
};

hello.i

%module hello
%include "std_string.i"

%{
void hello(void);
int sum(int d);
double get_sine(int size);
#include "hello.h"
%}


void hello(void);
int sum(int d);
double get_sine(int size);
%include "hello.h"

setup.py

%module hello
%include "std_string.i"

%{
void hello(void);
int sum(int d);
int sum2(int d);
double get_sine(int size);
#include "hello.h"
%}


void hello(void);
int sum(int d);
int sum2(int d);
double get_sine(int size);
%include "hello.h"