我可以以某种方式创建一个ism文件,它将自行工作,如in MDN here所述(通过实例化对象并调用它们上的函数)?
我能找到的所有指南(such as this one on MDN)都推荐使用emscripten;但是,它还包括~70kB“胶水代码”(具有~50 kB可选文件系统仿真),它具有额外的逻辑(如检测节点/浏览器环境和自动提取等),可能还有其他一些仿真.
如果我不想要“粘合代码”并且想直接创建WASM(可能来自C代码,但可能是其他东西)怎么办?这可能吗?
解决方法:
您可以使用emscripten生成相当少的代码输出.
考虑以下简单文件adder.c:
int adder (int a, int b) {
return a + b;
}
像这样编译它(需要一个相当新的emscripten):
emcc -O2 -s WASM=1 -s SIDE_MODULE=1 -o adder.wasm
要查看它生成的内容,请使用binaryen的wasm-dis将其反汇编为文本形式(您也可以使用来自wabt的wasm2wast):
wasm-dis adder.wasm -o adder.wast
反汇编的源应该看起来像这样:
(module
(type $0 (func (param i32 i32) (result i32)))
(type $1 (func))
(import "env" "memoryBase" (global $import$0 i32))
(import "env" "memory" (memory $0 256))
(import "env" "table" (table 0 anyfunc))
(import "env" "tableBase" (global $import$3 i32))
(global $global$0 (mut i32) (i32.const 0))
(global $global$1 (mut i32) (i32.const 0))
(export "__post_instantiate" (func $2))
(export "runPostSets" (func $1))
(export "_adder" (func $0))
(func $0 (type $0) (param $var$0 i32) (param $var$1 i32) (result i32)
(i32.add
(get_local $var$1)
(get_local $var$0)
)
)
(func $1 (type $1)
(nop)
)
(func $2 (type $1)
(block $label$0
(set_global $global$0
(get_global $import$0)
)
(set_global $global$1
(i32.add
(get_global $global$0)
(i32.const 5242880)
)
)
(call $1)
)
)
;; custom section "dylink", size 5
)
然后,您可以在节点(v8.X或更高版本)中运行此命令,如下所示:
const WA = WebAssembly,
env = {memoryBase: 0,
tableBase: 0,
memory: new WA.Memory({initial: 256}),
table: new WA.Table({initial: 0, element: 'anyfunc'})},
code = new Uint8Array(require('fs').readFileSync('adder.wasm'))
WA.compile(code).then(m => {
return new WA.Instance(m, {env: env})
}).then(i => {
console.log(i.exports._adder(7, 8))
})
请注意,如果要支持使用堆栈和/或堆内存的代码,事情会变得更复杂.即在调用任何其他导出之前,至少需要设置memoryBase并从主机环境调用__post_instantiate.
如果您想在没有JavaScript环境的情况下解释WebAssembly代码,可以使用wac/wace运行它(完全披露:我创建了这个项目).请注意,wace假定您定义了“_main”或“main”函数.