wasmtime-wasi: `p1` cannot be used without `wasmtime/async`, requiring a C toolchain for sync-only embedders
Summary
wasmtime-wasi's p1 feature cannot be enabled without also enabling wasmtime/async, which pulls in wasmtime-internal-fiber and therefore requires a working C toolchain. Embedders that use only the synchronous WASIp1 API pay that cost for a capability they never touch.
The chain
In wasmtime-wasi 48.0.1:
[features]
default = ["p1", "p2"]
p0 = ["p1"]
p1 = ["dep:wiggle", "p2"]
p2 = ["wasmtime/component-model", "wasmtime/async"]p1 requires p2, and p2 enables wasmtime/async. In wasmtime 48.0.1:
async = [
"dep:wasmtime-fiber",
"wasmtime-component-macro?/async",
"runtime",
]And wasmtime-internal-fiber 48.0.1 ships src/windows.c, compiled through cc in its build script. So enabling p1 transitively makes a pure-Rust build into one that needs a C compiler.
There is no feature combination that avoids this: default-features = false, features = ["p1"] still reaches wasmtime/async through p2.
Why this is surprising
p1's own module documentation describes the relationship as incidental rather than semantic:
Support for WASIp1 is built on top of support for WASIp2 available at the crate root, but that's just an internal implementation detail.
And p1 offers add_to_linker_sync alongside add_to_linker_async, so a fully synchronous embedder is a first-class supported use case. Our embedding uses p1::add_to_linker_sync and contains no call_async or async_support anywhere, yet still requires fibers.
Concrete impact
We distribute a compiler toolchain that embeds Wasmtime to run WASIp1 guest modules. On Windows the fiber dependency turns "download our release and run it" into "download our release and also install Visual Studio Build Tools or MinGW-w64", solely to build a feature we never call. For a language toolchain trying to offer a self-contained install, that is a significant prerequisite to inherit from an unused code path.
This is not Windows-specific in principle — it is a C toolchain requirement for every sync-only embedder on every host — but Windows is where it is most visible, because a C compiler is not present by default.
Request
Could p1 be usable without wasmtime/async? Two shapes that would work, without preference between them:
- Split
p2sowasmtime/component-modelandwasmtime/asynccan be enabled independently, lettingp1depend only on the former. - Give
wasmtime-wasianasyncfeature, default-on for compatibility, thatdefault-features = falsecan switch off, withadd_to_linker_asyncgated behind it.
If the p1 → p2 → async path is load-bearing rather than incidental, that would be useful to know too — we would then document the C toolchain as a permanent prerequisite rather than waiting on it.
Happy to help
We have a native Windows x64 environment set up and can test a patch on both the sync path and the removal of the C-compiler requirement.
Versions
Observed on wasmtime-wasi 48.0.1 and wasmtime 48.0.1; the same relationship holds in 46.0.3 and 47.0.4. In 36.x the coupling was even tighter — async was hardcoded in [dependencies.wasmtime] rather than feature-gated — so this has already improved, and the remaining step is the p1 → p2 edge.
Source: bytecodealliance/wasmtime