使用emscripten将JS对象传递给C++的内置方式



是否有一种简单的内置方法可以将JS对象传递给C++

我试着用显而易见的方式:

echo.cpp:

#include <iostream>
#include <emscripten.h>
#include <emscripten/val.h>
using emscripten::val;
#ifdef __cplusplus
extern "C"  {
#endif
EMSCRIPTEN_KEEPALIVE void echo(val x){
val::global("console").call<void>("log", x);
}
int main(int argc, char **argv){
return 0;
}

#ifdef __cplusplus
}
#endif

script.mjs:

import initEM from "./echo.mjs";
var mod = await initEM();
export function echo(x){
mod.ccall("echo", "void", ["object"], [x]);
}
echo({attr: 9});

编译使用:

emcc ./echo.cpp -o ./echo.mjs 
-sEXPORTED_FUNCTIONS=_main,_echo 
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,registeredTypes 
-lembind --bind

但我有一个错误:

Uncaught TypeError: Cannot read properties of undefined (reading 'refcount')
at __emval_incref (echo.mjs:2622:29)
at echo.wasm:0x1957
at echo.wasm:0x1842
at echo.wasm:0x121c
at echo.wasm:0x110f
at echo.wasm:0x104a
at echo.mjs:1639:22
at Object.ccall (echo.mjs:845:18)
at echo (script.mjs:6:7)
at script.mjs:9:1

经过一些尝试和错误,我开始工作:

echo.cpp:

#include <iostream>
#include <emscripten.h>
#include <emscripten/val.h>
using emscripten::val;
using emscripten::internal::EM_VAL;
#ifdef __cplusplus
extern "C"  {
#endif
EMSCRIPTEN_KEEPALIVE void echo(EM_VAL x_ptr){
// converts it to object from the pointer
val x = val::take_ownership(x_ptr);
val::global("console").call<void>("log", x);
}
int main(int argc, char **argv){
return 0;
}

#ifdef __cplusplus
}
#endif

script.mjs:

import initEM from "./echo.mjs";
var mod = await initEM();
let objToC = null;
for(let tp of Object.values(mod.registeredTypes)){
if(tp.name=="emscripten::val"){
// turns it into a pointer (I think)
objToC = (v) => tp.toWireType(null, v);
break;
}
}
if(objToC==null){
throw new ReferenceError("val.toWireType not found");
}
export function echo(x){
mod.ccall("echo", "void", ["number"], [objToC(x)]);
}
echo({attr: 9});

(使用与另一个相同的东西编译(

问题:

  1. 为什么这还没有出现在ccall/cwrap函数中
  2. 为什么emscripten不将val.toWireType作为模块对象的属性公开(即,为什么我必须循环所有类型才能找到它(,或者我遗漏了什么

通过文档:

EMSCRIPTEN_BINDINGS(my_module) {
function("lerp", &lerp);
}

my_module只是您必须添加的一个(全局(唯一名称,它没有任何其他用途。

void echo(EM_VAL x_ptr){
// converts it to object from the pointer
val x = val::take_ownership(x_ptr);
val::global("console").call<void>("log", x);
}
EMSCRIPTEN_BINDINGS(my_bindings) {
function("echo", echo);
}

现在您可以在不使用ccall:的情况下从JS调用echo

Module.echo({addr: 9});

请注意,这在网络工作者中不太适用;echo方法在Module中的注册作为WASM初始化的一部分并且仅在初始化线程中完成。

虽然EMSCRITEN_BINDINGS看起来很神奇,但它基本上只是生成一个静态全局函数,并在静态构造时调用它。它是

function("echo", echo);

完成所有工作;它确定echo的参数,并构建一个JS包装器,该包装器转换参数并使用名称"echo"调用C++函数echo

最新更新