我计划为 NodeJS 创建一个使用本机代码的库,这次我想尝试一下 WebAssembly。目前,我可以将 C 代码编译为 WebAssembly,但 Emscripten 会生成一个
.wasm
和一个 .js
文件。我知道幕后涉及一个运行时,但我想知道是否没有办法加载 WebAssembly(如下所列)并调用该函数。
我的主要.c
#include <stdio.h>
#include <emscripten/emscripten.h>
EMSCRIPTEN_KEEPALIVE
extern void hello() {
printf("Hello world!\n");
}
我的index.js
var a = require("./a.out.js");
a().then((instance) => {
instance.ccall("hello"); // Prints "Hello World!"
});
编译
emcc -s NO_EXIT_RUNTIME=1 -sMODULARIZE -s "EXPORTED_RUNTIME_METHODS=['ccall']" main.c
奔跑
node index.js
以上有效。下面的代码没有
const fs = require("node:fs");
const wasmBuffer = fs.readFileSync("a.out.wasm");
WebAssembly.instantiate(wasmBuffer).then((wasmModule) => {
const { hello } = wasmModule.instance.exports;
hello();
});
错误
node index.js
node:internal/process/promises:288
triggerUncaughtException(err, true /* fromPromise */);
^
[TypeError: WebAssembly.instantiate(): Imports argument must be present and must be an object]
Node.js v18.18.2
如果您的目标是 Node.js(而不是浏览器 JavaScript),我强烈建议您采用本机 Node-API 路线。它速度更快,有更好的支持,并且是一个非常成熟的环境。 WASM 仍然是一项稍微实验性的技术,有许多粗糙的地方。如果你不打算在浏览器中运行你的项目,那么你只能输给 WASM。
emscripten 依赖于一个特殊的加载器,因为它在创建时,WASM 没有指定的环境。这意味着 JavaScript 和 WASM 之间有很多粘合代码,而 emscripten 按照自己的方式行事。
今天有 WASI,它将成为未来的标准,但它仍处于起步阶段。它将通过为 WASI 软件指定标准环境和 ABI 来解决此类问题。
你不能直接加载 WASM,除非你愿意手动完成 emscripten 加载器所做的一切 - 我向你保证这并不容易 - 特别是如果你想要良好的跨平台兼容性。