c++google-closure-compileremscriptengoogle-closure-library

How to use emscripten in conjunction with the closure tools


For optimal performance I'd like to use emscripten in conjunction with the closure tools but poorly I can't call the function I've defined in JavaScript from emscripten.

Note that I extracted a minimal example from my project do demonstrate what I mean.

// test.cc
#include <iostream>

#include "emscripten.h"

int main() {
  std::cout << "Hello, World!\n";
  EM_ASM(goog.dom.appendChild(
      document.body,
      goog.dom.createDom('p', {'font-weight' : 700}, 'Hello, World!'));
  );
}

So "Hello, World!" is printed correctly but then:

exception thrown: ReferenceError: goog is not defined,ReferenceError: goog is not defined

even though goog should've been defined since I compiled and included the closure library even with advanced optimizations so that I have maximum performance.

Now if I do the same thing in JavaScript it works totally fine:

goog.provide('main');
goog.require('goog.dom');

console.log('Hello, World!');
goog.dom.appendChild(document.body, 
  goog.dom.createDom('p', {'font-weight': 700}, 'Hello, World!'));

By the way I'm using both in conjunction and I include this JavaScript file before the asmjs file just to make sure that goog is really defined.

Another interesting thing to note is that it actually works when I compile with simple optimizations.

So how can I use emscripten in conjunction with the closure library and closure compiler?


Solution

  • This is because the closure compiler with advanced optimizations will optimize out everything that isn't needed.

    Therefore, you need to export the symbols you want to call.

    I'd actually do the entire thing in JavaScript and then export a single symbol so that you don't have to export the entire goog.dom namespace:

    goog.provide('asmjs');
    goog.require('goog.dom');
    /** @export */
    asmjs.helloWorld = function() {
      goog.dom.appendChild(document.body, 
        goog.dom.createDom('p', {'font-weight': 700}, 'Hello, world!'));
    };
    goog.exportSymbol('asmjs.helloWorld', asmjs.helloWorld);
    

    So you can then call:

    EM_ASM(asmjs.helloWorld(););
    

    which should work as expected.