KyotoCabinetのRubyバインディングがFreeBSDで使えなくなった

% wget http://fallabs.com/kyotocabinet/rubypkg/kyotocabinet-ruby-1.32.tar.gz
% tar xf kyotocabinet-ruby-1.32.tar.gz
% cd kyotocabinet-ruby-1.32
% ruby extconf.rb
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
setting variables ...
  $CFLAGS = -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2
  $LDFLAGS = -L.  -Wl,-rpath,/usr/lib:/usr/local/lib -fstack-protector -rdynamic -L. -L/usr/local/lib
  $libs =  -lkyotocabinet -lz -lrt -lpthread -lm -lc
checking for kccommon.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

kcommon.hが無いのか.

 % locate kccommon.h
/usr/local/include/kccommon.h
/usr/ports/databases/kyotocabinet/files/patch-kccommon.h

いや,あるだろ.
ログを見てみる.

% cat mkmf.log 
have_header: checking for kccommon.h... -------------------- no

"cc -o conftest -I/usr/local/include/ruby-2.1//amd64-freebsd10 -I/usr/local/include/ruby-2.1//ruby/backward -I/usr/local/include/ruby-2.1/ -I. -I/usr/local/include   -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2 conftest.c  -L. -L/usr/local/lib -L.  -Wl,-rpath,/usr/lib:/usr/local/lib -fstack-protector -rdynamic -L. -L/usr/local/lib     -lkyotocabinet -lz -lrt -lpthread -lm -lc -lruby21  -lexecinfo -lcrypt -lm -L/usr/local/lib -pthread  -lc"
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: int main(int argc, char **argv)
4: {
5:   return 0;
6: }
/* end */

"g++ -E -I/usr/local/include/ruby-2.1//amd64-freebsd10 -I/usr/local/include/ruby-2.1//ruby/backward -I/usr/local/include/ruby-2.1/ -I. -I/usr/local/include   -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2  conftest.c -o conftest.i"
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: #include <kccommon.h>
/* end */

問題が無いように見える.ダミーのファイルを作ってみる.

% echo '#include <kccommon.h>' > conftest.c
% g++ conftest.c
g++: コマンドが見つかりません.

ん?!

% ls -l /usr/{bin,local/bin}/g++*
-r-xr-xr-x  4 root  wheel  550816  3月 14 10:58 /usr/local/bin/g++47

オーマイガッ.

ハードリンクにする.

# ln -v /usr/local/bin/g++47 /usr/local/bin/g++
/usr/local/bin/g++ => /usr/local/bin/g++47

再チャレンジ.

% ruby extconf.rb
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
setting variables ...
  $CFLAGS = -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2
  $LDFLAGS = -L.  -Wl,-rpath,/usr/lib:/usr/local/lib -fstack-protector -rdynamic -L. -L/usr/local/lib
  $libs =  -lkyotocabinet -lz -lrt -lpthread -lm -lc
checking for kccommon.h... yes
creating Makefile

警告は無視.

 % make
compiling kyotocabinet.cc
kyotocabinet.cc:602:5: warning: 'rb_thread_blocking_region' is deprecated [-Wdeprecated-declarations]
    rb_thread_blocking_region(execute_impl, func, RUBY_UBF_IO, NULL);
    ^
/usr/local/include/ruby-2.1/ruby/intern.h:870:18: note: 'rb_thread_blocking_region' declared here
DEPRECATED(VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1,
                 ^
/usr/local/include/ruby-2.1//amd64-freebsd10/ruby/config.h:115:52: note: expanded from macro 'DEPRECATED'
#define DEPRECATED(x) __attribute__ ((deprecated)) x
                                                   ^
kyotocabinet.cc:2185:20: error: no member named 'ruby_close' in 'kyotocabinet::PolyDB'
        rv_ = db_->close();
              ~~~  ^
/usr/local/include/ruby-2.1/ruby/subst.h:17:15: note: expanded from macro 'close'
#define close ruby_close
              ^
kyotocabinet.cc:2195:14: error: no member named 'ruby_close' in 'kyotocabinet::PolyDB'
    rv = db->close();
         ~~  ^
/usr/local/include/ruby-2.1/ruby/subst.h:17:15: note: expanded from macro 'close'
#define close ruby_close
              ^
1 warning and 2 errors generated.
*** Error code 1

ショボン.

こいつだけ倒せばなんとかなるような気がする.

kyotocabinet.cc:2185:20: error: no member named 'ruby_close' in 'kyotocabinet::PolyDB'

エラーはここ.

rv_ = db_->close();

db_はこう定義されてる感じ.

kc::PolyDB* db;

PolyDBは/usr/local/include/kcpolydb.hで定義されているクラスなので,close()はそのインスタンスのメッソッドが呼ばれている.
ところでエラーで出ている,ruby_closeというのは,KyotoCabinetのインクルードファイルの中には確かに出てこない.

% grep ruby_close /usr/local/include/* 
%

ruby_closeでググると,似たようなことで悩んでいるっぽい人がいた.
なぜか数学者にはワイン好きが多い

自分だ...

/usr/local/include/ruby-2.1/ruby/ruby.hが原因らしい.
そう言われてみると,コンパイル時のエラーメッセージで出ていたね.note,って.

/usr/local/include/ruby-2.1/ruby/subst.h:17:15: note: expanded from macro 'close'
#define close ruby_close

ちょっと追ってみれば分かることで,

バカにされた気がするが気にせず,指摘のとおりに直して再チャレンジ.

% ruby extconf.rb
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
extconf.rb:18:in `<main>': Use RbConfig instead of obsolete and deprecated Config.
setting variables ...
  $CFLAGS = -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2 -DRUBY_DONT_SUBST
  $LDFLAGS = -L.  -Wl,-rpath,/usr/lib:/usr/local/lib -fstack-protector -rdynamic -L. -L/usr/local/lib
  $libs =  -lkyotocabinet -lz -lrt -lpthread -lm -lc
checking for kccommon.h... yes
creating Makefile
% make
compiling kyotocabinet.cc
kyotocabinet.cc:602:5: warning: 'rb_thread_blocking_region' is deprecated [-Wdeprecated-declarations]
    rb_thread_blocking_region(execute_impl, func, RUBY_UBF_IO, NULL);
    ^
/usr/local/include/ruby-2.1/ruby/intern.h:870:18: note: 'rb_thread_blocking_region' declared here
DEPRECATED(VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1,
                 ^
/usr/local/include/ruby-2.1//amd64-freebsd10/ruby/config.h:115:52: note: expanded from macro 'DEPRECATED'
#define DEPRECATED(x) __attribute__ ((deprecated)) x
                                                   ^
kyotocabinet.cc:2185:20: error: no member named 'ruby_close' in 'kyotocabinet::PolyDB'
        rv_ = db_->close();
              ~~~  ^
/usr/local/include/ruby-2.1/ruby/subst.h:17:15: note: expanded from macro 'close'
#define close ruby_close
              ^
kyotocabinet.cc:2195:14: error: no member named 'ruby_close' in 'kyotocabinet::PolyDB'
    rv = db->close();
         ~~  ^
/usr/local/include/ruby-2.1/ruby/subst.h:17:15: note: expanded from macro 'close'
#define close ruby_close
              ^
1 warning and 2 errors generated.
*** Error code 1

ダメだよ.変わらないよ.
Makefileの中を見ていて,

CFLAGS   = $(CCDLFLAGS) -I. -I/usr/local/include -Wall -O2 -pipe -fno-strict-aliasing -fPIC -O2 -DRUBY_DONT_SUBST $(ARCH_FLAG)
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
DEFS     = 
CPPFLAGS = -DHAVE_KCCOMMON_H -I/usr/local/include $(DEFS) $(cppflags)

ひょっとしてkyotocabinet.ccは,さっきのg++が使われていて,CPPFLAGSにも手をいれないとダメな気がしてきたよ.

emacs Makefile

CPPFLAGS = -DHAVE_KCCOMMON_H -I/usr/local/include $(DEFS) $(cppflags)
↓
CPPFLAGS = -DHAVE_KCCOMMON_H -I/usr/local/include $(DEFS) $(cppflags) -DRUBY_DONT_SUBST

不屈の再チャレンジ.

% make
compiling kyotocabinet.cc
kyotocabinet.cc:602:5: warning: 'rb_thread_blocking_region' is deprecated [-Wdeprecated-declarations]
    rb_thread_blocking_region(execute_impl, func, RUBY_UBF_IO, NULL);
    ^
/usr/local/include/ruby-2.1/ruby/intern.h:870:18: note: 'rb_thread_blocking_region' declared here
DEPRECATED(VALUE rb_thread_blocking_region(rb_blocking_function_t *func, void *data1,
                 ^
/usr/local/include/ruby-2.1//amd64-freebsd10/ruby/config.h:115:52: note: expanded from macro 'DEPRECATED'
#define DEPRECATED(x) __attribute__ ((deprecated)) x
                                                   ^
1 warning generated.
linking shared-object kyotocabinet.so

イケたよ.

# make install
/usr/bin/install -c -o root -g wheel -m 0755 kyotocabinet.so /usr/local/lib/ruby/site_ruby/2.1/amd64-freebsd10
installing default kyotocabinet libraries

テストをする.

% ruby -e 'require "kyotocabinet"; db = KyotoCabinet::DB::new; db.open("test.kch"); db["key1"] = "val1"; db.close()'                           
% kcpolymgr list -pv test.kch 
key1    val1

いい感じ.