JSExport: C++ in the browser made easy
Recently, I have been working on one of Cheerp’s unique features,
For the last many weeks, I had been busy cleaning up, testing, and improving on
[[cheerp::jsexport]]. The first phase has now been merged into our main branch (GitHub), and it’s now available for everyone to experiment with (Cheerp’s PPA), so it’s the right moment to show some examples of how it can be used and what can be achieved with it + some discussion of the (current) limitations and the possible usage of JSExported classes and free functions.
Let’s start from the basics.
Say you need to calculate the Greatest Common Divisor of two numbers in your ilovenumbertheory.org website.
You happen to find that you already have a gcd implementation that you trust being correct, and it happens to be in C++.
You add then the tag
/opt/cheerp/bin/clang++ gcd.cpp -o gcd.js -target cheerp -cheerp-pretty-code
What just happened here? Let’s dissect.
What is this for?
Now you can play with something like this directly in your browser console:
Great. So a function with signature
Now once compiled with:
/opt/cheerp/bin/clang++ cheerpShuffle.cpp -o cheerpShuffle.js -Os -target cheerp
This is fun, but do not try it at home. (But feel free to do it here.)
Free functions limitations
Now it’s the right time to say that there are limitations on the free functions taggable with
They come in a few flavors:
- arguments/return types: bool/char/short/int/floats/doubles are supported. No 64 bit integers for now (we may support them in the future using BigInt to represent them)
- arguments/return types: only pointers to struct/classes tagged as
- no templated functions, since there is no way of instantiating new templates at runtime
Cheerp will give you a compile-time error whenever any of these rule are broken, explaining what went wrong AND how to fix the problem. There is also a more proper documentation to help out.
And now, stateful objects
Exporting free functions is helpful on its own, but the possibility of exporting classes or structs it’s even more powerful (and comes with an additional set of limitations).
I have here one basic example, a class that generates pseudo-random numbers according to the normal distribution.
Then compiling with:
/opt/cheerp/bin/clang++ normalDistribution.cpp -o normalDistribution.js -Os -target cheerp
Few things to note here:
- The instance of the class actually holds state (mostly the 624*32 bits representing the state of the Mersenne twister random engine + some additional variables)
- The class exports both a constructor (that has to be called with new ClassName(arguments)) and a generate() member function
For now the main limitations are basically the same of the free-functions, plus:
- JSExported classes needs a public constructor
- JSExported classes should have a trivial destructor
- No inheritance
- Fields are not JSExported (but you can and should define getter / setter methods)
Some of these limitations may and will be lifted.
I would love to have the possibility to just do:
class [[cheerp::jsexport]] SetOfElems :
and have it magically work. It may be possible in the future (with some caveats) but the main focus has been on building a stable set of features that’s useful AND forward compatible.
Either the problem you are trying to solve is already solved in a C++ library that you trust has already gone through the process of finding and fixing problems.
In all the examples there was a
The interactions between JSExport and Wasm, expecially for objects, require a few more details to be ironed out, I will be busy doing that until the next post, where I will expand on this side.
I would love to see any experiment done with