1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WASI Preview2 を使って Host / Guest を作ったのでメモ

1
Posted at

冬休みをまるまる2日使ってやっとできました。難しかった。。。

マニアックなことに手を付けてしまったようで、検索してもあまりヒットせず。最終的には公式のマニュアル(WASI, wasmtime)のサンプルを見ながらやることになりました。wasi を使っているのは、WASMコンポーネントから println を使いたかっただけなのですが、だけなのですが、、、難しかったー:cry:

host, guest を作ってみる

Host が実行ファイル。Guest が WASM コンポーネント(.wasm ファイル)です。WIT を使って設計を共有したかったのですが、それだけのことでこんなに時間がかかろうとは。

目標

  • host 側で guest の hello を呼ぶ
  • guest で hello world する
  • guest から host の message() をコール

setup

cargo component new myguest --lib
cargo component new myhost

myguest は、cargo component build で wasm を作成、myhost 側は cargo run で動かせます。cargo component build は --target wasm32-wasip2 を指定しないと p1 で作成すので注意です。

wit を作る

myhost/wit/myworld.wit

package component:my-example;

interface host-api {
    message: func(msg: string);
}

world my-world {
    // GuestがHostからインポートする(Hostの関数を呼ぶ)
    import host-api;

    // GuestがHostへエクスポートする(Hostから呼ばれる)
    export hello: func();
}

Guest

path を指定して host 側の WIT を共有しいます。cargo component build --target wasm32-wasip2 --release で wasm ファイルを作ります。

myguest/Cargo.toml

[package]
name = "myguest"
version = "0.1.0"
edition = "2024"

[dependencies]
wit-bindgen-rt = { version = "0.44.0", features = ["bitflags"] }

[lib]
crate-type = ["cdylib"]

[package.metadata.component]
package = "component:myguest"

[package.metadata.component.dependencies]

[package.metadata.component.target]
path = "../myhost/wit/myworld.wit"

myguest/src/lib.rs

#[allow(warnings)]
mod bindings;

use bindings::Guest;
use bindings::component::my_example::host_api;

struct Component;

impl Guest for Component {
    fn hello() {
        // 1. Guestでhello world
        println!("Guest: Hello world!");

        // 2. GuestからHostのmessage()をコール
        host_api::message("Hello from Guest via host-api!");
    }
}

bindings::export!(Component with_types_in bindings);

Host

ここが本当にめちゃくちゃ苦労しました。

myhost/src/main.rs

[package]
name = "myhost"
version = "0.1.0"
edition = "2024"

[package.metadata.component]
package = "component:myhost"

[package.metadata.component.target.dependencies]

[dependencies]
wasmtime = { version = "40.0.0", features = ['component-model'] }
wasmtime-wasi = "40.0.0"
wit-bindgen-rt = { version = "0.44.0", features = ["bitflags"] }

myhost/src/main.rs

use wasmtime::component::*;
use wasmtime::{Config, Engine, Store};
use wasmtime_wasi::{WasiCtx, WasiCtxView, WasiView};

// バインディングの生成 MyWorld trait はここで作られる
// world 名を指定すると wit ディレクトリから自動で使用する world を選びます
bindgen!("my-world");

struct State {
    ctx: WasiCtx,
    table: ResourceTable,
}
impl WasiView for State {
    fn ctx(&mut self) -> WasiCtxView<'_> {
        WasiCtxView { ctx: &mut self.ctx, table: &mut self.table }
    }
}

// Host側で提供する関数の実装
// <パッケージ名>::<interface名>::Host
impl component::my_example::host_api::Host for State {
    fn message(&mut self, msg: String) {
        println!("Host received message: {}", msg);
    }
}

fn main() -> wasmtime::Result<()> {
    let mut config = Config::new();
    config.wasm_component_model(true);
    let engine = Engine::new(&config)?;
    let component = Component::from_file(
      &engine,
      "../myguest/target/wasm32-wasip2/release/myguest.wasm")?;

    let mut linker = Linker::<State>::new(&engine);
    wasmtime_wasi::p2::add_to_linker_sync(&mut linker)?;

    MyWorld::add_to_linker::<_, HasSelf<_>>(&mut linker, |state| state)?;

    let mut builder = WasiCtx::builder();
    builder.inherit_stdout(); // Guest で println! を使うため
    builder.inherit_stderr();

    let mut store = Store::new(
        &engine,
        State {
            ctx: builder.build(),
            table: ResourceTable::new(),
        },
    );

    let bindings = MyWorld::instantiate(&mut store, &component, &linker)?;

    // 3. Host側でguestのhelloを呼ぶ
    bindings.call_hello(&mut store)?;

    Ok(())
}

まだ ResourceTable 周りがよくわかってませんが、あとはコピペで作っていける気がしてますが非同期対応はさせないとですね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?