Rust wasm32-unknown-unknown 数学函数不链接

Rust wasm32-unknown-unknown Math functions not linking

我正在尝试 Rust 的新 wasm32-unknown-unknown 目标,我在调用数学函数(例如 sin、cos、exp、atan2)时遇到问题。

Cargo.toml:

[package]
name = "wasm_math"
version = "0.1.0"
authors = ["..."]

[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]

[dependencies]

src/lib.rs:

#[no_mangle]
pub extern "C" fn invoke_sin(x: f64) -> f64 {
    x.sin()
}

index.html:

<!doctype html>
<html lang="en">
  <head><meta charset="utf-8"><title>Wasm Math</title></head>
  <body></body>
  <script>
    const imports = { env: { } };
    fetch("target/wasm32-unknown-unknown/release/wasm_math.wasm").then(response =>
      response.arrayBuffer()
    ).then(bytes =>
      WebAssembly.instantiate(bytes, imports)
    ).then(results => {
      alert(results.instance.exports.invoke_sin(1.0));
    });
  </script>
</html>

我用命令构建项目

cargo build --release --target wasm32-unknown-unknown

当我在 firefox 中打开 html 文件时,出现以下错误:

LinkError: import object field 'sin' is not a Function

我的设置有问题吗?或者这是 Rust/WebAssembly/Firefox 的缺点?我可以手动将 sin 函数添加到 javascript 中的 imports.env 对象,但这看起来很老套,我必须对我使用的每个数学函数都这样做。有没有更好的方法?

我正在使用夜间 Rust 工具链(nightly-x86_64-unknown-linux-gnu rustc 1.24.0-nightly (cddc4a62d 2017-12-26))和 Firefox 57.0.1(64 位)。

根据 WASM FAQ sin 不包括在内。

•WebAssembly doesn’t include its own math functions like sin , cos , exp , pow , and so on. WebAssembly’s strategy for such functions is to allow them to be implemented as library routines in WebAssembly itself (note that x86’s sin and cos instructions are slow and imprecise and are generally avoided these days anyway). Users wishing to use faster and less precise math functions on WebAssembly can simply select a math library implementation which does so.

Rust 似乎依赖 LLVM 提供 sinf64 impl here) which it does not do for WASM. I would think LLVM should provide it as part of their llvm.sin.f64 intrinsic, but it appears that they don't guarantee implementation for every target per https://llvm.org/docs/LangRef.html#llvm-sin-intrinsic(强调我的):

This is an overloaded intrinsic. You can use llvm.sin on any floating-point or vector of floating-point type. Not all targets support all types however.

或许,鉴于此,Rust 应该考虑自己实现 sin

Kyle 的诊断准确无误。我将添加两个建议。


我知道您说过您不想手动将 Math 函数添加到您的导入对象,但这样做也不错:

let mathImports = {};
for (let name of Object.getOwnPropertyNames(Math))
  if (typeof Math[name] === "function")
    mathImports[name] = Math[name];

棘手的事情是在常规导入之前弄清楚如何这样做(这样它们就不会覆盖你已经拥有的任何东西),并弄清楚将导入放在哪个 module 中(因为 WebAssembly 导入有一个名称空间规范调用 module 然后是一个 field 你在错误消息中看到的,FWIW Safari 中的错误消息将同时包含 modulefield) .


您可以将 C 库的子集构建到 WebAssembly 中,并将其用作导入对象的一部分。我有 musl libc available. The WebAssembly waterfall builds and uses it, instructions for building are in the waterfall's source.

端口

同样,将它的值放入导入对象中很难做到正确。我会用 WebAssembly.Module.exports 遍历模块的导出并确保名称修改是正确的(看起来你的代码直接期望 sin ,并且通常 C 名称在开始时用额外的下划线进行修改).然后和上面一样,将它们添加到导入对象并获得 module / field right.