WebAssembly with Tolc
In order for C++
to be called from javascript
there has to be an interface level. tolc
generates this level from your already written C++
interface.
To be as close to what an engineer would have written, tolc
generates human readable embind
.
This is then compiled to a .wasm
and a .js
file that javascript
can import.
Using a C++
library from javascript
This is a quick guide to using a C++
library (here called MyLib
) from javascript
. We will:
- Download and use
Tolc
- Download and set up
Emscripten
- Use the resulting
WebAssembly
fromjavascript
The following works on all supported platforms. On all platforms you need git
available in your path
. Commands that should be run from a terminal starts with $
, while comments starts with #
.
Downloading Tolc
Just add the following in a CMakeLists.txt
below where the library you intend to use from javascript
is defined:
# Download Tolc
# Can be ["latest", "v0.2.0", ...]
set(tolc_version latest)
include(FetchContent)
FetchContent_Declare(
tolc_entry
URL https://github.com/Tolc-Software/tolc/releases/download/${tolc_version}/tolc-${CMAKE_HOST_SYSTEM_NAME}.tar.xz
)
FetchContent_Populate(tolc_entry)
set(tolc_DIR ${tolc_entry_SOURCE_DIR}/lib/cmake/tolc)
find_package(
tolc
CONFIG
REQUIRED
)
tolc_create_bindings(
TARGET MyLib
LANGUAGE wasm
OUTPUT wasm-bindings
)
Assuming your library is called MyLib
, and the bindings should be generated to the directory wasm-bindings
.
Downloading Emscripten
In order to compile your library to WebAssembly
, you need to download the Emscripten compiler
. This is typically done via the Emscripten SDK
. Navigate to the directory where you want to install and run the following commands:
# Download SDK
$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
Now follow the specifig commands for your platform.
Linux/MacOS
From within the emsdk
directory:
# Download and install locally
$ ./emsdk install 3.1.3
# Writes configuration file .emscripten
$ ./emsdk activate 3.1.3
Windows
From within the emsdk
directory:
# Download and install locally
$ emsdk.bat install 3.1.3
# Writes configuration file .emscripten
$ emsdk.bat activate 3.1.3
Configuring Your Project
Since CMake
doesn't have native support for WebAssembly
we have to provide a toolchain
file, fortunately for us, Emscripten
provides us with one.
When configuring your CMake
project, just pass the toolchain flag -DCMAKE_TOOLCHAIN_FILE=${EMSDK_DIRECTORY}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
. Where you need to replace ${EMSDK_DIRECTORY}
with the directory of the previously downloaded Emscripten SDK
. Note that the directory separator used by CMake
is always forward slash (/
), even on Windows.
Example:
# Configures project to build using Emscripten
$ cmake -S. -Bbuild -DCMAKE_TOOLCHAIN_FILE=${EMSDK_DIRECTORY}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
Using From javascript
Looking into build/tolc
you should see MyLib.js
aswell as MyLib.wasm
. MyLib.js
exports a Promise
that loads the built WebAssembly
. Here is an example usage:
// run.js
const loadMyLib = require('./build/MyLib');
loadMyLib().then(MyLib => {
// From here you can use the C++ functions of your library as usual
MyLib.myCppFunction();
});
Running the file as normal:
$ node run.js
Using from a web page
By default Emscripten
assumes that you're running your code in a node
environment (e.g. having access to the filesystem).
This is not the case on a web page served to a browser. If we add the link flag -s ENVIRONMENT='web'
to Emscripten
it will produce a serveable WebAssembly
module.
Since Tolc
exposes a CMake
build target for the module, all we have to do is add the flag ourself:
# Creates the CMake target ${TARGET}_${LANGUAGE}
# In this case: MyLib_wasm
tolc_create_bindings(
TARGET MyLib
LANGUAGE wasm
OUTPUT wasm-bindings
)
# Want to deploy to a web page
set_property(
TARGET MyLib_wasm
APPEND_STRING
PROPERTY LINK_FLAGS "-s ENVIRONMENT='web'")
Then we copy over MyLib.js
and MyLib.wasm
to our web application and load them as shown previously:
// app.js
const loadMyLib = require('./MyLib');
loadMyLib().then(MyLib => {
// From here you can use the C++ functions of your library as usual
MyLib.myCppFunction();
});
Assuming you've loaded the javascript
within your page:
<!-- index.html -->
...
<head>
<script type="text/javascript" src="./app.js"></script>
</head>
...
For a complete example you can see the Tolc-demo
repository: https://github.com/Tolc-Software/tolc-demo.
If you want to see what more is supported you can take a look at the Examples section.