Interacting with code

Emscripten provides numerous methods to connect and interact between JavaScript and compiled C or C++:

This article explains each of the methods listed above, and provides links to more detailed information.

Note

For information on how compiled code interacts with the browser environment, see Emscripten Runtime Environment. For file system related manners, see the File System Overview.

Note

Before you can call your code, the runtime environment may need to load a memory initialization file, preload files, or do other asynchronous operations depending on optimization and build settings. See How can I tell when the page is fully loaded and it is safe to call compiled functions? in the FAQ.

Calling compiled C functions from JavaScript using ccall/cwrap

The easiest way to call compiled C functions from JavaScript is to use ccall() or cwrap().

ccall() calls a compiled C function with specified parameters and returns the result, while cwrap() “wraps” a compiled C function and returns a JavaScript function you can call normally. cwrap() is therefore more useful if you plan to call a compiled function a number of times.

Consider the test/hello_function.cpp file shown below. The int_sqrt() function to be compiled is wrapped in extern "C" to prevent C++ name mangling.

// 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 <math.h>

extern "C" {

int int_sqrt(int x) {
  return sqrt(x);
}

}

To compile this code run the following command in the Emscripten home directory:

emcc test/hello_function.cpp -o function.html -sEXPORTED_FUNCTIONS=_int_sqrt -sEXPORTED_RUNTIME_METHODS=ccall,cwrap

EXPORTED_FUNCTIONS tells the compiler what we want to be accessible from the compiled code (everything else might be removed if it is not used), and EXPORTED_RUNTIME_METHODS tells the compiler that we want to use the runtime functions ccall and cwrap (otherwise, it will not include them).

Note

EXPORTED_FUNCTIONS affects compilation to JavaScript. If you first compile to an object file, then compile the object to JavaScript, you need that option on the second command. If you do it all together as in the example here (source straight to JavaScript) then this just works, of course.

After compiling, you can call this function with cwrap() using the following JavaScript:

int_sqrt = Module.cwrap('int_sqrt', 'number', ['number'])
int_sqrt(12)
int_sqrt(28)

The first parameter is the name of the function to be wrapped, the second is the return type of the function (or a JavaScript null value if there isn’t one), and the third is an array of parameter types (which may be omitted if there are no parameters). The types are “number” (for a JavaScript number corresponding to a C integer, float, or general pointer), “string” (for a JavaScript string that corresponds to a C char* that represents a string) or “array” (for a JavaScript array or typed array that corresponds to a C array; for typed arrays, it must be a Uint8Array or Int8Array).

You can run this yourself by first opening the generated page function.html in a web browser (nothing will happen on page load because there is no main()). Open a JavaScript environment (Control-Shift-K on Firefox, Control-Shift-J on Chrome), and enter the above commands as three separate commands, pressing Enter after each one. You should get the results 3 and 5 — the expected output for these inputs using C++ integer mathematics.

ccall() is similar, but receives another parameter with the parameters to pass to the function:

// Call C from JavaScript
var result = Module.ccall('int_sqrt', // name of C function
  'number', // return type
  ['number'], // argument types
  [28]); // arguments

// result is 5

Note

This example illustrates a few other points, which you should remember when using ccall() or cwrap():

  • These methods can be used with compiled C functions — name-mangled C++ functions won’t work.

  • We highly recommended that you export functions that are to be called from JavaScript:

    • Exporting is done at compile time. For example: -sEXPORTED_FUNCTIONS=_main,_other_function exports main() and other_function().

    • Note that you need _ at the beginning of the function names in the EXPORTED_FUNCTIONS list.

    • Note that _main is mentioned in that list. If you don’t have it there, the compiler will eliminate it as dead code. The list of exported functions is the entire list that will be kept alive (unless other code was kept alive in another manner).

    • Emscripten does dead code elimination to minimize code size — exporting ensures the functions you need aren’t removed.

    • At higher optimisation levels (-O2 and above), code is minified, including function names. Exporting functions allows you to continue to access them using the original name through the global Module object.

  • The compiler will remove code it does not see is used, to improve code size. If you use ccall in a place it sees, like code in a --pre-js or --post-js, it will just work. If you use it in a place the compiler didn’t see, like another script tag on the HTML or in the JS console like we did in this tutorial, then because of optimizations and minification you should export ccall from the runtime, using EXPORTED_RUNTIME_METHODS, for example using -sEXPORTED_RUNTIME_METHODS=ccall,cwrap, and call it on Module (which contains everything exported, in a safe way that is not influenced by minification or optimizations).

Interacting with an API written in C/C++ from NodeJS

Say you have a C library that exposes some procedures:

//api_example.c
#include <stdio.h>
#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
void sayHi() {
  printf("Hi!\n");
}

EMSCRIPTEN_KEEPALIVE
int daysInWeek() {
  return 7;
}

Compile the library with emcc:

emcc api_example.c -o api_example.js -sMODULARIZE -sEXPORTED_RUNTIME_METHODS=ccall

Require the library and call its procedures from node:

var factory = require('./api_example.js');

factory().then((instance) => {
  instance._sayHi(); // direct calling works
  instance.ccall("sayHi"); // using ccall etc. also work
  console.log(instance._daysInWeek()); // values can be returned, etc.
});

The MODULARIZE option makes emcc emit code in a modular format that is easy to import and use with require(): require() of the module returns a factory function that can instantiate the compiled code, returning a Promise to tell us when it is ready, and giving us the instance of the module as a parameter.

(Note that we use ccall here, so we need to add it to the exported runtime methods, as before.)

Call compiled C/C++ code “directly” from JavaScript

Functions in the original source become JavaScript functions, so you can call them directly if you do type translations yourself — this will be faster than using ccall() or cwrap(), but a little more complicated.

To call the method directly, you will need to use the full name as it appears in the generated code. This will be the same as the original C function, but with a leading _.

Note

If you use ccall() or cwrap(), you do not need to prefix function calls with _ – just use the C name.

The parameters you pass to and receive from functions need to be primitive values:

  • Integer and floating point numbers can be passed as-is.

  • Pointers can be passed as-is also, as they are simply integers in the generated code.

  • JavaScript string someString can be converted to a char * using ptr = stringToNewUTF8(someString).

    Note

    The conversion to a pointer allocates memory, which needs to be freed up via a call to free(ptr) afterwards (_free in JavaScript side) -

  • char * received from C/C++ can be converted to a JavaScript string using UTF8ToString().

    There are other convenience functions for converting strings and encodings in preamble.js.

  • Other values can be passed via emscripten::val. Check out examples on as_handle and take_ownership methods.

Calling JavaScript from C/C++

Emscripten provides two main approaches for calling JavaScript from C/C++: running the script using emscripten_run_script() or writing “inline JavaScript”.

The most direct, but slightly slower, way is to use emscripten_run_script(). This effectively runs the specified JavaScript code from C/C++ using eval(). For example, to call the browser’s alert() function with the text ‘hi’, you would call the following JavaScript:

emscripten_run_script("alert('hi')");