Embind: sharing bindings between javascript and compiled C++ code.

266 views
Skip to first unread message

Joshua Auerbach

unread,
Dec 15, 2015, 9:07:17 AM12/15/15
to emscripte...@googlegroups.com
Hi all,

I have a question that I'd be grateful for any assistance with. I have
a piece of software that I want to support using both as web software,
where we use Emscripten to convert the C++ to Javascript, but also as
desktop/server software running natively compiled C++ (since that is
still quite a bit more efficient than the web version).

I also want to allow for some scripting by the users. I now have this
working in the web version using Embind. A user can provide a js source
file that implements an interface I provide. But, I also want to be
able to use the same user-provided js files with the desktop version (by
using v8 to run the javascript, for example).

My question is this: is there anyway I can reuse the bindings I have
made with Embind so they will work when the software is running on the
desktop? Or will I just have to create a separate set of bindings for
this purpose using a different API? Has anyone done something like this
already? Any other suggestions?

Thanks++
Josh

--
Dr. Joshua E. Auerbach
Postdoctoral Researcher
Laboratory of Intelligent Systems
École Polytechnique Fédérale de Lausanne

Joshua Auerbach

unread,
Dec 22, 2015, 9:29:19 AM12/22/15
to emscripte...@googlegroups.com
I guess there is no straightforward way to do this?

nbind: https://github.com/charto/nbind looked like one potential way to
do this (that is most similar to Embind) but then still need to invoke
the node.js from C++ for my purposes.

Other options I've looked at are v8pp: https://github.com/pmed/v8pp
Or, trying to leverage QT's scripting functionality (which is also
ECMAScript). This seems like it might actually be the most straightforward.

Any of these will mean I have two sets of bindings to manage though,
which is not ideal.

-Josh

Brian Gavin

unread,
Dec 22, 2015, 3:12:55 PM12/22/15
to emscripten-discuss
I do not work with V8 on the desktop so I am not sure how V8 communicates between C++ and Javascript.   I would guess you will need 2 sets of bindings, but it should pretty easy.  I assume the functions you need to bind are the same?  I would write the actual work in a regular C++ function/class and then just call it in the bind function.   The amount of code in the bind function should be very small and because the code is shared the risk of unique platform bugs is much smaller.

Something like this.

Shared code

float CalcSalesTaxCommon( float amount )
{
     return amount * 0.08;
}

Emscripten / Embind specific code

float CalcSalesTax( float amount )
{
   return CalcSalesTaxCommon( amount );
}


EMSCRIPTEN_BINDINGS(my_module) {
    function( "CalcSalesTax",&CalcSaleTax);
}

Do the same for V8

arnab choudhury

unread,
Dec 28, 2015, 5:25:43 PM12/28/15
to emscripten-discuss
At Tableau, we have had a similar problem where we wanted to reuse a set of bindings to emit non JS code. We came up with a clean solution where we modified embind.js to contain "hooks" for each embind function. This ensures that you only have one set of bindings, reducing the risk of bugs.

To understand how this works, you have to take a slightly deeper look at how embind works:
a. Use variadic templates to allow for binding declaration via .class_, .function calls, etc.
b. The variadic templates in turn invoke a set of _embind* functions (e.g. _embind_register_bool, _embind_register_function, etc).
c. Them _embind* functions are implemented in embind.js which gets added to the generated JS at link time by the emscripten compiler if you supply the --bind option. The _embind functions maintain a type registry that associates a type ID with each C++ type, ensuring that you can go from JS to C++ and from C++ to JS using the type ID.

The solution we came up with was to update each _embind* function in embind.js so that we could emit whatever custom code we wanted using the emscripten bindings supplied by the user. 

For example, consider the _embind_register_class function in embind.js. We add a hook called Custom_registerClass to it that we implement in a separate JS file.


 

_embind_register_class: function(

                        rawType,

                        rawPointerType,

                        rawConstPointerType,

                        baseClassRawType,

                        getActualTypeSignature,

                        getActualType,

                        upcastSignature,

                        upcast,

                        downcastSignature,

                        downcast,

                        name,

                        destructorSignature,

                        rawDestructor

                        ) {

    name = readLatin1String(name);

 

    ...

 

    whenDependentTypesAreResolved(

        [rawType, rawPointerType, rawConstPointerType],

        baseClassRawType ? [baseClassRawType] : [],

        function(base) {


        ...


        if (typeof Custom_registerClass != "undefined") {

            Custom_registerClass(rawType, name, baseClassName);

        }


        ...

    }

 

Next, its a simple matter of making sure Custom.js gets included when you are generating your custom bindings. We had to update emcc to allow for this - we added a new parameter called --csbind (similar to --bind) for this:


emcc --csbind bindingsFile.cpp -o mycustomcode.<suffix>


mycustomcode.<suffix> will contain whatever bindings you need (in your language of choice - you just have to update Custom.js to support that). 


This took some time to set up (a couple of weeks), but is turning out to be a fairly clean solution since we can use the same set of bindings for multiple purposes. If you need more clarification, do let me know, I'd be happy to explain further.

Joshua Auerbach

unread,
Dec 31, 2015, 2:43:06 AM12/31/15
to emscripte...@googlegroups.com
Thanks so much for this description.  It does sound like in the end you have a pretty clean solution, though I would have to dig into the embind code to fully understand how this would work.

Since I did not have a few weeks to devote to this, I ended up spending a few days making a second set of bindings, and tweaking things a bit so that the same js file will work in both versions.  Definitely not the ideal solution as we now have these two sets of bindings to maintain, but it works for the time being, and hopefully at some point I will find the time (or will recruit a student) to re-implement this more along the lines you describe.... keeping your response bookmarked for future reference.

Cheers,
Josh
--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages