如何使用 Rust 生成最小的 wasm 文件?

How do I generate a minimal wasm file with Rust?

我可以通过 运行 emcc -O3 -s WASM=1 -s SIDE_MODULE=1 -o sum.wasm sum.c.

从以下 C 代码生成一个相当小的(203 字节)wasm 文件
#include <emscripten/emscripten.h>

int EMSCRIPTEN_KEEPALIVE sum(int a, int b) {
    return a + b;
}

反汇编输出:

(module
 (type [=11=] (func (param i32 i32) (result i32)))
 ... trim 9 lines ...
 (export "_sum" (func [=11=]))
 (func [=11=] (type [=11=]) (param $var[=11=] i32) (param $var i32) (result i32)
  (i32.add
   (get_local $var)
   (get_local $var[=11=])
  )   
 )   
 ... trim 17 lines ...
)

但给定以下 Rust 代码

pub fn main() {}

#[no_mangle]
pub extern fn sum(a: i32, b: i32) -> i32 {
    a + b
}

我似乎无法制作任何类似的东西。

rustc -O --target=wasm32-unknown-emscripten sum.rs 有效,但给了我一个 85k 的 wasm 文件和一个 128k 的 js 文件。

我试过导出 EMMAKEN_CFLAGS='-s WASM=1 -s SIDE_MODULE=1' 但这给了我很多警告,比如

Input file "/tmp/.../rust.metadata.bin" exists but was not an LLVM bitcode file suitable for Emscripten. Perhaps accidentally mixing native built object files with Emscripten?

然后无法 link。

我的 Rust 版本是 1.22.0-nightly (c6884b12d 2017-09-30),我的 emcc 版本是 1.37.21

我做错了什么?

对于 wasm32-unknown-emscripten 目标,您使用的是基于 Emscripten 的编译器工具链。 Emscripten 在 wasm 模块中添加了大量额外的运行时代码,以及额外的 JavaScript 代码用于在运行时与之集成。正如您还观察到的,Emscripten 可以使用 SIDE_MODULE 选项进行编译,该选项删除了绝大部分运行时代码。这减少了 wasm 二进制大小,但意味着您必须自己处理诸如绑定复杂类型之类的事情。

最近(2017 年 11 月)一个新的 wasm32-unknown-unknown target was added to Rust,它使用 LLVM 后端(而不是 Emscripten 及其 fastcomp 分支),从而产生最小的输出。

此目标可以按照 setup guide:

中的描述使用
rustup update
rustup target add wasm32-unknown-unknown --toolchain nightly
rustc +nightly --target wasm32-unknown-unknown -O hello.rs