wasm32-wasip1-threads

层级:2

wasm32-wasip1-threads 目标是一个新的且仍然处于实验阶段的目标(截至 2023 年 7 月)。此目标是 wasm32-wasip1 目标的扩展,最初被称为 wasm32-wasi。它通过一组标准化的系统调用扩展了原始目标,旨在为 WebAssembly 二进制文件提供原生多线程功能。

注意:在 2024 年 3 月之前,此目标被称为 wasm32-wasi-preview1-threads,更早之前它被称为 wasm32-wasi-threads

目标维护者

  • Georgii Rylov, https://github.com/g0djan
  • Alex Crichton, https://github.com/alexcrichton
  • Andrew Brown, https://github.com/abrown
  • Marcin Kolny, https://github.com/loganek

要求

此目标是交叉编译的。该目标完全支持 std

这里的 Rust 目标定义在几个方面很有趣。我们希望通过这个目标满足两个用例

  • 首先,我们希望 Rust 对该目标的使用尽可能无障碍,最好避免配置和安装本地 wasm32-wasip1-threads 工具链的需求。
  • 其次,LLVM 新的 wasm 后端和 LLD 中 wasm 支持的主要用例之一是任何编译语言都可以与其他任何语言互操作。wasm32-wasip1-threads 目标是第一个具有可行的 C 标准库和 sysroot 通用定义的目标,因此我们希望在编译到 wasm32-unknown-unknown 时,Rust 和 C/C++ 代码可以互操作。

但是,您会注意到,上述两个目标在某种程度上是相互矛盾的。为了尝试一次性解决这两个用例,我们定义了一个目标,它(滥用)crt-static 目标特性来指示您所处的用例。

不需要与 C 互操作

默认情况下,crt-static 目标特性已启用,启用后,这意味着将使用 liblibc.rlib 中找到的捆绑版本 libc.a。这实际上不是为了与 C 互操作,因为 Rust 捆绑的 C 库可能与外部编译的 C 库不兼容。但是,在这种用例中,我们使用 rust-lld 和一些复制的 crt 启动对象文件,以确保您可以下载 Rust 的 wasi 目标,并且您可以直接开始,无需进一步配置。总而言之,默认情况下,不需要外部依赖项。您可以直接编译 wasm32-wasip1-threads 二进制文件。但是,在这种模式下,您(尚未)无法可靠地与 C 代码互操作。

需要与 C 互操作

对于第二个目标,我们重新利用 target-feature 标志,这意味着您需要做一些事情才能使 C/Rust 代码互操作。

  1. 所有 Rust 代码都需要使用 -C target-feature=-crt-static 进行编译,表明不会使用 Rust sysroot 中捆绑的 C 标准库。
  2. 如果您正在使用 rustc 构建链接的工件,那么您需要将 -C linker 指定为支持 wasm32-wasip1-threads 并配置了 wasm32-wasip1-threads sysroot 的 clang 二进制文件。这将导致 Rust 代码链接到指定的 clang 提供的 libc.a。
  3. 如果您正在构建 staticlib 并在其他地方集成 Rust 代码,那么使用 -C target-feature=-crt-static 进行编译就是您需要做的全部操作。

总而言之,默认情况下,不需要外部依赖项。您可以直接编译 wasm32-wasip1-threads 二进制文件。但是,在这种模式下,您(尚未)无法可靠地与 C 代码互操作。

另请注意,目前 wasm32-wasip1-threads 目标假定存在其他合并的 wasm 提案,例如(及其 LLVM 特性标志)

  • 批量内存 - +bulk-memory
  • 可变导入的全局变量 - +mutable-globals
  • 原子操作 - +atomics

此目标需要 LLVM 16。原因是与链接器标志相关:在 LLVM 16 之前,不允许同时使用 --import-memory 和 --export-memory。之所以两者都需要,是因为 WASI 当前的工作方式的产物;有关更多详细信息,请参阅 https://github.com/WebAssembly/WASI/issues/502。

该目标旨在匹配其 "C" ABI 的相应 Clang 目标。

注意:由于此目标处于相对早期的阶段,因此在使用此目标时,您可能会遇到 LLVM 错误。如果发现断言命中或错误,建议在 rust-lang/rust 或理想情况下在 LLVM 本身中打开一个问题。

平台要求

运行时应支持与任何其他受支持的 wasi 目标相同的 API 集,以便通过 WASI 标准与主机环境进行交互。运行时还应具有 wasi-threads 提案的实现。

此目标不是稳定目标。这意味着有一些引擎实现了 wasi-threads 功能,如果它们实现了,它们很可能位于标志后面,例如

  • Wasmtime - --wasm-features=threads --wasi-modules=experimental-wasi-threads
  • WAMR - 需要使用 WAMR_BUILD_LIB_WASI_THREADS=1 构建

构建目标

用户需要安装或构建 wasi-sdk,因为 20.0 版 https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20 和指定 wasi-root 的路径 config.toml

[target.wasm32-wasip1-threads]
wasi-root = ".../wasi-libc/sysroot"

之后,用户可以通过将其添加到 config.toml 中的 target 列表或使用 -Zbuild-std 来构建它。

构建 Rust 程序

从 Rust Nightly 1.71.1 (2023-08-03) 开始,工件已预先编译

rustup target add wasm32-wasip1-threads --toolchain nightly

可以为该目标构建 Rust 程序

rustc --target wasm32-wasip1-threads your-code.rs

交叉编译

此目标可以从任何主机进行交叉编译。

测试

当前对 wasm32-wasip1-threads 的测试支持不佳,并且 Rust 项目没有为此目标运行任何测试。但是,可以通过以下说明手动运行 UI 测试套件

  1. 确保已安装 wamrwasmtime 或其他支持 wasi-threads 的引擎,并且可以在 $PATH 环境变量中找到。
  2. 克隆 master 分支。
  3. 应用这样的 更改,并使用步骤 1 中的引擎。
  4. 运行 ./x.py test --target wasm32-wasip1-threads tests/ui 并保存失败的测试列表。
  5. 检出带有更改的分支。
  6. 应用这样的 更改,并使用步骤 1 中的引擎。
  7. 运行 ./x.py test --target wasm32-wasip1-threads tests/ui 并保存失败的测试列表。
  8. 对于失败的两个测试列表,运行 cat list | sort > sorted_list 并将其与 diff sorted_list1 sorted_list2 进行比较。

有条件地编译代码

建议使用以下方式为此目标有条件地编译代码

#[cfg(all(target_os = "wasi", target_env = "p1", target_feature = "atomics"))]

在 Rust 1.80 之前,未设置 target_env = "p1" 键。目前,target_feature = "atomics" 仅限 Nightly 版本。请注意,随着目标变得更加稳定,检测此目标所需的精确 #[cfg] 可能会发生变化。

启用的 WebAssembly 功能

为编译启用的默认 WebAssembly 功能集除了 wasm32-unknown-unknown 启用的功能外,还包括另外两个功能

  • bulk-memory
  • atomics

有关功能的更多信息,请参阅 wasm32-unknown-unknown 的文档,但请注意,LLVM 中的 mvp CPU 不支持此目标,因为它要求启用 bulk-memoryatomicsmutable-globals