Webassembly: calling C functions from Javascript with emscripten
I started to look into webassembly with the goal of implementing a version of Conway’s Game of Life which was able to use an engine written in C to calculate the next state of the game.

In this short article I want to illustrate the steps I made to compile a simple C function into a webassembly module callable by Javascript.
To compile the C code I used emscripten, an open source LLVM (Low Level Virtual Machine) to Javascript compiler.
Installing emscripten

Installing the emscripten toolchain is pretty straightforward, the official documentation is available at https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html. The installation process could take quite a lot of time anyway (depending on your network and machine speed), since the project is quite big.
Note: I use macOS therefore the syntax used in the article may be slightly different on Windows or Linux :)
Once emscripten is installed you have to set the system path to the active version of it (from the emsdk directory):
source ./emsdk_env.shTo test if emscripten is correctly configured just run:
emcc -vWriting and compiling a C function
The C function that I am going to compile implements the logic to define if a cell of the grid will be dead or alive in the next iteration of the game.
Let’s create a file called getCellStatus.c and paste this code in it.
The logic of getCellStatus is pretty simple. It accepts two integer parameters: the status and the number of neighbours, and returns the new status of the cell as an integer.
Now run:
emcc getCellStatus.c -o getCellStatus.js -s EXPORTED_FUNCTIONS=”[‘_getCellStatus’]”This command will generate a javascript file (getCellStatus.js) wrapping our C code in a module.
For the moment we need to manually export the function that we want to call from Javascript by adding the EXPORTED_FUNCTIONS options to the command.
Now there are two ways to call a C compiled function from Javascript:
- Wrapping the function using cwrap() (this returns Javascript function callable multiple times)
- Directly called the function using ccall() (this returns directly the return value of the C function)
We can now call getCellStatus by adding some code to the end of our Javascript module.
Wrapping a function with cwrap
cwrap accepts three parameters and returns a Javascript function:
- The name of the function to be wrapped
- The return type of the function
- An array with the types of the parameters of the function (which can be omitted if the function has no parameter)
In our case a call to cwrap would be as follows:
const getCellStatus = Module.cwrap('getCellStatus ', 'number', ['number', 'number']);console.log(getCellStatus(1,3));
console.log(getCellStatus(0,3));
console.log(getCellStatus(0,2));
console.log(getCellStatus(1,1));// Prints 1 1 0 0
Calling a function with ccall
ccall is similar to cwrap. It returns the value returned by the C function and requires an additional parameter defining the actual arguments to pass to the function call.
const getCellStatus = Module.ccall('getCellStatus ', 'number', ['number', 'number'], [1, 3]);// Prints 1
Using EMSCRIPTEN_KEEPALIVE to export functions
When we compiled our C file to Javascript we had to manually declare in the command which functions we wanted to export.
Emscripten provide us with an useful annotation to avoid this: EMSCRIPTEN_KEEPALIVE. So let’s rewrite our C file:
Compile the function (no need to declare exported functions now)
emcc getCellStatus.c -o getCellStatus.jsThen we can just create an index.js file to test our function
And run it with
node index_getCellStatus.js// Prints 0 1
Conclusion
As you can see using emscripten to generate a Javascript module from a C file and to call compiled C function with it is pretty easy.
To get further details about how you can use emscripten to interact with C functions read the official documentation at https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html.
Anyway this is a really basic usage of this tool, more advanced access to the memory or to wasm files requires a little more effort. I will try to explain how to do that in the second part of this article.
Thanks for reading :)
