Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
emruby: ブラウザで動くRuby
Search
Yusuke Endoh
April 23, 2021
Programming
0
19
emruby: ブラウザで動くRuby
銀座Rails #32
https://ginza-rails.connpass.com/event/207692/
Yusuke Endoh
April 23, 2021
Tweet
Share
More Decks by Yusuke Endoh
See All by Yusuke Endoh
An Invitation to TRICK: How to write weird Ruby programs
mame
1
810
TypeProf進捗
mame
0
29
12年前の『型システム入門』翻訳の思い出話
mame
14
2k
Good first issues of TypeProf
mame
4
6.9k
Revisiting TypeProf - IDE support as a primary feature
mame
1
2.4k
error_highlight: User-friendly Error Diagnostics
mame
0
22
TRICK 2022 Results
mame
0
40
クックパッド春の超絶技巧パンまつり 超絶技巧プログラミング編 資料
mame
0
46
Enjoy Ruby Programming in IDE and TypeProf
mame
0
35
Other Decks in Programming
See All in Programming
楽しく向き合う例外対応
okutsu
0
120
苦しいTiDBへの移行を乗り越えて快適な運用を目指す
leveragestech
0
600
XStateを用いた堅牢なReact Components設計~複雑なClient Stateをシンプルに~ @React Tokyo ミートアップ #2
kfurusho
1
910
密集、ドキュメントのコロケーション with AWS Lambda
satoshi256kbyte
0
190
AIの力でお手軽Chrome拡張機能作り
taiseiue
0
170
2,500万ユーザーを支えるSREチームの6年間のスクラムのカイゼン
honmarkhunt
6
5.3k
データベースのオペレーターであるCloudNativePGがStatefulSetを使わない理由に迫る
nnaka2992
0
150
2024年のkintone API振り返りと2025年 / kintone API look back in 2024
tasshi
0
220
WebDriver BiDiとは何なのか
yotahada3
1
140
Kubernetes History Inspector(KHI)を触ってみた
bells17
0
230
『GO』アプリ バックエンドサーバのコスト削減
mot_techtalk
0
140
1年目の私に伝えたい!テストコードを怖がらなくなるためのヒント/Tips for not being afraid of test code
push_gawa
0
170
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
4
330
Thoughts on Productivity
jonyablonski
69
4.5k
How to Ace a Technical Interview
jacobian
276
23k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
12
960
Large-scale JavaScript Application Architecture
addyosmani
511
110k
Raft: Consensus for Rubyists
vanstee
137
6.8k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Bash Introduction
62gerente
611
210k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
StorybookのUI Testing Handbookを読んだ
zakiyama
28
5.5k
Git: the NoSQL Database
bkeepers
PRO
427
64k
KATA
mclloyd
29
14k
Transcript
emruby: ブラウザで動くRuby 銀座Rails #32 Yusuke Endoh 1
自己紹介:遠藤侑介 (@mametter) • クックパッドで働くフルタイムRubyコミッタ • Ruby 3添付の静的解析ツールTypeProf作ってます • https://github.com/ruby/typeprof •
でも今日はぜんぜん違う話をします 2
emruby: ブラウザの上で動くRuby https://mame.github.io/emruby/ 3
emrubyの狙い • ブラウザでRubyが動くのは楽しい • 頑張ればTryRuby(お試し環境)くらいにはなるか? • 将来的にJavaScriptの代替になるかはWASM次第? • Rust /
Go / KotlinなどもWASM出力に対応してるので • おことわり • この発表にはRailsもRuby言語もほとんど出てきません • Rubyのビルドの知識が少し身につきます 4
Rubyをブラウザで動かす関連研究 • Opal: JavaScriptで書かれたRubyインタプリタ • https://github.com/opal/opal • Artichoke: Rustで書かれたRubyインタプリタ(WASM出力対応) •
https://github.com/artichoke/artichoke • repl.it: Ruby 1.8をEmscriptenしたもの(らしい) • https://github.com/replit-archive/emscripted-ruby • Ruby on WebAssembly: mrubyをEmscriptenしたもの • https://github.com/blacktm/ruby-wasm • RubyのNaClサポート(2012~2017) • よくまとまってる記事 • https://blog.unasuke.com/2021/products-about-webassembly-and-ruby/ 5
アジェンダ • ➔WASM / Emscriptenとは • emrubyが動くまで • まとめ 6
WebAssembly (WASM) • ブラウザの上で動く実行ファイル形式 • 2017年頃からメジャーブラウザが対応している • JavaScriptより速くて (?) 小さいらしい
7
Emscripten • C/C++のプログラムをWASMに変換するコンパイラ • LLVMベース • デモ一覧(古そう):https://github.com/emscripten- core/emscripten/wiki/Porting-Examples-and-Demos • http://kripken.github.io/boon/boon.html
• https://files.unity3d.com/jonas/AngryBots/ • http://coolwanglu.github.io/vim.js/emterpreter/vim.html 8
Emscriptenの基本的な使いかた 9 #include <stdio.h> int main() { printf("hello, world!¥n"); return
0; } emcc hello.c –o hello.js && node hello.js emcc hello.c –o hello.html
アジェンダ • WASM / Emscriptenとは • ➔emrubyが動くまで • まとめ 10
前提知識:Rubyのふつうのビルド • Rubyソースのディレクトリで次のコマンドを打つ • ./configure: 環境ごとにビルド方法を調整する • どのシステム関数が使えるか、コンパイラオプションが使えるか • OS、コンパイラ、バージョンなどの違いを調べる
• make: ソースコードをコンパイルする • まずminirubyという制限版ruby実行ファイルを作る • minirubyを使ってスクリプト(Rubyで書かれている)を動かし、 拡張ライブラリや最終的なruby実行ファイルを作る 11 ./configure && make
話の流れ • minirubyをWASMにする • 本当のrubyをWASMにする • 最終目標:irbを動かす? 12
./configure && makeのEmscripten化 • Emscriptenはconfigure+makeに対応している • emconfigure / emmakeはビルドをうまくだまして Emscriptenコンパイラを使わせる
• これだけ……ではない • 実用プログラムがゼロ変更でビルドできることは無いと思う 13 emconfigure ./configure && emmake make
Emscriptenが未実装のC関数に対処する • 問題:Emscriptenで利用できないC関数がいっぱいある • popenがない • pthread_createはあるがpthread_killはない • pthread_createはあるがpthread_attr_getguardsizeがない •
pthread_sigmaskはあるけど実際には動かない (!) 、など • configureの盲点をつくような未実装がいろいろあった • 対処:Rubyのconfigureを改善して対応した • コミッタなので、Ruby側を直接変更しまくった 14
Rubyは関数の引数の数にルーズだった • C言語では、関数に引数を余分に渡しても良い (!?) • C言語仕様違反だが、 多くのCコンパイラで動く • Rubyはこれに依存していた •
Emscriptenのオプションで 対応した • -s EMULATE_FUNCTION_POINTER_CASTS=1 15 int foo(int a) { printf("%d¥n", a); } int main() { int(*foo2)(int,int) = (int(*)(int,int))foo; foo2(42, 43); // 42 } 1引数の関数fooを2引数で呼び出す例
miniruby.wasmできた! • 2018年はこの段階で公開した • 残念なお知らせ • EMULATE…オプションがEmscirptenから削除された • コンパイルできなくなった •
どうしたか • 放置した → 3年経ったら、Ruby側が直っていた! • 微修正で2021年1月に再ビルドに成功した 16
話の流れ • minirubyをWASMにする • ここまでできた • 本当のrubyをWASMにする • 最終目標:irbを動かす? 17
ruby.wasmを作るには • ふつうのrubyのビルドには、minirubyが必要 • しかしminiruby.wasmはLinuxで実行できない • クロスコンパイルする • ビルド環境とはちがう環境の実行ファイルを作ること •
Linuxでruby.exe(Windowsの実行ファイル)を作る、とか • 今回はLinuxでruby.wasmを作る • emconfigureはかえってややこしくなるのでやめた 18
Rubyのクロスコンパイル • Rubyのconfigureはクロスコンパイルに対応している • minirubyの代わりにビルド環境のrubyを使ってくれる • これで一応ruby.wasmはできた • が、全然動かないのでデバッグ&ドキュメント&ソース読み 19
$ ./configure ¥ --build x86_64-pc-linux-gnu ¥ --host wasm32-unknown-emscripten ¥ CC=emcc LD=emcc AR=emar RANLIB=emranlib $ make ビルド環境 対象環境 Emscripten
問題:Rubyの保守的GC • 保守的GCとは • マシンスタックの値がオブジェクトの参照であると仮定して マーク対象とするガベージコレクタの方式 • https://ja.wikipedia.org/wiki/%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%BB%E3%82%A2%E3%83%B3%E3%83%89%E3%83%BB%E3%82%B9%E3%82%A4%E3%83%BC%E3% 83%97#%E4%BF%9D%E5%AE%88%E7%9A%84%E3%81%AA%E3%82%AC%E3%83%99%E3%83%BC%E3%82%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%BF •
つまり意図的にC言語仕様違反なメモリアクセスをする • Emscriptenのメモリモデルでは全然動かない • 対処:Emscriptenが保守的GC用のAPIを用意していた • emscripten_scan_stack / emscripten_scan_registers • スタックの先頭と終端がわかる、これらを使うようにした 20
余談:Fiberに対応する(未完) • Rubyは2018年末にFiberの一部をアセンブリで実装した • Emscriptenでx86アセンブリはコンパイルできないので コンパイルエラーになっていた • 対処:EmscriptenのAPIを使って実装した • emscripten_fiber_init
/ emscripten_fiber_swap • コンパイルオプション -s ASYNCIFY と合わせて使う • miniruby.wasmでは動いたが、ruby.wasmでは動かない • 原因未解明、今後の課題 • とりあえずFiber使わなければ問題ない 21
問題:動的リンクができない • つまり、拡張ライブラリの require ができない • require "ripper"したらripper.soを動的リンクする • しかしEmscriptenは動的リンクに未対応(たぶん)
• 解決:ripperを静的リンクした • 他にも必要な拡張ライブラリを色々足した 22 $ ./configure ¥ --with-static-linked-ext --with-ext=ripper … $ make
その他Emscripten特有っぽい話 • リンクが失敗する(htonsが見つからない、とか) • -lcでlibcを明示的にリンクすれば動いた • -fstack-protectorも対応してないようなので消した • すぐメモリ不足エラーになる •
Emscriptenはデフォルトでメモリサイズを固定確保する • サイズ可変にするオプションをつけた (-s ALLOW_MEMORY_GROWTH=1) • stack overflowの検出が動かないので止めた、など 23
ruby.wasmできた! • require "ripper.so"も動く • ある程度複雑なRubyスクリプトも動く 24
話の流れ • minirubyをWASMにする • 本当のrubyをWASMにする • ここまでできた • 最終目標:irbを動かす? 25
irbを動かすのに必要なもの • Rubyインタプリタ(できた) • ripper.soなどの拡張ライブラリ(できた) • irbのソースコード(あるけどまだ組み込んでない) • 端末エミュレータ(無い) 26
仮想ファイルシステム • Emscriptenのfile_packagerツールで作れる • irbやrubygemsなど必要なRubyソースコードをまとめた • fs.jsとfs.dataができた • がんばってロードできるようにした •
コンパイルオプションに-s FORCE_FILESYSTEM=1追加 • fs.jsを<script>で呼ぶだけ……なのだが意外と苦労した 27
xterm.jsを組み込む • xterm.js: ブラウザで動く端末エミュレータ • https://xtermjs.org/ • VS Codeでも使われている •
残念なお知らせ • Emscriptenは標準入出力の実装がいまいち • とりあえずの対応 • ライン編集はxterm.js側でやり、irbには行単位で送る • reline(irbの新しい編集機能)の活用は今後の課題 28
ということで https://mame.github.io/emruby/irb/ 29
CPU 100%を防ぐ • Emscriptenの生成物はほぼ同期で動く(asyncでない) • 入力待ちをポーリングでやるみたい(ゲーム想定?) • 対処:別スレッド(Web Worker)で動かすようにした •
通信方法はvim.wasmに習った(SharedArrayBuffer使用) https://rhysd.hatenablog.com/entry/2019/06/13/090519 • 残念なお知らせ:5月に動かなくなる見込み 30
ということで • (かなり妥協したけど)irbがブラウザで動いた! • rubygems、did_you_meanなども一応動いているっぽい 31
落ち穂拾い • ruby.wasmのサイズ:29 MB • コンパイルオプションで調整して8 MB • -Os: 省サイズ重視で最適化する
• -g0: デバッグ情報を省く 32
Emscripten所感 • 夢の技術ではない • 現実のC言語コードをゼロ変更でビルドできることは無い • いっぱい問題に遭遇する • が、とてもよくできている •
一生懸命調べればたいてい対処方法やAPIがある • 検索に頼らずドキュメントを通して読むのが早道 • 動いたらとても嬉しい 33
まとめ • ブラウザで動くRuby、emrubyを紹介しました • 大体Ruby側で対応したのでたったこれだけでビルドできる 34 $ ./configure ¥ --build
x86_64-pc-linux-gnu ¥ --host wasm32-unknown-emscripten ¥ --with-static-linked-ext ¥ --with-ext=ripper,date,strscan,io/console,…,psych ¥ optflags=-Os debugflags=-g0 ¥ CC=emcc LD=emcc AR=emar RANLIB=emranlib $ make
今後の予定 • ほそぼそとメンテナンスするつもり • WASMが大ヒットする日に備える • そのとき「RubyもWASM対応してます」と言いたい • RubyからJSやDOMを操作できたらいいなあ •
当面はOpalを使うのがいいと思います • WASM版TryRubyができたらいいなあ • Opalであまり問題はないですが 35