Custom emcc flags
Link-time emscripten flags — SIMD, exceptions, BigInt, EVAL_CTORS, optimisation level, environment.
Once your YAML symbol list is right, the second knob is emccFlags. Use it to
tune optimisation level, exception model, SIMD, and target environments.
Recommended baseline
mainBuild:
emccFlags:
- -O3
- -fwasm-exceptions # native wasm exceptions; faster than JS exceptions
- -msimd128 # baseline SIMD (Safari + everyone else)
- -sWASM_BIGINT # i64 stays as BigInt, no legalisation glue
- -sEVAL_CTORS=2 # static-init evaluation at build time
- -sMODULARIZE=1 # init() returns Promise<Module>
- -sEXPORT_ES6=1 # ESM output
- -sENVIRONMENT=web,worker,node
- -sALLOW_MEMORY_GROWTH=1
- -sMAXIMUM_MEMORY=4GB # wasm32 ceilingFlag-by-flag rationale
| Flag | Why |
|---|---|
-O3 | Full LLVM optimisation. -Os is ~5% smaller, ~10% slower at runtime. -O0 for debugging only. |
-fwasm-exceptions | Uses Wasm try_table. ~5–10% smaller and faster than -fexceptions (JS-based) when supported (every modern engine). |
-msimd128 | Baseline SIMD. ~15% perf win on mesh and boolean kernels. Safari-compatible. |
-mrelaxed-simd | Chrome/Firefox-only additional SIMD ops. Adds another ~5% perf but breaks Safari — only ship if you can fall back. |
-sWASM_BIGINT | Removes the i64↔i32-pair shim. Saves ~30 KB JS glue. |
-sEVAL_CTORS=2 | Runs static initialisers at build time. Smaller payload + faster startup. |
-sMODULARIZE=1 -sEXPORT_ES6=1 | Required for import init from '...'. |
-sENVIRONMENT=web,worker,node | Strips dead env detection. Without this the runtime probes for process/window/importScripts. |
-sALLOW_MEMORY_GROWTH=1 | Required for any non-trivial geometry — initial 16 MB heap is not enough. |
-sMAXIMUM_MEMORY=4GB | wasm32 hard ceiling (2³² bytes). |
Trade-offs
Wasm exceptions vs JS exceptions
-fwasm-exceptions requires that all .o files AND the linker use the flag
consistently. Mixed builds produce __cpp_exception as an unresolved import at
link time. The default OCJS build sets OCJS_EXCEPTIONS=1 everywhere; only
override if you have a very narrow constraint (e.g. a wasm engine without
try_table support).
SIMD: baseline vs relaxed
Browsers diverged. Baseline -msimd128 is universal. Relaxed-SIMD
(-mrelaxed-simd) is Chrome + Firefox at the time of writing — Safari (as of
26.x) refuses to parse the relaxed opcodes and the wasm module fails to
instantiate. Ship relaxed-SIMD only if you maintain a fallback baseline build.
EVAL_CTORS levels
| Level | Behaviour |
|---|---|
| 0 | Off — every static init runs at startup |
| 1 | Eval ctors with safe side effects |
| 2 | Recommended — full ctor evaluation, requires -O2+ |
EVAL_CTORS=2 is the OCJS shipped default and the right answer almost always.
What you can NOT change at link time
The wasm bitwidth (wasm32 vs wasm64), the C++ stdlib version, the OCCT
commit pin, and the libclang version are all baked in during the bindgen
pipeline that produces the published Docker image. Customise via a fork of the
Docker image if you need any of those.