I'm trying to compile a full C++ program to Wasm using Emscripten as a learning opportunity. The following command does generate full valid and working HTML+JS+Wasm:
emcc main.cpp [...libraries] -Oz --std=c++17 -o output.html\
-s "EXPORTED_FUNCTIONS=['_solve']"
However, I got the following error when I tried to generate a standalone Wasm binary, ie:
emcc main.cpp [...libraries] -Oz --std=c++17 -o output.wasm\
-s "EXPORTED_FUNCTIONS=['_solve']"
and instantiate it in JS:
// `buffer` is pre-defined and contains the wasm binary in a typed array.
const module = new WebAssembly.Module(buffer);
// `imports` is an object of values and functions.
new WebAssembly.Instance(module, imports);
import function env:_assert must be callable (evaluating 'new WebAssembly.Instance(module, imports)')
Inspecting the generated Wasm binary reveals that it requires the host environment to supply quite a long list of functions and variables:
(import "env" "_abort" (func (;0;) (type 12)))
(import "env" "___assert_fail" (func (;1;) (type 13)))
(import "env" "abort" (func (;2;) (type 7)))
(import "env" "_llvm_stacksave" (func (;3;) (type 21)))
(import "env" "_llvm_stackrestore" (func (;4;) (type 7)))
(import "env" "_getenv" (func (;5;) (type 2)))
(import "env" "___setErrNo" (func (;6;) (type 7)))
(import "env" "___unlock" (func (;7;) (type 7)))
(import "env" "___syscall140" (func (;8;) (type 1)))
(import "env" "___map_file" (func (;9;) (type 1)))
(import "env" "___lock" (func (;10;) (type 7)))
(import "env" "___cxa_uncaught_exceptions" (func (;11;) (type 21)))
(import "env" "___cxa_throw" (func (;12;) (type 6)))
(import "env" "___cxa_pure_virtual" (func (;13;) (type 12)))
(import "env" "abortOnCannotGrowMemory" (func (;14;) (type 2)))
(import "env" "_strftime_l" (func (;15;) (type 10)))
(import "env" "_pthread_cond_wait" (func (;16;) (type 1)))
(import "env" "_llvm_trap" (func (;17;) (type 12)))
(import "env" "___cxa_allocate_exception" (func (;18;) (type 2)))
(import "env" "_emscripten_resize_heap" (func (;19;) (type 2)))
(import "env" "_emscripten_memcpy_big" (func (;20;) (type 3)))
(import "env" "_emscripten_get_heap_size" (func (;21;) (type 21)))
(import "env" "___wasi_fd_write" (func (;22;) (type 9)))
(import "env" "___syscall91" (func (;23;) (type 1)))
(import "env" "___syscall6" (func (;24;) (type 1)))
(import "env" "__table_base" (global (;0;) i32))
(import "env" "DYNAMICTOP_PTR" (global (;1;) i32))
(import "global" "NaN" (global (;2;) f64))
(import "global" "Infinity" (global (;3;) f64))
(import "env" "memory" (memory (;0;) 256 256))
(import "env" "table" (table (;0;) 725 725 funcref))
I could instruct Emscripten to compile the source code to a complete JS + Wasm bundle or a pure JS file, however:
My question is: Is there a way to compile with those dependencies removed or implemented directly in the binary? If not, are there libraries, ideally lightweight, that can provide implementations for those functions?
UPDATE: emscripten now supports -s STANDALONE_WASM which will build wasm files that are as portable as possible. For low level system calls the resulting binary will use WASI syscalls.
It sounds like you may be able to achieve you goal by using the -s WASM_ASYNC_COMPILATION=0
option.
To answer the wider question, the emscripten-built wasm files are fairly tied to the emscripten JS library code. There is some support for building stand alone wasm files and that support is being improved over time, but a fully standalone wasm file is not possible in the general case.