Stream: wasmtime

Topic: Wasmtime failing to run component binary


view this post on Zulip Landon James (Feb 18 2024 at 05:17):

I am trying to invoke a wasm component binary (with some wasi::http functionality) via wasmtime in Rust using both wasmtime 17.0.1 and 16.0.0. I have the cargo feature "component-model" enabled and I am setting .wasm_component_model(true) on the config passed to the engine, but I am still getting the following error:

failed to parse WebAssembly module

Caused by:
    Unsupported feature: component model

Before I dig too far in is there anything obvious I am missing for running a component binary? The example is pretty deep in a larger repo so its going to take me awhile to pull out a repro.

Related question, is there anything like jco or wasmtime-py for autocreating Rust bindings for component binaries? I see that cargo-component creates a bindings.rs file, but it doesn't quite seem to be what I would expect for using a component as a library.

view this post on Zulip Alex Crichton (Feb 18 2024 at 18:24):

I think this may be a situation where you're using Module::new to compile a component instead of Component::new. If that's the case then we should definitely improve this error message!

For bindings generation on the host you'll want to use wasmtime::component::bindgen! and that should suit your needs

view this post on Zulip Landon James (Feb 19 2024 at 02:18):

I am using cargo component build --release to create the binary, so not totally sure if which it is using under the hood. I'll try moving back to wasm-tools component new and see if that gets around the issue. Will look into wasmtime::component::bindgen! thanks for the pointer!

view this post on Zulip Alex Crichton (Feb 19 2024 at 15:40):

Oh cargo component build produces a component, and under the hood that's calling wasm-tools component new. I mostly meant that in the Wasmtime embedding API make sure you're using the Component type instead of the Module type

view this post on Zulip Landon James (Feb 19 2024 at 19:48):

Cool got around that error with the Component::new API so thank you for that. Facing a new one now related to the preview2 imports.

Error {
        context: "import `wasi:io/poll@0.2.0` has the wrong type",
        source: Error {
            context: "instance export `pollable` has the wrong type",
            source: "expected resource found nothing",
        },
    },

I am creating a WasiCtx and passing it to the Store like:

let wasi_ctx = WasiCtxBuilder::new().inherit_stdio().build();
let mut store = Store::new(&engine, wasi_ctx);

And I was also attempting to add the wasi functions to the linker with:

wasmtime_wasi::add_to_linker(&mut linker, |cx| cx)?;

but wasmtime_wasi::add_to_linker expects a wasmtime::Linker instead of a wasmtime::component::Linker. Not sure if I am missing something there or if maybe the component::Linker automatically handles that linking?

Heres a link to the code I'm currently running if that might help.

view this post on Zulip bjorn3 (Feb 19 2024 at 19:50):

You may be looking for one of the add_to_linker methods in wasmtime_wasi::preview2.

view this post on Zulip bjorn3 (Feb 19 2024 at 19:51):

wasmtime_wasi::add_to_linker is for wasi-preview1.

view this post on Zulip Lann Martin (Feb 19 2024 at 19:52):

:point_of_information: Note that this is expected to change in wasmtime 19: https://github.com/bytecodealliance/wasmtime/pull/7933

Following #7881, wasi-common's re-exports from wasmtime-wasi will be marked as deprecated for the 18.0 release series. This PR lands the change into main to delete those entirely, and promote wasmt...

view this post on Zulip Landon James (Feb 19 2024 at 21:13):

Ahh those do seem like what I want. Although I am having trouble using them since the generic type for my Linker is Linker<WasiCtx> and that is causing a trait bound issue:

error[E0277]: the trait bound `wasmtime_wasi::WasiCtx: WasiView` is not satisfied
   --> src/latest/wasm_canary.rs:54:5
    |
54  |     wasmtime_wasi::preview2::bindings::io::poll::add_to_linker(&mut linker, |ctx| ctx);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `WasiView` is not implemented for `wasmtime_wasi::WasiCtx`
    |
    = note: required for `wasmtime_wasi::WasiCtx` to implement `wasmtime_wasi::preview2::bindings::io::poll::Host`

I gave a shot at passing them in via the with parameter on the wasmtime::component::bindgen! macro as well but that didn't seem to change anything:

bindgen!({
    inline: "
    package aws:component;

    interface canary-interface {
        run-canary: func() -> result<string, string>;
    }

    world canary-world {
        export canary-interface;
    }
",
with: {
    "wasi:io/error": wasmtime_wasi::preview2::bindings::io::error,
    "wasi:io/streams": wasmtime_wasi::preview2::bindings::io::streams,
    "wasi:io/poll": wasmtime_wasi::preview2::bindings::io::poll,
}
});

view this post on Zulip bjorn3 (Feb 19 2024 at 21:24):

You need to implement the WasiView trait for your own context type. An example: https://github.com/bytecodealliance/wasmtime/blob/b736585e2515f253d4507ae32f2e3180f4385192/examples/wasi-async/main.rs#L20

view this post on Zulip Landon James (Feb 19 2024 at 23:18):

Unfortunately doing that still doesn't get me any further. I replicated the impl of WasiView and passed the constructred host_ctx to my Store. Doing this still left me with the error:

"import `wasi:io/poll@0.2.0` has the wrong type",

I then tried to manually add the io/poll to the linker:

wasmtime_wasi::preview2::bindings::io::poll::add_to_linker(&mut linker, |cx| cx);

And that compiles, but fails at runtime with:

cannot use `func_wrap_async` without enabling async support in the config

So adding .async_support(true) to the engine config, and running again produces a new error:

must use async instantiation when async support is enabled

And unfortunately I get stuck there again because the wasmtime::component::bindgen! macro doesn't appear to provide an async instantiation method. It seems there are still some rough edges trying to use both WASI and Component functionality at the same time. Once I get this figured out I'll try to contribute a new example to cover the overlap.

view this post on Zulip Alex Crichton (Feb 20 2024 at 15:21):

You'll need to be sure to call the "right" add_to_linker function as there's a few. They're pre-generated with various configuration options, with the idea being:

view this post on Zulip Landon James (Feb 20 2024 at 19:34):

Awesome! Finally found the right invocation of various add_to_linker functions last night. I believe my last question here relates to how this all plays with async code.

Currently the function that creates the wasmtime Engine and runs my wasm binary is synchronous and that works fine. When I change this function to be async (since thats what the canary runner expects) I get the following panic from the wasmtime-wasi crate:

thread 'latest::wasm_canary::test_wasm_canary' panicked at /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasmtime-wasi-17.0.1/src/preview2/mod.rs:246:15:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.

I see that crate exports in_tokio and with_ambient_tokio_runtime functions, but I'm not entirely certain how they are meant to be used.

The panic seems to be triggered by some of the preview2::bindings::sync_io code, so I suspect to run this in an async context I might need to use the async io options and the .async_support(true) config for the Engine. But doing so triggers another error:

thread 'latest::wasm_canary::test_wasm_canary' panicked at /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasmtime-17.0.1/src/component/linker.rs:276:9:
must use async instantiation when async support is enabled

And the bindgen! macro doesn't seem to create an async instantiation method.

view this post on Zulip Pat Hickey (Feb 20 2024 at 19:37):

wasmtime_wasi::{in_tokio, with_ambient_tokio_runtime} are really meant for other wasi proposal crates to use, not for the host to use

view this post on Zulip Pat Hickey (Feb 20 2024 at 19:38):

if you are running wasmtime_wasi inside tokio, you need to use Config::async_support(true), and use wasmtime_wasi::command::add_to_linker as opposed to wasmtime_wasi::command::sync::add_to_linker

view this post on Zulip Pat Hickey (Feb 20 2024 at 19:39):

and then additionally, if you are running bindgen yourself, you need to use async: { names... } as an option to bindgen, which will make the Host traits be #[async_trait]s and whatever component method names you select be async fn in the trait

view this post on Zulip Pat Hickey (Feb 20 2024 at 19:41):

this story is kinda complicated, unfortunately - hopefully my explanation is sufficient but let me know.

view this post on Zulip Landon James (Feb 21 2024 at 17:53):

Ahh very helpful, that was the last link in the puzzle and its all working now. I think what I was getting stuck on is that the documentation for the async value for the bindgen! macro indicates that it makes the calls to individual functions async, but it doesn't mention that it also enables instantiate_async for the component itself.


Last updated: Nov 22 2024 at 17:03 UTC