我可以以某种方式构建webassembly代码*而不使用emscripten"glue"吗?

Kar*_*lek 19 javascript emscripten webassembly

我可以以某种方式创建一个ism文件,这将在MDN中描述(通过实例化对象并调用它们上面的函数)吗?

我能找到的所有指南(例如MDN上的这个指南)都建议使用emscripten; 但是,它还包括~70kB"胶水代码"(具有~50 kB可选文件系统仿真),它具有额外的逻辑(如检测节点/浏览器环境和自动提取等),可能还有其他一些仿真.

如果我不想要"粘合代码"并且想直接创建WASM(可能来自C代码,但可能是其他东西)怎么办?这可能吗?

kan*_*aka 12

您可以使用emscripten生成相当少的代码输出.

考虑以下简单文件adder.c:

int adder (int a, int b) {
    return a + b;
}
Run Code Online (Sandbox Code Playgroud)

像这样编译它(需要一个相当新的emscripten):

emcc -O2 -s WASM=1 -s SIDE_MODULE=1 -o adder.wasm
Run Code Online (Sandbox Code Playgroud)

要查看它生成的内容,请wasm-dis使用binaryen 将其反汇编为文本形式(您也可以使用wabt中的wasm2wast):

wasm-dis adder.wasm -o adder.wast
Run Code Online (Sandbox Code Playgroud)

反汇编的源应该看起来像这样:

(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
)
Run Code Online (Sandbox Code Playgroud)

然后,您可以在节点(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))
})
Run Code Online (Sandbox Code Playgroud)

请注意,如果要支持使用堆栈和/或堆内存的代码,事情会变得更复杂.也就是说,在__post_instantiate调用任何其他导出之前,至少需要设置memoryBase并从主机环境调用.

如果你想在没有JavaScript环境的情况下解释WebAssembly代码,你可以使用wac/wace运行它(完全披露:我创建了这个项目).请注意,wace假设您定义了"_main"或"main"函数.


小智 6

您可以使用 ONLY_MY_CODE 标志,这将只生成没有glue.js 的wasm 模块,例如

emcc -O1 ./src/foo.cpp -o release/foo.wasm -s WASM=1 -s ONLY_MY_CODE=1
Run Code Online (Sandbox Code Playgroud)

从 Settings.js https://github.com/kripken/emscripten/blob/master/src/settings.js#L583

var ONLY_MY_CODE = 0; // This disables linking and other causes of adding extra code
                      // automatically, and as a result, your output compiled code
                      // (in the .asm.js file, if you emit with --separate-asm) will
                      //  contain only the functions you provide.
Run Code Online (Sandbox Code Playgroud)


JF *_*ien 5

你可以,而且随着时间的推移它变得越来越容易!

如果您想完全避免使用 C++,则可以创建 WebAssembly 模块,例如在规范测试WebKit 测试套件中所做的。

即使使用 C++,您也可以,无需 Emscripten。wasm-stat.us是为 GCC 酷刑测试做的。查看它的构建输出,或者查看它的 source

例如,它将为编译/链接/组装执行以下操作:

# Get a .o file:
src/work/wasm-install/bin/clang src/work/gcc/gcc/testsuite/gcc.c-torture/execute/20020227-1.c -o src/work/torture-o/20020227-1.c.o --std=gnu89 -DSTACK_SIZE=1044480 -w -Wno-implicit-function-declaration --target=wasm32-unknown-unknown-wasm -c -O2 --sysroot=src/work/wasm-install/sysroot
# Link with libc:
src/work/wasm-install/bin/lld -flavor wasm -entry=main --allow-undefined-file=src/work/wasm-install/sysroot/lib/wasm.syms -o src/work/torture-lld-musl/20020510-1.c.o.wasm src/work/torture-o/20020510-1.c.o src/work/wasm-install/sysroot/lib/libc.a
# Or without a libc (you need to provide one somehow):
src/work/wasm-install/bin/lld -flavor wasm -entry=main --allow-undefined-file=src/work/wasm-install/sysroot/lib/wasm.syms -o src/work/torture-lld/20020510-1.c.o.wasm src/work/torture-o/20020510-1.c.o

# Or, if you want an assembly file instead:
src/work/wasm-install/bin/clang src/work/gcc/gcc/testsuite/gcc.c-torture/execute/20020227-1.c -o src/work/torture-s/20020227-1.c.s --std=gnu89 -DSTACK_SIZE=1044480 -w -Wno-implicit-function-declaration --target=wasm32-unknown-unknown -S -O2 --sysroot=src/work/wasm-install/sysroot
# And get the binary file:
src/work/wasm-install/bin/wast2wasm src/work/torture-s2wasm/loop-6.c.s.wast -o src/work/torture-wast2wasm/loop-6.c.s.wast.wasm
Run Code Online (Sandbox Code Playgroud)

您甚至可以下载瀑布的所有构建工件,包括完整的工具链。只需单击一个绿色框并找到您正在寻找的下载。

如果您有胆量,甚至可以用 JavaScript 编写 libc,而不是链接用 C 编写的现有实现。

当你说“靠它自己”时,请记住 WebAssembly 目前不能在不链接到其嵌入器(即 JavaScript)的情况下做任何事情。Emscripten 遵循的模型(我希望其他人也这样做)是 JavaScript 是微内核并提供系统调用。


Ric*_*aca 5

LLVM 现在支持使用 WASI 将 C 直接编译为 wasm。不再需要 Emscripten。

如果不需要 libc,您可以直接使用 LLVM。例如,该文件foo.c可以编译为:

clang --target=wasm32 --no-standard-libraries -Wl,--export-all -Wl,--no-entry -o foo.wasm foo.c
Run Code Online (Sandbox Code Playgroud)

否则,WASI-libc 项目有一个可以使用的独立 libc。

这篇文章提供了使用 LLVM 将 C 编译为 WebAssembly 并在浏览器中运行它的完整过程。


小智 5

2020 年更新

使用 Emscripten,您可以使用 -o my_file.wasm

这样,您将只有 WASM 文件,如果您使用该标志STANDALONE_WASM,它将在需要时创建.wasmAND 一个可选的.js粘合代码。