-
Notifications
You must be signed in to change notification settings - Fork 3.3k
WebAssembly Standalone
By default emcc
creates a combination of JS files and WebAssembly, where the JS loads the WebAssembly which contains the compiled code. There is also progress towards an option to emit standalone WebAssembly files, which is detailed here.
Status: This is all a work in progress! Things will change and break.
This approach to creating a standalone WebAssembly module is based on Emscripten's side module concept. A side module makes sense here, since it is a form of dynamic library, and does not link in system libraries automatically, etc. - it is a self-contained compilation output.
Currently you need the incoming
branches in emscripten. master
is fine for binaryen.
Build with
emcc [params for your input files, optimization level, etc.] -s WASM=1 -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
]https://github.com/kripken/emscripten/blob/65271b0ed8e77d07ced7f6873c3582b6b0ae2719/src/runtime.js#L351) for some example loading code. An explanation of how that works is next.
- 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).
If you build
#include <stdio.h>
int main() {
printf("hello, world!\n");
return 0;
}
with emcc -s WASM=1 -s SIDE_MODULE=1 -Os -g
(-Os
optimizes for size; -g
keeps function names in the binary), then the wasm output is
(module
(type $FUNCSIG$ii (func (param i32) (result i32)))
(import "env" "gb" (global $gb$asm2wasm$import i32))
(import "env" "_puts" (func $_puts (param i32) (result i32)))
(import "env" "memory" (memory $0 256))
(import "env" "table" (table 0 anyfunc))
(import "env" "memoryBase" (global $memoryBase i32))
(import "env" "tableBase" (global $tableBase i32))
(data (get_global $memoryBase) "hello, world!")
(global $gb (mut i32) (get_global $gb$asm2wasm$import))
(export "__post_instantiate" (func $__post_instantiate))
(export "_main" (func $_main))
(export "runPostSets" (func $runPostSets))
(func $_main (result i32)
(drop
(call $_puts
(i32.add
(get_global $gb)
(i32.const 0)
)
)
)
(i32.const 0)
)
(func $runPostSets
(nop)
)
(func $__post_instantiate
(call $runPostSets)
)
)
Notes:
-
puts
from libc is not linked in. You must provide it as an import. - The module imports the memory and table and offsets for them. (
gb
is also imported due to internal details in fastcomp, we should remove it probably.) - The string "hello, world!" is in a data segment, written to the memory offset.
- The
main
method callsputs
as expected. Note how it offsets the address of the string. -
__post_instantiate
is exported, but on this simple module it does nothing useful.
README.md ``