How to use a C function using EMCC and WASM on the web?

63 Views Asked by At

I am trying to make a simple website that displays the results of a function call from a javascript file that makes a call to a WASM file. So far I have the following files:

Makefile

FILES = add.c
OUTPUT = MyWasmLib
CC = emcc
EMCC_VERSION := $(shell command -v $(CC) 2> /dev/null)
EMCC_FLAGS = -s EXPORT_ALL=1 -s EXPORTED_RUNTIME_METHODS='["cwrap"]' -s ALLOW_MEMORY_GROWTH=1  -s EXPORT_ES6=1 -sMODULARIZE

all: check_emcc $(OUTPUT)

check_emcc:
ifndef EMCC_VERSION
    $(error "emcc is not installed. please install emscripten.")
endif

$(OUTPUT): $(FILES)
    $(CC) $(EMCC_FLAGS) -o [email protected] $(filter %.c, $(FILES))

clean:
    rm -i $(OUTPUT).js $(OUTPUT).wasm

.PHONY: all check_emcc clean

add.c

#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
    return a + b;
}

wasm_mjs_interface.js

import { default as MyWasmLib } from "./MyWasmLib.js";

let addWasmFunction;

let WASM_initialized;
const initializeWASM = () => {
    WASM_initialized = new Promise((resolve, reject) => {
        MyWasmLib.onRuntimeInitialized = () => {
            try {
                addWasmFunction = MyWasmLib.cwrap(
                    "add", "number", ["number", "number"]
                );

                resolve();
            }
            catch (error) {
                reject(error);
            }
        };
    });
};

initializeWASM();

export const WASM_add = async (a, b) => {
    await WASM_initialized;
    try {
        return addWasmFunction(a, b);
    }
    catch (error) {
        console.error("Error calling add function in WASM: ", error);
        throw error;
    }
};

index.js

import { WASM_add } from "./wasm_mjs_interface.mjs";

async function loadWasmAdd() {
    try {
        const result = await WASM_add(5, 3);
        console.log("WASM addition result: ", result);
        document.getElementById("result").textContent = `${result}`;
    }
    catch (error) {
        console.error("Error performing WASM addition: ", error);
    }
}

if (document.readyState === "loading") {
    window.addEventListener("DOMContentLoaded", loadWasmAdd);
} else {
    loadWasmAdd();
}

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>WASM Module Example</title>
        <script type="module" src="./index.js"></script>
    </head>
    <body>
        <p id="result"></p>
    </body>
</html>

I am running a simple python server with

python3 -m http.server 8000

I am viewing the server with

firefox 0.0.0.0:8000/index.html

Finally the problem I am getting is that in the actual console and on the page there is nothing happening. In the console I can see that there is a GET request for index.html MyWasmLib.js and wasm_mjs_interface.mjs however there are no errors in the console and nothing actually displays in the browser where I have the p tag.

2

There are 2 best solutions below

1
user21489919 On

I'm not sure how you solve this with emscripten, but tiny-wasm-runtime (which i wrote) has a few examples that do what you are trying to do, including the python server.

see https://www.npmjs.com/package/tiny-wasm-runtime

0
Volodymyr Boich On

In your case you don't load .wasm file. You need to load it and then initialise everything else.

something like this:

// loadWasm.js
Module = {};    // create the Module object to hold the wasm code
loadWASM = () => {
  
  return new Promise((resolve) => {
    
    fetch('myWasm.wasm')    // load the .wasm file
      .then(response => response.arrayBuffer())
      .then((buffer) => {    //return ArrayBuffer
        Module.wasmBinary = buffer;   // assign buffer to Module
        
        const script = document.createElement('script');
        script.src = 'myWasm.js';   // set script source
        
        script.onload = () => {    // once script has loaded
          console.log("Loaded Emscripten.");
          resolve(Module);    // return Module
        };
        document.body.appendChild(script); // append script to DOM
      });
  });
};

You can find example here https://medium.com/@matzewagner/creating-a-webassembly-work-environment-c584b15fdb73