Interacting with code¶
Emscripten provides numerous methods to connect and interact between JavaScript and compiled C or C++:
Call compiled C functions from normal JavaScript:
Using direct function calls (faster but more complicated).
Call compiled C++ classes from JavaScript using bindings created with:
Call JavaScript functions from C/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_functionexportsmain()andother_function().Note that you need
_at the beginning of the function names in theEXPORTED_FUNCTIONSlist.Note that
_mainis 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 (
-O2and above), code is minified, including function names. Exporting functions allows you to continue to access them using the original name through the globalModuleobject.
The compiler will remove code it does not see is used, to improve code size. If you use
ccallin a place it sees, like code in a--pre-jsor--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, usingEXPORTED_RUNTIME_METHODS, for example using-sEXPORTED_RUNTIME_METHODS=ccall,cwrap, and call it onModule(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
someStringcan be converted to achar *usingptr = stringToNewUTF8(someString).Note
The conversion to a pointer allocates memory, which needs to be freed up via a call to
free(ptr)afterwards (_freein JavaScript side) -
char *received from C/C++ can be converted to a JavaScript string usingUTF8ToString().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')");