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.
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
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!
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
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.
You may be looking for one of the add_to_linker
methods in wasmtime_wasi::preview2
.
wasmtime_wasi::add_to_linker
is for wasi-preview1.
:point_of_information: Note that this is expected to change in wasmtime 19: https://github.com/bytecodealliance/wasmtime/pull/7933
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,
}
});
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
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.
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:
bindings
module is auto-generated by wasmtime::component::bindgen!
and might only add a single interface. The handwritten versions add a suite of interfaces at once.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.
wasmtime_wasi::{in_tokio, with_ambient_tokio_runtime} are really meant for other wasi proposal crates to use, not for the host to use
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
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
this story is kinda complicated, unfortunately - hopefully my explanation is sufficient but let me know.
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: Dec 23 2024 at 13:07 UTC