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

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.

wasi 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:

wasm web server

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:

webassembly wasm dynamic linking

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://www.dynamsoft.com/codepool/wasi-sdk-zxing-barcode-wasm.html