asm.js Module.ccall / Module.cwrap 回调
asm.js Module.ccall / Module.cwrap callback
我在 c++ 中有一些回调函数,我想在使用 emscripten 编译后在 javascript 中重新创建。
有谁知道如何调用那些使用 ccall 或 cwrap 的方法吗?
谢谢!
我使用的技术是将指针转换为 unsigned int(技术上,uint32_t),然后将其传递给 JS。当我准备好回调时,我将值传回C++,将其转换回函数指针,然后调用关联的函数。
其中很多都可以自动化;例如,您可以将回调 class 设置为具有一个基 class,在调用虚函数之前将所有指针转换为该基,该虚函数重定向到正确的派生 class(在我的例子中,我用它来处理参数和 return 类型)。
我很乐意帮助您编写一些代码。我正在开展一个名为 Empirical 的项目,该项目将是一个 header-only 库,主要用于将科学软件移植到网络上。它仍处于活跃的早期开发阶段,但您可能会发现一些有用的部分。
https://github.com/mercere99/Empirical
emp::JSWrap()
是一个接受 std::function object 和 return 一个 uint32_t
的函数。你可以在这里找到它的定义:https://github.com/mercere99/Empirical/blob/master/emtools/JSWrap.h 它应该正确处理基本参数和 return 类型和 std::string
,但我正在努力扩展它。如果您只是从项目中获取一些文件,请注意 JSWrap 确实包含一些其他文件,但不会太多。
另外一个你需要担心的相关文件是library_emp.js(https://github.com/mercere99/Empirical/blob/master/emtools/library_emp.js),里面定义了emp.Callback()
,可以在JS端使用
要将这两个文件集成到您的程序中,您需要:
- 添加到您的 C++ 代码
#include "JSWrap.h"
和 #include "init.h"
(可能带有附加路径信息)
- 添加到您的汇编中:
--js-library ../../emtools/library_emp.js
- 在使用任何回调之前,运行
emp::Initialize();
在 C++ 端。
- 通过调用
uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped);
包装你正在使用的函数它将return一个你可以传递给JS的函数ID值。或者,您可以调用 uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped, "JS_Function_Name");
,它会为您创建一个具有指定名称的 JS 函数。
- 在 JS 中,您可以通过使用
emp.Callback(id, parameters)
触发回调来提供指定的函数 ID - 或者 - 如果您使用了 emp.JS_Function_Name(parameters...)
,则可以使用提供的名称,它会回调原来的功能。任何 return 值都将被传回。
如果有帮助请告诉我!在 JSWrap.h 的顶部还有一些文档,在 https://github.com/mercere99/Empirical/tree/master/UTests/emtools 的测试文件(包括一个 Makefile,一个名为 JSWrap.cc 的代码文件,以及一个名为 HTML 的文件71=]tml).
编辑: 下面是将函数指针object发送给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([=10=], 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++ 函数指针。
在这种情况下,您需要提前知道函数签名,但正如我上面提到的,您可以使用可以记住签名的更精细的回调。
我在 c++ 中有一些回调函数,我想在使用 emscripten 编译后在 javascript 中重新创建。
有谁知道如何调用那些使用 ccall 或 cwrap 的方法吗?
谢谢!
我使用的技术是将指针转换为 unsigned int(技术上,uint32_t),然后将其传递给 JS。当我准备好回调时,我将值传回C++,将其转换回函数指针,然后调用关联的函数。
其中很多都可以自动化;例如,您可以将回调 class 设置为具有一个基 class,在调用虚函数之前将所有指针转换为该基,该虚函数重定向到正确的派生 class(在我的例子中,我用它来处理参数和 return 类型)。
我很乐意帮助您编写一些代码。我正在开展一个名为 Empirical 的项目,该项目将是一个 header-only 库,主要用于将科学软件移植到网络上。它仍处于活跃的早期开发阶段,但您可能会发现一些有用的部分。
https://github.com/mercere99/Empirical
emp::JSWrap()
是一个接受 std::function object 和 return 一个 uint32_t
的函数。你可以在这里找到它的定义:https://github.com/mercere99/Empirical/blob/master/emtools/JSWrap.h 它应该正确处理基本参数和 return 类型和 std::string
,但我正在努力扩展它。如果您只是从项目中获取一些文件,请注意 JSWrap 确实包含一些其他文件,但不会太多。
另外一个你需要担心的相关文件是library_emp.js(https://github.com/mercere99/Empirical/blob/master/emtools/library_emp.js),里面定义了emp.Callback()
,可以在JS端使用
要将这两个文件集成到您的程序中,您需要:
- 添加到您的 C++ 代码
#include "JSWrap.h"
和#include "init.h"
(可能带有附加路径信息) - 添加到您的汇编中:
--js-library ../../emtools/library_emp.js
- 在使用任何回调之前,运行
emp::Initialize();
在 C++ 端。 - 通过调用
uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped);
包装你正在使用的函数它将return一个你可以传递给JS的函数ID值。或者,您可以调用uint32_t fun_id = emp::JSWrap(FunctionToBeWrapped, "JS_Function_Name");
,它会为您创建一个具有指定名称的 JS 函数。 - 在 JS 中,您可以通过使用
emp.Callback(id, parameters)
触发回调来提供指定的函数 ID - 或者 - 如果您使用了emp.JS_Function_Name(parameters...)
,则可以使用提供的名称,它会回调原来的功能。任何 return 值都将被传回。
如果有帮助请告诉我!在 JSWrap.h 的顶部还有一些文档,在 https://github.com/mercere99/Empirical/tree/master/UTests/emtools 的测试文件(包括一个 Makefile,一个名为 JSWrap.cc 的代码文件,以及一个名为 HTML 的文件71=]tml).
编辑: 下面是将函数指针object发送给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([=10=], 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++ 函数指针。
在这种情况下,您需要提前知道函数签名,但正如我上面提到的,您可以使用可以记住签名的更精细的回调。