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()みたいに衝突しないようにするのは邪道か。邪道ですか。