14

I was playing with WebAssembly and so far and I was able to manage emscripten compile my test C++ project to wasm file em++ provides me 2 files i.e.

mainTest.js mainTest.wasm

When I load mainTest.js in my html page then I get a JavaScript object called "Module".

I did found how to call C++/wasm methods from javascript i.e. something like:

var myTestInteger = Module._callMyTestMethod();

and read strings from the Module.wasmMemory.buffer , but I do NOT understand how to call JavaScript from C++ code.

i.e. I would like to be able to do something like that:

#ifdef __cplusplus
extern "C" {
#endif
extern void testExternJSMethod();

int main() 
{
    cout << " Hello From my Test1 !" << endl;

    testExternJSMethod();
    return 0;
}
int EMSCRIPTEN_KEEPALIVE callMyTestMethod(){
    return 26;
}
#ifdef __cplusplus
}
#endif

and the my js method testExternMethod that I am loading in another js file called utils.js

function testExternMethod() {
  console.log("Hello from testExternMethod!" + )
}

Here I would like to call the JavaScript testExternJSMethod from C++.

When I run the page in Firefox get "-1" in the debugger console.

So what I am missing in this case? Unfortunately The Mozilla documentation is giving only examples in those S-expressions instead of C++.

What am I missing in example? In C++ I have defined the method with the extern keyword i.e.

extern void testExternJSMethod();

but I get the feeling that that is not all I have to do.

I believe that I should somehow link that JavaScript method to the Module somehow but I do not know how. Module.asm gives me the exports. Which method call should give me the imports? since I believe that this _testExternJSMethod() should be in some imports method I can not figure out how to get to it.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Tito
  • 2,234
  • 6
  • 31
  • 65

2 Answers2

19

I'm not exactly sure of your use case, but you are missing important steps to be able to use your function testExternalJSMethod. You have two options here:

Option 1 - Library

1 - Define your function in c/c++ .

extern void testExternalJSMethod();

2 - Create a file called myLibrary.js

3 - The JS function needs to be added to the LibraryManager in your library file with the following code:

function makeAlert(text) {
    alert(text);
}

if (typeof mergeInto !== 'undefined') mergeInto(LibraryManager.library, {
    testExternalJSMethod: function() {
        makeAlert("Hello world");
    }
});

4 - If testExternalJSMethod depends on anything outside of its own scope (for example, makeAlert above), make sure to include the script in your html page

<script async type="text/javascript" src="myLibrary.js"></script>

5 - Add option --js-library to your emcc command, and immediately after the relative path to myLibrary.js

emcc ... --js-library myLibrary.js

Option 2 - Passing Pointers

1 - Define your javascript function type in c/c++

typedef void testExternalJSMethod()

2 - Wherever you want this function to be used, accept an int param which will be the function pointer, and cast the pointer to your function

void passFnPointer(int ptr) {
    ((testExternalJSMethod*)ptr)();
}

3 - Use emscripten's addFunction() and store its returned value (the pointer in c/c++)

var fnPtr = Module.addFunction(function () {
    alert("You called testExternalJSMethod");
});

4 - Use the stored pointer value from step 3 to pass to our function passFnPointer

var passFnPointer = Module.cwrap('passFnPointer', 'undefined', ['number']);
passFnPointer(fnPtr);

5 - Add option -s RESERVED_FUNCTION_POINTERS to your emcc command

emcc ... -s RESERVED_FUNCTION_POINTERS=10
Clint
  • 2,696
  • 23
  • 42
8

Have you tried looking at the Emscripten documentation? It has a whole section on interacting with code that details how to expose C / C++ functions to JavaScript and call JavaScript functions from C / C++.

Emscripten provides two main approaches for calling JavaScript from C/C++: running the script using emscripten_run_script() or writing “inline JavaScript”.

It is worth noting that the Mozilla documentation details plain WebAssembly, whereas Emscripten adds a lot more framework and tooling around WebAssembly in order to make it easier to port large C / C++ codebases.

ColinE
  • 68,894
  • 15
  • 164
  • 232
  • thank you for your answer. I did found the page you are referring to one hour after i posted this question. emscripten_run_script() does work. But what i was specifically looking for to make that example work with a function poiter thus i can pass values back and fort. Unfortunately i can not find a full example of that, and i still have not found my mistake. – Tito Nov 14 '17 at 19:53
  • I'm researching this very topic, & am trying to establish if the "inline Javascript" method can call existing Javascript functions, & not merely the code embedded in the call. – Jack Mar 26 '18 at 21:15