Skip to content

Commit 717c9ee

Browse files
committed
Document Wasm builds
1 parent 31285d0 commit 717c9ee

3 files changed

Lines changed: 116 additions & 5 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Started as an `rlua` fork, `mlua` supports Lua 5.5, 5.4, 5.3, 5.2, 5.1 (includin
2424

2525
`mlua` is tested on Windows/macOS/Linux including module mode in [GitHub Actions] on `x86_64` platforms and cross-compilation to `aarch64` (other targets are also supported).
2626

27-
WebAssembly (WASM) is supported through the `wasm32-unknown-emscripten` target for all Lua/Luau versions excluding JIT.
27+
Lua 5.1–5.5 and Luau support `wasm32-unknown-unknown` with a WASI C runtime and the `wasm32-wasip` targets. See [Compiling for WebAssembly](docs/wasm32.md) for setup and build instructions.
2828

2929
[GitHub Actions]: https://github.com/mlua-rs/mlua/actions
3030
[Luau]: https://luau.org

‎docs/wasm32.md‎

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Compiling for WebAssembly
2+
3+
Lua 5.1-5.5 and Luau can be compiled for WebAssembly. The WASI
4+
builds use [WASI SDK](https://github.com/WebAssembly/wasi-sdk) to compile and link
5+
the C/C++ code, and [Wasmtime](https://github.com/bytecodealliance/wasmtime) to run it.
6+
7+
| Rust target | Rust toolchain | Output |
8+
| --- | --- | --- |
9+
| `wasm32-wasip1` | stable | WASI Preview 1 module |
10+
| `wasm32-wasip2` | stable | WASI Preview 2 component |
11+
| `wasm32-wasip3` | nightly | WASI Preview 3 component |
12+
| `wasm32-unknown-unknown` | stable | Module or component, linked with a WASI Preview 1 or 2 C runtime |
13+
14+
LuaJIT and Luau's JIT backend are not supported.
15+
16+
## Setup
17+
18+
Run the commands below from the mlua repository root.
19+
20+
Install WASI SDK, for example on Apple Silicon:
21+
22+
```bash
23+
WASI_SDK_VERSION=34
24+
WASI_SDK_ARCHIVE="wasi-sdk-${WASI_SDK_VERSION}.0-arm64-macos"
25+
mkdir -p "$HOME/.local"
26+
curl -fL "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/${WASI_SDK_ARCHIVE}.tar.gz" \
27+
| tar -xz -C "$HOME/.local"
28+
export WASI_SDK_PATH="$HOME/.local/$WASI_SDK_ARCHIVE"
29+
```
30+
31+
Install Wasmtime:
32+
33+
```bash
34+
brew install wasmtime
35+
```
36+
37+
Install the Rust target(s):
38+
39+
```bash
40+
rustup target add wasm32-wasip1 wasm32-wasip2 wasm32-unknown-unknown
41+
```
42+
43+
The [setup script](../tests/wasm/setup.sh) selects the SDK compilers,
44+
libraries, linker flags and Cargo runner. Source it in the same shell as the
45+
Cargo commands. It also enables Wasm exceptions, which the Lua runtimes need
46+
for error handling.
47+
48+
## WASI Preview 1 and 2
49+
50+
To compile and run the basic tests with Lua 5.5 on Preview 2:
51+
52+
```bash
53+
source tests/wasm/setup.sh wasm32-wasip2
54+
cargo test --manifest-path tests/wasm/Cargo.toml \
55+
--target wasm32-wasip2 --lib --features lua55
56+
```
57+
58+
The test crate accepts `lua55`, `lua54`, `lua53`, `lua52`, `lua51` or `luau`.
59+
It enables vendored Lua automatically.
60+
61+
For your own application, enable `vendored` for Lua.
62+
Source the setup script using the path to your mlua checkout,
63+
then build or run your application:
64+
65+
```bash
66+
source /path/to/mlua/tests/wasm/setup.sh wasm32-wasip2
67+
cargo build --target wasm32-wasip2
68+
cargo run --target wasm32-wasip2
69+
```
70+
71+
Cargo uses Wasmtime as its runner. To run the output directly:
72+
73+
```bash
74+
wasmtime -W exceptions target/wasm32-wasip2/debug/your-app.wasm
75+
```
76+
77+
## wasm32-unknown-unknown
78+
79+
This build uses Rust's `wasm32-unknown-unknown` target with a WASI C runtime.
80+
The host must provide the matching WASI imports and support Wasm exceptions.
81+
Loading the output in a browser requires those facilities too.
82+
83+
The [test crate](../tests/wasm/src/lib.rs) is a working example. Run it with
84+
either C runtime:
85+
86+
```bash
87+
./tests/wasm/run.sh lua55 wasm32-wasip1
88+
./tests/wasm/run.sh lua55 wasm32-wasip2
89+
```
90+
91+
Append `--release` to build and run with optimizations, or `--debug` for the default debug build.
92+
93+
With Preview 1, it builds a `cdylib` and invokes the exported `run_tests` function.
94+
With Preview 2, it builds a Rust `staticlib`, then links it with a small
95+
[C entry point](../tests/wasm/main.c) into a command component.
96+
97+
To adapt this to your project:
98+
99+
1. Use the `allocator` module from the test crate as your global allocator. Rust
100+
and WASI libc must share an allocator so they do not independently manage the
101+
same linear memory.
102+
2. Export your entry point as an `extern "C"` function with `#[unsafe(no_mangle)]`.
103+
3. Follow [run.sh](../tests/wasm/run.sh) for the build and link commands, replacing
104+
the crate path, output name and entry point with your own. Its call to
105+
`setup.sh` selects the C runtime separately from the Rust target.

‎tests/wasm/run.sh‎

100644100755
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,22 @@ set -euo pipefail
33

44
lua="${1:-luau}"
55
c_target="${2:-wasm32-wasip1}"
6-
if [[ $# -gt 2 || ! "$lua" =~ ^(luau|lua5[1-5])$ || ! "$c_target" =~ ^wasm32-wasip[12]$ ]]; then
7-
echo "Usage: $0 [lua55|lua54|lua53|lua52|lua51|luau] [wasm32-wasip1|wasm32-wasip2]" >&2
6+
if [[ $# -gt 3 || ! "$lua" =~ ^(luau|lua5[1-5])$ || ! "$c_target" =~ ^wasm32-wasip[12]$ || ! "${3:---debug}" =~ ^--(debug|release)$ ]]; then
7+
echo "Usage: $0 [lua55|lua54|lua53|lua52|lua51|luau] [wasm32-wasip1|wasm32-wasip2] [--debug|--release]" >&2
88
exit 2
99
fi
1010

1111
cd "$(dirname "$0")/../.."
1212
source tests/wasm/setup.sh wasm32-unknown-unknown "$c_target"
1313
export CARGO_TARGET_DIR="$PWD/target/wasm-tests"
1414
cargo_args=(--manifest-path tests/wasm/Cargo.toml --target wasm32-unknown-unknown --features "$lua")
15-
wasm_output="$CARGO_TARGET_DIR/wasm32-unknown-unknown/debug/mlua_wasm_tests.wasm"
15+
profile=debug
16+
if [[ "${3:-}" == --release ]]; then
17+
cargo_args+=(--release)
18+
profile=release
19+
fi
20+
wasm_output_dir="$CARGO_TARGET_DIR/wasm32-unknown-unknown/$profile"
21+
wasm_output="$wasm_output_dir/mlua_wasm_tests.wasm"
1622
if [[ "$c_target" == wasm32-wasip1 ]]; then
1723
cargo build "${cargo_args[@]}"
1824
"${wasm_runner[@]}" --invoke run_tests "$wasm_output"
@@ -21,7 +27,7 @@ else
2127
wasm_output="${wasm_output%.wasm}.component.wasm"
2228
cargo rustc "${cargo_args[@]}" --lib --crate-type staticlib
2329
"$WASI_SDK_PATH/bin/clang" --target="$c_target" tests/wasm/main.c \
24-
"$CARGO_TARGET_DIR/wasm32-unknown-unknown/debug/libmlua_wasm_tests.a" \
30+
"$wasm_output_dir/libmlua_wasm_tests.a" \
2531
-L"$wasm_lib/eh" -lc++ -lsetjmp -o "$wasm_output"
2632
"${wasm_runner[@]}" "$wasm_output"
2733
fi

0 commit comments

Comments
 (0)