evanw/emscripten-library-generator

A basic example of '--js-library' external JavaScript library usage with Emscripten?

sixman9 opened this issue · 3 comments

Hi,
Before I go on, I'm a newbie to both Emscripten and GCC (I'm a Java dev).

I think I've already grasped the 'EXPORTED_FUNCTIONS' flag of Emscripten/emcc compiler as highlighting the C/C++ functions we want to hang on to/access after compilation to JavaScript, however, the inclusion of 3rd party Javascript libraries, to emcc's compilation phase (via the '--js-library' flag) is confusing me, a bit.

How are these extra JavaScript files being used (or not) from the yet-to-be-compiled C/C++ target code? Can you explain or give a simple example?

Thanks

Sure, I'll give the explanation a shot. The emscripten compiler has a strange JavaScript library format (the files passed via '--js-library'). Instead of a library being JavaScript code that is copied into the output like you'd expect, the "library" is actually code that is invoked at compile time by the compiler. From what I understand, the expectation is that the code should mutate the internal global object LibraryManager.library inside the compiler by adding all of your extra JavaScript functions as properties on that object.

All code passed via '--js-library' is called using something like eval() after the LibraryManager.library global is initialized but before the final JavaScript code is generated. After the library code is invoked, the emscripten compiler then presumably looks at all of the properties in LibraryManager.library and decides what JavaScript to emit during the dead code elimination pass. There are also some magical property names that change the behavior of the compiler. For example, if a given function "foo" uses other functions internally, you can add the "foo__deps" property to indicate which functions must also be treated as used if the function "foo" is used.

After I figured this out, it seemed silly to have to contort my code to fit this format and to write out all of the dependencies manually since that can all be figured out automatically assuming you don't use eval(). That's why I wrote this library, which automatically transforms normal JavaScript code into emscripten's special library format. I also added some example C++ code to the readme. Hopefully that helps!

Evan,
Thanks for getting back to me so quickly.

I think there may have been a little ambiguity in my question. The difference might have been not in what you're doing, but _why_ you're doing it. Basically, I couldn't quite grasp why external JavaScript files needed to be referenced from pre-existing, and presumably, unchanged C/C++ code (i.e. C/C++ code with no prior awareness of 3rd party, external, JavaScript). I think I get it now, and what you're actually doing is substituting (linking?) external C/C++-based library artifacts/calls with JavaScript based alternatives. This satisfies my 'why'.

For prosperity, and anyone possibly coming accross this question/answers, I'd like to leave the following links, which I found very helpful:

http://stackoverflow.com/questions/25800382/how-to-write-an-emscripten-shim-for-a-c-library

http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#implement-a-c-api-in-javascript

Assuming I now understand this*:

  1. Might it also be possible to come at this from another angle and to generate the necessary Emscripten library file(s) from the original '.h' header files?
  2. Could this latter approach (from header files) also allow for generation of JavaScript function call API interface skeleton code, ahead of the JavaScript implementation?

*(Thinking about it, simply generating the JavaScript API function calls, then running that through your generator would be enough, right?).

This Emscripten-related project, 'emStructObj' might offer some, forgive the pun, pointers regarding extracting useful [JavaScript] info from .h header files (the project is pure JavaScript, itself).

Cheers

I see. The difference in our case is that we're writing an app in emscripten from scratch instead of porting existing code. For example, we have a custom shim for the RegExp object instead of using std::regex to avoid downloading a regular expression library with our app since the browser already has one.

There are also other ways of doing this, such as embind or EM_ASM(), which are listed on the page you found. This library just provides a different way to accomplish the "Using a C API implemented in JavaScript" approach. For your use case of automatically generating an API from headers, it may be easier for you to generate and compile embind code. See http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html for more information.