This project makes use of JSPI which is able to suspend/resume wasm execution which avoids the need to export functions to call them from JS. Combined with pdclib allows for porting some desktop programs to run in the browser with little changes.
This requires a modern chrome version or javascript.options.wasm_js_promise_integration enabled in firefox.
CC = clang --target=wasm32 --sysroot=/path/to/wasm/libc
CFLAGS += -fno-builtin # fixes math.h undefined symbols, but also disables other builtins (specific -fno-builtin-X might break as later clang versions have more builtins) TODO a proper libm would fix this, but openlibm gave wrong results.
LDFLAGS += -nodefaultlibs -lc -lm # avoids system path libclang_rt.builtins-wasm32.a, or `-nostdlib -Dmain=_start -lc -lm` for no crt1 as well
LDFLAGS += -Wl,--export-table # for function pointers access in JS, such as for event listeners
LDFLAGS += -Wl,--export=malloc # for JS functions that allocate internally (JS_openFilePicker/glGetString)
LDFLAGS += -Wl,--stack-first # to fail fast on stack overflow, else it will quietly overwrite data
LDFLAGS += -Wl,-z,stack-size=value # increase stack size
more options: https://lld.llvm.org/WebAssembly.html
To have clangd work create a compile_flags.txt file with the same flags as CC
- run
make html > /path/to/project/index.html(ormake js) to bundle/minify libjs - run a http server
esbuild --servedir=.and pass program name + args similar to CLI/?program&arg 1&arg 2in the url.
Builtin key shortcuts are alt+enter for fullscreen toggle, shift+enter for image scaling toggle
- add wasm platform to the codebase or just replace SDL, use
#include <js/glue.h>to have access to JS functions - pdclib doesn't implement posix, see musl for implementations
- call JS_setTimeout(ms) or JS_requestAnimationFrame() in any long running loops (main loop, ones waiting for input or http requests)
https://medium.com/oasislabs/webassembly-debugging-bec0aa93f8c6
build your program with -g -O0 and optionally -lc-dbg instead of -lc for better stack traces
git clone https://github.com/emscripten-core/emscripten.git
../emscripten/tools/wasm-sourcemap.py out.wasm -w out.wasm -p $(CURDIR) -s -u ./out.wasm.map -o out.wasm.map --dwarfdump=/usr/bin/llvm-dwarfdump
or
llvm-dwarfdump -a out.wasm > out.wasm.dwarf
../emscripten/tools/wasm-sourcemap.py out.wasm -w out.wasm -p $(CURDIR) -s -u ./out.wasm.map -o out.wasm.map --dwarfdump-output=out.wasm.dwarf
If your systems llvm-dwarfdump isn't compatible with the latest wasm-sourcemap.py, you can also use emsdk/upstream/bin/llvm-dwarfdump.
After this chrome will automatically load the sourcemap linked in the modified wasm file.
Optional:
- bundler/minifier/http server: esbuild, npm/node are not needed!
- emscriptens wasm-sourcemap.py
- wasm-strip
- wasm-opt: this one doesn't appear to do much if already using clang optimizations
- compiler-rt (maybe wasi?): If you provide this to clang you won't need to pass -nodefaultlibs -lc but it has to be placed in system path? Without this you may get undefined symbol errors especially with
-lc-dbgdue to use of long doubles, which have to be stubbed out like __unordtf2 - wcc: alternative to clang+wasm-ld but lacking goto, no dwarf debuginfo and may have other issues compiling. use
/path/to/wcc -isystem=/path/to/libc/include -L/path/to/libc/lib -Wl,--export-table --stack-size=amount.
- no proper file modes for writing/appending files etc, use JS_saveFile(). For sockets you have to use the functions in websocket.h not syscalls.
- Chrome performance drops with dev console open, Firefox can't fully make use of the wasm sourcemaps
- TODO: webgpu/webworker + some events: touch/gamepad/glctx loss+restore etc https://developer.mozilla.org/en-US/docs/Web/Events
- WIP: webgl2, pdclib can't format floats yet causing issues with EG printing fps and quake options/keys (use JS_logFloat, stb_sprintf or nanoprintf
In some forks the non-wasm targets haven't been kept in a working state, and most programs don't support saves load/download yet
- Client3
- PL3D-KC
- doomgeneric
- quakegeneric
- agnes
- Peanut-GB
- agbemu
- ntremu - only runs decrypted roms, need to provide firmware.bin or touch won't work
- minecraft-weekend - uses WebGL2 > OpenGL ES 3.0 bindings
These emulators are not so accurate but still serve as examples