WebAssembly: Building Standalone and Dynamic Linking Modules in Windows
Emscripten supports compiling C/C++ code to wasm files. Dynamic linking is a basic need for building complicated projects. In this article, I will share how to build a standalone wasm file and how to link multiple wasm files in Windows.
Tool Installation
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
emsdk.bat install latest
emsdk.bat activate latest
emsdk install mingw-4.6.2-32bit
emsdk activate mingw-4.6.2-32bit
- Wabt(The WebAssembly Binary Toolkit)
- Wasmer for Windows
- Web Server for Chrome
- WebAssembly for VSCode
WebAssembly Standalone
I created three simple C files: foo1.c, foo2.c and main.c.
Foo1.c
int foo1()
{
return 1;
}
Foo2.c
int foo2()
{
return 2;
}
Main.c
#include <stdio.h>
int foo1();
int foo2();
int main()
{
int result = foo1() + foo2();
printf("hello world %d\n", result);
return 0;
}
Build a standalone wasm file:
emcc main.c foo1.c foo2.c -o main.wasm
The generated wasm file doesn’t depend on an Emscripten JS runtime. We can run it in wasi-supporting runtimes, such as wasmer:
> wasmer run main.wasm
> hello world 3
Or open the .wasm file in WASI browser polyfill.
With STANDALONE_WASM
option, It will also emit a .js file for running the wasm file on the web:
emcc main.c foo1.c foo2.c -s STANDALONE_WASM -o main.wasm
CMake Build
Create a CMakeLists.txt file:
cmake_minimum_required (VERSION 3.1.3)
project (Main)
if (EMSCRIPTEN)
set(CMAKE_AR "emcc")
set(CMAKE_STATIC_LIBRARY_SUFFIX ".bc")
set(CMAKE_C_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_CREATE_STATIC_LIBRARY "<CMAKE_AR> -o <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
set(CMAKE_C_FLAGS "-s STANDALONE_WASM" )
add_executable(main
main.c
foo1.c
foo2.c
)
Run the following command to build the project:
emsdk activate mingw-4.6.2-32bit
mkdir build
cd build
emconfigure cmake ..
emmake make -j4
Dynamic Linking
We can also build the *.c files to wasm files respectively for linking dynamically.
Build the side modules:
emcc foo1.c -s SIDE_MODULE=1 -o foo1.wasm
emcc foo2.c -s SIDE_MODULE=1 -o foo2.wasm
Build the main module to emit the main.wasm, main.js and main.html files:
emcc main.c -s MAIN_MODULE=1 -o main.html
Serve the HTML and wasm files with Web Server for Chrome:
The dynamic libraries have not been linked yet. If you visit main.html, you will see the error message:
external function 'foo1' is missing. perhaps a side module was not linked in? if this function was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment
Open main.js to add following code for linking dynamic libraries:
Module['dynamicLibraries'] = ['foo1.wasm', 'foo2.wasm'];
Refresh the page. The dynamic linking sample is working now:
Downsides of Using Dynamic Libraries
Note: dynamic linking so far is not recommended because dynamic libraries have relocations for memory and function pointers, which add overhead.
Reference
- https://webassembly.org/getting-started/developers-guide/
- https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone
- https://emscripten.org/docs/compiling/Building-Projects.html
- https://github.com/emscripten-core/emscripten/wiki/Linking
- https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html
Related Articles
https://www.dynamsoft.com/codepool/wasi-sdk-zxing-barcode-wasm.html