我正在为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
对象,但这似乎非常hacky,我必须为我使用的每个数学函数执行此操作。还有更好的方法吗?
我正在使用夜间Rust工具链(nightly-x86_64-unknown-linux-gnu rustc 1.24.0-nightly(cddc4a62d 2017-12-26))和Firefox 57.0.1(64位)。
答案 0 :(得分:5)
根据WASM FAQ sin
不包括在内。
•WebAssembly不包含自己的数学函数,如sin,cos,exp,pow等。 WebAssembly对这些函数的策略是允许它们在WebAssembly本身中实现为库例程(注意x86的sin和cos指令是缓慢且不精确的,并且这些天通常都会被避免)。希望在WebAssembly上使用更快和更精确的数学函数的用户可以简单地选择一个这样做的数学库实现。
Rust似乎依赖LLVM提供sin
(f64 impl here),但它不能为WASM做。我认为LLVM 应将其作为llvm.sin.f64
内在函数的一部分提供,但看起来它们并不能保证每个目标的实现https://llvm.org/docs/LangRef.html#llvm-sin-intrinsic(强调我的): / p>
这是一个过载的内在因素。您可以在任何浮点或浮点类型的向量上使用llvm.sin。 并非所有目标都支持所有类型。
也许,鉴于此,Rust应考虑自己实施sin
。
答案 1 :(得分:1)
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中的错误消息将同时包含module
和field
。 / p>
您可以在WebAssembly中构建C库的子集,并将其用作导入对象的一部分。我有一个musl libc端口可用。 WebAssembly waterfall构建并使用它,构建are in the waterfall's source的说明。
同样,将其值放入导入对象中是很难做的。我将使用WebAssembly.Module.exports迭代模块的导出,并确保名称修改是正确的(看起来你的代码需要直接sin
,并且通常在开始时使用额外的下划线来修改C名称)。然后与上面相同,将它们添加到导入对象并获得module
/ field
。