Compiling Rust Code with lind-glibc (Shared Memory Enabled)
To compile Rust programs against lind-glibc:
- Ensure that the
scripts/cargo-lind_compilescript exists inPATH - Run
cargo lind_compileat the root of your Rust crate.
cargo-lind-compile is a drop-in replace for cargo build. It supports the same flags (such as --release) and is intended to be used in same contexts.
Internally, cargo lind_compile runs cargo build with the configurations detailed below.
It then runs lind-compile --opt-only on this output .wasm binary to optimize it in place.
Alternatively, you can use lind-cargo-build at the root of your Rust crate to run this script.
1. Cargo Configuration (.cargo/config.toml)
Create or modify .cargo/config.toml as follows (based on
scripts/rust/config.toml.template):
[build]
# Compile all Rust code for WASI Preview 1
target = "wasm32-wasip1"
[target.wasm32-wasip1]
# Use lind’s custom clang wrapper for glibc-based WASI linking
linker = "/home/lind-wasm/scripts/wasip1-clang.sh"
rustflags = [
# Do not use Rust’s built-in self-contained WASI linker
"-C", "link-self-contained=no",
# Enable WebAssembly features required for shared memory
# - atomics: required for multi-threading
# - bulk-memory: required for memory.copy / memory.fill
# - crt-static: ensure static runtime linking
"-C", "target-feature=+crt-static,+atomics,+bulk-memory",
# Import and export the linear memory so the runtime can control it
"-C", "link-arg=-Wl,--import-memory",
"-C", "link-arg=-Wl,--export-memory",
# Enable shared linear memory (threads proposal)
"-C", "link-arg=-Wl,--shared-memory",
# Set maximum memory size (64 MiB)
"-C", "link-arg=-Wl,--max-memory=67108864",
# Export stack symbols required by lind runtime
"-C", "link-arg=-Wl,--export=__stack_pointer",
"-C", "link-arg=-Wl,--export=__stack_low",
]
Why this is necessary
- Shared memory requires
atomics + bulk-memory - These features must be enabled for both your crate and
std - Rust’s prebuilt
stddoes not include these features by default - Therefore,
stdmust be rebuilt explicitly
2. Custom Linker Wrapper (scripts/wasip1-clang.sh)
The following script replaces Cargo’s default linker and ensures that:
lind-glibcis used instead of WASI libc- The correct
crt1.ostartup object is injected pthreadand glibc are linked properly- All Rust-provided linker arguments are preserved
Linker Script
#!/usr/bin/env bash
set -euo pipefail
# Path to lind-glibc sysroot
SYSROOT=/home/lind-wasm/src/glibc/sysroot
LIBDIR="$SYSROOT/lib/wasm32-wasi"
CRT1="$LIBDIR/crt1.o"
# Sanity checks (fail early with a clear message)
[ -r "$CRT1" ] || { echo "Missing $CRT1"; exit 1; }
[ -d "$LIBDIR" ] || { echo "Missing $LIBDIR"; exit 1; }
# Base clang invocation
cmd=(
clang
--target=wasm32-unknown-wasip1
--sysroot="$SYSROOT"
-nostartfiles # Prevent clang from injecting its own crt1.o
)
# Forward all arguments from rustc unchanged
cmd+=("$@")
# Inject lind-glibc startup object and libraries
cmd+=(
"$CRT1"
-L"$LIBDIR"
-lc # lind-glibc
-pthread # enable pthread support
)
# Print the final command for debugging (stderr keeps rustc output clean)
echo "[clang wrapper exec]" "${cmd[@]}" 1>&2
# Execute the linker
exec "${cmd[@]}"
Why this script exists
Rust’s default WASI linker:
- Uses WASI-libc instead of glibc
- Does not support lind’s threading and memory model
- Cannot inject a custom
crt1.o
This wrapper ensures full control over startup, libc, and threading behavior.
3. Build Rust with a Custom std
After configuring Cargo, compile your Rust project using nightly and rebuild the standard library:
cargo build -Z build-std=std,panic_abort
Alternatively, you can add the following to .cargo/config.toml, which achieves the same effect and is often easier to avoid missing during builds:
[unstable]
build-std = ["std", "panic_abort"]
This ensures that std is always rebuilt with the required features whenever you run cargo build.
What this does
- Forces Rust to rebuild
stdforwasm32-wasip1 - Applies your
rustflagstostditself - Enables atomics + bulk-memory inside
libstd