chenyan2002 opened issue #14346:
When
-W component-model-canonical-namesfeature is enabled, the guest side component encodes interface names with canonical names, while the host-side bindgen is still using the full version. This causes the linking to fail.
NameMapcurrently supports matchinga:b/c@0.2.1with its alternate keya:b/c@0.2. But if the component is importinga:b/c@0.2, we cannot match it back witha:b/c@0.2.1. We need to refactorNameMap/alternate_lookup_keyto be able to handle both canonical version and full version during the transition period.Another fix is to add an option in the host side
wit-bindgento emit canonical names. But when the component is importing a full version,NameMapneeds to know how to match it with the canonical name.Raised from https://github.com/bytecodealliance/wasmtime/pull/14344#discussion_r4019873593
alexcrichton added the wasm-proposal:component-model label to Issue #14346.
alexcrichton commented on issue #14346:
I haven't sat down to think through a full solution just yet, but the main property I think that should be upheld is that turning on and/or rolling out canonical names should not break any preexisting behaviors. For example turning on the CLI feature shouldn't cause any existing workflows to break. Additionally if this were a
bindgen!feature then turning that on inwasmtime-wasishouldn't cause any existing workflows to break. I think it's fine if the way this is configured opts-in to more behaviors or perhaps disallows some pretty edge-case-y behaviors but for big things like "instantiating a preexisting component using WASI not using canonical-names" should not break.I'd probably personally lean towards not changing insertion into a linker and leave
bindgen!dealing with full versions. Internally theNameMapwould satisfy requests for 0.2 with 0.2.1 then, for example. I haven't fully thought this through, however.
chenyan2002 commented on issue #14346:
Thinking a bit more, I think it makes more sense to keep the host side to use the full version. But there is a tricky corner case. Currently, host can import both
a:b/c@0.2.0anda:b/c@0.2.1, and have different host implementations. If we emit canonical version, this two interfaces somehow need to merge. I'm not sure if we want to merge them?Asking the same question from the guest side, if guest imports
a:b/c@0.2, does it get0.2.0or0.2.1? Followingalternate_lookups, we always get the highest version0.2.1. But if the guest side hasversionsuffix ".0", should we get0.2.0instead? Ideally, we should never look atversionsuffixin the lookup. Then that means0.2.0will never be linked, and thus need to be merged into0.2.1?
alexcrichton commented on issue #14346:
If we keep the current behavior of
NameMapwhich allows multiple versions to be defined, then we should probably mostly keep the same behavior it has today. Importing@0.2would get the maximum version and@0.2 ... suffix .0would import 0.2.0 if defined or otherwise the maximum.Personally though that behavior of
NameMapwas mostly done out of necessity, and I'd be open to consider removing it to only allow one-implementation-per-semver-track
chenyan2002 commented on issue #14346:
For consistency, I think it's cleaner to merge the semver track on the host side, just like we do on the guest side. This will be a breaking change though. Do we want to gate it under a flag?
alexcrichton commented on issue #14346:
I'm not personally aware of anyone actively leveraging the ability to define multiple versions, so in that sense I think it'd be ok to have a breaking change. Things like this that are so core often tend to pull people out of the woodwork, though, so this'll probably cause difficult-to-resolve breakage somewhere. That being said this is the direction we generally want to go in, so I think it's ok to do that.
chenyan2002 commented on issue #14346:
The "one-implementation-per-semver-track" approach is likely to trigger many behavior changes. There are too many corner cases during the transition period: mixed use of canonical and non-canonical name in a component, some interfaces are semver merged, some are not...I think I would try to preserve the current
NameMapsemantics, storing everything using the full version, and rely on thealternate_lookup_keyfor canonical name matching.For host APIs that define names (
linker.instance("a:b/c@0.2.1")), currently it's using just string equality. Do we want to extend it toalternate_lookup_keyif an alternative key exist? Do we want to support canonical version likeinstance("a:b/c@0.2")?
alexcrichton commented on issue #14346:
That's ok with me yeah, but I'll also point out that in some sense this is kicking the can down the road because this transition period mostly isn't going to go away any time soon. Eventually Wasmtime will likely want to consider a behavioral change here and handle any fallout from that, but if you'd perfer to not take that on right now that's also ok.
You say that host APIs are just using string equality, but can you clarify what for? Insertion into
NameMaphappens at the full version, but querying uses the alternate key as well to see if something is present. TheNameMapand Wasmtime are pretty agnostic to the strings that are inserted so I don't think there's anything preventing you from inserting@0.2today and I don't think it's worth trying to specifically allow or disallow it. In general it's mostly geared towards getting idiomatic usage working
chenyan2002 commented on issue #14346:
I mean into_instance is using
map.raw_get_mutfor lookup, instead ofmap.get. So if you havea:b/c@0.1.1in the map,into_instance("a:b/c@0.1.0")would create a new entry, instead of locating to0.1.1. It's more about the semantics of instance name, is it purely a string, or it's semver aware.Similarly, for
Linker::define_unknown_imports_as_traps, it callslinker.instance. So if there is aa:b/c@0.1.1on the host side, and the guest importsa:b/c@0.1.0, it will trap for this imports, instead of calling0.1.1.
alexcrichton commented on issue #14346:
Ah ok makes sense, although arguably both of those situations are bugs.
a:b/c@0.1.1satisfies a guest import fora:b/c@0.1.0sodefine_unknown_Improts_as_trapsarguably shouldn't do anything. Forinto_instance(...)that it's necessarily a bug that it yields a unique instance right now but I don't think it'd be overly problematic yielding the same instance
Last updated: Oct 11 2026 at 02:20 UTC