ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

Component Model対応したruby.wasmをビルドする方法

あまり公式にアナウンスされていない気がするが*1ruby.wasm は実はComponent Model対応が済んでいる。

github.com

多分この辺から。なので、RubyKaigi 2024の段階ではComponent Model対応したものを動かせていた。スライドで言うとこの辺 *2

この記事では簡単にビルドの仕方をまとめておく。

command でビルドする

以下の内容の Gemfile を使って:

source "https://rubygems.org"
gem "ruby_wasm", "~> 2.7"

以下のコマンドでビルドすればOK*3

$ RUBY_WASM_EXPERIMENTAL_DYNAMIC_LINKING=1 bundle exec rbwasm build -o rubyp2.wasm --target wasm32-unknown-wasip2

witを見ると以下の感じになっている(抜粋)。

package root:component;

world root {
  import wasi:cli/exit@0.2.0;
  import wasi:clocks/wall-clock@0.2.0;
  import wasi:random/random@0.2.0;
  import wasi:cli/environment@0.2.0;
  import wasi:io/error@0.2.0;
  import wasi:io/poll@0.2.0;
  import wasi:io/streams@0.2.0;
  import wasi:clocks/monotonic-clock@0.2.0;
  import wasi:cli/stdin@0.2.0;
  import wasi:cli/stdout@0.2.0;
  import wasi:cli/stderr@0.2.0;
  import wasi:cli/terminal-input@0.2.0;
  import wasi:cli/terminal-output@0.2.0;
  import wasi:cli/terminal-stdin@0.2.0;
  import wasi:cli/terminal-stdout@0.2.0;
  import wasi:cli/terminal-stderr@0.2.0;
  import wasi:filesystem/types@0.2.0;
  import wasi:filesystem/preopens@0.2.0;

  export wasi:cli/run@0.2.0;
}

こうなので、成果物は wasmtime でそのまま実行できる。

$ wasmtime rubyp2.wasm --version
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [wasm32-wasi]

reactor でビルドする

Gemfilejs gemを含む必要があるらしい。参照

source "https://rubygems.org"
gem "ruby_wasm", "~> 2.7"
gem "js"

コマンドは同じでOK。

$ RUBY_WASM_EXPERIMENTAL_DYNAMIC_LINKING=1 bundle exec rbwasm build -o rubyp2-reactor.wasm --target wasm32-unknown-wasip2

wit が結構変わっていて、 ruby:js/js-runtime を必要とし、 ruby:js/ruby-runtime を export している。

package root:component;

world root {
  import wasi:cli/exit@0.2.0;
  import wasi:clocks/wall-clock@0.2.0;
  import wasi:random/random@0.2.0;
  import ruby:js/js-runtime;
  import wasi:cli/environment@0.2.0;
  import wasi:io/error@0.2.0;
  import wasi:io/poll@0.2.0;
  import wasi:io/streams@0.2.0;
  import wasi:clocks/monotonic-clock@0.2.0;
  import wasi:cli/stdin@0.2.0;
  import wasi:cli/stdout@0.2.0;
  import wasi:cli/stderr@0.2.0;
  import wasi:cli/terminal-input@0.2.0;
  import wasi:cli/terminal-output@0.2.0;
  import wasi:cli/terminal-stdin@0.2.0;
  import wasi:cli/terminal-stdout@0.2.0;
  import wasi:cli/terminal-stderr@0.2.0;
  import wasi:filesystem/types@0.2.0;
  import wasi:filesystem/preopens@0.2.0;

  export ruby:js/ruby-runtime;
}

これらは js.gem の方でwitを置いている 。したがって、JS側でどういう関数を用意して、Rubyの機能としてはどういうものが使えるのかが大変わかりやすくなっている。

僕はこう思ったっス

すでにComponent化して import/export で何を切り出すか調整できる状態になってそうだし、そもそもComponentなので薄いアダプターComponentをいい感じに作れば、 componetize-rb は普通にできるっぽい。wasmcloudで頑張って動かすというのをやるとかはいいと思った。Go、Rust、TypeScriptしかない ので、Pythonが追加される前に...。

で、そうすると、純粋にjsじゃないreactor版が欲しい感じがする。

*1:見逃してたらすいません!

*2:と言うか、自分でこの辺の手を動かして、やっとスライドで言っていることの意味がわかったともいう

*3:RUBY_WASM_EXPERIMENTAL_COMPONENT_MODEL=1 は何かしらのファイルがないらしく、動作しなかった