对 WebAssembly 目标的更改以及未定义符号的处理
Source: Rust Blog
TL;DR
- Rust 中的所有 WebAssembly 目标在链接时都使用了传递给 wasm‑ld 的
--allow-undefined标志。 - 该标志正被 移除。
- 此更改将在 Rust 1.96(2026‑05‑28)中发布。
什么是 --allow-undefined?
Rust 中的 WebAssembly 二进制文件是通过 wasm‑ld(WebAssembly 链接器)进行链接生成的。自从首次引入 WebAssembly 目标以来,链接时一直会向 wasm‑ld 传递以下标志:
--allow-undefined其文档说明如下:
--allow-undefined Allow undefined symbols in linked binary.
This option is equivalent to
--import-undefined and
--unresolved-symbols=ignore-all在此上下文中的 “未定义”
- 未定义符号 是指链接器在当前对象文件集合中找不到对应定义的符号。
- 在 Rust 中,你可以通过
extern "C"块引用这些符号,例如:
unsafe extern "C" {
fn mylibrary_init();
}
fn init() {
unsafe {
mylibrary_init();
}
}mylibrary_init在链接时是未定义的,直到另一个组件(例如 C 库)提供了它的实现。
当使用 --allow-undefined 时,链接器会把未定义符号当作 导入 处理,并在生成的模块中输出类似如下内容:
(module
(import "env" "mylibrary_init" (func $mylibrary_init))
;; …
)因此,未定义符号会被链接器 忽略,并在最终的 WebAssembly 模块中作为导入出现。
为什么会添加这个标志?
在 wasm‑ld 集成的早期阶段,--allow-undefined 实际上是让链接能够成功的必需选项。这个变通办法一直沿用下来,甚至成为默认行为,尽管现在已经不再需要它。
--allow-undefined 有什么问题?
在所有 WebAssembly 目标上使用 --allow-undefined 会导致 行为分歧,因为在本地平台上未定义的符号默认会报错。主要问题包括:
静默失败 – 配置错误会生成一个看似可运行的模块,但实际上导入了错误的符号。
难以诊断的错误 – 消费该模块的工具(例如
wasm-bindgen、wasm-tools component new)无法识别默认的"env"导入,从而产生令人困惑的提示。运行时意外 – 在浏览器中可能会看到类似以下的错误
Uncaught TypeError: Failed to resolve module specifier "env". Relative references must start with either "/", "./", or "../".真正的问题是一个未定义的符号泄漏进了模块,而不是缺少
"env"模块。
所有本地平台都将未定义符号视为错误,因此 Rust 当前在 WebAssembly 上的行为令人惊讶。去掉该标志可以使 WebAssembly 与本地平台保持一致,并为开发者提供更早、更清晰的诊断信息。
什么会被破坏,如何修复?
预期影响
在大多数情况下不会出现破坏——二进制文件如果导入了嵌入环境未提供的符号,只会无法运行。这实际上是一件好事:你会得到链接错误,而不是运行时失败。
对该标志的有意依赖
一些项目有意依赖 --allow-undefined 来生成导入,例如:
unsafe extern "C" {
fn js_log(n: u32);
}以及提供该导入的 JavaScript:
let instance = await WebAssembly.instantiate(module, {
env: {
js_log: n => console.log(n),
},
});修复方案
显式导入模块 – 使用
#[link]属性告诉链接器符号所属的模块:#[link(wasm_import_module = "env")] unsafe extern "C" { fn js_log(n: u32); }这使导入显式化,符号因此不再被视为未定义,且在更改前后都能工作。
临时恢复旧行为 – 如果需要快速解决方案,手动使用该标志编译:
cargo rustc -- -Clink-arg=--allow-undefined(或在
.cargo/config.toml中添加-Clink-arg=--allow-undefined。)
这个更改何时发生?
对 --allow-undefined 的移除已在 rust-lang/rust#149868 中跟踪。
- Nightly:此更改即将上线。
- Stable:它将在 Rust 1.96 与 2026‑05‑28 一起发布。
如果在更改后遇到任何问题,请在 Rust 仓库中提交 issue。
敬请关注,祝编码愉快!