[英]asm.js Module.ccall / Module.cwrap callback
我在c ++中有一些回调函数,希望在用emscripten编译后在javascript中重新创建。
任何人都知道如何使用ccall或cwrap打电话给那些人吗?
谢谢!
我使用的技术是将指针转换为无符号的int(技术上是uint32_t),然后将其传递给JS。 准备好回调时,我将值传递回C ++,将其转换回函数指针,然后调用了关联的函数。
其中很多可以自动化。 例如,您可以将回调类设置为具有一个基类,在调用虚函数之前将所有指针都转换为该基类,该虚函数将重定向到正确的派生类(在我的情况下,我使用它来处理参数和返回类型)。
我很乐意为您提供一些代码。 我正在一个名为Empirical的项目,它将是仅标头的库,主要用于将科学软件移植到Web。 它仍然处于活跃和早期的开发中,但是您可能会发现一些有用的东西。
https://github.com/mercere99/Empirical
emp::JSWrap()
是一个接受std :: function对象并返回uint32_t
函数。 您可以在这里找到其定义: https : //github.com/mercere99/Empirical/blob/master/emtools/JSWrap.h它应该正确处理基本参数并返回类型和std::string
,但是我正在努力扩展那。 如果您只是从项目中获取一些文件,请注意,JSWrap确实包含一些其他文件,但不是太多。
您需要担心的另一个相关文件是library_emp.js( https://github.com/mercere99/Empirical/blob/master/emtools/library_emp.js ),该文件定义了emp.Callback()
,可以使用它在JS方面。
要将这两个文件集成到程序中,您需要:
#include "JSWrap.h"
和#include "init.h"
(可能包含其他路径信息) --js-library ../../emtools/library_emp.js
emp::Initialize();
在C ++方面。 uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped);
包装您正在使用的uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped);
它将返回一个可以传递给JS的函数ID值。 或者,您可以调用uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped, "JS_Function_Name");
它将为您创建一个具有指定名称的JS函数。 emp.Callback(id, parameters)
触发回调来提供指定的函数ID;或者-如果使用了一个emp.JS_Function_Name(parameters...)
,则可以使用提供的名称,它将调用返回原始功能。 任何返回值将被传回。 让我知道这是否有帮助! JSWrap.h的顶部还有一些文档, https ://github.com/mercere99/Empirical/tree/master/UTests/emtools上有测试文件(包括Makefile,名为JSWrap.cc的代码文件,以及一个名为JSWrap.html的HTML文件)。
编辑 :下面是示例代码,该示例代码将功能对象的指针发送到JS,然后从JS进行回调。
#include <emscripten.h>
#include <functional>
// A couple of possible callbacks, all with the same signature.
double Times2(double val) { return val * 2; }
double Plus7(double val) { return val + 7; }
// A function callback from JS that takes a callback id and an arg and does the callback.
extern "C" {
double Callback_dd(uint32_t cb_id, double val) {
auto * fun_ptr = reinterpret_cast<std::function<double(double)>*>(cb_id);
return (*fun_ptr)(val);
}
}
int main() {
// Pick the function you want to run
auto fun = std::function<double(double)>(Times2);
// auto fun = std::function<double(double)>(Plus7);
// Convert a function pointer to a uint32_t.
// Note double casting to first convert it to a number and then reduce it to 32-bits.
// Using reintepret_cast would be better, but looked confusing with the double cast.
uint32_t cb_id = (uint32_t) (long long) &fun;
// The following code passed the callback ID to JavaScript. The JS code then uses the
// ID to call back the original function.
EM_ASM_ARGS({
Callback_dd = Module.cwrap('Callback_dd', 'number', ['number']);
var x = 12.5;
alert('Result: fun(' + x + ') = ' + Callback_dd($0, x));
}, cb_id);
}
请注意,如果要在main()结束后执行回调,则需要确保所调用的函数将持续存在。
要编译此代码,请将其放入文件中(我们将其称为callback_test.cc),然后从命令行运行:
em++ -s EXPORTED_FUNCTIONS="['_Callback_dd', '_main']" -std=c++11 callback_test.cc -o callback_test.html
现在,您应该能够在网络浏览器中打开callback_test.html,它将通过JS传递给您的C ++函数指针进行调用。
在这种情况下,您需要提前知道函数签名,但是如上所述,您可以使用更复杂的回调来记住签名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.