作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/130859548
【介绍】:本文记叙如何将一个 Rust 语言编译成可执行的 WebAssembly 文件。
目 录
1. 概述
1.1 什么是 WebAssembly
WebAssembly 是一种低级的类汇编语言,它是一种可以在现代的网络浏览器中运行的新的编码方式,并且可以接近原生的性能运行。依据官网的介绍,WebAssembly(缩写为 Wasm)是 基于堆栈的虚拟机 的 二进制指令格式。Wasm被设计为编程语言的可移植编译目标,支持 客户端和服务器应用程序 在 Web 上的部署。
通过 WebAssembly 技术,我们可以为 Rust、C / C ++、Go 等多种语言提供一个编译目标,以便它们可以在 Web 上运行,并且是可以与 JavaScript 一起工作的。
1.2 WebAssembly 的特点
WebAssembly 官方对于该技术的优势归纳为以下几个方面:高效、安全、开放。
1.2.1 高效
Wasm堆栈机被设计为 以 大小 和 加载时间 有效的 二进制格式编码。WebAssembly 旨在利用各种平台上可用的通用硬件功能,以本机速度执行。
1.2.2 安全
WebAssembly描述了一个内存安全的沙盒执行环境,甚至可以在现有的JavaScript虚拟机中实现。当嵌入到web中时,WebAssembly将实施浏览器的同源和权限安全策略。
1.2.3 开放
WebAssembly 被设计成文本格式,用于调试、测试、实验、优化、学习、教学和手工编写程序。在网上查看Wasm模块的源代码时,将使用文本格式。同时,WebAssembly 被作为网络平台的一部分,其旨在维护 Web 的无版本、经过功能测试和向后兼容的特性。WebAssembly 模块将能够调入和调出 JavaScript 上下文,并通过可从 JavaScript 访问的相同 Web APIs 访问浏览器功能。WebAssembly 还支持 非web嵌入。
1.3 本文受众与脉络
1.3.1 关于受众
本文针对 Web 前端 以及 NodeJS 或基于NodeJS 的桌面(如electron)或其它场景应用的开发人员进行讲解,假定已有 浏览器 或 NodeJS 的开发经验。
1.3.2 脉络引导
本文从零搭建一个 Rust 项目,在其中穿插讲解需要用到的一些知识,如 Rust 的 wask-pack 模块。然后在实际项目中简单将 Rust 项目编译好,分别讲述如何在 浏览器、NodeJS 中运行它。
2. 快速入门 Rust-WebAssembly
2.1 搭建 Rust 开发环境
请参考博文 《开发环境搭建与 rust 工具介绍》,文本不再赘述。
2.2 编写你的 Rust 代码
新建 Rust 项目 hello-wasm:
cargo new hello-wasm
进入该项目:
cd hello-wasm
可以看到有以下目录和文件:
在 src
目录下,有一个名为 main.rs
的文件。我们可以使用 VScode 或者 Vim 等程序编辑它,修改为我们自己的代码。
vim src/main.rs
由于我们目标是写一个用于 npm 的模块,这个自动生成的代码没有任何作用的。
然后,我们另外编辑一个 src/lib.rs
文件:
# 此处假定当前位于项目根目录
# 如果使用 VSCode,则使用命令 code src/lib.rs
vim src/lib.rs
内容如下:
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
2.3 在当前项目中添加 wasm_bindgen 和 wasm-pack 模块
前一节的代码中用到了 wasm_bindgen 模块,该模块用于 Rust 与 JavaScript 交互。另外还有 wasm-pack 模块用于构建 wasm,它们都需要单独在项目中安装。你可以直接使用 cargo 工具添加:
cargo add wasm-pack
cargo add wasm_bindgen
完成后,在项目配置文件中增加依赖项的记录:
关于 添加 wasm-pack 模块 更详细的方法请参考 《3.2 将 wasm-pack
模块添加到你的 Rust 项目》 小节。
然后编辑 Cargo.toml
的 lib
部分,以告诉 Rust 为我们的包建立一个 cdylib 版本。添加以下内容:
[lib]
crate-type = ["cdylib", "rlib"]
2.4 可能用到的各种各种工具
在本文对应的实操,将会用到各种工具,由于不同的人习惯不一样,尤其是某些软件在官方不发布二进制文件仅仅发布源代码时,大家习惯于使用不同的社区构建版本。在这里博主我已经为读者提前下载好了各种工具,提供这些工具安装方式的介绍,这些工具都在我的资源上传区可以找到。rust 语言自生就需要各种依赖,如:
- python 3 or 2.7
- git
- 一个C编译器 (为主机搭建时,
cc
就够了;交叉编译可能需要额外的编译器) - curl (在Windows上不需要)
- pkg-config 如果您在Linux上编译并以Linux为目标
- libiconv (已经包含在基于Debian的发行版的glibc中)
要构建Cargo,还需要OpenSSL(大多数Unix发行版上的 libssl-dev 或 openssl-devel)。如果从源代码构建LLVM,您将需要额外的工具:
g++
,clang++
, 或LLVM文档中列出的 MSVC 版本ninja
, 或 GNU make 3.81 或更新 (推荐Ninja,特别是在Windows上)cmake
3.13.4 或更新libstdc++-static
在一些Linux发行版上可能需要,比如Fedora和Ubuntu
这一节记录相关的一些工具是如何安装的。
Visual Studio 生成工具
Rust的MSVC版本还需要安装Visual Studio 2017(或更高版本),以便 rustc 可以使用其链接器。最简单的方法就是通过 Visual Studio 安装。
你可以访问 https://visualstudio.microsoft.com/zh-hans/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&passive=false&cid=2030下载 Visual Studio 安装工具,然后选择安装 Visual Studio 生成工具安装:
MinGW
MinGW(Minimalist GNU on Windows)也就是 GCC 的 Windows 版本,其中GNU 编译器集合包括 C、C++、 Objective-C, Fortran, Ada、Go 和 D,以及这些语言的库 (libstdc++,…),而 GCC 最初是作为 GNU 操作系统的编译器编写的。
针对 MSVC 的 Windows 平台(例如,您的目标三端in -msvc
)要求cl.exe
,可用并在 path
环境变量中。这通常出现在标准的Visual Studio 安装中,并且可以通过运行适当的开发人员工具 shell 来设置路径。
面向 MinGW 的 Windows平台(例如-gnu中的目标三端)要求cc在 path
环境变量中可用。推荐使用 Win-builds 安装系统的 MinGW-w64 发行版。您也可以通过 MSYS2 获得它。确保安装与你的 rustc 安装相对应的适当架构。来自老 MinGW 项目的 GCC 仅与 32位 rust编译器 兼容。
你可以在 https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/mingw-w64-v11.0.0.zip/download下载 MinGW 安装管理器:
MinGW踩坑记录:安装构建rust后会提示没有 clang,其bin目录也确实没有这个文件。
然后通过它选择包完成安装。
你也可以自己在 https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/ 上下载 MinGW-w64 的不同版本:
而 MinGW-w64 官方网站的地址是:http://mingw-w64.org ,你可以在 https://sourceforge.net/projects/mingw-w64/ 寻找下载链接。
choco
在 Windows 上安装 mingw 的另外一个方式是使用 choco 包管理工具,你需要单独安装该工具。然后:
choco install mingw
msys2
或者使用 MSYS2 ,下载会相对容易些。其官网为:https://www.msys2.org/。你也可以访问 Mingw-w64 的官网 https://www.mingw-w64.org/ 安装其它版本。
MSYS2踩坑记录:安装后会提示没有 clang,打开其目录,有一个clang64.exe和一个 clang32.exe。我尝试将它们改为 clang.exe 然后构建 rust,有弹框报错,不能处理文件。
安装完成后,将你的安装目录添加到系统的 path
环境变量中,然后运行:
msys2_shell -mingw64
以开 mingw64 窗口,在该窗口中输入以下命令:
# 更新软件包镜像(如果您全新安装了MSYS2,则可能需要)
pacman -Sy pacman-mirrors
# 安装Rust所需的构建工具。如果您正在构建32位编译器,那么请将下面的“x86_64”替换为“i686”。
# 如果您已经安装了Git、Python或CMake,并且在 PATH 中,您可以从这个列表中删除它们。
# 请注意,不要**使用“msys2”子系统中的“python2”、“cmake”和“ninja”包,这一点很重要。众所周知,使用这些包时,构建会失败。
pacman -S git \
make \
diffutils \
tar \
mingw-w64-x86_64-python \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-ninja
这写都将安装到 mingw 的目录下,建议如果已经独立按照就不需要再安装了。
安装完成以上这些后,在你的电脑上将可以导航到你的 Rust源代码,然后这样构建它:
python x.py setup user && python x.py build && python x.py install
如果内有安装,也不想使用 pacman 命令来安装。在 Windows也可以运行 winget 工具安装:
winget install -e Python.Python.3
winget install -e Kitware.CMake
winget install -e Git.Git
然后使用 pip 工具安装:
pip install setuptools-rust
pip install cryptography
pip install paramiko
LLVM
或者使用 LLVM,这个我尝试时是好用的。
LLVM-16.0.0-win64.exe:https://download.csdn.net/download/qq_28550263/87821395
关于在类 Unix 系统上安装
在 类 Unix 平台要求 cc
是 C 编译器。例如,这可以通过在 Linux 发行版上安装 cc/clang 和在 macOS 上安装 Xcode 来找到。
OpenSSL
在 Windows 上使用 wasm-pack
构建 WebAssembly 时,需要 OpenSSL 库。请确保你的系统上已安装 OpenSSL。
a. 下载 OpenSSL:OpenSSL 官方不以二进制形式分发包,因此你无法下载官方版本的二进制安装包。
可以先将源码下载过来:
git clone https://github.com/openssl/openssl.git
你需要参考:https://github.com/openssl/openssl/blob/master/NOTES-WINDOWS.md进行构建。
社区提供了一些构建好的二进制版本,可以在社区的页面查看:
https://wiki.openssl.org/index.php/Binaries
(或者使用我准备地这个版本:https://download.csdn.net/download/qq_28550263/87821455)
b. 安装 OpenSSL:构建的 OpenSSL 安装程序,并按照安装向导的指示完成安装过程。
-
设置 OpenSSL 环境变量:如果已经安装了 OpenSSL,但
wasm-pack
无法找到它,您可以尝试手动设置 OpenSSL 的环境变量。a. 打开系统环境变量设置:在 Windows 11 上,点击 “开始” 按钮,搜索并打开 “编辑系统环境变量”。
b. 点击 “环境变量” 按钮:在 “系统属性” 窗口中,点击 “环境变量” 按钮。
c. 添加 OpenSSL 环境变量:在 “系统变量” 部分,点击 “新建” 按钮,并添加以下变量:
- 变量名:
OPENSSL_DIR
- 变量值:OpenSSL 安装目录的路径(例如:
D:\Program Files\OpenSSL
)
d. 点击 “确定” 保存设置,并关闭所有打开的窗口。
- 变量名:
-
重新运行
cargo install wasm-pack
:在设置完 OpenSSL 环境变量后,重新运行cargo install wasm-pack
命令,看是否仍然出现错误。这样做会将 OpenSSL 的路径信息传递给构建过程,以便成功编译和安装wasm-pack
。
如果上述步骤仍然无法解决问题,请确保您按照正确的顺序执行了上述步骤,并且 OpenSSL 的安装路径正确设置。如果问题仍然存在,请尝试使用较新版本的 OpenSSL 或 wasm-pack
,以确保软件版本的兼容性。
如果问题仍然存在,请提供更多错误信息或运行命令时使用 RUST_BACKTRACE=1
环境变量,以便我能够更详细地了解问题并提供进一步的帮助。
Win32OpenSSL
Win32OpenSSL 也是一个社区预构建的 Windows 二进制版本:
https://slproweb.com/products/Win32OpenSSL.html 上找到你需要的安装包版本,然后安装到指定文件夹。
接着使用 Powershell 设置环境变量(依据你的安装位置修改):
# 设置 OpenSSL-Win64 目录
[System.Environment]::SetEnvironmentVariable('OPENSSL_DIR','D:\Program Files\OpenSSL-Win64','User')
# 设置 OpenSSL-Win64 的 bin 目录
[System.Environment]::SetEnvironmentVariable('OPENSSL_LIB_DIR','D:\Program Files\OpenSSL-Win64\bin','User')
# 设置 OpenSSL-Win64 的 include 目录
[System.Environment]::SetEnvironmentVariable('OPENSSL_INCLUDE_DIR','D:\Program Files\OpenSSL-Win64\include','User')
Perl 运行时
某些模块在构建时期用到 Perl 运行时。我已经为读者朋友准备好了一个 Perl 运行时,其下载地址为:
https://download.csdn.net/download/qq_28550263/87837427。下载好后可以自行安装。
安装完成后,需要将 Perl 的二进制文件目录添加到系统的环境变量,以方便我们和程序日后进行访问或调用 Perl 解释器:
比如我将 Strawberry 安装到 D 盘下,那么 Perl 的目录位于:D:\Strawberry\perl\bin。
在 Windows 菜单中搜索 环境变量编辑器,将其单击打开:
点击 “环境变量”:
打开系统变量的 Path 变量名,点击新建,将我们刚刚的路径新增进去,然后保存退出。
你可以使用以下命令查看是否安装成功:
perl -v
如果看到版本号等信息,说明你已经在你的计算机上成功地部署了 Perl:
2.5 构建基于 wasm 的 npm 模块
构建npm包
可能你对一些地方还不是很明白,不过作为快速上手,可以跟着本文先构建上面的 rust 项目为 npm 模块,这需要用到 wasm-pack CLI,可以参考 《3.3 安装 wasm-pack
的命令行工具》 进行安装。
安装后,回到本项目的根目录,使用该脚手架的 build
命令进行构建,格式如下:
wasm-pack build --target web
第一次执行这个命令会需要很长一段时间,尤其是第一次执行时,需要下载一些相关模块,需要耐心等待。如图:
一旦执行完成,可以在项目根目录下的 pkg 目录中找到为你生成的 npm模块,如图所示:
这个目录就是一个包含 xxx.wasm
、xxxx.wasm.d.ts
、xxxx.js
、xxxx.d.ts
的 一个 npm包:
关于构建的过程 wasm-pack 干的活
wasm-pack build 将做以下几件事:
- 编译Rust:将你的 Rust 代码编译成 WebAssembly。
- 生成JS接口:在编译好的 WebAssembly 代码基础上运行 wasm-bindgen,生成一个 JavaScript 文件将 WebAssembly 文件包装成一个模块以便 npm 能够识别它。
- 移入新建
pkg
目录:创建一个 pkg 文件夹并将 JavaScript 文件和生成的 WebAssembly 代码移到其中。 - 转换项目配置文件:读取你的 Cargo.toml 并生成相应的 package.json。
- 复制 readme.md 文件:复制你的 README.md (如果有的话) 到文件夹中。
- 结果:在 pkg 文件夹下得到了一个 npm 包。
3. 关于 wasm-pack
模块
3.1 wasm-pack
是什么
依据该模块主页对自身的描述,该工具旨在成为 构建和使用 rust 生成的 WebAssembly 的 “一站式商店”(one-stop shop),你可以在 浏览器 或 Node.js 中使用 javascript 进行交互。
wasm-pack 帮助您 构建 rust 生成的 WebAssembly 包,您可以将其发布到 npm 注册表,或者在您已经使用的工作流中与任何 JavaScript 包一起使用,如 Webpack。
3.2 将 wasm-pack
模块添加到你的 Rust 项目
和其它任意 Rust 模块一样,有两种方式添加该模块到你的项目中。第一种方式是直接使用 cargo
包管理工具:
cargo add wasm-pack
或者使用第二种方式,编辑项目的 Cargo.toml 文件,在模块依赖项处添加该行:
wasm-pack = "0.11.1"
【注意】:此项目需要 Rust 1.30.0 或更高版本。
其中右侧双引号中的是该模块的版本号,本文写作时最新的版本号为"0.11.1",读者可以指定自己尝试时的最新版本号。
3.3 安装 wasm-pack
的命令行工具
wasm-pack
模块提供了一个命令行工具,你需要手动安装它。
3.3.1 在 Windows 上安装 wasm-pack CLI
你可以直接下载该初始化工具:
https://github.com/rustwasm/wasm-pack/releases/download/v0.11.1/wasm-pack-init.exe,这个工具仅支持 64 位系统。下载完成后运行,将显示一个命令行窗口并很快就能够完成,完成后退出即可。一旦安装完成,将可以在你的系统中使用 wasm-pack 命令。
3.3.1 在 Linux 上安装 wasm-pack CLI
如果你是Linux或者Linux的Windows子系统用户,请在您的终端中运行以下程序,然后按照屏幕上的说明安装wasm-pack:
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
3.3.3 wasm-pack CLI 的用法解析
该命令的语法格式为:
wasm-pack [FLAGS] [OPTIONS] <SUBCOMMAND>
其中,FLAGS 表示标志。提供以下标志项:
命令 | 别名 | 描述 |
---|---|---|
-h | --help | 打印帮助信息 |
-q | --quiet | 不输出信息到控制台 |
-V | --version | 打印版本信息 |
-v | --verbose | 日志详细程度基于使用的v的数量 |
其中,OPTIONS 表示选项。提供以下选项:
选项 | 描述 |
---|---|
--log-level <log-level> | 表示 wasm-pack 应记录的最大消息级别。 可能的值包括: info , warn , error 。默认值为:info 。 |
其中,SUBCOMMAND 表示子命令。提供以下子命令:
子命令 | 描述 |
---|---|
build | 🏗️ 构建您的 npm 包! |
help | 打印该消息或给定子命令的帮助 |
login | 👤 添加npm注册表用户帐户!(别名:adduser 、add-user ) |
new | 🐑 使用模板创建新项目 |
pack | 🍱 为你的 npm包 创建一个 tar,但是不要发布! |
publish | 🎆 打包你的 npm包 并发布! |
3.3.4 关于 wasm-pack 日志的补充
wasm-pack 模块在内部使用 env_logger 模块作为其日志器。要配置日志级别,请使用 RUST_LOG
环境变量。例如(powershell):
- 仅仅在当前窗口中有效的设置:
$env:RUST_LOG="info"
- 长期保存到当前用户的环境变量设置:
[System.Environment]::SetEnvironmentVariable('RUSTUP_LOG','info','User')
3.3.5 改用 wasm-pack CLI 创建 Rust 项目
在 《3.3.3 wasm-pack CLI 的用法解析》 小节中,我们介绍了 wasm-pack 提供的脚手架,其中有一个 new
命令也是可以用来创建 Rust 项目的。现在我们使用该项目来“实操”一下:
wasm-pack new hello-wasm
该命令创建了一个名为 hello-wasm 的项目,其中包含了以下子目录和文件:
该使用 wasm-pack 创建的项目配置文件 Cargo.toml 初始内容为:
[package]
name = "hello-wasm"
version = "0.1.0"
authors = ["your_user_name <xxxxxx+xxxxx@users.noreply.github.com>"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.63"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
wee_alloc = { version = "0.4.5", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.13"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
其中默认为我们安装了 wasm-bindgen 模块,该模块用于 促进 Wasm模块 和 JavaScript之间的高级交互。
4. 小结
要在将 Rust 程序编译为 WebAssembly(Wasm),您可以按照以下步骤进行操作:
-
安装 Rust:首先,您需要安装 Rust 编程语言的工具链。您可以从 Rust 官方网站(https://www.rust-lang.org)下载并安装 Rust。
-
安装 wasm-pack:wasm-pack 是一个用于打包和构建 WebAssembly 的工具。您可以使用 Cargo(Rust 的包管理器)安装 wasm-pack。在命令行中运行以下命令来安装 wasm-pack:
cargo install wasm-pack
-
创建 Rust 项目:在命令行中,进入您的 Rust 项目的根目录,并执行以下命令创建一个新的 Rust 项目:
cargo new my_project
-
进入项目目录:使用
cd
命令进入新创建的项目目录:cd my_project
-
编写 Rust 代码:使用您喜欢的文本编辑器编写 Rust 代码。将您的 Rust 代码保存在
src
目录下的.rs
文件中。 -
配置 Cargo.toml:在项目的根目录中,打开
Cargo.toml
文件,并添加以下内容来配置您的项目以构建为 WebAssembly:[lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2"
-
构建 WebAssembly:在命令行中,执行以下命令以构建 WebAssembly:
wasm-pack build --scope xxxxx --target web
这将使用 wasm-pack 将 Rust 项目构建为 WebAssembly 模块。生成的 WebAssembly 文件将位于
pkg
目录下。 -
集成 WebAssembly 到 Web 项目:将生成的 WebAssembly 文件(
.wasm
和.js
文件)复制到您的 Web 项目中,并通过 JavaScript 脚本加载和使用 WebAssembly。
这些步骤将帮助您在 Windows 11 上将 Rust 程序编译为 WebAssembly。请注意,要成功编译为 WebAssembly,您的 Rust 代码和相关依赖库需要与 WebAssembly 目标兼容。在开发过程中,您可能还需要学习和了解 wasm-bindgen,它是一个用于在 Rust 和 JavaScript 之间进行交互的工具库。