WebAssembly: Building GUI for C++ libraries with Embind
Published: 2023-09-17 04:47:42

This post will probably not be very long of full of technical details. Instead, I would like to share some thought about using [Embind](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html) -- a WebAssembly tool for binding high-level C++ code to JavaScript, and an example of an open-source project (that is of personal interest to me) that uses Embind to make GUI for its main product -- a numeric motion planning library. So if you are a C/C++ software/library developer, and you are looking for new tools to visualize, advertise or present you work, WebAssembly is something to thing about...

If you are new to WebAssembly, it is a relatively new web-technology that allows to compile code in languages such as C, C++ and Rust into a low-level assembly language that can be executed in a virtual stack-based machine inside a browser with reasonable productivity (compared to pure JavaSript). There are several resources that provide a good dive into WebAssembly basics:
* MDN Web Docs: [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly).
* [WebAssembly.org](https://webassembly.org/): nice collection of resouces.
* [Emscipten](https://emscripten.org) C/C++ to WebAssembly compiler.

# What should I use it for?

What are benefits of using WebAssebmly with compiled languages like C/C++ or Rust? 
* You can run computationally intensive stuff client-side in browser, and have it on a web page. Think about fractal rendering, 3D graphics, or some physics simulations.
* If you have library already written in C++ or C, it can be (in most cases) recompiled into WebAssembly bytecode with moderate efforts.

Of course, with benefits come limitations ([Dialectics](https://en.wikipedia.org/wiki/Dialectic), eh?).
* There are some [limitations](https://emscripten.org/docs/porting/guidelines/portability_guidelines.html) with _what_ you can port to WebAssembly. Exceptions? Threads? Fancy memory layout?
* To use it in a web browser, the code should be compiled with a dedicated compiler (e.g. `emcc`). It not possible to grab a production `library.a` compiled for x86-64 and just use it (would be nice, eh?).
* Some work has to be done to bind data from web application to WebAssembly (read C/C++). Low-level memory management is clumsy, and tools like Embind are real help.

One possible application of WebAssembly is to provide a web access to a (low-level) numeric library API, so that users may turn the knobs in the browser and see what goes on without deploying this library to a hardware of making it a part of larger project. And in this post I will provide and example of a cool project in robotics that uses this approach. Of course, there is always an option to bind such code to Python or Julia which might make more sense in most cases, but sometimes a web app might be an interesting option.

# A little bit about Embind

If you would like to jump start with C/C++ in WebAssembly, just install [Emscipten](https://emscripten.org/) SDK. It will install the `emcc` compiler and some basic environment. If you don't have XTerm/Bash at hand, don't worry -- it works in Windows PowerShell out of the box. Compiling C/C++ with `emcc` produces `*.wasm` binary file and optionally JavaScript module to embed `*.wasm` into a web application. Making it work in React may require a [little bit more work](https://dev.to/iprosk/cc-code-in-react-using-webassembly-7ka). But that's pretty much it.

The problem is how to get something into WebAssembly internal memory space, and how to get stuff out of there. There is always low-level API at our disposal, but this is [tedious and error prone](https://dev.to/iprosk/playing-with-low-level-memory-in-webassembly-257i), and that's where our today's hero comes in.

[Embind](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html). I will not write much about it here, because the official documentation is quite comprehensive to get hands on. Just one remark from the official docs to make this discussion complete. Binding class methods and properties with `EMSCRIPTEN_BINDINGS(my_class_example) {class_<MyClass>("MyClass") /* ... */}` allows to use it from JavaScript in a "normal" way without worrying about how this works at low level.
```
var instance = new Module.MyClass(10, "hello");
instance.incrementX();
instance.x; // 11
instance.x = 20; // 20
Module.MyClass.getStringFromInstance(instance); // "hello"
instance.delete();
```

Let's now look at the example from some real-world project...

# Example: GUI for a motion planning library

There is an open-source project which is of personal interest for me -- a robotic motion planning library which is called [_Ruckig_](https://ruckig.com/). It is a relatively small C++17 tool which [does one thing and does it well](https://en.wikipedia.org/wiki/Unix_philosophy) -- it plans kinematically-optimal multi-degrees-of-freedom trajectories for robotics controllers. Doesn't matter what it really means. It is a software library that is supposed to be a part of another software tools or libraries. It has Python bindings (of course), and can be used from a Jupyter notebook. Well, as I found recently, it now has WebAssembly bindings too to provide a simple [web GUI](https://gui.ruckig.com/).

For it is a good chance to peek inside and learn something by example...

## Install it for local development and peek inside

Let us quickly look inside _Ruckig_ project. Jump into the [GitHub repository](https://github.com/pantor/ruckig) of the community version (MIT license) and clone it.

```
git clone https://github.com/pantor/ruckig
```
We don't have to build it with CMake, so don't worry about right building tools. It can just live in a Windows folder for now if it is your platform. 

If we go to `src/ruckig`, we will find a file `wasm.cpp` which contains all the  Embind bindings for the [web GUI](https://gui.ruckig.com/), which allows to seamlessly bind input/output into underlying C++ library.

The web GUI itself is in `doc/web-gui`. To build it, we need to compile the C++ library to the `ruckig.wasm` binary first. This can be done by running `doc/web-gui/make_wasm.sh` in Bash, or if you are in Windows PowerShell, just run the following command in the terminal or put it in a `*.bat` file (this implies that Emscipten SDK is [installed and activated](https://emscripten.org/docs/getting_started/downloads.html) and the environmental variables are already sources into current shell)

```
emcc src/ruckig/wasm.cpp src/ruckig/brake.cpp src/ruckig/position_first_step1.cpp src/ruckig/position_first_step2.cpp src/ruckig/position_second_step1.cpp src/ruckig/position_second_step2.cpp src/ruckig/position_third_step1.cpp src/ruckig/position_third_step2.cpp src/ruckig/velocity_second_step1.cpp src/ruckig/velocity_second_step2.cpp src/ruckig/velocity_third_step1.cpp src/ruckig/velocity_third_step2.cpp -Iinclude -Ithird_party -std=c++17 -lembind -Os -s MODULARIZE -s EXPORT_ES6 -s EXPORT_NAME='RuckigModule' -s ENVIRONMENT='web' -s EXPORTED_RUNTIME_METHODS=ccall,cwrap -o doc/web-gui/src/ruckig.js
```
This gives us two files `ruckig.wasm` binary, and `ruckig.js` glue code to load this binary into a browser session and interface with a Plotly.js React component, which shows fancy plots on the web page.

If you have resent version of Node.js, you can quickly build you local copy of [web GUI](https://gui.ruckig.com/) by running the [following commands](https://github.com/pantor/ruckig/tree/master/doc/web-gui) in the root directory of the project.
```
npm install
npm run start
```
This will serve the page at `localhost:1234`. Now, make a cup of coffee (if it is still morning) and just look inside the `doc/web-gui/` at `index.html` and `gui.js`. That's it.