Stream: general

Topic: Partial wasip2


view this post on Zulip Kenny (Apr 23 2025 at 23:22):

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?

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:24):

wasmtime does semver resolution automatically

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:25):

so the unknown import error you got shouldnt happen

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:25):

lets see if we can resolve that - can you make a minimal reproduction?

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:27):

(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)

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant - bytecodealliance/wasmtime

view this post on Zulip Kenny (Apr 23 2025 at 23:28):

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.

view this post on Zulip Kenny (Apr 23 2025 at 23:30):

https://github.com/bytecodealliance/wasmtime/blob/main/crates/environ/src/component/names.rs#L102-L104

It seems like it is "supposed" to match a demand for 0.2.3 to 0.2.5. :thinking:

A lightweight WebAssembly runtime that is fast, secure, and standards-compliant - bytecodealliance/wasmtime

view this post on Zulip Kenny (Apr 23 2025 at 23:32):

Oh, I wonder if define_unknown_imports_as_traps is disagreeing here.

view this post on Zulip Kenny (Apr 23 2025 at 23:32):

to do a partial wasip2 implementation, I have to define_unknown_imports_as_traps and allow_shadowing on the linker.

view this post on Zulip Kenny (Apr 23 2025 at 23:34):

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

view this post on Zulip Kenny (Apr 23 2025 at 23:35):

so it defines an exact match, which I'm sure the name map prefers to a squishy match

view this post on Zulip Alex Crichton (Apr 23 2025 at 23:36):

ah yeah I wouldn't be surprised if this was a bug in define_unknown_imports_as_traps, good catch!

view this post on Zulip Alex Crichton (Apr 23 2025 at 23:36):

mind filing an issue for this?

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:44):

thanks, I hadn't thought of define_unknown_imports_as_traps!

view this post on Zulip Kenny (Apr 23 2025 at 23:48):

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.0 defined 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?

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:49):

can you get rid of define_unknown_imports_as_traps completely? what do you need it for?

view this post on Zulip Kenny (Apr 23 2025 at 23:50):

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.

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:50):

ok. those can be very straightforward to define empty impls of

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:51):

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

play around with integrating wasmtime-wasi-io with an external event loop - pchickey/toy-external-events

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:52):

(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)

view this post on Zulip Kenny (Apr 23 2025 at 23:56):

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"))

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:56):

yes that will trap. for things like environment you may as well just return the empty environment

view this post on Zulip Pat Hickey (Apr 23 2025 at 23:57):

for stdin i defined a stream which never succeeds at reading, always just waits.

view this post on Zulip Kenny (Apr 24 2025 at 01:32):

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!

view this post on Zulip Alex Crichton (Apr 24 2025 at 21:11):

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

Test Case Any rust at all compiled with --target wasm32-wasip2 Steps to Reproduce Set up the host linker: fn link(linker: &mut Linker) { my_own_interface::add_to_linker(linker, |s| s)?; only_wasi_t...

view this post on Zulip Kenny (Apr 25 2025 at 17:08):

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)

view this post on Zulip Pat Hickey (Apr 25 2025 at 17:29):

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

view this post on Zulip Pat Hickey (Apr 25 2025 at 17:30):

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

view this post on Zulip Pat Hickey (Apr 25 2025 at 17:32):

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.

view this post on Zulip Pat Hickey (Apr 25 2025 at 17:32):

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.

view this post on Zulip Kenny (Apr 25 2025 at 18:15):

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:

view this post on Zulip Alex Crichton (Apr 25 2025 at 19:07):

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

view this post on Zulip Christof Petig (Apr 26 2025 at 07:44):

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 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!

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