全文検索エンジンGroongaはmrubyを組み込んでいます。理由は、速度はそれほど必要ではなく込み入った処理をCではなくRubyで書けると開発が捗るからです。
この記事ではどのようにmrubyを組み込んでいるかについてビルド周りだけを説明します。(ビルド周り以外には、バインディングをどうやって書くか、.rb
ファイルをどこに置くか、実装をCにするかRubyにするかの判断基準などの話があります。)
方針
mrubyはRakeを使ったビルドシステムを使っています。GroongaはGNU AutotoolsまたはCMakeを使ったビルドシステムを使っています。(どちらでもビルドできます。)
mrubyはRakeを使ってビルド、GroongaはGNU Autotoolsを使ってビルド、とするとコンパイルオプションの統一・クロスコンパイルあたりで面倒になります。また、Rakeを使ってビルドするためにはビルド時にRubyが必要になるのも面倒です。Groongaの開発者がGroongaをビルドするためにRubyが必要になるのはよいですが、GroongaのユーザーがGroongaをビルドするためにRubyが必要になるのはビルドの敷居が上がるのでできれば避けたいです。
以上の理由からGroongaではmrubyをビルドするためにRakeを使っていません。
ではどうしているかというと、次のようにしています。
-
Groonga開発者はRakeを使って(= Rubyが必要)mrubyのビルドに必要なファイルを生成(一部自動生成のファイルがあるため)
-
Groongaはmrubyのビルドに必要なファイルをGNU Autotools(またはCMake)を使ったビルドシステムに統合(= mrubyのビルドにRakeを使っていない = Rubyは必要ない)
-
Groonga開発者はリリース版のソースアーカイブに1.で生成したファイルをすべて含める(= Groongaユーザーは1.を実行する必要がない = Rubyは必要ない)
それぞれどのようにしているか説明します。
Groongaの開発者はRakeを使ってmrubyのビルドに必要なファイルを生成
Groongaはvendor/mruby-source
をGitのsubmoduleにしています。つまり、mrubyのリポジトリーのソースをまるっと参照しています。
この状態ではmrubyのビルドに必要なファイルは足りません。具体的にはRubyで実装されたコードをmrubyに組み込むファイル(mrblib.c
。mrbc -B
で生成するファイル。)や利用するmrbgemsを組み込むファイル(mrbgems_init.c
)が足りません。
これらを生成するためにRakeを使ってビルドします。出力先はvendor/mruby-build/
にしています。ビルドした後vendor/mruby-build/
に出力されたファイルの中から必要なファイルをvendor/mruby/
にコピーします。vendor/mruby-build/
を直接ビルドに使って「いません」。ビルドに使っているのはvendor/mruby/
にコピーしたファイルです。このあたりの実装がvendor/mruby/mruby_build.rb
です。
Groongaはmrubyのビルドに必要なファイルをGNU Autotools(またはCMake)を使ったビルドシステムに統合
必要なファイルが揃ったらGNU Autotools(またはCMake)のビルドシステムに統合することは難しくありません。
GNU Autotoolsの場合はvendor/mruby/Makefile.am
で実現しています。
CMakeの場合はvendor/mruby/CMakeLists.txt
で実現しています。
工夫しているところはソースファイルのリストを共有しているところくらいです。mruby本体やmrbgemsが更新されるとソースファイルのリストは変わることがあるのでvendor/mruby/update.rb
で自動生成しています。Makefile.am
とCMakeLists.txt
では自動生成されたリストを読み込んでビルドシステムに統合しています。
Groonga開発者はリリース版のソースアーカイブに生成したファイルをすべて含める
mrubyをRakeでビルドして生成されたファイルをソースアーカイブに含めることでGroongaユーザーはビルドするときにRubyがなくてもビルドできます。
ソースアーカイブには生成されたファイルといつ生成されたかを示すタイムスタンプファイルを入れています。タイムスタンプファイルが新しければ再生成(mrubyをRakeでビルドし直すこと)せずにすでにあるファイルを使うようにしています。こうすることでソースアーカイブからビルドするGroongaユーザーはRubyがなくてもビルドできるようになっています。
実現方法のポイントはvendor/mruby/Makefile.am
でBUILT_SOURCES
をlibmruby_la_SOURCES
に追加しているところとmruby_build.timestamp
があったら再生成しないようにしているところです。
libmruby_la_SOURCES += $(BUILT_SOURCES)
mrblib.c: mruby_build.timestamp
mrbgems_init.c: mruby_build.timestamp
# ...
mruby_build.timestamp: build_config.rb version
# ...
まとめ
Groongaがどうやってmrubyを組み込んでいるかについてビルド周りだけを説明しました。
Groongaのmruby組み込み周りを触る人や自分のアプリケーションにmrubyを組み込みたい人は参考にしてください。