mruby と mgem と rbenv と


久しぶりに mruby の話。

<blockquote class="twitter-tweet" lang="ja"><p>mruby、アブリケーションの配布方法が決まるだけでもだいぶ違う気がするなー。コマンド一発でインストール出来るのあったらツール作り出す人いるんじゃないかな。</p>&mdash; mattn (@mattn_jp) <a href="https://twitter.com/mattn_jp/statuses/506818255877857280">2014, 9月 2</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" lang="ja"><p>アプリケーション配布？ mgem や Rakefile がそれだろ！と断定出来ない所に悔しさがある。 <a href="https://twitter.com/hashtag/mruby?src=hash">#mruby</a></p>&mdash; mattn (@mattn_jp) <a href="https://twitter.com/mattn_jp/statuses/506818801854185472">2014, 9月 2</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" lang="ja"><p>確かにmgemコマンドが進化していない（設定を吐くだけ）ので、そこを改修する必要はありますねぇ</p>&mdash; MATSUMOTO, Ryosuke (@matsumotory) <a href="https://twitter.com/matsumotory/statuses/506819166347620352">2014, 9月 2</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

この辺の話が出てたのを見て自分はどうしてたっけなと思ったので書いておく。

# 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 でこんな感じのことを実行している)

```bash
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 で行う事が出来る。

```bash
rbenv install mruby-dev
```

ところがこれは使うのが厳しい。

なぜかというと、mruby の build 時に build_config.rb を変更することが困難だからである。

何を意味するかというと、rbenv でインストールした mruby には、mgem を入れることが出来ない。

というわけで、ruby-build の bin/ruby-build の build_package_mruby 関数を以下のように変更して使っている。

```bash
  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 はインストール済みとする)

```bash
rbenv global 2.1.2
gem install mgem
mgem add mruby-mysql
rbenv install mruby-dev
rbenv global mruby-dev
```

新しく mruby-uv を入れたいときは次のようにする。

```bash
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 管理はもう少しなんとかなると良いなと思いつつ、自分のあまりベストでは無さそうな解決策を提示した。

更に何か改善できたり、こういうツールがあるよとか、こういうの作ろうよとかあれば教えて欲しい。