久しぶりに mruby の話。
mruby、アブリケーションの配布方法が決まるだけでもだいぶ違う気がするなー。コマンド一発でインストール出来るのあったらツール作り出す人いるんじゃないかな。
— mattn (@mattn_jp) 2014, 9月 2
アプリケーション配布? mgem や Rakefile がそれだろ!と断定出来ない所に悔しさがある。 #mruby
— mattn (@mattn_jp) 2014, 9月 2
確かにmgemコマンドが進化していない(設定を吐くだけ)ので、そこを改修する必要はありますねぇ
— MATSUMOTO, Ryosuke (@matsumotory) 2014, 9月 2
この辺の話が出てたのを見て自分はどうしてたっけなと思ったので書いておく。
TL;DR
mruby のライブラリ管理ツールの mgem を使う時に、rbenv と組み合わせて楽をしてみたという話。
mgem
語弊を恐れず簡単に言うと、CRuby の gem に対応するものが、mruby の mgem である。
サードパーティのライブラリをインストール出来るという点ではほぼ同じであるものの、色々違いがある。
CRuby での gem の使い方はみんな知ってると思うので特に書いたりしない。
mgem は、CRuby の gem と違い、コマンドを実行しただけでライブラリをインストールできるものではない。
mruby は、その言語特性上、ライブラリのほとんどが C 拡張を含むものである。
C 拡張を含むライブラリをインストールする際には、mruby 自体の rebuild を実行する必要がある。
mruby をいじったことのある人でないと、何を言っているのかわからないかもしれないので例を示しておく。
MySQL ライブラリのインストール
CRuby の場合
CRuby では gem を使用して次のようにすれば入る。(もろもろの依存関係などはもちろん解決する必要がある)
gem install mysql2
mruby の場合
ところが mruby だとこうは行かない。
/usr/local/mruby 配下に mruby のソースコードが存在する場合を考える。
更に、CRuby がインストール済みであり、更に gem install mgem
が実施されているとする。
mgem add mruby-mysql
この先に更に作業がある。
cd /usr/local/mruby
mgem config default > build_config.rb
ruby ./minirake
(./bin に生成される mruby 実行ファイルのパスを通したりする...)
これは大変面倒であるような気がする。
コマンドにして数個増えただけ、と感じるかもしれないが、何度も繰り返したり、何個も mgem を入れようとするとどんどん面倒になってくる。
そう、冒頭にもあったとおり、mgem は build_config.rb を生成してくれるだけのもので、その先のことは自分でやらなければならない。
mruby に慣れ親しんだ人には苦ではないが、始めて触る人には確実に辛い作業だと思う。
どうしていたか
mruby を build するためには CRuby が必要なのだが、いつも rbenv + ruby-build を使ってインストールし、管理していた。
いつもこんなかんじでシステムワイドに rbenv + ruby-build を入れている。
(本当は ansible の playbook でこんな感じのことを実行している)
git clone git://github.com/sstephenson/rbenv.git /usr/local/rbenv
git clone git://github.com/sstephenson/ruby-build.git /usr/local/rbenv/plugins/ruby-build
cat << 'EOF' > /etc/profile.d/rbenv.sh
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"
EOF
exec ${SHELL} -l
ところで、rbenv + ruby-build は mruby のインストールと環境切り替えもサポートしている。
なので、rbenv + ruby-build を入れると、mruby のインストールも rbenv で行う事が出来る。
rbenv install mruby-dev
ところがこれは使うのが厳しい。
なぜかというと、mruby の build 時に build_config.rb を変更することが困難だからである。
何を意味するかというと、rbenv でインストールした mruby には、mgem を入れることが出来ない。
というわけで、ruby-build の bin/ruby-build の build_package_mruby 関数を以下のように変更して使っている。
build_package_mruby() {
local package_name="$1"
- { rake
+ { type mgem &>/dev/null && mgem config default > build_config.rb
+ rake
mkdir -p "$PREFIX_PATH"
cp -fR build/host/* "$PREFIX_PATH"
cd "$PREFIX_PATH/bin"
( https://github.com/rrreeeyyy/ruby-build/commit/1c6569e4bc8bbaca54f6056f3a0a4b221d6b3f72 )
build の前に、mgem の有無を確認し、存在すれば build_config.rb を mgem config default
の結果で置き換えてるだけである。
あんまり良いとは思わないが、マシではある、というだけの解決策だった。
例えば MySQL ライブラリのインストール手順は以下のようになる。
(rbenv, ruby-build, CRuby 2.1.2 はインストール済みとする)
rbenv global 2.1.2
gem install mgem
mgem add mruby-mysql
rbenv install mruby-dev
rbenv global mruby-dev
新しく mruby-uv を入れたいときは次のようにする。
rbenv global 2.1.2
mgem add mruby-uv
rbenv install mruby-dev
rbenv global mruby-dev
このようにすることで、既存の手順よりはやや楽をしていた。
本当は確か mgem コマンドをラップしたシェルスクリプトを用意して、
mgem コマンドが呼び出された場合、rbenv の global を適当な CRuby に変更し、
その上で mgem add $1 を実行し、rbenv install mruby-dev まで自動で行うようにしていた記憶がある。
これは気が向いたら載せようと思う。
何がいいたいか
アプリケーションを作ったり、配布したりするときは、インストールの敷居が限りなく、限りなく低いほうがはるかに良い。
ということで、mruby の gem 管理はもう少しなんとかなると良いなと思いつつ、自分のあまりベストでは無さそうな解決策を提示した。
更に何か改善できたり、こういうツールがあるよとか、こういうの作ろうよとかあれば教えて欲しい。