この広告は、90日以上更新していないブログに表示しています。
何に使うわけでもないけど、とにかくブラウザでRuby を動かしたかったんです。
その夢が、ついにかなった気がします。
長年の念願だったEmscripten と xterm.js でブラウザでirb を動かすやつがついに(一応)できたhttps://t.co/ubentOzj7p
— Yusuke Endoh (@mametter)2024年1月27日
振り返ってみると、ここに来るまで 6 年もかかったようです。ちょっと嬉しくなったので経緯を書き残します。
2018 年、ふと思い立って、Emscripten でRuby をビルドできるようにしました。
Emscripten は、要するにC/C++ プログラムをJavaScript や Wasm に変換してくれるコンパイラです。C で書かれたRuby をEmscripten でビルドすれば、ブラウザで動くRuby が作れるはず。
意外と微修正だけで miniruby*1 がビルドできて、簡単なコードなら動かせるようになりました。
ただ、ちょっと凝ったコードを走らせると落ちたり刺さったりして、まともに使えるクオリティにはできませんでした。また、Ruby もEmscripten も変わっていくので、しばらくしたらビルドできなくなってしまいました。
しょうがないので放置していたら、kateinoigakukun さんっていうスーパーハッカーがさっそうと現れて、Ruby の Wasm/WASI 対応をはじめてくれました。RubyKaigi 2022のキーノートは記憶に新しいですね。
kateinoigakukun さんは自分と違って Wasm にちゃんと超詳しいので、不安定な挙動に対して場当たり的に対応するのではなく、まじめに根本原因を調べて改善することをやってくれました。また、ビルドシステムのメンテナンス力も高く、Wasm/WASIRuby の nightly ビルドを配布してくれるようになりました。
katei さんの興味は WASI*2 のはずですが、なぜかEmscripten ビルドも提供してくれました。このおまけにより、そこそこ安定的なRuby のEmscripten ビルドを無料で得られるようになったのでした。最高。
ブラウザでRuby が動くようになったので、いくつかアプリを書けました。楽しい。
ruby-puzzles-2022.cookpad.techmame.github.io
ただ、別にRuby でブラウザアプリが書きたかったわけではないんですよ。やっぱり REPL を動かしたい。何に使うわけでもないけど。
そのためには、ブラウザで動く端末につないでirb を動かさなきゃいけない。ブラウザで動く端末エミュレータにはxterm.js があり、これはvscode でも使われている超安定ライブラリなので、あとはEmscripten'edRuby とつなぐだけでした。
これがまた大変でした。
Emscripten プログラムに限らないのですが、端末エミュレータとプログラムは通常、直結していません。Linux でも、C プログラムがprintf("Hello\n"); とやると、端末エミュレータにはHello\r\n という文字列が渡されます。\r が挿入されていることに注意。これを挿入するのは、プログラムでも端末エミュレータでもなく、実はLinuxカーネルです。Line discipline という機能がそれです。*3
xterm.js でLinux プログラムを動かす場合、node-pty という定番ライブラリがあり、vscode などもこれを使っているようです。が、これはLinux の pty のラッパなので、ブラウザでは動きません。Emscripten のために、ブラウザの上で動く pty がほしいという声はちらほらあるようでしたが、作った人はいないようでした。
ないなら作るかってことで、xterm-pty というEmscripten プログラムとつなぐための xterm.js アドオンを作りました。
これは要するに Line discipline を気合で実装したものです。ブラウザでRuby を動かしたいと思ったら、いつのまにか Line discipline をJavaScript で実装していた。
まあ、xterm-pty でVim が動いたときはなかなかの達成感でした。Vim のデモは↓を参照。
なお、Vim を Emscripten すること自体は既出でした。あちらはVim に特化したレンダラを自作したのに対し、こちらは xterm.js とつないで動かしたところが新規性。汎用的なのでVim 以外のCUI プログラムも動きます。詳しくはデモを参照。
で、irb を動かすために作った xterm-pty でしたが、実際にirb と満足につなぐには課題がありました。
Line discipline は、IO のやり取りだけでなく、シグナルを投げる役割もあります。Ctrl+C が押されたときに SIGINT を投げるのは、実は Line discipline です。しかしEmscripten プログラムにはシグナルという概念そのものがなかったので、投げようがありませんでした。
また、xterm-pty とEmscripten プログラムとつなぐ部分が極めて不安定でした。Emscripten ランタイムをモンキーパッチして read/write/select などのシステムコールをインターセプトしていたので、Emscripten がちょっと変数名を変えると動かなくなる。
そんなわけで、しょうがなく放置していたのですが、なんかIngvar Stepanyan っていうEmscripten に超詳しいスーパーハッカーがさっそうと現れて、「Emscripten にシグナルを実装した」「モンキーパッチでなくEmscripten のプラグイン的に xterm-pty を使えるようにした」と言う、ほとんど作り直しに近い PR をくれたので、突如解決しました。最高。
刷新された xterm-pty をリリースしたので、組み合わせてirb を動かしてみたら、なんと一切のパッチを必要とせずに動きました。すごい、すごすぎる。6 年前と比べると別世界。
補完も出るし、イースターエッグのアニメーションも動きます。
twitter.comemscriptenirb でイースターエッグが安定的に動くようになってきたhttps://t.co/ubentOzj7ppic.twitter.com/wkRb2DxYeF
— Yusuke Endoh (@mametter)2024年1月31日
いやー、これが見たかったんですよ。夢がかなった瞬間。何に使うわけでもないけど。
ブラウザでRuby を動かす夢がかないました。かなったんじゃないかな。
まあ、Thread.new が動かないとか、拡張ライブラリをロードできないとか、まだまだ課題はあるわけですが。
適当なものを作って放置してたらスーパーハッカーたちが直してくれる人生だったので、さらなるスーパーハッカーの登場を待ちたい。
実は、kateinoigakukun さん自身がirb.wasm をやっています。
これはEmscripten ではなく WASI で実現されています。
irb.wasm はjquery-terminal を使っているそうで、補完などは出ません。が、RubyWorld Conference 2022 で picoruby/picoirb を発表してたhasumikin さんに相談したらirb.wasm で xterm.js を使うモードを実装してくれたので、そっちなら補完が出ます。ただ、pty をまじめに模倣しているわけではなく、irb や reline にモンキーパッチをあててどうにかしているようなので、再現性はやや微妙かも。たとえば例のイースターエッグは(まだ)動かなかった。irb.wasm で xterm-pty を使うようにするとよさそうだけど、できるのかな?
*1:Ruby のビルド時に中間的に作られる簡易なRubyインタプリタ。拡張ライブラリがロードできないなど、制限がある。
*2:WASI は、Wasm のポータブルなシステムインターフェイス。Emscripten がブラウザ特化の Wasm を出力するのに対し、WASI に基づいた Wasm はブラウザだけでなく配布用実行ファイルやエッジコンピューティング環境などで共通して使える。
*3:pty とか termios とかのキーワードのほうがわかりやすいかも。pty は Line discipline で繋がれたマスター・スレーブのペアで、termios はスレーブ側から Line discipline を制御するためのAPI 、だと思ってますが、正確な定義は自信ない。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。