[Scheme] で Web アプリかもしれない

MP3 を管理しようと思い立ったので、まずid3libなるものの Gauche バインディングを作ることを試みようと思います。id3lib は ID3 タグを扱う C++ ライブラリです。使ったこと無いですが。この企画がいつまで続くかも分からないですが。

さて、 Gauche 本体についてくる C++ バインディングのサンプルとして名高い mqueue-cpp の README をお手本に、とにかくやってみることにします。

まずスケルトンを生成するみたいです。多分第二引数がディレクトリ名で、第三引数がモジュール名でしょう。適当につけます。

gauche-package generate id3lib media.id3lib

今回は C++ のライブラリを使うので、コンパイラを特別に指定する必要があるそうです。
C のライブラリであれば、Gaucheコンパイルされたコンパイラを使えば良い(guache-config が知っている)ので、特に設定は要らないっぽい。

=== Makefile.in
==================================================================
--- Makefile.in (revision 1210)
+++ Makefile.in (revision 1211)
@@ -24,6 +24,8 @@
 OBJEXT = @OBJEXT@
 EXEEXT = @EXEEXT@
 
+CXX      = @CXX@
+
 # Module-specific stuff
 PACKAGE   = id3lib
 
@@ -45,7 +47,7 @@
 all : $(TARGET)
 
 id3lib.$(SOEXT): $(id3lib_SRCS)
-       $(GAUCHE_PACKAGE) compile --verbose id3lib $(id3lib_SRCS)
+       $(GAUCHE_PACKAGE) compile cc=$(CXX) --verbose id3lib $(id3lib_SRCS)
 
 check : all
        @rm -f test.log

次に、id3lib_glue.h を作ります。glue は、グルー言語のグルーだと思います。多分つなぎとかそういう意味でしょう。あとで調べるかもしれない。

mqueue_glue.h を参考に、型名等を合わせてそれっぽく書いてみます。

#include <id3/tag.h>

#include <gauche.h>
#include <gauche/extend.h>

SCM_DECL_BEGIN   // start "C" linkage

extern ScmClass *ID3TagClass;

#define ID3LIB_P(obj)      SCM_XTYPEP(obj, ID3TagClass)
#define ID3LIB_UNBOX(obj)  SCM_FOREIGN_POINTER_REF(ID3_Tag*, obj)
#define ID3LIB_BOX(ptr)    Scm_MakeForeignPointer(ID3TagClass, ptr)

extern void Scm_Init_ID3Tag();

SCM_DECL_END

つぎに id3lib_glue.cpp も、同じようにそれっぽく書いてみます。

#include "id3lib_glue.h"

ScmClass *ID3TagClass;

static void id3tag_print(ScmObj obj, ScmPort *out, ScmWriteContext *ctx)
{
  ID3_Tag *tag = ID3LIB_UNBOX(obj);
  /* とりあえずポインタの値を出力しとく */
  Scm_Printf(out, "#<id3tag \"%p\">", tag);
}

static void id3tag_cleanup(ScmObj obj)
{
  ID3_Tag *q;
  q = ID3LIB_UNBOX(obj);
  delete q;
}

extern void Scm_Init_id3lib_lib(ScmModule*);

void Scm_Init_ID3Tag()
{
  ScmModule *mod;

  /* Register this DSO to Gauche */
  SCM_INIT_EXTENSION(id3lib);

  /* Create media.id3lib module */
  mod = SCM_MODULE(SCM_FIND_MODULE("media.id3lib", TRUE));

  ID3TagClass =
    Scm_MakeForeignPointerClass(mod, "<id3tag>",
                                id3tag_print,
                                id3tag_cleanup,
                                SCM_FOREIGN_POINTER_KEEP_IDENTITY|SCM_FOREIGN_POINTER_MAP_NULL);

  /* Initialize stub functions */
  Scm_Init_id3lib_lib(mod);
}

mqueue-cpp の README には、Scm_MakeForeignPointerClass のところを、特に cleanup 手続きについて注意するように書いてあります。GC 関係だと思われますが、とりあえずそんなに気にしないでおくことにします。中のオブジェクトが Scheme 世界と交わらなければ大丈夫なはず。

この部分が非常に謎。

  /* Register this DSO to Gauche */
  SCM_INIT_EXTENSION(id3lib);

stub ファイルがこんな感じ。

;;;
;;; id3liblib.stub
;;;

"
#include \"id3lib_glue.h\"
"

(define-type <id3tag> "ID3_Tag*" "ID3Tag"
  "ID3LIB_P" "ID3LIB_UNBOX" "ID3LIB_BOX")

(define-cproc make-id3tag (name::<const-cstring>)
  (expr <id3tag> "new ID3_Tag(name)"))

(define-cproc id3tag-filename (tag::<id3tag>)
  (expr <const-cstring> "tag->GetFlieName()"))

;; Local variables:
;; mode: scheme
;; end: