-
Notifications
You must be signed in to change notification settings - Fork 3.3k
WebAssembly Standalone
When compiling to WebAssembly, emcc
by default emits both a JavaScript file and a WebAssembly file. The JavaScript loads the WebAssembly which contains the compiled code. This is necessary in many cases as WebAssembly currently depends on a JavaScript runtime for features like longjmp, C++ exceptions, checking the date or time, printing to the console, using an API like WebGL, etc. However, if your WebAssembly only contains pure computational code, it may require almost no JavaScript support. If it in fact doesn't need any of the Emscripten runtime, then it is completely "standalone", and you may be able to run it in a wasm runtime like Wasmer or wasmtime, or write your own custom JS to load it on the Web, etc.
Emscripten has a STANDALONE_WASM
option that is the main way we support this (note that it requires the LLVM wasm backend). The flag is turned on automatically if you tell emcc to only emit a wasm file,
$ emcc source.c -o output.wasm
Otherwise, if you build with the flag,
$ emcc source.c -s STANDALONE_WASM
then it will emit a .js
and .wasm
file. The wasm is standalone as before, so you don't need the JS, but it may be convenient for running it on the Web.
Many APIs that emscripten uses depend on JS or Web APIs, though, like C++ exceptions as mentioned earlier, things like WebGL or WebAudio, etc. Calls to those APIs will still be emitted in standalone mode because we have no better alternative; this also gives you the option to add necessary APIs to a custom wasm embedding.
emcc can optionally emit useful metadata in the wasm file, that a runtime can use. See the EMIT_EMSCRIPTEN_METADATA
option, added in #7815. The metadata includes versioning as well as things like the memory and table sizes the wasm needs, that the runtime needs to provide.
As of 1.37.29, emcc
's optimizer is powerful enough to remove all runtime elements that are not used (it does this using meta-dce, dead code elimination that crosses the JavaScript/WebAssembly boundary). This can be helpful as then the necessary runtime is smaller and easier to replace, making the output even more standalone. To try this, simply build with something like
emcc source.c -Os
-Os
is needed to make the optimizer work at full power (you can also use -Oz
or -O3
).
Notes:
- If you use C++ objects, the compiler must in many cases emit code to catch exceptions so that RAII destructors are called, and exceptions require a lot of runtime support. Build with
-fno-exceptions
to disable exceptions entirely. - More details on how this works.
Dynamic libraries have a formal definition, and are designed to be loadable in a standard way. They also do not link in system libraries like libc. For those reasons they may be useful in some cases, but dynamic libraries also have downsides, such as having relocations for memory and function pointers, which add overhead that may be unnecessary if you are only using one module (and not linking several together), so overall they are not recommended - use STANDALONE_WASM
as described earlier.
If you do want to build a dynamic library, use
emcc source.c -s SIDE_MODULE=1 -o target.wasm
That will emit the output dynamic library as target.wasm
.
To use a side module, see loadWebAssemblyModule
in src/runtime.js
for some example loading code.
- The conventions for a wasm dynamic library are here.
- Note that there is no special handling of a C stack. A module can have one internally if it wants one (it needs to ask for the memory for it, then handle it however it wants).
- Full example.
To just see your own compiled code you can build to a wasm object file,
emcc input.cpp -o output.wasm -c
You can inspect that wasm file using wabt's wasm2wat
or binaryen's wasm-dis
.
README.md ``