トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

BugTrack-その他のメモ/12

R備忘録 /状態空間モデリング/donlp2/その他のメモ

Python + SWIG

  • 投稿者: みゅ
  • カテゴリ: Python
  • 優先度: 普通
  • 状態: 完了
  • 日時: 2010年01月03日 12時37分56秒

内容

Makefile

  • こんなMakefileを用意
CC=gcc
CFLAGS=-O2
includeDir=/usr/include/python2.5

%_wrap.c : %.i
	swig -python $^

%.o : %.c
	$(CC) $(CFLAGS) -c $^ -I $(includeDir)

_%.so : %.o %_wrap.o
	$(CC) -shared $^ -o $@

19.3 基本的なC/C++ラッピングの概要

19.3.2 関数

  • example.c
int  fact(int n) {
	if (n <= 1) return 1;
	else return n*fact(n-1);
}
  • example.i
%module example
int fact(int n);
  • make、_example.soを作る
$ make _example.so
gcc -O2 -c example.c -I /usr/include/python2.5
swig -python example.i
gcc -O2 -c example_wrap.c -I /usr/include/python2.5
gcc -shared example.o example_wrap.o -o _example.so
/usr/lib/gcc/i486-pc-linux-gnu/4.3.2/../../../../i486-pc-linux-gnu/bin/ld: warni
ng: creating a DT_TEXTREL in object.
  • 動作
$ python
Python 2.5.4 (r254:67916, Jun  8 2009, 13:35:50)
>>> import example
>>> example.fact(4)
24

19.3.3 大域変数

  • example.c
double  My_variable  = 3.0;
double density;

/* Compute factorial of n */
int  fact(int n) {
	if (n <= 1) return 1;
	else return n*fact(n-1);
}
  • example.i
/* File : example.i */
%module example
%{
	/* Put headers and other declarations here */
	extern double My_variable;
	extern double density;
%}
extern double My_variable;
extern double density;
int    fact(int);
  • 「%{」と「%}」の間に入れるのと入れないのとの違いがまだ良くわからない・・・
  • 「extern double My_variable;」と「extern double density;」は両方に書かないと、実行時にエラーが出た.
  • 動作
$ python
>>> import example
>>> print example.fact(4)
24
>>> print example.cvar.My_variable
3.0
>>> example.cvar.density
0.0
>>> example.cvar.density = 0.8442
>>> example.cvar.density
0.84419999999999995
>>> example.cvar.density*1.10
0.92862
>>> example.cvar.density = example.cvar.density*1.10
>>> example.cvar.density
0.92862

19.3.4 定数と列挙数(enums)

  • example.iに以下を追加
#define PI 3.14159
#define VERSION "1.0"

%constant int FOO = 42;
%constant const char *path = "/usr/local";
  • 動作
>>> import example
>>> example.PI
3.1415899999999999
>>> example.VERSION
'1.0'
>>> example.FOO
42
>>> example.path
'/usr/local'
  • 「enum Beverage { ALE, LAGER, STOUT, PILSNER };」は
    • 【引用】列挙数に対しては、列挙の定義が必ずヘッダファイルかラッパーファイルに現れていることを確認すること -- Cコンパイラに何も知らせずにSWIGインターフェース内に列挙数を書き込むと、ラッパーはコンパイルできなくなるのだ。

19.3.6 構造体

  • example.iに以下を追加
%inline %{
struct Vector {
	double x,y,z;
};
%}
  • 動作
>>> import example
>>> v = example.Vector()
>>> v
<example.Vector; proxy of <Swig Object of type 'Vector *' at 0x804df40> >
>>> example.Vector()
<example.Vector; proxy of <Swig Object of type 'Vector *' at 0x80b05b0> >
>>> v.x
0.0
>>> v.y
0.0
>>> v.x = 3.5
>>> v.y = 7.2
>>> print v.x, v.y, v.z
3.5 7.2 0.0

19.7.1 入出力パラメータ

  • example.cに以下を追加
void add(int x, int y, int *result) {
	*result = x + y;
}
int sub(int *x, int *y) {
	return *x-*y;
}
  • example.iに以下を追加
%include "typemaps.i"
void add(int, int, int *OUTPUT);
int  sub(int *INPUT, int *INPUT);
  • 動作
>>> import example
>>> add(3,4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'add' is not defined
>>> example.add(3,4)
7
  • example.iのみに以下を追加してもよさげ
    • inlineのほうが、後に記述されてないとだめっぽい
%include "typemaps.i"
void add(int, int, int *OUTPUT);
int  sub(int *INPUT, int *INPUT);
%inline %{
	void add(int x, int y, int *result) {
		*result = x + y;
	}
	int sub(int *x, int *y) {
		return *x-*y;
	}
%}
  • 動作
>>> import example
>>> example.add(3,4)
7
>>> example.sub(7,4)
3

19.7.3 境界なしC配列

  • example.iに以下を追加
%module example
%{
	・・・
	int sumitems(int *first, int nitems) {
	    int i, sum = 0;
	    for (i = 0; i < nitems; i++) {
	        sum += first[i];
	    }
	    return sum;
	}
%}
・・・
%include "carrays.i"
%array_class(int, intArray);
  • 動作
>>> import example
>>> a = example.intArray(10000000)
>>> for i in xrange(10000):
...     a[i] = i
...
>>> example.sumitems(a,10000)
49995000

19.9.1 Pythonリストからchar **への変換

  • example.iに以下を追加
// SWIGにchar **を特別扱いするように知らせる
%typemap(in) char ** {
  /* リストかどうかチェック */
  if (PyList_Check($input)) {
    int size = PyList_Size($input);
    int i = 0;
    $1 = (char **) malloc((size+1)*sizeof(char *));
    for (i = 0; i < size; i++) {
      PyObject *o = PyList_GetItem($input,i);
      if (PyString_Check(o))
	$1[i] = PyString_AsString(PyList_GetItem($input,i));
      else {
	PyErr_SetString(PyExc_TypeError,"list must contain strings");
	free($1);
	return NULL;
      }
    }
    $1[i] = 0;
  } else {
    PyErr_SetString(PyExc_TypeError,"not a list");
    return NULL;
  }
}

// 関数呼びだしの前にmallocしてあったchar **配列を片付ける
%typemap(freearg) char ** {
  free((char *) $1);
}

// そしてテスト関数
%inline %{
int print_args(char **argv) {
    int i = 0;
    while (argv[i]) {
         printf("argv[%d] = %s\n", i,argv[i]);
         i++;
    }
    return i;
}
%}
  • 動作
>>> import example
>>> print_args(["Dave","Mike","Mary","Jane","John"])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'print_args' is not defined
>>> example.print_args(["Dave","Mike","Mary","Jane","John"])
argv[0] = Dave
argv[1] = Mike
argv[2] = Mary
argv[3] = Jane
argv[4] = John
5

コメント