在 WASM-WASI 上運行 Rust 的 6 個基礎常識

在受限的環境中運行 Rust 會帶來挑戰,代碼可能無法訪問完整的操作系統,如 Linux、Windows 或 macOS。可能對文件、網絡、時間、隨機數甚至內存的訪問有限(或沒有)。我們將探索變通方法和解決方案。

這篇文章主要關注在 “WASM-WASI”(一種類似容器的環境)上運行 Rust 代碼。作爲在瀏覽器或嵌入式系統中運行 Rust 的第一步,它是有價值的。

將代碼運行在 WASM-WASI 上需要許多步驟和規則,瀏覽這些規則可能會很耗時。錯過一步就可能導致失敗,我們將通過提供 9 條規則來減少這種複雜性。

1,WASI 很簡單,就目前而言,除了作爲一個墊腳石之外,基本上沒什麼用。

2019 年,Docker 聯合創始人所羅門 · 海克斯在推特上寫道:“如果 WASM-WASI 在 2008 年就存在,我們就不需要創建 Docker 了。這就是它的重要性,服務器上的 Webassembly 是計算的未來。但是,標準化的系統接口是缺失的環節,讓我們希望 WASI 能夠勝任這項任務。”

如果 WASM WASI 真的準備好並且有用,那麼每個人都應該已經在使用它了。但是,它還沒有準備好。

從 WASI Preview 1 開始,情況是這樣的:你可以訪問一些文件操作、環境變量,並可以訪問時間和生成隨機數。但是,它不支持網絡。

那麼,WASM WASI 有什麼好處呢?目前,它的主要價值在於向在瀏覽器或嵌入式系統上運行代碼邁出了一步。

2,理解 Rust targets

讓我們更深入地瞭解 Rust targets——不僅是 WASM WASI 的基本信息,也是一般 Rust 開發的基本信息。

在 Windows 機器上,可以編譯一個 Rust 項目以在 Linux 或 macOS 上運行。同樣,在 Linux 機器上,也可以編譯 Rust 項目以 Windows 或 macOS 爲目標。下面是用來在 Windows 機器上添加和檢查 Linux target 的命令:

rustup target add x86_64-unknown-linux-gnu
cargo check --target x86_64-unknown-linux-gnu

要查看 Rust 支持的所有目標,使用命令:

rustc --print target-list

它將列出 200 多個目標,包括 x86_64-unknown-linux-gnu、wasm32-wasip1 和 wasm32-unknown-unknown。

目標名稱最多包含四個部分:CPU 系列、供應商、操作系統和環境(例如,GNU vs LVMM):

現在我們瞭解了一些 targets,讓我們繼續安裝 WASM WASI 所需的 targets。

3,安裝 wasm32-wasip1 target 和 WASMTIME,然後創建 “Hello, WebAssembly!”

爲了在瀏覽器外的 WASM 上運行我們的 Rust 代碼,我們需要安裝 wasm32-wasip1 target(帶有 WASI Preview1 的 32 位 WebAssembly)。我們還將安裝 WASMTIME,一個允許我們在瀏覽器外使用 WASI 運行 WebAssembly 模塊的運行時。

rustup target add wasm32-wasip1
cargo install wasmtime-cli

爲了測試我們的安裝,讓我們使用以下命令創建一個新的 Rust 項目:

cargo new hello_wasi

在 src/main.rs 文件中寫入以下代碼:

fn main() {
    #[cfg(not(target_arch = "wasm32"))]
    println!("Hello, world!");
    #[cfg(target_arch = "wasm32")]
    println!("Hello, WebAssembly!");
}

現在,使用 cargo run 運行該項目,應該看到 Hello, world! 打印到控制檯。

接下來,創建. cargo/config.toml 文件,它指定了 Rust 在以 WASM-WASI 爲目標時應該如何運行和測試項目。

[target.wasm32-wasip1]
runner = "wasmtime run --dir ."

現在執行以下命令:

cargo run --target wasm32-wasip1

應該看到 Hello, WebAssembly! 恭喜,我們剛剛成功地在類似容器的 WASM-WASI 環境中運行了一些 Rust 代碼。

4,理解條件編譯

現在,讓我們研究一下#[cfg(…)]——Rust 中條件編譯代碼的重要工具。我們看一下如下代碼:

fn main() {
    #[cfg(not(target_arch = "wasm32"))]
    println!("Hello, world!");
    #[cfg(target_arch = "wasm32")]
    println!("Hello, WebAssembly!");
}

#[cfg(…)] 告訴 Rust 編譯器根據特定條件包含或排除某些代碼項。“代碼項” 指的是一個代碼單元,如函數、語句或表達式。

使用 #[cfg(…)],可以有條件地編譯代碼。換句話說,可以爲不同的情況創建不同版本的代碼。例如,在以 wasm32 爲目標編譯時,編譯器會忽略#[cfg(not(target_arch = "wasm32"))] 塊,並且只包含以下內容:

fn main() {
    println!("Hello, WebAssembly!");
}

可以將表達式與邏輯操作符 not、any 和 all 結合使用。

#[cfg(not(target_arch = "wasm32"))]
...
#[cfg(target_arch = "wasm32")]
...

要有條件地編譯整個文件,請在文件的頂部放置 #![cfg(…)]。當文件僅與特定目標或配置相關時,這很有用。

也可以在 Cargo.toml 中使用 cfg 表達式,有條件地包含依賴項。這可以爲不同的目標定製依賴項。例如,下面配置表示 “當目標不是 wasm32 時,依賴於 criterion 的 Rayon 特性”

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
criterion = { version = "0.5.1"features = ["rayon"] }

5,WASM-WASI 不支持網絡

如果你的項目需要訪問網絡,使用 Tokio 的異步任務,或使用 Rayon 的多線程,不幸的是,這些功能在 WASM-WASI Preview 1 中不支持。

在 Rust 中,有一個常見的說法:“如果它能編譯,它就能工作。” 不幸的是,這並不總是適用於 WASM-WASI。如果使用不支持的特性,如網絡,編譯器將無法捕獲錯誤。相反,它將在運行時失敗。例如,這段代碼在 WASM-WASI 上編譯和運行,但總是返回一個錯誤,因爲網絡不被支持。

use std::net::TcpStream;

fn main() {
    match TcpStream::connect("crates.io:80") {
        Ok(_) => println!("Successfully connected."),
        Err(e) => println!("Failed to connect: {e}"),
    }
}

幸運的是,WASM-WASI Preview 2 有望改進這些限制,提供更多的特性,包括對網絡和異步任務的更好支持。

6,將 WASM-WASI 添加到 CI(持續集成)測試中

持續集成 (CI) 是一種系統,它可以在每次更新代碼時自動運行測試,確保代碼繼續按預期工作。通過將 WASM-WASI 添加到 CI 管道中,可以保證將來的更改不會破壞項目與 WASM-WASI 目標的兼容性。

一般項目代碼託管在 GitHub 上,會使用 GitHub Actions 作爲 CI 管道系統。下面是.github/workflows/ci 中的配置:

test_wasip1:
      name: Test WASI P1
      runs-on: ubuntu-latest
      steps:
        - name: Checkout
          uses: actions/checkout@v4
        - name: Set up Rust
          uses: dtolnay/rust-toolchain@master
          with:
            toolchain: stable
            targets: wasm32-wasip1
        - name: Install Wasmtime
          run: |
            curl https://wasmtime.dev/install.sh -sSf | bash
            echo "${HOME}/.wasmtime/bin" >> $GITHUB_PATH
        - name: Run WASI tests
          run: cargo test --verbose --target wasm32-wasip1

通過將 WASM-WASI 集成到 CI 管道中,我們可以自信地向項目中添加新代碼。CI 將自動測試所有的代碼在將來是否繼續支持 WASM-WASI。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/VNPT6OaJ4fNAijUKNNZR4A