Emscripten is a complete Open Source compiler toolchain to WebAssembly. Using Emscripten you can:

  • Compile C and C++ code, or any other language that uses LLVM, into WebAssembly, and run it on the Web, Node.js, or other wasm runtimes.

Practically any portable C or C++ codebase can be compiled into WebAssembly using Emscripten, ranging from high-performance games that need to render graphics, play sounds, and load and process files, through to application frameworks like Qt.

Emscripten generates small and fast code! Its default output format is WebAssembly , a highly optimizable executable format, that runs almost as fast as native code, while being portable and safe. Emscripten does a lot of optimization work for you automatically, by careful integration with LLVM, BinaryenClosure Compiler, and other tools.

Porting code to use Emscripten

Emscripten support for portable C/C++ code is fairly comprehensive.

There are differences between the native and Emscripten Runtime Environment, which mean some changes usually need to be made to the native code. That said, many applications will only need to change the way they define their main loop, and also modify their file handling to adapt to the limitations of the browser/JavaScript.

Getting started

  • Make sure you have downloaded and installed Emscripten (the exact approach for doing this will depend your operating system: Linux, Windows, or Mac).
  • Emscripten is accessed using the Emscripten Compiler Frontend (emcc). The Emscripten Compiler Frontend (emcc) is used to call the Emscripten compiler from the command line. It is effectively a drop-in replacement for a standard compiler like gcc or clang. This script invokes all the other tools needed to build your code.  It is called on the command line using ./emcc or ./em++

PS: On Windows the tool is called using the slightly different syntax: emcc or em++. The remainder of this tutorial uses the Linux approach (./emcc).

For the next section you will need to open a command prompt:

  • On Linux or macOS, open a Terminal.
  • On Windows open the Emscripten Command Prompt, a command prompt that has been pre-configured with the correct system paths and settings to point to the active Emscripten tools. To access this prompt, type Emscripten in the Windows 8 start screen, and then select the Emscripten Command Prompt option.

Navigate with the command prompt to the emscripten directory under the SDK. This is a folder below the emsdk root directory, typically <emsdk root directory>/upstream/emscripten/. The examples below will depend on finding files relative to that location.

Verifying Emscripten

If you haven’t run Emscripten before, run it now with:

./emcc -v

If the output contains warnings about missing tools, see Verifying the Emscripten Development Environment for debugging help.

Running Emscripten

You can now compile your first C/C++ file to JavaScript.

First, lets have a look at the file to be compiled: hello_world.c. This is the simplest test code in the SDK, and as you can see, all it does is print “hello, world!” to the console and then exit.

/*
 * Copyright 2011 The Emscripten Authors.  All rights reserved.
 * Emscripten is available under two separate licenses, the MIT license and the
 * University of Illinois/NCSA Open Source License.  Both these licenses can be
 * found in the LICENSE file.
 */

#include <stdio.h>

int main() {
  printf("hello, world!\n");
  return 0;
}

To build the JavaScript version of this code, simply specify the C/C++ file after emcc (use em++ to force compilation as C++):

./emcc tests/hello_world.c

You should see two files generated by that command: a.out.js and a.out.wasm. The second is a WebAssembly file containing the compiled code, and the first is a JavaScript file containing the runtime support to load and execute it. You can run them using node.js:

node a.out.js

This prints “hello, world!” to the console, as expected.

PS: Older node.js versions do not have WebAssembly support yet. In that case you will see an error message suggesting that you build with -s WASM=0 to disable WebAssembly, and then emscripten will emit the compiled code as JavaScript. In general, WebAssembly is recommended as it has widespread browser support and is more efficient both to execute and to download (and therefore emscripten emits it by default), but sometimes you may need your code to run in an environment where it is not yet present and so should disable it.

PS: If an error occurs when calling emcc, run it with the -v option to print out a lot of useful debug information.

Generating HTML

Emscripten can also generate HTML for testing embedded JavaScript. To generate HTML, use the -o (output) command and specify an html file as the target file:

./emcc tests/hello_world.c -o hello.html

You can now open hello.html in a web browser.

PS: Unfortunately several browsers (including Chrome, Safari, and Internet Explorer) do not support file:// XHR requests, and can’t load extra files needed by the HTML (like a .wasm file, or packaged file data as mentioned lower down). For these browsers you’ll need to serve the files using a local webserver and then open http://localhost:8000/hello.html).

Using files

Your C/C++ code can access files using the normal libc stdio API (fopenfclose, etc.).

But JavaScript is usually run in the sandboxed environment of a web browser, without direct access to the local file system. Emscripten simulates a file system that you can access from your compiled C/C++ code using the normal libc stdio API.

Files that you want to access should be preloaded or embedded into the virtual file system. Preloading (or embedding) generates a virtual file system that corresponds to the file system structure at compile time, relative to the current directory.

The hello_world_file.cpp example shows how to load a file (both the test code and the file to be loaded shown below):

// Copyright 2012 The Emscripten Authors.  All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License.  Both these licenses can be
// found in the LICENSE file.

#include <stdio.h>

int main() {
  FILE *file = fopen("tests/hello_world_file.txt", "rb");
  if (!file) {
    printf("cannot open file\n");
    return 1;
  }
  while (!feof(file)) {
    char c = fgetc(file);
    if (c != EOF) {
      putchar(c);
    }
  }
  fclose (file);
  return 0;
}

The example expects to be able to load a file located at tests/hello_world_file.txt:

FILE *file = fopen("tests/hello_world_file.txt", "rb");

We compile the example from the directory “above” tests to ensure that virtual filesystem is created with the correct structure relative to the compile-time directory.

./emcc tests/hello_world_file.cpp -o hello.html --preload-file tests/hello_world_file.txt

The above command is used to specify a data file to preload into Emscripten’s virtual file system — before running any compiled code. This approach is useful because Browsers can only load data from the network asynchronously (except in Web Workers) while a lot of native code uses synchronous file system access. Preloading ensures that the asynchronous download of data files is complete (and the file is available) before compiled code has the opportunity to access the Emscripten file system.

 You can now open hello.html in a web browser to see the data from hello_world_file.txt being displayed.

Reference

https://emscripten.org/docs/index.html

By Shabazz

Software Engineer, MCSD, Web developer & Angular specialist

Leave a Reply

Your email address will not be published. Required fields are marked *