@ledsun blog

無味の味は佳境に入らざればすなわち知れず

wasmtime-dotnetを使ってruby.wasmを実行する

前提条件

手順

プロジェクトを作成

dotnet new console -n wasmintro
cd wasmintro
dotnet add package Wasmtime

wasmtime向けruby.wasmバイナリを用意する

# 1. ダウンロード
Invoke-WebRequest `
  -Uri https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-3.4-wasm32-unknown-wasip1-full.tar.gz `
  -OutFile ruby-3.4-wasm32-unknown-wasip1-full.tar.gz

# 2. 展開
tar -xvzf ruby-3.4-wasm32-unknown-wasip1-full.tar.gz

# 3. ruby.wasm を移動(元の ruby 実行ファイルをリネーム)
Move-Item `
  -Path "ruby-3.4-wasm32-unknown-wasip1-full/usr/local/bin/ruby" `
  -Destination "ruby.wasm"

https://github.com/ruby/ruby.wasm/?tab=readme-ov-file#quick-example-how-to-package-your-ruby-application-as-a-wasi-application に記載されているwasmtimeで動かす手順を参考にしてます。

ruby.wasmでは何種類かのwasmバイナリを作ります。 例えば rake npm:ruby-head-wasm-wasi で作る packages/npm-packages/ruby-head-wasm-wasi/dist/ruby.wasm を使うとうまく行きません。 このwasmバイナリにはJavaScriptでホストするための関数が定義されています。 このwasmバイナリをインスタンス化するには、これらの関数にC#側のスタブ関数を紐付ける必要があります。 紐付けないと次のようなエラーメッセージ表示されます。

Unhandled exception. Wasmtime.WasmtimeException: unknown import: `rb-js-abi-host::rb_wasm_throw_prohibit_rewind_exception` has not been defined
   at Wasmtime.Linker.Instantiate(Store store, Module module)
   at Program.<Main>$(String[] args) in C:\Users\led_l\wasmintro\Program.cs:line 18

wasmtimeで動かしやすいwasmバイナリを選ぶ必要があります。

ソースコード

using System;
using Wasmtime;

var engine  = new Engine();
var module  = Module.FromFile(engine, "ruby.wasm");

using var linker = new Linker(engine);
linker.DefineWasi();

using var store  = new Store(engine);
store.SetWasiConfiguration(
    new WasiConfiguration()
        .WithArgs("ruby", "--version")   // Rubyのバージョンを表示
        .WithInheritedStandardOutput()
        .WithInheritedStandardError()
);

var instance = linker.Instantiate(store, module);
instance.GetFunction("_start")?.Invoke();

実行する

dotnet run
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [wasm32-wasi]