Skip to main content

ログ取得ツール (移転先予定地)

名前の問題

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