gauche拡張モジュールの書き方(C++ライブラリ編)[途中:明日更新する]

c++のライブラリの場合は、以前紹介したものCライブラリの拡張モジュールの書き方と少し違います。opencvの一部の関数のbindingを書く例を参考に、C++ライブラリに対するgaucheの拡張モジュールの書き方を説明してみます。

gauche-cv-subset

今回作るパッケージの名前はgauche-cv-subsetという名前にします。また、graphics.cvというモジュール名でuseするとgauche-cv-subsetで提供された手続きが使えるようにします。

準備

gauche-packageを使って作業ディレクトリを作って作業していきます。

$ gauche-package generate gauche-cv-subset graphics.cv

gauche-packageはライブラリがCであることを前提として働くので、.soの作成にはデフォルトでgccを利用します。
c++のライブラリをコンパイルする際には、g++を利用するよう以下の2つのファイルを書き換えます。

これらは"./DIST gen"を実行する前に行ってください。

configure.acの変更

AC_PROG_CXXという行を追加してください。以下は変更の前後のdiffです。(ちなみに、dnlで始まる行は単なるコメントです)

diff --git a/configure.ac b/configure.ac
index ada52aa..f8d0d52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,6 +33,10 @@ AC_PATH_PROG([GAUCHE_PACKAGE], gauche-package)
 AC_PATH_PROG([GAUCHE_INSTALL], gauche-install)
 AC_PATH_PROG([GAUCHE_CESCONV], gauche-cesconv)
 
+dnl gauche-package doesn't know that the target library is written by C++.
+dnl so We need to use AC_PROG_CXX macro for getting the name of C++ compiler.
+AC_PROG_CXX
+
 dnl Usually these parameters are set by AC_PROG_CC, but we'd rather use
 dnl the same one as Gauche has been compiled with.
 SOEXT=`$GAUCHE_CONFIG --so-suffix`
Makefile.inの変更

Makefile.inの変更は2点あります。CXXにC++コンパイラの名前を格納する箇所と、依存するライブラリの場所を指定する箇所です。
以下が変更後のdiffです。

diff --git a/Makefile.in b/Makefile.in
index c7081a4..cd4923e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -16,6 +16,7 @@ VPATH       = $(srcdir)
 # These may be overridden by make invocators
 DESTDIR        =
 GOSH           = @GOSH@
+CXX            = @CXX@
 GAUCHE_CONFIG  = @GAUCHE_CONFIG@
 GAUCHE_PACKAGE = @GAUCHE_PACKAGE@
 INSTALL        = @GAUCHE_INSTALL@ -C
@@ -47,7 +48,8 @@ gauche_cv_subset_SRCS = $(srcdir)/gauche_cv_subset.c $(srcdir) all : $(TARGET)
 
 gauche_cv_subset.$(SOEXT): $(gauche_cv_subset_SRCS)
-       $(GAUCHE_PACKAGE) compile \
+       $(GAUCHE_PACKAGE) compile --cc=$(CXX)\
+      --libs="`pkg-config --libs opencv`" --cflags="`pkg-config --cflags opencv          --local=$(LOCAL_PATHS) --verbose gauche_cv_subset $(gauche_cv_subset_S 
 check : all

Makefile.inはconfigureで生成されるMakefileの雛型となるファイルです。今回は、"CXX = @CXX@"という記述を加えました。これは上記のconfigure.acに記述したAC_PROG_CXXによってc++のライブラリ名に書き換えられます。結果は、./configureで生成されるMakefileで確認してみてください。また、gauche-packageに渡すオプションも追加しています。

大雑把に言えば、以下のような順でファイルが生成されます。

  1. ./DIST gen
    1. autoconfが呼ばれる。(configure.acを利用)
    2. configureが生成される
  2. ./configure
    1. (Makefile.inを利用)
    2. Makefileが生成される

Makefile.inとconfigure.acを書き換えたら、以前と同様にMakefileを生成しコンパイルしてみてください。

./DIST gen && ./configure && make && gosh -I. test.scm

# ...
#  checking for g++... g++     # g++の存在をcheckしてます
#  checking whether the C++ compiler works... yes
# ...
#                              #--libs,--cc,--cflagsのオプションが渡されてます。g++が使われてます。
#  /usr/bin/gauche-package compile --cc=g++\ 	
#        --libs="`pkg-config --libs opencv`" --cflags="`pkg-config --cflags opencv`" \
#        --local= --verbose gauche_cv_subset ./gauche_cv_subset.c ./gauche_cv_subsetlib.stub
#  g++ -c  -I/usr/lib/gauche/0.9/include -I/usr/include/opencv   -fPIC -o 'gauche_cv_subset.o' './gauche_cv_subset.c'
# ...

おそらく以下のようなエラーがでます。

Testing graphics.cv ...                                          
gosh: "error": Compile Error: dynamic linking of ./gauche_cv_subset.so failed: couldn't find initialization function _Scm_Init_gauche_cv_subset
"./test.scm":8:(use graphics.cv)

Scm_Init_gauche_cv_subsetが見つからないと言われています。.hに追加して見えるようにしましょう。他にも色々と忘れていたことがありました。

  • Scm_Init_gauche_cv_subsetのプロトタイプ宣言を追加(.h)
  • 拡張子を.cから.cppにする
  • 依存するライブラリをincludeする(.stub)

忘れてた作業を行いましょう。.cのファイルを.cppに変えて、ファイルに変更を加えます。

$ for i in *.c; do mv $i $(i%.c).cpp; done
$ vi gauche_cv_subsetlib.stub  # includeを追加
$ vi gauche_cv_subset.h        # プロトタイプ宣言を追加
$ vi Makefile.in               # .cを.cppに直す

変更後のdiffは以下です。

diff --git a/gauche_cv_subset.h b/gauche_cv_subset.h
index cf51e82..0afb4df 100644
--- a/gauche_cv_subset.h
+++ b/gauche_cv_subset.h
@@ -18,6 +18,8 @@ SCM_DECL_BEGIN
 
 extern ScmObj test_gauche_cv_subset(void);
 
+extern void Scm_Init_gauche_cv_subset(void);
+
 /* Epilogue */
 SCM_DECL_END
 
diff --git a/gauche_cv_subsetlib.stub b/gauche_cv_subsetlib.stub
index 22d28ef..cc9b7a2 100644
--- a/gauche_cv_subsetlib.stub
+++ b/gauche_cv_subsetlib.stub
@@ -3,6 +3,8 @@
 ;;;
 
 "
+#include <cvaux.h>
+#include <highgui.h>
 #include \"gauche_cv_subset.h\"
 "

今度はテストが通ります。

$ make clean && make && gosh -I. test.scm
#   Testing graphics.cv ...                                          
#   testing bindings in #<module graphics.cv> ... ok
#   test test-gauche_cv_subset, expects "gauche_cv_subset is working" ==> ok
#   passed.