Stream: wit-bindgen

Topic: ✔ simple rust guest & host with shared WIT definition


view this post on Zulip yonil (Feb 16 2023 at 21:36):

Hi,

I'm struggling with making a very basic guest & host setup with a shared WIT definition work smoothly.
I've based my code mostly on the content of https://github.com/bytecodealliance/wit-bindgen/tree/main/tests, specifically the "smoke" test.
everything compiles successfully, however during runtime of the host I get the following error message, when using cargo run for the host:

Error: import `wasi-stderr` has the wrong type

Caused by:
    0: instance export `print` has the wrong type
    1: expected func found nothing

Hopefully, someone would be able to point out what I'm doing wrong.

WIT (smoke.wit):

interface imports {
  thunk: func()
}

default world smoke {
  import imports: self.imports

  export thunk: func()
}

guest Cargo.toml:

[package]
name = "guest"
version = "0.1.0"
edition = "2021"

[dependencies]
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen" }

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

guest lib.rs:

wit_bindgen::generate!("smoke");

struct Exports;

export_smoke!(Exports);

impl Smoke for Exports {
    fn thunk() {
        imports::thunk();
    }
}

i'm building the guest component using the following commands:

cargo build --target wasm-wasi32

wasm-tools component new <...>/guest.wasm -o <...>/guest.wasm" --adapt <...>/wasi_snapshot_preview1.wasm"

host Cargo.toml:

[package]
name = "host"
version = "0.1.0"
edition = "2021"

[dependencies]
wasmtime = { git = 'https://github.com/bytecodealliance/wasmtime', features = ['component-model'] }
wit-bindgen = { git = "https://github.com/bytecodealliance/wit-bindgen" }
anyhow = "1.0.69"

host main.rs:

use anyhow::Result;
use std::error::Error;
use wasmtime::component::{Component, Instance, Linker};
use wasmtime::{Config, Engine, Store};

wasmtime::component::bindgen!("smoke");

#[derive(Default)]
struct Wasi<T>(T);

#[derive(Default)]
pub struct MyImports {
    hit: bool,
}

impl imports::Imports for MyImports {
    fn thunk(&mut self) -> Result<()> {
        self.hit = true;
        println!("in the host");
        Ok(())
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let wasm = "<...>/guest.wasm";

    run(
        wasm,
        |linker| Smoke::add_to_linker(linker, |x| &mut x.0),
        |store, component, linker| Smoke::instantiate(store, component, linker),
        run_test,
    )?;

    Ok(())
}

fn run<T, U>(
    wasm: &str,
    add_to_linker: fn(&mut Linker<Wasi<T>>) -> Result<()>,
    instantiate: fn(&mut Store<Wasi<T>>, &Component, &Linker<Wasi<T>>) -> Result<(U, Instance)>,
    test: fn(U, &mut Store<Wasi<T>>) -> Result<()>,
) -> Result<()>
where
    T: Default,
{
    let mut config = Config::new();
    config.cache_config_load_default()?;
    config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
    config.wasm_component_model(true);
    let engine = Engine::new(&config)?;

    let component = Component::from_file(&engine, &wasm)?;
    let mut linker = Linker::new(&engine);

    add_to_linker(&mut linker)?;
    let mut store = Store::new(&engine, Wasi::default());
    let (exports, _) = instantiate(&mut store, &component, &linker)?;

    println!("testing {wasm:?}");
    test(exports, &mut store)?;

    Ok(())
}

fn run_test(exports: Smoke, store: &mut Store<crate::Wasi<MyImports>>) -> Result<()> {
    exports.call_thunk(&mut *store)?;

    assert!(store.data().0.hit);

    Ok(())
}
A language binding generator for WebAssembly interface types - wit-bindgen/tests at main · bytecodealliance/wit-bindgen

view this post on Zulip Mossaka (Joe) (Feb 16 2023 at 23:29):

The error is saying that "wasi-stderr" has the wrong type.

When you compile your guest program to wasm32-wasi targeted Wasm component, the component will import some WASI functions. To see what functions are imported, you can do wasm-tools component wit guest.wasm where guest.wasm is the output of wasm-tools component new.

The command will print a WIT file that has all the WASi imports and you are able to see what's the function signature in wasi-stderr interface. My guess is that it looks like

interface wasi-stderr {
  print: func(message: string)
}

Once you were able to verify that, the missing part is in your host implementation. Your host should meet the requirements of the guest by implementing all the imports of the WIT file. Specifically you need to implement functions in wasi-stderrin the host and added them to the Linker.

view this post on Zulip Mossaka (Joe) (Feb 16 2023 at 23:30):

This is all is too much, I'd recommend using WasiCtxBuilder from wasi-common in preview2-prototyping repo.

Polyfill adapter for preview1-using wasm modules to call preview2 functions. - preview2-prototyping/wasi-common at main · bytecodealliance/preview2-prototyping

view this post on Zulip Mossaka (Joe) (Feb 16 2023 at 23:32):

Here is an example repo of how you can use preview2-prototyping host implementation https://github.com/Mossaka/wit-bindgen-go-template/blob/main/Cargo.toml#L16-L23

This template will help you start writing a wasm component in TinyGo / Go! - wit-bindgen-go-template/Cargo.toml at main · Mossaka/wit-bindgen-go-template

view this post on Zulip yonil (Feb 17 2023 at 00:02):

Thank you very much @Mossaka (Joe) , these references have helped resolve my issue.

view this post on Zulip Notification Bot (Feb 17 2023 at 00:17):

Mossaka (Joe) has marked this topic as resolved.


Last updated: Nov 22 2024 at 16:03 UTC