【问题标题】:Problem with Emscripten with MINIMAL_RUNTIMEEmscripten 与 MINIMAL_RUNTIME 的问题
【发布时间】:2020-10-24 17:05:00
【问题描述】:

我是 emscripten 的新手,所以这对其他人来说可能很容易回答。我无法访问我的 C 函数。这是设置:

简单的C文件square.c:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE 
double square(double x){
    return x*x;
}

ready.js 的内容:

ready = function () {
    startup();
}

startup 是我添加到 square.html 中的一个函数,用于了解一切何时准备就绪。

Emcc 命令行:

emcc square.c -DNDEBUG -s MINIMAL_RUNTIME -s ALLOW_MEMORY_GROWTH=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 -s SUPPORT_ERRNO=0 --pre-js ./ready.js -s EXPORT_NAME=wasmMod -o square.html 

输出如预期:square.html、square.js、square.wasm

一切都按预期在 Chrome 中运行,启动被调用。现在我想访问 square 函数:

function startup(){
  console.log('startup called');
  let y = _square(2);
  console.log(`square: ${y}`);
}

这给了我一个错误:“VM291:1 Uncaught ReferenceError: _square is not defined” 如果我使用

let y = wasmMod._square(2);

相反,我得到 "square.js:783 TypeError: wasmMod._square 不是函数"

我尝试了很多东西并搜索了网络,但我似乎无法找到错误。 如果我删除 -s MODULARIZE=1,我可以毫无问题地调用 _square(2),但是,在这种情况下 wasmMod 不包含任何内容,所有变量和函数都在全局上下文中,这是我想要避免的。 一旦它工作了,我想使用 ES6 模块将此部分嵌入到一个更大的 JS 项目中,所以我的目标是将与 emscripten 相关的所有内容都保存在一个模块中。

非常感谢任何帮助。提前致谢!

2020/10/27:从 html 文件添加脚本:

// Depending on the build flags that one uses, different files need to be downloaded
// to load the compiled page. The right set of files will be expanded to be downloaded
// via the directive below.
  function binary(url) { // Downloads a binary file and outputs it in the specified callback
      return new Promise((ok, err) => {
        var x = new XMLHttpRequest();
        x.open('GET', url, true);
        x.responseType = 'arraybuffer';
        x.onload = () => { ok(x.response); }
        x.send(null);
      });
    }
  
  function script(url) { // Downloads a script file and adds it to DOM
    return new Promise((ok, err) => {
      var s = document.createElement('script');
      s.src = url;
      s.onload = () => {
        var c = wasmMod;
        delete wasmMod;
        ok(c);
      };
      document.body.appendChild(s);
    });
  }
  Promise.all([script('square.js'), binary('square.wasm')]).then((r) => {
  // Detour the JS code to a separate variable to avoid instantiating with 'r' array as "this" directly to avoid strict ECMAScript/Firefox GC problems that cause a leak, see https://bugzilla.mozilla.org/show_bug.cgi?id=1540101
  var js = r[0];
  js({ wasm: r[1] });
});

2020/10/27:添加了一些来自 square.js 的内容:

var wasmMod=
function(wasmMod) {
  wasmMod = wasmMod || {};

var Module = wasmMod;

...lots of javascript follows ...

var imports = {
 "env": asmLibraryArg,
 "wasi_snapshot_preview1": asmLibraryArg
};

var _square, _fflush, stackSave, stackRestore, stackAlloc, _emscripten_get_sbrk_ptr, _sbrk;

if (!Module["wasm"]) throw "Must load WebAssembly Module in to variable Module.wasm before adding compiled output .js script to the DOM";

WebAssembly.instantiate(Module["wasm"], imports).then(function(output) {
 var asm = output.instance.exports;
 _square = asm["square"];
 _fflush = asm["fflush"];
 stackSave = asm["stackSave"];
 stackRestore = asm["stackRestore"];
 stackAlloc = asm["stackAlloc"];
 _emscripten_get_sbrk_ptr = asm["emscripten_get_sbrk_ptr"];
 _sbrk = asm["sbrk"];
 wasmTable = asm["__indirect_function_table"];
 initRuntime(asm);
 ready();
}).catch(function(error) {
 console.error(error);
});


  return {}
}

【问题讨论】:

  • 使用MODULARIZE 选项,您可以访问和调用您的函数,就像我的回答here 一样。
  • 感谢您的回复,@Thomas。也许我错过了一些东西,但我看不到承诺会被退回。这是js文件的结构: var wasmMod= function(wasmMod) { wasmMod = wasmMod || {}; ...很多 js.. return {} } 我将在我最初的帖子中的 html 页面上添加脚本,让你看看它是如何被调用的。
  • 在您的情况下,wasmMod 是返回 Promise 的函数。您也可以在EXPORT_NAME......上查看您的报价...
  • 我在上面添加了square.js的重要部分。 wasmMod 以“return {}”结尾。看起来 EXPORT_NAME 正在工作,查看该文件的开头。所以函数通过返回一个空对象退出,然后在实例化调用中调用就绪函数。再次感谢您查看此内容。 PS:这是emcc生成的所有代码,除了函数启动,什么都不做。
  • 你为什么不试试呢?与其试图理解 1000 行生成的 JavaScript 胶水代码,不如相信 documentation 并按照它所说的去做。我可以确认它有效。使用它或失去它。一遍又一遍。

标签: javascript emscripten


【解决方案1】:

我做了更多的测试,现在我有了一个基于@Thomas 提供的建议的可行解决方案。再次感谢您。 但是,只有当我删除 MINIMAL_RUNTIME 标志时,它才能工作。

区别: 没有 MINIMAL_RUNTIME

emcc square.c -DNDEBUG  -s ALLOW_MEMORY_GROWTH=1 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 -s SUPPORT_ERRNO=0 -s "EXPORT_NAME='wasmMod'" -o square.html 

从 square.html 调用:

let res = binary('square.wasm')
.then(wasm => { wasmMod({wasm: wasm})
.then(MyModule => { 
  console.log('WebAssembly loaded!');
  console.log(MyModule._square(3));
});
});

MyModule 包含我需要的一切。我可以毫无问题地使用我的 wasm 函数。

现在使用 MINIMAL_RUNTIME

emcc square.c -DNDEBUG -s MINIMAL_RUNTIME -s ALLOW_MEMORY_GROWTH=1 -s SAFE_HEAP=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web,worker -s MODULARIZE=1 --pre-js ./ready.js -s SUPPORT_ERRNO=0 -s "EXPORT_NAME='wasmMod'" -o square.html -s EXTRA_EXPORTED_RUNTIME_METHODS="['getValue','setValue']"

在 HTML 文件中使用相同的调用序列会报错:

square.html:44 Uncaught (in promise) TypeError: wasmMod(...).then is not a function at square.html:44 

我无法让它像没有 MINIMAL_RUNTIME 的版本一样工作。内部函数 ready() 我可以访问 wasmMod 闭包内的 _square(),但是,在该闭包之外,不存在我可以访问的模块。 wasmMod 仅指向 js 函数,而不指向模块。 我希望错误在我这边,但是,我不能再花时间在这上面了,所以我现在将使用完整版。

【讨论】:

    猜你喜欢
    • 2020-08-28
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多