QDBMのrubygem化

ラズパイの32bit環境で2GB超のデータベースを扱えるアプリケーション組み込み型のKVS(Key-Value Store)を使いたかったので、QDBMをgem化してみた。

経緯

ラズパイ上でGDBMを使ってアプリケーションを動かしていたが、データベースファイルのサイズが2Gバイトを超えてエラーになってしまった。2Gバイト超を扱えるKVSに移行しようと探してみたらQDBMのcuriaが使えそうだった。アプリケーションはRubyで作っているのでbundlerで管理したいが、Ruby拡張ライブラリのdebパッケージはあるもののgemはなかった。なのでgem化してみた。

準備

QDBMの開発パッケージ(libqdbm-dev, qdbm-util, qdbm-doc)をOSにインストールする。 管理のためAnsibleでインストールした。

ステップ1

Debパッケージのソースコードをダウンロードする。

admin@5409c2159082:~/tmp$ apt source ruby-qdbm
Reading package lists... Done
Picking 'qdbm' as source package instead of 'ruby-qdbm'
NOTICE: 'qdbm' packaging is maintained in the 'Git' version control system at:
git://anonscm.debian.org/collab-maint/qdbm.git
Please use:
git clone git://anonscm.debian.org/collab-maint/qdbm.git
to retrieve the latest (possibly unreleased) updates to the package.
Need to get 1035 kB of source archives.
Get:1 http://archive.ubuntu.com/ubuntu bionic/universe qdbm 1.8.78-6.1ubuntu2 (dsc) [2299 B]
Get:2 http://archive.ubuntu.com/ubuntu bionic/universe qdbm 1.8.78-6.1ubuntu2 (tar) [1015 kB]
Get:3 http://archive.ubuntu.com/ubuntu bionic/universe qdbm 1.8.78-6.1ubuntu2 (diff) [17.2 kB]
Fetched 1035 kB in 7s (157 kB/s)
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = (unset),
        LC_ALL = (unset),
        LC_TIME = "C",
        LANG = "ja_JP.UTF-8"
    are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C").
dpkg-source: info: extracting qdbm in qdbm-1.8.78
dpkg-source: info: unpacking qdbm_1.8.78.orig.tar.gz
dpkg-source: info: unpacking qdbm_1.8.78-6.1ubuntu2.debian.tar.xz
dpkg-source: info: applying qdbm-pkgconfig
dpkg-source: info: applying qdbm-header-path
dpkg-source: info: applying qdbm-ruby-compat
dpkg-source: info: applying qdbm-man
dpkg-source: info: applying qdbm-split-gdbm-wrapper
dpkg-source: info: applying qdbm-hurd-compat
dpkg-source: info: applying qdbm-perl-vendor
dpkg-source: info: applying O1-opt.diff
admin@5409c2159082:~/tmp$ ls -l
total 1020
drwxrwxr-x 14 admin admin    4096 Nov 11 12:57 qdbm-1.8.78
-rw-r--r--  1 admin admin   17216 Mar  1  2018 qdbm_1.8.78-6.1ubuntu2.debian.tar.xz
-rw-r--r--  1 admin admin    2299 Mar  1  2018 qdbm_1.8.78-6.1ubuntu2.dsc
-rw-r--r--  1 admin admin 1015429 Nov 11  2011 qdbm_1.8.78.orig.tar.gz

QDBM元のソースコードに付属しているRuby拡張ライブラリは古すぎて今のRubyではコンパイルできないのだが、apt sourceでダウンロードするとDebianのパッチ適用済みで、今のRubyコンパイルできるようになっている。

ちなみにパッチはqdbm_1.8.78-6.1ubuntu2.debian.tar.xzに入っている。

admin@5409c2159082:~/tmp$ tar tvf qdbm_1.8.78-6.1ubuntu2.debian.tar.xz debian/patches/qdbm-ruby-compat
-rw-r--r-- 0/0           12223 2014-06-19 14:09 debian/patches/qdbm-ruby-compat
admin@5409c2159082:~/tmp$

ステップ2

Ruby拡張ライブラリのソースコードだけを取り出す。

admin@5409c2159082:~/tmp$ mv qdbm-1.8.78/ruby ruby-qdbm

マニュアルでコンパイルしてみるとエラーになってしまった。

admin@5409c2159082:~/tmp$ cd ruby-qdbm/curia/
admin@5409c2159082:~/tmp/ruby-qdbm/curia$ ruby extconf.rb
checking for main() in -lc... yes
checking for main() in -lpthread... yes
checking for main() in -lz... yes
checking for main() in -lbz2... no
checking for main() in -llzo2... no
checking for main() in -liconv... no
checking for main() in -lqdbm... yes
creating Makefile
admin@5409c2159082:~/tmp/ruby-qdbm/curia$ make V=1
gcc -I. -I/usr/local/include/ruby-2.5.0/x86_64-linux -I/usr/local/include/ruby-2.5.0/ruby/backward -I/usr/local/include/ruby-2.5.0 -I.   -fPIC -I. -I../.. -I/home/admin/include -I/usr/local/include  -o mod_curia.o -c mod_curia.c
mod_curia.c:18:10: fatal error: depot.h: No such file or directory
 #include <depot.h>
          ^~~~~~~~~
compilation terminated.
Makefile:248: recipe for target 'mod_curia.o' failed
make: *** [mod_curia.o] Error 1
admin@5409c2159082:~/tmp/ruby-qdbm/curia$

ステップ3

エラーの原因を調べたらコンパイルオプションの-I../..が元のソースツリーに依存していることが判明。OSのライブラリを使えるようにpkg-configで置き換えた。

pkg-config qdbm · y10k/ruby-qdbm@183eba8 · GitHub

ステップ4

コンパイルできるようになったので、gemspecを書いたりRakefileを書いたりディレクトリ構成を見直したりしてgem化し、githubに登録した。 ちなみにC拡張ライブラリのコンパイルrake-compilerというgemを使った。 あとQDBMのテストケースのバグを直したりとか、こまごまといじったりしてるので、詳細はgithub参照。

github.com