swigメモ。いつか問題が解決するだろうと信じている。 ライブラリって、swigでPythonからも使えるようにするじゃん。このとき、小さいライブラリだと、「ライブラリの名前=モジュールの名前=唯一の構造体の名前」っていうことも珍しくない。例えば"name"だとすると、C側の関数名もname_func1()にするでしょ。こうしたときに、ややこしいから整理すると、
typedef struct name{
int member;
}name;
name *name_init(int id);
void name_exit(name *arg);
int name_func1(name *arg);
int name_func2(name *arg, int arg2);
がname.hで定義されているとする。これをswigのソースname.iで
// swig -python name.i
// gcc -c name_wrap.c -I/usr/include/python2.2 -I.
// gcc -shared name_wrap.o -lname -L. -o _name.so
%module name
%{
#include "name.h"
%}
%include "name.h"
とするとする。使っている側のココロとしては、
if a=name.init(100):
a.func1()
a.func2(1)
だと思う。しかし実際できあがってみると、
if a=name.name_init(100):
name.name_func1(a)
name.name_func2(a, 1)
という悲しい状況になる。これを回避するための方法は%rename
を使う方法である。name.iで
%rename(init) name_init;
%rename(func1) name_func1;
などとしておくと、
if a=name.init(100):
name.func1(a)
name.func2(a, 1)
まではとりあえずあっさりスッキリシャッキリするわけだ。しかしa
というオブジェクト、おまえはどういうつもりなのか。C struct以上の機能はないのか。そこで、name.iにこう書き加える(name構造体がPythonのクラスになったものにメンバを追加する)。
%extend name {
char *__str__(){
static char tmp[10];
snprintf(tmp, sizeof(tmp), "name(%d)", self->member);
return tmp;
}
name(int arg){
return name_init(arg);
}
~name(){
return name_exit(self);
}
int func1(){
return name_func1(self);
}
int func2(int arg){
return name_func2(self, arg);
}
};
しかしですね、これには問題があって、extendの中にあるname::func1()はswigによってname_func1というシンボルになるので、元々のライブラリにあるname_func1()と衝突してしまうのです。どうにかならんかなー。悩ましい。という問題だ。状況説明、長すぎ(笑)。 なんか一発で解決しそうな気がするんだけど、SWIGのドキュメントを漁れば出てくるかな。namespaceとか使えるのかもしれないな。よくわからない。name::func_one()みたいに衝突しないようにするのは邪道か。邪道ですか。