I'm implementing the time component of wasip2 for a server which will host guests compiled with wasm32-wasip2. I can control the minimum supported rust version, but I need to not change it often: Many guests may never re-compile.
So I implemented wasi:clocks@0.2.5 but the test guests fail to link with unknown import: wasi:clocks/monotonic-clock@0.2.3#now has not been defined).
Of course, if I change the wasi wits to wasi:clocks@0.2.3 it works, but I have some users back at 0.2.0 and ostensibly someday wasm32-wasip2 will imply wasi:clocks@0.2.5 or later.
How can I set up my host such that any guest looking for wasi:clocks@0.2.0 _or later_ up to wasi:clocks@0.2.5 can link?
wasmtime does semver resolution automatically
so the unknown import error you got shouldnt happen
lets see if we can resolve that - can you make a minimal reproduction?
(by automatically, i mean that wit contains a version number and wasmtime will satisfy it with anything semver compatible, see https://github.com/bytecodealliance/wasmtime/blob/main/crates/environ/src/component/names.rs for the implementation which has detailed comments and tests)
I'll need to extract out to a whole separate application. Let me see if I can get it together for you. Do you want a zip of a complete project?
Fwiw, I'm not using the wasmtime binary. I'm using wasmtime::component::Linker and friends directly, and hosting the engine and all myself.
It seems like it is "supposed" to match a demand for 0.2.3 to 0.2.5. :thinking:
Oh, I wonder if define_unknown_imports_as_traps is disagreeing here.
to do a partial wasip2 implementation, I have to define_unknown_imports_as_traps and allow_shadowing on the linker.
linker.func_new(&item_name, move |_, _, _| {
bail!("unknown import: `{fully_qualified_name}` has not been defined")
})?;
I'm pretty sure this is the implementation it is using, which comes from define_unknown_imports_as_traps
so it defines an exact match, which I'm sure the name map prefers to a squishy match
ah yeah I wouldn't be surprised if this was a bug in define_unknown_imports_as_traps, good catch!
mind filing an issue for this?
thanks, I hadn't thought of define_unknown_imports_as_traps!
I am happy to file an issue, but I do need to find a workaround. It's in the way of my company's product :sweat_smile:.
// Add new host interfaces for features
functions::cache_scalar::add_to_linker(&mut linker, |s| s)?;
functions::topic::add_to_linker(&mut linker, |s| s)?;
// Add partial wasm32-wasip2 support
functionswasi::time::add_to_linker::<HostContext>(&mut linker)?;
// Add all the other wasm32-wasip2 definitions as traps so the experience is
// similar to wasm32-unknown-unknown, but with std::time::Instant::now() support.
linker.define_unknown_imports_as_traps(component)?;
This is what I want to do, but without shadowing allowed, ~~define_unknown_imports_as_traps~~ errors:
map entry
momento:functions/cache-scalar@1.0.0defined twice
To work around that issue, I put define_unknown_imports_as_traps and allow_shadowing up front. But I certainly don't want to allow shadowing, and I super don't want to insert bogus trap definitions for interfaces I know I support.
Is there a better workaround, or a pattern that works that I'm missing?
can you get rid of define_unknown_imports_as_traps completely? what do you need it for?
I do not have all of wasi. If I try to link a guest, it has a bunch of wasi imports that are missing. Environment, stdin, and so on.
ok. those can be very straightforward to define empty impls of
heres a bunch of them defined in here as the most trivial thing i could come up with https://github.com/pchickey/toy-external-events/tree/main/embedding/src/bindings
(that repo is basically "what if you need to write your own wasi impl in no_std", not really taken to any sort of conclusion, just a template for how some stuff interacts)
Oh hey, nice. I think I'd be even simpler, with all the bodies being something along the lines of Err(wasmtime::Error::msg("unsupported, some helpful message about who to contact"))
yes that will trap. for things like environment you may as well just return the empty environment
for stdin i defined a stream which never succeeds at reading, always just waits.
looks like with wasip2 you can link with these interfaces done:
time
environment
error
exit
filesystem_preopens
filesystem_types
stderr
stdin
stdout
streams
what a relief. Your repo was helpful too, with the deps folder example!
I wrote up a long response on the issue (sorry for the wall) but I'm curious if others have thoughts on how best to proceed as I'm unsure myself
You guys are amazing maintainers. Thank you :heart:
I wrote in the issue, but I'd love the unknown imports trap behavior to be more granular - so I can allow time and other unsupported wasi interfaces to evolve, but carefully manage my own interfaces. This way users can know at link time whether or not their program will run (modulo std stuff, which was an issue on wasm32-unknown-unknown anyway)
agreed that users knowing at link time whether their programs will run is a huge goal for the component ecosystem. Unfortunately, std and not wanting to proliferate target triples makes that tricky, because the whole model of std and target triples was designed for a different sort of idea for how programs interface with the outside world (i.e. via syscalls). components are deliberately something much closer to an ESM module than a posix program
so we're trying to find the balance where toolchains work as well as possible, but users and platform creators get those link-time validation properties
in general one of the things i hope i can demystify or make easier is to just redefine wasi impls as appropriate for any given platform.
I don't want wasi's implementation to feel mysterious or special, theyre "just" import functions and resources like anything else. unfortunately, wasi-io is kinda more than that, since its the scheduler... thats being resolved in component model async and wasip3.
Yeah, I'm sensitive to these goals. I think having more granularity on allowlisting interfaces to be fast-and-loose rather than setting that linker-wide would be a nice compromise.
For wasi itself, and I guess interface types more broadly, this is awesome infrastructure. Having the ability to hook into a guest's std is an incredible achievement. When I first approached wasi, it seemed magical and opaque. It was easier to write my own interfaces. But as I gained comfort with that and with Resources, and as I read some wasi pal code in std, I understood it's all quite straightforward.
That initial mystery, and interface type mystery generally, I think would be massively helped by making some small changes to what bindgen! does. Have you used prost? It generates tons of code like bindgen!, but it spits it out where you want - by default, to OUT_DIR. You can navigate to source, read the code, step with a debugger, etc., and you can even check in the generated source if you desire. I'd love to be able to use bindgen! in build.rs to get friendlier rs files!
I'm looking forward to trying out wasip3 :smile:
That's a good point about having a per-instance "ok everything in this instance unknown traps", I like that suggestion as well, thanks!
You can navigate to source, read the code, step with a debugger, etc., and you can even check in the generated source if you desire. I'd love to be able to use
bindgen!in build.rs to get friendlier rs files!
There's some documentation of doing this here and here, although I'm not opposed to adding more various options and I agree the defaults may not be the best
Kenny said:
That initial mystery, and interface type mystery generally, I think would be massively helped by making some small changes to what
bindgen!does. Have you usedprost? It generates tons of code likebindgen!, but it spits it out where you want - by default, toOUT_DIR. You can navigate to source, read the code, step with a debugger, etc., and you can even check in the generated source if you desire. I'd love to be able to usebindgen!in build.rs to get friendlier rs files!
There exists a poorly documented environment variable (WIT_BINDGEN_DEBUG from memory) which creates files in the build folder you can debug into.
cargo-component creates sibling files you can inspect with your IDE, and while I don't like that the generator is often outdated and important configuration options are missing, this part appealed to me.
Last updated: Dec 06 2025 at 05:03 UTC