Repository navigation
Add Emscripten support - #43
Open
cyberneticangel wants to merge 4 commits into
Open
cyberneticangel wants to merge 4 commits into
cyberneticangel wants to merge 4 commits into
Conversation
Add a default target configuration for `wasm32-emscripten`, mirroring upstream's CMake configuration for Emscripten. The Emscripten sysroot is not bundled with Zig, so it must be passed with `-Dinclude_path`. - Add `src/emscripten.zig` with the Emscripten sources and build config. Threads are disabled, matching upstream's default without `-pthread`. C sanitizers trap instead of calling into a runtime, since Zig's UBSan runtime can't be built for Emscripten and `emcc` does the final link. - Fix `src/sdl.zon`: add the missing Emscripten sensor driver and the dummy tray, and split the generic main callbacks into their own group so they aren't linked in place of Emscripten's implementation. - Build the example for Emscripten by linking it with `emcc` into `zig-out/web`, and run it with `emrun`. - Port the example to SDL's main callbacks so it doesn't block the browser's event loop, and work around `std.Io.Threaded` failing to compile for Emscripten on Zig 0.16. - Build the Emscripten example in CI.
- Fail early with a clear error when `-Dlinkage=dynamic` is used for Emscripten, which upstream doesn't support. - Mark Emscripten as supported in the README, and document the `-Dinclude_path` and `emcc`/`emrun` setup needed to build for it.
Zig 0.17 renamed the `std.builtin.OptimizeMode` fields, keeping the old names only as deprecated declarations, so the bare `.Debug` enum literal no longer resolves. Spell out `std.builtin.OptimizeMode.Debug` like the rest of `build.zig` does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5.
Adds a default target configuration for
wasm32-emscripten, anemcc-linked build of the example, and a CI job that builds it.The Emscripten sysroot isn't bundled with Zig, so, as with Android and iOS, its headers are passed in with
-Dinclude_path:Changes
src/emscripten.zig: sources andSDL_build_config.hvalues for Emscripten. These mirror upstream'scmake/PreseedEmscriptenCache.cmakeand the Emscripten section ofCMakeLists.txt:SDL_THREADS_DISABLED). This matches upstream's default when building without-pthread.SDL_LOADSO_DUMMY, plus dummy haptics, process, dialog and tray. HIDAPI is disabled.src/sdl.zon:sensor/emscripten/SDL_emscriptensensor.c, which was missing.tray/dummy/SDL_tray.cto the Emscripten group, the same way the Android group does.main/generic/SDL_sysmain_callbacks.cout ofgenericinto its ownmain_callbacks_genericgroup.build.zigcompiles that group for every target except Emscripten (see below).build.zig:-Dinclude_pathtotranslate_con Emscripten, because the SDL headers include libc headers.-Dlinkage=dynamicon Emscripten. Upstream doesn't support shared builds there either.emccintozig-out/web, andrun-examplerunsemrun.src/example.zig: switched to SDL's main callbacks (see below).mymindstorm/setup-emsdk(emsdk 6.0.12) and an Emscripten example build to the Linux jobs.Notes for reviewers
These are the decisions you may want to weigh in on:
The generic main callbacks were silently overriding Emscripten's.
main/generic/SDL_sysmain_callbacks.cis only#ifdef'd out on iOS. With both it andmain/emscripten/SDL_sysmain_callbacks.cin the archive, the linker picked the generic one, whose blocking loop froze the browser and left the canvas black. Upstream CMake only adds the generic file when a platform has no implementation of its own, and the new group mirrors that. Behavior is unchanged for every other target.The example uses main callbacks on all platforms now. A blocking
whileloop can't run in the browser, so the example usesSDL_AppInit/SDL_AppIterate/SDL_AppEvent/SDL_AppQuit.SDL_main.hisn't part of the translated module, so the example declaresSDL_EnterAppMainCallbacksitself. Errors are now logged withSDL_Logand returnSDL_APP_FAILUREinstead of panicking. I can keep the old loop for native targets if you'd rather not change the desktop example.UBSan traps instead of calling a runtime on Emscripten. In Debug/ReleaseSafe, Zig instruments C code with UBSan handlers whose runtime it normally links itself. Here
emccdoes the final link. Zig's UBSan runtime can't be built for Emscripten (I triedbundle_ubsan_rt = true), sosanitize_cis set to.trapin those modes. Undefined behavior still stops execution, but with a wasmunreachablerather than a diagnostic. Release modes are untouched.Workaround for a Zig 0.16 std bug.
std.Io.Threadeddoesn't compile for Emscripten:std.os.emscripten.W.STOPSIGis declared to returnu32but builds an enum with@enumFromInt. Startup code references the default debugIo, so even an empty program hits it. On Emscripten the example setsstd_options_debug_threaded_io = nullandstd_options_debug_io = std.Io.failing, which is also why it logs throughSDL_Log. This is already fixed in Zig 0.17.0, so the workaround is only needed on 0.16. It's harmless on newer versions and can be dropped once 0.17 is the minimum supported version. User apps targeting Emscripten with Zig 0.16 need the same workaround.Users link their own apps with
emcc. Zig can't link Emscripten executables. The example's build step shows how to do it, and the README points to it. The example links with-sALLOW_MEMORY_GROWTH.Testing
emccinto a small C test program that uses the main callbacks.emscriptenvideo driver and theopengles2renderer, and a pixel readback from the canvas showed the clear color changing every frame.wasm32-emscriptenin Debug and ReleaseFast with both Zig 0.16.0 and 0.17.0. Ran it in Firefox: it started withvideo driver: emscripten, rendered frames and logged no errors.x86_64-linux-gnu,x86_64-windows-gnuand native, andzig fmt --checkpasses. Ran the callback-based example natively on Linux: it shows the pulsing gradient as before.Not included
-pthread), which need extraemccflags and cross-origin isolation headers from the server.SDL_EMSCRIPTEN_PERSISTENT_PATHis left empty).