How to Fix: Build failed on FreeBSD/i386: error[E0432]: unresolved import `wasmtime_asm_macros::asm_sym`
FreeBSD/i386 build failure in libwasmtime happens because the target tries to import wasmtime_asm_macros::asm_sym on an architecture path where that symbol is not available. On FreeBSD 13.2/i386, this usually means the crate is compiling code that assumes an assembly macro export intended for other supported targets, but the i386 build does not provide that import path.
Understanding the Root Cause
The error error[E0432]: unresolved import wasmtime_asm_macros::asm_sym is a Rust compile-time import failure. It means the compiler reached a module that expects asm_sym to exist in the wasmtime_asm_macros crate, but for the active platform configuration that item was not exported.
In practice, this build failure is typically triggered by one of these conditions:
- Unsupported architecture path: parts of wasmtime are optimized for architectures such as x86_64 or aarch64, while i386 may not be fully supported by the same assembly macro layer.
- Conditional compilation mismatch: a module guarded by cfg flags is still being compiled on FreeBSD/i386 even though the underlying macro or assembly support is missing.
- Ports framework version skew: the devel/libwasmtime port may be packaging a crate combination where macro exports and crate consumers are out of sync.
For FreeBSD ports, this usually is not a generic Rust toolchain bug. It is more often a target support gap or a port patching issue where the package needs to disable assembly-backed code paths on i386.
The key takeaway is simple: the build is trying to compile architecture-specific code that FreeBSD/i386 cannot satisfy.
Step-by-Step Solution
The most reliable fix is to patch the port so i386 does not build the unsupported assembly-dependent path. Depending on the exact libwasmtime version in the port tree, that means either disabling problematic features or applying a small source patch to exclude the import on i386.
1. Confirm the failing target
uname -m
uname -r
rustc -Vv
You should confirm that the failing builder is really i386 and not a cross-build environment with unexpected target flags.
2. Inspect the failing import in the extracted work tree
cd /usr/ports/devel/libwasmtime
make extract
cd work
find . -type f | xargs grep -n "wasmtime_asm_macros::asm_sym" 2>/dev/null
This identifies which source file imports asm_sym. In most cases, it will be inside a backend or runtime component that should not compile on i386.
3. Add an i386-specific conditional compilation guard
If the source currently contains something like this:
use wasmtime_asm_macros::asm_sym;
Patch it so the import is only compiled on supported architectures, for example:
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use wasmtime_asm_macros::asm_sym;
If the surrounding code block also depends on that symbol, guard the whole implementation:
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
mod trampolines;
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
compile_error!("This libwasmtime configuration is not supported on this architecture without disabling asm-backed components.");
If the port already has a portable fallback path, guard the assembly path and let the fallback compile instead.
4. Create a FreeBSD port patch
In the port directory:
cd /usr/ports/devel/libwasmtime
make extract
make patch
mkdir -p files
Create a patch file such as files/patch-crates-wasmtime-src-runtime-example with content similar to:
--- crates/wasmtime/src/runtime/example.rs.orig
+++ crates/wasmtime/src/runtime/example.rs
@@
-use wasmtime_asm_macros::asm_sym;
+#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
+use wasmtime_asm_macros::asm_sym;
Then rebuild:
make clean
make build
5. If feature flags are exposed, disable the assembly-dependent feature
Some versions of wasmtime expose optional features through Cargo. Check the port Makefile and the crate manifest:
grep -n "CARGO_FEATURES\|CARGO_CARGOTOML\|CARGO_ARGS" Makefile
grep -n "\[features\]" work/*/Cargo.toml work/*/*/Cargo.toml 2>/dev/null
If there is a feature enabling assembler trampolines or platform-specific runtime code, disable it in the port:
CARGO_FEATURES= default
CARGO_ARGS+= --no-default-features
Or selectively remove the problematic feature from the existing list.
6. Regenerate distinfo only if the port version changes
For a local patch-only fix, you usually do not need to regenerate distinfo. If you update the crate version itself to a newer upstream release that already fixes i386 gating, then run:
make makesum
7. Test in a clean poudriere environment
poudriere testport -j 13_2i386 -o devel/libwasmtime
This is the safest way to verify the fix because it catches missing patch context, hidden dependencies, and architecture-specific packaging issues.
8. Prefer an upstream-supported fix if available
If a newer upstream version of wasmtime already removed or gated the bad import, updating the port may be cleaner than carrying a local patch. Review upstream history through the Wasmtime repository and search for asm_sym changes before finalizing the FreeBSD port patch.
Common Edge Cases
- The import is guarded, but the module still fails: the symbol may be referenced elsewhere, so you must guard both the use statement and every dependent function or static item.
- x86 and x86_64 were treated as equivalent: they are not interchangeable in Rust cfg logic. target_arch = “x86” is 32-bit i386, while x86_64 is 64-bit only.
- Feature disabling breaks another crate: if you remove a default feature, another internal crate may expect it. In that case, targeted source gating is safer than broad feature removal.
- Port builds locally but fails in poudriere: local environments often leak cached Cargo artifacts. Always validate in a clean jail.
- Upstream simply does not support i386: if Wasmtime officially dropped 32-bit support for the affected component, the correct ports action may be to mark the port NOT_FOR_ARCHS=i386 rather than maintain an increasingly fragile patch.
If i386 support is no longer realistic, the packaging-level fallback is:
NOT_FOR_ARCHS= i386
NOT_FOR_ARCHS_REASON= upstream wasmtime asm macro path is unsupported on 32-bit x86
That approach is appropriate when the software cannot function correctly even if the immediate import error is patched away.
FAQ
1. Why does this fail only on FreeBSD/i386 but not on amd64?
Because amd64 usually follows a supported architecture path where asm_sym is exported and consumed correctly. On i386, conditional compilation may expose an unsupported code path or a missing assembly macro implementation.
2. Should I fix this by updating Rust?
Usually no. This error is most often caused by crate source compatibility or architecture gating, not by an outdated compiler. A Rust upgrade alone rarely fixes an unresolved import from a crate that does not export the symbol for the active target.
3. Is it better to patch the source or mark the port unsupported on i386?
If upstream still intends to support 32-bit x86 and there is a valid non-assembly fallback, patching is reasonable. If upstream has effectively dropped i386 support, the more maintainable solution is to restrict the port with NOT_FOR_ARCHS.
For most FreeBSD maintainers, the decision tree is straightforward: first verify whether wasmtime still supports the target, then either gate the asm import correctly or declare i386 unsupported. That resolves the E0432 asm_sym failure cleanly and prevents future build churn.