docs: wasm exceptions as the review left them
The README called an exception escaping main a trap. It is an uncaught WebAssembly exception, and nothing prints its type or what(); the README says so now. It also lists what a wasm build refuses and why, says that setjmp needs -lsetjmp and that a longjmp across a noexcept function ends the program, that a wasmtime older than 47 needs -W exceptions=y, and that an old wasm-opt on PATH breaks release links. It documents exit and park in a page from EnableWasiBrowserRuntime, with the declaration of the park import. The wasi example still sent Arch users to wasi-libc++, which has no exception-enabled libraries. It asks for a wasi-sdk 33 sysroot or the Flatpak now, and names the browsers a page needs. AGENTS.md notes that the runtime test needs node, so it runs in the native loop and not in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2a05b8e6fb
commit
3e125d83f0
3 changed files with 18 additions and 4 deletions
|
|
@ -192,5 +192,6 @@ Local builds are two scripts in `project.cpp`. Run them with the native binary:
|
|||
- A warning is printed only when its unit actually recompiles. A build with nothing to do is silent, which is not evidence that a warning is gone.
|
||||
- A std module source only compiles against the headers of its own libc++ release, and a sysroot does not always ship one (Alpine). The Flatpak therefore carries the sources of the release next to the bundled one under `share/crafter-build/libc++-modules/<major>/`, one `libcxx-<major>-modules` manifest module each. When the bundled LLVM is bumped, keep the release it leaves behind as such a module: sysroots on the stable distro stay on it for months. The native loop has no such directory; stage one by hand under `share/crafter-build/` to test against a foreign sysroot.
|
||||
- The wasm compile flags live in one place, `WasmBaselineFlags` in `Crafter.Build-Clang.cppm`: the std module and every unit have to agree on them, and `VariantId()` and the std PCM directory hash them, so a change rebuilds instead of mixing old and new BMIs. They enable C++ exceptions, so the link takes the exception-enabled libc++ and libunwind from the sysroot's `lib/<triple>/eh/` (wasi-sdk 33 and later). The Flatpak's sysroot has them and a distro's may not; where they are missing the wasm tests skip, so run those through the Flatpak. A browser page checks the engine with the `WasmBaselineProbes` named in `variants.json`.
|
||||
- `WasiBrowserRuntimeExit` runs `wasi-runtime/runtime.js` under node and skips where there is none. The Flatpak has no node, so CI never runs it: after touching `runtime.js`, run the suite in the native loop with node on `PATH`.
|
||||
- `VariantId()` names the output directory, so CI globs `bin/crafter.build-exe-<target>-<march>-*/` rather than predicting the hash. The hash includes the compiler, so after a toolchain update the previous variant's directories stay in `bin/` and `build/` until `clean`, and such a glob matches both.
|
||||
- The self-host build and `test` keep the dependency notes section of this very file. None of Crafter.Math, Crafter.Asset and Crafter.LintRules ships an `AGENTS.consumer.md` yet. Once one does, a build here can change AGENTS.md whenever that repository changes its notes, since all three are unpinned. The tree is then dirty, so the next build's `git describe --dirty` version differs, which is a new `crafter.build-lib` variant and a full rebuild. Commit the section to settle it.
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -187,7 +187,15 @@ For cross-arch builds, set `cfg.sysroot` on the `Configuration` to point at a sy
|
|||
|
||||
For `--target=x86_64-w64-mingw32` (Windows from Linux), the pipeline cross-compiles as long as `mingw-w64` is installed, with libstdc++ 15 or newer for its std module. clang finds it by the `x86_64-w64-mingw32-gcc` on `PATH`; `CRAFTER_MINGW_DIR` names another prefix (the directory holding `x86_64-w64-mingw32/` and `lib/gcc/`), and inside the Flatpak the host's `/usr` is used when it has mingw-w64. Without one the build stops with a message saying where it looked. Pair it with `--runner=cmd:wine` to run the result. Only the MinGW ABI is supported, there is no MSVC target and no Windows host. `-fuse-ld=lld` is auto-injected on every link, and `-lstdc++exp` is auto-linked for the mingw target so user projects don't need to declare those flags.
|
||||
|
||||
For `--target=wasm32-wasip1`, the WASI sysroot is the one beside the toolchain (the Flatpak bundles one) unless `CRAFTER_BUILD_WASI_SYSROOT` names another, and tests run under `wasmtime`. C++ exceptions work as on the other targets: every unit and the std module are compiled with `-fwasm-exceptions` in the standardized form of WebAssembly exception handling (exnref), against the exception-enabled libc++ in the sysroot's `lib/<triple>/eh/`, and `-lunwind` is linked automatically. A sysroot without that libc++ (wasi-sdk before 33) stops the build with one line saying so. The result runs on engines with that proposal: Chrome 137, Firefox 131 and Safari 18.4 or newer, and the wasmtime the Flatpak bundles. A page from `EnableWasiBrowserRuntime` checks first and names what an older browser lacks in the console, instead of failing to compile the module. An exception that escapes `main` ends the program with a trap (wasmtime exits 1) without calling `std::terminate`, so a `std::set_terminate` handler does not run: wasm exception handling unwinds in a single phase, and nothing finds out that no handler is left until the stack is gone.
|
||||
For `--target=wasm32-wasip1`, the WASI sysroot is the one beside the toolchain (the Flatpak bundles one) unless `CRAFTER_BUILD_WASI_SYSROOT` names another, and tests run under `wasmtime`. C++ exceptions work as on the other targets: every unit and the std module are compiled with `-fwasm-exceptions` in the standardized form of WebAssembly exception handling (exnref), against the exception-enabled libc++ in the sysroot's `lib/<triple>/eh/`, and `-lunwind` is linked automatically. A sysroot without that libc++ (wasi-sdk before 33) stops the build with one line saying so. The result runs on engines with that proposal: Chrome 137, Firefox 131 and Safari 18.4 or newer, and the wasmtime the Flatpak bundles. A page from `EnableWasiBrowserRuntime` checks first and names what an older browser lacks in the console, instead of failing to compile the module. An exception that escapes `main` leaves the program as an uncaught WebAssembly exception (wasmtime reports `thrown Wasm exception` and exits 1, a page gets a `WebAssembly.Exception`) without calling `std::terminate`, so a `std::set_terminate` handler does not run and nothing prints the exception's type or `what()`: wasm exception handling unwinds in a single phase, and nothing finds out that no handler is left until the stack is gone. Catch it in `main` to report it.
|
||||
|
||||
A wasm build refuses three things before it starts, each with a message that says why: `-flto` in `compileFlags` or `linkFlags` (LTO code generation drops the exception handling, [WebAssembly/wasi-sdk#629](https://github.com/WebAssembly/wasi-sdk/issues/629)), `-fno-exceptions` (the std module is built with exceptions, and a unit without them cannot import it) and a shared library (the exception-enabled libc++ is static archives only). `setjmp` and `longjmp` work in C and C++ sources once `-lsetjmp` is in `linkFlags`; a `longjmp` across a `noexcept` function ends the program, because it is a wasm exception and the function's terminate handler catches it. Outside the Flatpak, a wasmtime older than 47 has exception handling off and needs `-W exceptions=y`, and a `wasm-opt` on `PATH` from a binaryen that cannot read the standardized encoding breaks release links, since clang runs it on optimized wasm links when it finds one.
|
||||
|
||||
In a page from `EnableWasiBrowserRuntime`, `exit` and `_Exit` end the program as they would anywhere else: none of its code runs on the way out, no destructor and no `catch (...)`, its status is in `window.crafter_wasi.exitCode`, and bridges that call into it on their own are expected to stop. A program that hands the thread to the browser for good and goes on serving calls, as Crafter.Graphics's `Window::StartSync()` does, parks instead of exiting. Parking never returns, runs nothing of the program either, and leaves `main`'s locals valid for the calls that follow:
|
||||
|
||||
```cpp
|
||||
extern "C" [[noreturn]] __attribute__((import_module("crafter_runtime"), import_name("park"))) void Park();
|
||||
```
|
||||
|
||||
### Configuring runners
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,14 @@ Build a C++26 program for the `wasm32-wasi` target and run it in a browser.
|
|||
|
||||
## Prerequisites
|
||||
|
||||
- `wasi-libc`, `wasi-libc++`, `wasi-libc++abi` (Arch packages — provide
|
||||
`/usr/share/wasi-sysroot/`, which `crafter-build` finds automatically).
|
||||
Other distros: install the WASI SDK and set `cfg.sysroot` in `project.cpp`.
|
||||
- A WASI sysroot with the exception-enabled libc++, `lib/wasm32-wasip1/eh/`
|
||||
from wasi-sdk 33 or later: wasm builds compile C++ exceptions and link those
|
||||
libraries. The Flatpak bundles one, which `crafter-build` uses as it is.
|
||||
Elsewhere, point `CRAFTER_BUILD_WASI_SYSROOT` at a wasi-sdk sysroot, or set
|
||||
`cfg.sysroot` in `project.cpp`. Arch's `wasi-libc++` packages have no such
|
||||
libraries, and the build stops with a message saying so.
|
||||
- For the browser: WebAssembly exception handling, in Chrome 137, Firefox 131,
|
||||
Safari 18.4 or newer.
|
||||
|
||||
## Build
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue