1、安装wasm编译目标
rustup target add wasm32-unknown-unknown
wasm32-unknown-unknown 是 WebAssembly (Wasm) 的一个编译目标,表示一个独立于特定环境(如浏览器或Node.js)的 32 位 WebAssembly 二进制文件。
它是 Rust 等语言编译成 WebAssembly 的基础,用于生成可在任何支持 Wasm 的环境中运行的代码。
- wasm32: 指示目标架构是 32 位 WebAssembly。
- unknown: 表示目标操作系统和 ABI(应用程序二进制接口)是未知的,因为 Wasm 是一种通用格式,它不依赖于特定的操作系统。
- 用途: 它是生成独立于特定环境的 WebAssembly 模块的基础。
- 扩展: 在 wasm-bindgen 等项目中,wasm32-unknown-unknown 是基础目标,其他特定环境的目标会基于它进行扩展,以添加与 JavaScript 或其他环境的绑定代码和加载逻辑。
2、安装wasm-pack可执行工具
cargo install wasm-pack
3、以lib形式新建项目
cargo new wasm-demo --lib
4、在wasm-demo的toml文件加上
[package]
name = "wasm-demo"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.105"
解析: crate-type是什么
crate-type = ["cdylib"] 是 Rust 项目中的一个配置,它告诉编译器将项目编译成一个动态库,该库可以被其他语言(如 C, C++)通过 FFI (Foreign Function Interface) 调用。这意味着生成的库不是一个独立的 Rust 可执行文件,而是供其他程序集成的共享库文件,例如生成 .so (Linux), .dylib (macOS) 或 .dll (Windows) 文件。
详细解释:
- [lib]: 这表示该配置是针对库 (lib) 的。在 Cargo.toml 文件中,[lib] 部分通常包含关于如何构建这个库的设置。
- crate-type: 这个键指定了 Rust crate 的类型。
- ["cdylib"]: 这是 crate-type 的一个值,表示创建的是一个 "C-compatible dynamic library"。
- c: 强调这是一个可以被 C 语言使用的动态库。
- dylib: 表示这是一个动态库文件,而不是静态库。
- 用途: 这种设置主要用于希望将 Rust 代码作为库提供给其他非 Rust 语言的项目使用,例如开发操作系统组件、游戏引擎、浏览器插件等。
与其他库类型的区别
- rlib: 这是 Rust 自身的静态库格式,只能被其他 Rust 项目链接使用。
- staticlib: 创建一个可以在其他语言中作为静态库使用的库,它会被直接链接到目标程序中,而不是作为单独的动态共享库
5、lib.rs文件写上
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
#[wasm_bindgen]
pub fn sum_bytes(data: &[u8]) -> u32 {
data.iter().map(|&b| b as u32).sum()
}
#[wasm_bindgen]
pub fn make_data(size: usize) -> Vec<u8> {
(0..size as u8).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
#[test]
fn greet_works() {
let result = greet("World");
assert_eq!(result, "Hello, World!");
}
#[test]
fn sum_bytes_works() {
let data = vec![1, 2, 3, 4, 5];
let result = sum_bytes(&data);
assert_eq!(result, 15);
}
#[test]
fn make_data_works() {
let size = 5;
let result = make_data(size);
assert_eq!(result, vec![0, 1, 2, 3, 4]);
}
}
6、编译成wasm
- 运行后可以看见一个pkg文件夹,里面有wasm、ts和js的后缀文件,这些就是可以在网页中直接使用的文件。
- 目标参数可以有web(浏览器项目:原生JS, Vue, React),bundler(使用打包工具的现代项目),nodejs(非浏览器Node.js环境),no-modules(老旧浏览器)
wasm-pack build --target web
7、调用
<!DOCTYPE html>
<html>
<body>
<button id="btn">add</button>
<button id="btn1">greet</button>
<button id="btn2">sum</button>
<button id="btn3">array</button>
<script type="module">
import init, { add, greet,sum_bytes,make_data} from "./wasm-demo/pkg/wasm_demo.js";
// 初始化 WASM 模块
async function main() {
await init();
}
main();
// 绑定按钮事件
document.getElementById("btn").onclick = () => {
alert("ADD" + add(10n, 20n));
};
document.getElementById("btn1").onclick = () => {
alert(greet("Rust"));
};
document.getElementById("btn2").onclick = () => {
alert(sum_bytes(new Uint8Array([1,2,3,4,5])));
};
document.getElementById("btn3").onclick = () => {
alert(make_data(5));
};
</script>
</body>
</html>
8、wasm里rust和js类型的对应问题
number:
- i8
- i16
- i32
- u8
- u16
- u32
- f32
- f64
BigInt:
- i64
- u64
boolean:
- bool
string:
- char
- &str
- String
Array:
- vec
TypedArray:
- &[T]
- Uint8Array = &[u8]
- Int8Array = &[i8]
- Uint16Array = &[u16]
- Float32Array = &[f32]
- Float64Array = &[f64]