Compiling a New C/C++ Module to WebAssembly

When you've written a new code module in a language like C/C++, you can compile it into WebAssembly using a tool like Emscripten. Let's look at how it works.

Emscripten Environment Setup

First, let's set up the required development environment.

Prerequisites

Compiling an example

With the environment set up, let's look at how to use it to compile a C example to Wasm. There are a number of options available when compiling with Emscripten, but the main two scenarios we'll cover are:

We will look at both below.

Creating HTML and JavaScript

This is the simplest case we'll look at, whereby you get emscripten to generate everything you need to run your code, as WebAssembly, in the browser.

    First we need an example to compile. Take a copy of the following simple C example, and save it in a file called hello.c in a new directory on your local drive:

#include int main()  printf("Hello World\n"); return 0; > 
-o hello.html 

The options we've passed in with the command are as follows:

At this point in your source directory you should have:

Running your example

Now all that remains is for you to load the resulting hello.html in a browser that supports WebAssembly. It is enabled by default from Firefox 52, Chrome 57, Edge 57, Opera 44.

Note: If you try to open generated HTML file ( hello.html ) directly from your local hard drive (e.g. file://your_path/hello.html ), you will end up with an error message along the lines of both async and sync fetching of the wasm failed . You need to run your HTML file through an HTTP server ( http:// ) — see How do you set up a local testing server? for more information.

image

If everything has worked as planned, you should see "Hello world" output in the Emscripten console appearing on the web page, and your browser's JavaScript console. Congratulations, you've just compiled C to WebAssembly and run it in your browser!

Using a custom HTML template

Sometimes you will want to use a custom HTML template. Let's look at how we can do this.

    First of all, save the following C code in a file called hello2.c , in a new directory:

#include int main()  printf("Hello World\n"); return 0; > 
-o hello2.html hello2.c -O3 --shell-file html_template/shell_minimal.html 

Note: You could specify outputting just the JavaScript "glue" file* rather than the full HTML by specifying a .js file instead of an HTML file in the -o flag, e.g. emcc -o hello2.js hello2.c -O3 . You could then build your custom HTML completely from scratch, although this is an advanced approach; it is usually easier to use the provided HTML template.

Calling a custom function defined in C

If you want to call a function defined in your C code from JavaScript, you can use the Emscripten ccall() function and the EMSCRIPTEN_KEEPALIVE declaration, which adds your functions to the exported functions list (see Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?). Let's look at how this works.

    To start with, save the following code as hello3.c in a new directory:

#include #include  int main()  printf("Hello World\n"); return 0; > #ifdef __cplusplus #define EXTERN extern "C" #else #define EXTERN #endif EXTERN EMSCRIPTEN_KEEPALIVE void myFunction(int argc, char ** argv)  printf("MyFunction Called\n"); > 

By default, Emscripten-generated code always just calls the main() function, and other functions are eliminated as dead code. Putting EMSCRIPTEN_KEEPALIVE before a function name stops this from happening. You also need to import the emscripten.h library to use EMSCRIPTEN_KEEPALIVE .

Note: We are including the #ifdef blocks so that if you are trying to include this in C++ code, the example will still work. Due to C versus C++ name mangling rules, this would otherwise break, but here we are setting it so that it treats it as an external C function if you are using C++.

-o hello3.html hello3.c --shell-file html_template/shell_minimal.html -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']" 
button id="mybutton">Run myFunctionbutton> 
.getElementById("mybutton").addEventListener("click", () =>  alert("check console"); const result = Module.ccall( "myFunction", // name of C function null, // return type null, // argument types null, // arguments ); >); 

This illustrates how ccall() is used to call the exported function.

See also