【发布时间】: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