【问题标题】:WebAssembly calling JavaScript methods from wasm i.e. within C++ codeWebAssembly 从 wasm 调用 JavaScript 方法,即在 C++ 代码中
【发布时间】:2018-04-25 04:10:37
【问题描述】:

到目前为止,我一直在使用 WebAssembly,并且能够管理 emscripten 将我的测试 C++ 项目编译为 wasm 文件 em++ 为我提供了 2 个文件,即

mainTest.js mainTest.wasm

当我在我的 html 页面中加载 mainTest.js 时,我会得到一个名为的 JavaScript 对象 “模块”。

我确实找到了如何从 javascript 调用 C++/wasm 方法,例如:

var myTestInteger = Module._callMyTestMethod();

并从 Module.wasmMemory.buffer ,但我不明白如何从 C++ 代码调用 JavaScript。

即我希望能够做这样的事情:

#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

以及我在另一个名为 utils.js 的 js 文件中加载的 js 方法 testExternMethod

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

这里我想从 C++ 调用 JavaScript testExternJSMethod。

当我在 Firefox 中运行页面时,在调试器控制台中得到“-1”。

那么在这种情况下我缺少什么?不幸的是,Mozilla 文档只给出了这些 S 表达式而不是 C++ 的示例。

我在示例中缺少什么?在 C++ 中,我使用 extern 关键字定义了该方法,即

extern void testExternJSMethod();

但我觉得这并不是我必须做的全部。

我相信我应该以某种方式将该 JavaScript 方法链接到模块,但我不知道如何。 Module.asm 给了我exports。哪个方法调用应该给我imports?因为我相信这个_testExternJSMethod() 应该是某种导入方法,所以我不知道如何得到它。

【问题讨论】:

    标签: javascript c++11 emscripten webassembly


    【解决方案1】:

    我不太确定您的用例,但您缺少能够使用您的函数testExternalJSMethod 的重要步骤。您有两种选择:

    选项 1 - 库

    1 - 在 c/c++ 中定义你的函数。

    extern void testExternalJSMethod();
    

    2 - 创建一个名为myLibrary.js的文件

    3 - 需要将 JS 函数添加到库文件中的 LibraryManager 中,代码如下:

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

    4 - 如果 testExternalJSMethod 依赖于其自身范围之外的任何内容(例如,上面的 makeAlert),请确保在您的 html 页面中包含该脚本

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

    5 - 在您的 emcc 命令中添加选项 --js-library,并紧跟在 myLibrary.js 的相对路径之后

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

    选项 2 - 传递指针

    1 - 在 c/c++ 中定义您的 javascript 函数类型

    typedef void testExternalJSMethod()
    

    2 - 无论你想在哪里使用这个函数,接受一个将作为函数指针的 int 参数,并将指针转换为你的函数

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

    3 - 使用 emscripten 的 addFunction() 并存储其返回值(c/c++ 中的指针)

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

    4 - 使用第 3 步中存储的指针值传递给我们的函数passFnPointer

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

    5 - 将选项 -s RESERVED_FUNCTION_POINTERS 添加到您的 emcc 命令中

    emcc ... -s RESERVED_FUNCTION_POINTERS=10
    

    【讨论】:

      【解决方案2】:

      您是否尝试过查看 Emscripten 文档?它在interacting with code 上有一个完整的部分,详细介绍了如何将 C/C++ 函数暴露给 JavaScript 以及从 C/C++ 调用 JavaScript 函数。

      Emscripten 提供了两种从 C/C++ 调用 JavaScript 的主要方法:使用 emscripten_run_script() 运行脚本或编写“内联 JavaScript”。

      值得注意的是,Mozilla 文档详细介绍了普通的 WebAssembly,而 Emscripten 围绕 WebAssembly 添加了更多框架和工具,以便更轻松地移植大型 C/C++ 代码库。

      【讨论】:

      • 感谢您的回答。在发布此问题一小时后,我确实找到了您所指的页面。 emscripten_run_script() 确实有效。但是我特别希望使该示例与函数指针一起工作,因此我可以将值传回和传递。不幸的是,我找不到完整的例子,我仍然没有发现我的错误。
      • 我正在研究这个主题,并试图确定“内联 Javascript”方法是否可以调用现有的 Javascript 函数,而不仅仅是调用中嵌入的代码。
      猜你喜欢
      • 2021-12-11
      • 2018-04-15
      • 2013-01-04
      • 1970-01-01
      • 2023-02-09
      • 1970-01-01
      • 2016-08-17
      • 2020-03-12
      • 2011-06-15
      相关资源
      最近更新 更多