11

I am currently working on a personal Node.js (>=8.0.0) project which requires me to call C subroutines (to improve execution time). I am trying to use WebAssembly to do this since I need my final code to be compatible when opened in a browser.

I have used Emscripten to compile C code into WebAssembly, and do not know how to proceed after this.

Any help in the right direction would be great. Thanks!

Cheran
  • 113
  • 2
  • 7

2 Answers2

16

You can build a .wasm file (standalone) without JS glue file. Someone has answered the similar question.

Create a test.c file:

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

Build the standalone .wasm file:

emcc test.c -O2 -s WASM=1 -s SIDE_MODULE=1 -o test.wasm

Use the .wasm file in Node.js app:

const util = require('util');
const fs = require('fs');
var source = fs.readFileSync('./test.wasm');
const env = {
    memoryBase: 0,
    tableBase: 0,
    memory: new WebAssembly.Memory({
      initial: 256
    }),
    table: new WebAssembly.Table({
      initial: 0,
      element: 'anyfunc'
    })
  }

var typedArray = new Uint8Array(source);

WebAssembly.instantiate(typedArray, {
  env: env
}).then(result => {
  console.log(util.inspect(result, true, 0));
  console.log(result.instance.exports._add(9, 9));
}).catch(e => {
  // error caught
  console.log(e);
});

The key part is the second parameter of WebAssembly.instantiate(). Without it, you will get the error message:

TypeError: WebAssembly Instantiation: Imports argument must be present and must be an object at at process._tickCallback (internal/process/next_tick.js:188:7) at Function.Module.runMain (module.js:695:11) at startup (bootstrap_node.js:191:16) at bootstrap_node.js:612:3

JBaczuk
  • 13,886
  • 10
  • 58
  • 86
yushulx
  • 11,695
  • 8
  • 37
  • 64
  • Although I figured out the answer a couple of days ago, your answer helped me understand better. Thanks! – Cheran Jul 24 '18 at 15:06
  • 2
    Getting `LinkError: WebAssembly Instantiation: Import #0 module="env" function="__memory_base" error: global import must be a number` – JBaczuk Nov 19 '18 at 14:45
  • The example don't work with node 10.x and 8.91. and emcc 1.38.21. Same error as @JBaczuk: `LinkError: WebAssembly Instantiation: Import #0 module="env" function="__memory_base" error: global import must be a number` – sven Dec 28 '18 at 17:41
  • Found the problem: test.c #include int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a+b; } Node.js app: replace `memoryBase` with `__memory_base` – sven Dec 28 '18 at 17:56
  • With node 8.93 I get LinkError: WebAssembly Instantiation: table import 0 is smaller than minimum 2, got 0 – frankster Apr 05 '19 at 14:29
1

Thanks @sven. ( translate only )

test.c:

#include <emscripten/emscripten.h>

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

compiling:

emcc test.c -O2 -s WASM=1 -s SIDE_MODULE=1 -o test.wasm

test.js:

const util = require('util');
const fs = require('fs');
var source = fs.readFileSync('./test.wasm');
const env = {
  __memory_base: 0,
  tableBase: 0,
  memory: new WebAssembly.Memory({
    initial: 256
  }),
  table: new WebAssembly.Table({
    initial: 0,
    element: 'anyfunc'
  })
}

var typedArray = new Uint8Array(source);

WebAssembly.instantiate(typedArray, {
  env: env
}).then(result => {
  console.log(util.inspect(result, true, 0));
  console.log(result.instance.exports._add(10, 9));
}).catch(e => {
  // error caught
  console.log(e);
});
Helmut Kemper
  • 662
  • 1
  • 6
  • 15
  • 1
    Is there any way to do this with c++ instead of c? –  Jan 16 '20 at 02:54
  • Excuse me. I left C aside and went to Golang. Golang becomes webassembly very easy https://github.com/golang/go/wiki/WebAssembly https://stdiopt.github.io/gowasm-experiments/hexy/ – Helmut Kemper Jan 22 '20 at 11:34