Skip to content

feat: add emscripten build to ci - #392

Merged
webern merged 8 commits into
mainfrom
claude/386-context-discussion-r2yosn
Aug 7, 2026
Merged

feat: add emscripten build to ci#392
webern merged 8 commits into
mainfrom
claude/386-context-discussion-r2yosn

Conversation

@webern

@webern webern commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Human Summary

Add a smoke build to WASM and run something trivial to make sure we don't break denigma.

Summary

mx already gets cross-compiled to WebAssembly downstream today: denigma (github.com/rpatters1/denigma) builds it client-side for browser use in a musx-to-MusicXML converter, but nothing here proves that keeps working, so a regression would only surface in someone else's CI. This adds an Emscripten build to mx's own CI.

  • mx-sdk's Dockerfile gets a pinned emsdk install (6.0.6), matching how every other tool in that image is version-pinned rather than "latest". EM_CACHE is redirected to the mounted build volume, same reasoning as CCACHE_DIR/GOPATH right below it in the file: the container runs as the caller's uid:gid, which can't write under the root-owned /opt/emsdk at runtime.
  • CMakeLists.txt now enables exception catching under EMSCRIPTEN (-fexceptions, compile and link). Emscripten disables catching by default, which turns mx's internal MX_THROW/catch boundary in DocumentManager (src/private/mx/utility/Throw.h) into a fatal abort instead of a caught ResultCode::internalError. Previously only denigma's own build set this flag (globally, before FetchContent-ing mx) -- mx didn't configure itself correctly for EMSCRIPTEN on its own. Confirmed this is the same fix denigma-examples' top-level CMakeLists.txt already applies, so this reproduces a known-working setup rather than a new one.
  • New make wasm-lib / wasm-build / wasm-test targets, driven inside mx-sdk like every other gate. wasm-test builds mx::api and runs the existing mxread/mxwrite/mxhide examples under Node -- it exercises the library through DocumentManager, not just a compile.
  • New test-wasm CI job (mirrors test-linux/quality/gen's Docker setup) running make wasm-test.

Testing

  • make -n wasm-test (dry run, both outside- and inside-container branches) resolves to the expected emcmake/emmake/node commands
  • Native cmake -S . -B ... -DMX_API=on still configures cleanly with the new EMSCRIPTEN block present (a no-op when not cross-compiling)
  • ci.yaml still parses as valid YAML
  • CI

References

mx already gets cross-compiled to WebAssembly downstream (denigma,
github.com/rpatters1/denigma, uses it for browser-side musx-to-MusicXML
conversion), but nothing here proves it keeps working. Add emsdk to the
pinned mx-sdk toolchain, teach mx's own CMakeLists.txt to enable exception
catching under Emscripten (it disables catching by default, which turns
mx's internal MX_THROW/catch boundary in DocumentManager into a fatal abort
-- previously only denigma's build set this, not mx itself), and wire up
`make wasm-test` to build mx::api and run the mxread/mxwrite/mxhide
examples under Node so the check exercises the library, not just a
compile.

Closes #386
@webern webern added testing ai Issues opened by, or through, a coding agent. labels Aug 7, 2026 — with Claude
webern added 2 commits August 7, 2026 20:30
emsdk's node dependency ships as a .tar.xz; without xz-utils the tar
extraction fails, so the mx-sdk image itself never finished building --
taking test-linux, quality, and the new wasm job down with it (they all
build the same image first). Also rename the wasm CI job to `emscripten`.
Emscripten's own tree (upstream/emscripten/) contains a subdirectory
literally named `cmake` (its CMake toolchain-file module). Prepending
that directory onto PATH meant every `cmake` lookup resolved to it
instead of /usr/bin/cmake -- execve() on a directory returns EACCES,
which surfaced as "make: cmake: Permission denied" and broke every job
that builds through mx-sdk (test-linux, quality), not just wasm. Append
emsdk's dirs after the existing PATH instead. Also drop emsdk's
downloads/ (raw .tar.xz archives) once installed -- pure dead weight
after extraction.
Comment thread Dockerfile Outdated
Comment thread Dockerfile Outdated
Comment thread Makefile Outdated
Comment thread Makefile Outdated
Comment thread CMakeLists.txt Outdated
webern added 4 commits August 7, 2026 20:54
Same bug as the cmake fix, one PATH entry earlier: bare /opt/emsdk
contains a node/ subdirectory, searched before /opt/emsdk/node/current-bin
where the real node binary lives -- so `node` resolved to a directory and
failed with EACCES. Reorder PATH and drop the now-unused bare /opt/emsdk
entry (nothing here invokes the emsdk CLI by name).

Also trims several comments flagged as too long in review.
Emscripten's default MEMFS starts empty -- writeToFile("build/wasm/...")
failed because that parent directory doesn't exist inside the virtual
filesystem, not because of anything wrong with mx::api itself. A bare
filename writes to MEMFS's root, which always exists.
The emscripten job was the slowest in CI (8m32s vs ~3-4m for every
other job) because wasm-lib explicitly blanked the compiler-launcher
env, so it rebuilt all of mx_core + mx from scratch on every run --
unlike test-linux/quality/gen, which all get a persisted per-job
ccache dir. ccache wrapping emcc's Python driver was an untested
worry, not a real conflict (no coverage-instrumentation clash like the
targets that legitimately blank it); wire up a ccache cache step for
this job matching the existing pattern and let CI confirm it works.
Comment thread .github/workflows/ci.yaml Outdated
Comment thread .github/workflows/ci.yaml Outdated
Comment thread Makefile Outdated
@webern
webern merged commit 62d945e into main Aug 7, 2026
8 checks passed
@webern
webern deleted the claude/386-context-discussion-r2yosn branch August 7, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai Issues opened by, or through, a coding agent. testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add emscripted build to CI

1 participant