This post will probably not be very long of full of technical details. Instead, I would like to share some thought about using Embind -- 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.
- WebAssembly.org: nice collection of resouces.
- Emscipten 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, eh?).
- There are some limitations 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 productionlibrary.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 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. 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, and that's where our today's hero comes in.
Embind. 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. It is a relatively small C++17 tool which does one thing and does it well -- 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.
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 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, 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 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 by running the following commands 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.
Top comments (10)
I've been using Embind with my C++ code and HTML DOM. Now I am moving to using Embind with React. Have you tried this?
Haven't done anything serious yet, besides simple experiments.
I will let you know. I managed to replicate your work, and further get hello_react emscripten to work with my React code. I'm still trying to get it working with my own emscripten compiled from C++, which uses embind - currently encountering eslint errors.
As soon as I get it working you'll be able to hear me yell "wahoo!" from over there in Victoria - I am not far away on Orcas Island.
Cool! I am glad if this post would be of any help for your project. Would be certainly interesting to hear about your experience.
I have managed to get my C++ / emscripten working in React, thanks in part to your article! It is displaying animated graphics coming from a cellular automaton. I'll make some optimizations and wire up more of the controls, then deploy on GitHub and maybe write a quick article for this site. Thank you so much!
Nice! I am very glad if my experience could help you a little. Could you drop me a link to your project/article when it is ready. I may go back to these after a while.
Here is the repo for my project. While it is not deployed onto the web yet, it's possible to download and run it from GitHub using the generated file lux.js ... would love your thoughts on this.
I'm talking with some of the other contributors about migrating to Vite + React or another framework as create-react-app is now deprecated.
Thanks for sharing. Couldn't see a link to your project here for some reason. If you could re-share, I would definitely have a look.
github.com/joyhughes/Jen/tree/main...
I have taken this further and now have a web app using C++ compiled int WASM using Emscripten, Vite+React, and a web worker
dev.to/joyhughes/a-simple-web-app-...