Changes to WebAssembly targets and handling undefined symbols
Rust's WebAssembly targets are soon going to experience a change which has a risk of breaking existing projects, and this post is intended to notify users of this upcoming change, explain what it is, and how to handle it. Specifically, all WebAssembly targets in Rust have been linked using the --allow-undefined flag to wasm-ld , and this flag is being removed. What is --allow-undefined ? WebAssembly binaries in Rust today are all created by linking with wasm-ld . This serves a similar purpose to ld , lld , and mold , for example; it takes separately compiled crates/object files and creates one final binary. Since the first introduction of WebAssembly targets in Rust, the --allow-undefined flag has been passed to wasm-ld . This flag is documented as: --allow-undefined Allow undefined symbols in linked binary. This options is equivalent to --import-undefined and --unresolved-symbols=ignore-all The term "undefined" here specifically means with respect to symbol resolution in wasm-ld itself. Symbols used by wasm-ld correspond relatively closely to what native platforms use, for example all Rust functions have a symbol associated with them. Symbols can be referred to in Rust through extern "C" blocks, for example: unsafe extern " C " { fn mylibrary_init ( ) ; } fn init ( ) { unsafe { mylibrary_init ( ) ; } } The symbol mylibrary_init is an undefined symbol. This is typically defined by a separate component of a program, such as an externally compiled C library, which will provide a definition for this symbol.

Rust's WebAssembly (Wasm) targets are set to undergo a significant change that may impact existing projects. This article aims to inform users about the upcoming modification, explain its implications, and provide guidance on how to adapt to it.
For years, Rust has been linking WebAssembly targets using the `--allow-undefined` flag with `wasm-ld`. This flag is about to be removed, which could potentially break projects that rely on it. To understand the change and how to handle it, it's essential to grasp what `--allow-undefined` does and how it affects WebAssembly binaries.
`wasm-ld` serves a similar purpose as traditional linkers like `ld`, `lld`, or `mold`. It takes separately compiled Rust crates or object files and combines them into a single WebAssembly binary. Since the inception of Rust's WebAssembly support, the `--allow-undefined` flag has been passed to `wasm-ld`. This flag, as documented, allows undefined symbols in the linked binary. It is equivalent to `--import-undefined` and `--unresolved-symbols=ignore-all`.
The term "undefined" in this context refers to symbols that `wasm-ld` cannot resolve during the linking process. These symbols are typically defined by separate components of a program, such as externally compiled C libraries. For instance, consider the following Rust code using an `extern "C"` block:
```rust
unsafe extern "C" {
fn mylibrary_init() -> ();
}
fn init() {
unsafe { mylibrary_init() }
}
```
Here, the symbol `mylibrary_init` is undefined in the Rust code. It is expected to be defined by an external library, which will provide a definition for this symbol.
By passing `--allow-undefined` to `wasm-ld`, the linker ignores these undefined symbols and treats them as imported symbols in the final WebAssembly module. This results in a module like:
```wat
(module
(import "env" "mylibrary_init" (func $mylibrary_init))
;; ...
)
```
The exact history of this flag's inclusion is unclear, but it has been part of Rust's WebAssembly workflow for some time.
The upcoming change involves removing the `--allow-undefined` flag from Rust's WebAssembly targets. This means that projects relying on this flag will need to adapt to avoid linking errors. To handle this transition smoothly, developers should ensure their projects are compatible with the new behavior.
One approach is to define all symbols that are currently marked as undefined. If a symbol is intended to be provided by an external library, the library should be properly linked or included in the project. Alternatively, if a symbol is not needed, it should be removed from the code.
Another option is to use the `--unresolved-symbols=ignore-all` flag explicitly, which has the same effect as `--allow-undefined`. However, this flag is deprecated, and it's recommended to avoid relying on it in the long term.
For projects that cannot modify their code to define undefined symbols, there is a workaround. They can continue using the `--allow-undefined` flag by adding it to their build configuration. This ensures that the linking process remains unchanged.
In conclusion, the removal of the `--allow-undefined` flag from Rust's WebAssembly targets poses a risk to existing projects. Understanding the flag's role and the implications of its removal is crucial. Developers should proactively address undefined symbols in their code to ensure compatibility with the new linking behavior. By defining symbols, linking external libraries, or adjusting build configurations, projects can smoothly transition to the updated WebAssembly targets.










