Calling javascript function in c++ with emscripten embind - javascript

This question comes in two parts. What I want to do is to put most of my program logic in c++ classes and some view related function in js (like DOM manipulation and styling.) I use emscripten embind the classes and it works fine while I don't know how to interact with the js code (there are really limited resources on their tutorial.)
I was thinking to pass a val object to the c++ class according to their tutorial (https://github.com/kripken/emscripten/wiki/Tutorial) The passing works just fine while the "call" function doesn't work. I got a compile time error.
Here is the example I tried which they put on their tutorial:
#include <emscripten/val.h>
using namespace emscripten;
int main(){
val Math = val::global("Math");
Math.call("abs",-10);
return 0;
}
and I got the following errors:
error: no matching member function for call to 'call'
Math.call("abs",-10);
~~~~^~~~
emscripten/1.5.6/system/include/emscripten/val.h:247:21: note: candidate template ignored: couldn't infer template argument 'ReturnValue'
ReturnValue call(const char* name, Args&&... args) const {
Basically it says the the compiler doesn't know the return type of the "call" function.
Did I do anything wrong or is there a better way to interact with js code?
Thanks,
yi

That's a common C++ problem. As a general rule, the following message should always make you double check in C++:
note: candidate template ignored: couldn't infer template argument 'ReturnValue' ReturnValue call(const char* name, Args&&... args) const
This mostly means that you tried to call a templated function but did not specify the necessary types.
If you look at the signature (in system/include/emscripten/val.h):
template<typename ReturnValue, typename... Args>
ReturnValue call(const char* name, Args&&... args) const
While it can infer Args quite fine, it has no idea, what ReturnValue might be. So calling this function should be done via e.g.:
Math.call<int>("abs",-10);

Related

WebAssembly calling JavaScript methods from wasm i.e. within C++ code

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.
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
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.

Higher order function, Flow type annotations

I'm trying to write some very simple, functional examples to evaluate the Flow type system. Am I missing something obvious, or should this sample work:
function logger (message: string): void {
console.log(message);
}
function consumer (logFunc: logger) {
logFunc('foo');
}
consumer(logger);
When I try it on Try Flow I get "Callable signature not found in prototype". I'm getting the same message when run locally (flow 0.21.0):
8: logFunc('foo');
^^^^^^^^^^^^^^ function call. Callable signature not found in
8: logFunc('foo');
^^^^^^^ prototype
I can solve the problem by declaring a type alias explicitly, but that seems like unnecessary duplication (especially for more complex modules):
type loggerType = (message: string) => void;
function logger (message: string): void {
console.log(message);
}
function consumer (logFunc: loggerType) {
logFunc('foo');
}
consumer(logger);
The only relevant documentation I've found so far is: http://flowtype.org/docs/functions.html#function-based-type-annotations
Imagine that consumer and logger are separate modules (perhaps even in separate npm packages) and are more complicated, and logger is imported (es6, or commonJS).
It doesn't seem reasonable to write the types twice (logger and loggerType).
It also doesn't seem reasonable to repeat the type signature of logger in the consumer function - I want the type of the logFunc argument to exactly match the function called logger. Especially, repeating the types would be tedious for more complex functions.
Any ideas on how to accomplish this without explicitly repeating the type annotations?
You can use typeof:
function consumer (logFunc: typeof logger) {
logFunc('foo');
}
Seems like a Flow bug that using an expression in a type position doesn't give you a meaningful error, but I'm not as familiar with it so maybe it means something else.
The error experience here is pretty confusing, though -- you may be better off with a type alias. Certainly in this snippet I would prefer an error on line 15 rather than on 1 and 9

How do you call JavaScript delete from Kotlin?

I am working with a third party library from Kotlin and one of the things I must do is call delete thing[key] in order to remove an item from thing. I am unable to figure out how to do this from Kotlin code.
I did try js("delete thing[key]"), but thing is a parameter to a function and is name-mangled by the Kotlin > JavaScript compiler so an exception is thrown when the line is executed. I also tried js("delete ") thing[key] but unsurprisingly that didn't work either.
For delete operator You can write:
external fun delete(p: dynamic): Boolean = noImpl
//...
delete(thing[key])
For more convenient use I'd added some helpers:
fun delete(thing: dynamic, key: String) {
delete(thing[key])
}
// or
fun String.deleteFrom(d: dynamic) {
delete(d[this])
}
fun test(a: Any, k: String) {
delete(a, k)
k.deleteFrom(a)
k deleteFrom a
}
Note: using the delete operator is not a good practice and it'll leads to deoptimizations in JS VMs

js - How to decorate/proxy/spy on all functions? For creating a runtime profiler

So I have this decorate function that takes an object and a method-name and wraps it with external logic.
function decorate(object, methodName) {
var originalMethod = object[methodName];
object[methodName] = function () {
// pre-logic
var retVal = originalMethod.apply(this, arguments);
// post-logic
return retVal;
};
}
Now I want to wrap ALL of the functions in my application, i.e.
All the recursive public functions of the object
All private scope functions
All anonymous functions
Anything else I might have forgotten.
My purpose in doing this is to implement a "JS Profiler" that will run alongside my application during automated testing, and output performance data to logs.
I need this for testing purposes, so the solution must have minimal changes to the actual code of my application.
Possible solutions I've considered:
Public methods can be easily traversed and replaced using a recursive object traversal function.
Some hack using eval() to be able to access private methods.
Ideally, to handle all cases, I could use a proxy HTTP server (Node.js for example) that will transform each javascript file before sending it to the browser. This way my codebase will remain clean, but my tests will have the necessary changes.
The first 2 are only partial solutions, and the last one seems like an overkill and also a potential "bug factory"...
Does anyone have any other ideas on how to achieve what I need?

Does Awesomium allow me to call/use C++ variables/methods in JS?

Awesomium easily allows for C++ code to call Javascript methods, but I haven't found a definite answer as to if it can do the opposite. This site seems to say that you can, but looking through the text and examples doesn't enlighten me.
So, I'm looking for a definite answer: can I call C++ variables/methods in my Javascript(Jquery), or not?
If you could include a simple example, that would be extremely appreciated as well.
Thank you!
You definitely can-- you'll just need to build an extra layer on top of WebView::setObjectCallback and WebViewListener::onCallback using delegates/function-pointers.
I wrote a quick JSDelegate.h class (view it here) that you can use to hookup "onCallback" events directly to C++ member functions.
The basic idea is to maintain a mapping of callback names to delegates:
typedef std::map<std::wstring, Awesomium::JSDelegate> DelegateMap;
DelegateMap _delegateMap;
And call the corresponding function from your WebViewListener::onCallback:
void MyListener::onCallback(Awesomium::WebView* caller, const std::wstring& objectName,
const std::wstring& callbackName, const Awesomium::JSArguments& args)
{
DelegateMap::iterator i = _delegateMap.find(callbackName);
if(i != _delegateMap.end())
i->second(caller, args);
}
And then, each time you wish to bind a specific C++ function, you would do it like so:
// Member function we wish to bind, must have this signature for JSDelegate
void MyClass::myFunction(Awesomium::WebView* caller, const Awesomium::JSArguments& args)
{
// handle args here
}
// Instantiate MyClass instance in C++
MyClass* myClass = new MyClass();
// Create corresponding 'MyClass' object in Javascript
webView->createObject(L"MyClass");
// Do the following for each member function:
// Bind MyClass::myFunction delegate to MyClass.myFunction in JS
_delegateMap[L"myFunction"] = Awesomium::JSDelegate(myClass, &MyClass::myFunction);
webView->setObjectCallback(L"MyClass", L"myFunction");
Then, you should be able to call MyClass::myFunction directly from Javascript like so:
MyClass.myFunction("foo", 1, 2 3)
Hope this helps! I haven't tested any of the code but I wrote it with Awesomium v1.6 RC4 SDK in mind.

Categories

Resources