emruby: emscripten でブラウザで動く MRI

(この記事は Ruby 25th anniversary のための寄稿です)

Ruby をブラウザで動かすというと Opal ですが、他の選択肢として、C で書かれた Ruby 処理系を emscripten で JS に変換するという選択肢もあります。
しかし調べてみたところ、mruby を WebAssembly に変換した記録は見つかりましたが、MRI でやった例が見つけられなかったので、やってみました。

手順

https://github.com/mame/emruby/ に書いてあるとおりです。

ビルドコマンドは次の通り。

$ emconfigure ./configure CFLAGS="-m32 -s EMULATE_FUNCTION_POINTER_CASTS=1"
$ emmake make V=1 miniruby.js EXEEXT=.js

emconfigure は emscriptenコンパイラとして使う前提で configure を動かすためのラッパ。しかしあまり出来はよくなくて、64 bit 環境で動かすと SIZEOF_LONG が 8 と推定されてしまった(JS 上で sizeof(long) は 4 になるので食い違う)ので、手動で "-m32" を与えています。そのため -m32 でコンパイルできる環境が必要で、ubuntu なら apt-get install libc6-dev-i386 などする必要があります。
また、MRI は関数ポインタについてあまり行儀がよくない(3 引数の関数に 4 つの引数を渡すとかがそこらじゅうにある)ので、"-s EMULATE_FUNCTION_POINTER_CASTS=1" を与える必要があります(参考:emscripten の Function Pointer Issues)。
emmake は make のラッパ。単に miniruby.js を生成するだけです。

所感など

  • 動作するまでに細かい問題がいくつかありましたが、Ruby 側を少しだけいじって対応しました(変更 1変更 2変更 3)。Ruby が公式に emscripten に対応するのは難しそうな印象ですが、本体に無害なパッチならこっそり取り込めると思うので、プルリクお願いします。
  • Kernel#emscripten_run_script を生やしています。(パッチ)
  • miniruby ではなく ruby が動かしたい。(プルリクウェルカム)
  • ファイルシステムを調べて irb くらい動くようにしたい。(プルリクウェルカム)
  • Run ボタンが一回しか押せない。プロセス再実行する方法が見つけられなかった。
  • miniruby.js が 29 MB もある。WebAssembly だと 5 MB くらいになるようですが、Chrome で素直に動かなかったのでよく見ていません。
  • WebAssembly で Ruby が Web フロントエンド市場に(今度こそ)進出できるといいなあ。Opal は JS に合わせて Ruby の仕様を歪めてるのがあんまり好きじゃなくて、emscripten/WebAssembly なら幸せになるかと思ったけど、まだよくわかりません。