首頁 > 後端開發 > Python教學 > 為 WebAssembly 構建

為 WebAssembly 構建

Mary-Kate Olsen
發布: 2024-12-02 01:26:09
原創
422 人瀏覽過

Building for WebAssembly

我目前正在為 Memphis(我的 Rust 中的 Python 解釋器)探索兩個有趣的主題:建立 WebAssembly 和嵌入 CPython。由於本週沒有重大里程碑要報告,我想分享一些正在進行的想法。對我來說,孟菲斯是一個透過實際實驗來擴展我的概念理解的項目 - 希望這篇文章可以為您做同樣的事情,因為我們正在探索我正在探索的一些設計決策。

瀏覽器中的 Python

將 Memphis 編譯為 WebAssembly 目標已經在我腦海中浮現了一段時間,兩個星期六前,我終於嘗試了一下。在杯墊上放了一杯溫熱的滴濾咖啡,我掰響指關節開始了。

WebAssembly 是現代 Web 瀏覽器內的沙盒執行環境,它補充了傳統的 JavaScript 環境。 Wasm 環境更接近本機程式碼,可用於受益於更高效能的 CPU 上下文的任務;想想數字運算或愚蠢的繁忙迴圈。我對它的興趣不是從性能的角度來看,而是因為它完全是可能的。 Rust 的賣點之一(實際上有無數賣點)是它可以針對 Wasm。有人可能會問,怎麼辦?這是可能的,因為 Rust 使用 LLVM 作為其編譯器後端。 Rust 編譯器前端會產生 LLVM 中間表示 (IR) 程式碼,LLVM 可以將其編譯為數十個目標的本機程式碼。

這是一個相當巨大的好處,我很好奇它是否只適用於孟菲斯。我之前對在瀏覽器中運行 Python 的想法幾乎為零,所以這似乎是測試 Wasm 學習曲線的絕佳機會。

設定 wasm-pack 並建置 WebAssembly

我啟動了人工智慧助理並詢問啟動順序。發出嘟嘟嘟嘟嘟的聲音。以下是我一路上學到的註解的步驟。

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm
登入後複製
登入後複製
登入後複製

我第一次嘗試就建造成功了!然而,因為我們沒有將 Rust 二進位檔案中的任何函數標記為可從 WebAssembly 調用,所以它沒有做太多事情。

我們可以安裝 wasm-bindgen 箱來執行此操作,我將其放在功能標誌後面。我將其添加到我的 Cargo.toml 中。

[dependencies]
wasm-bindgen = { version = "0.2", optional = true }

[features]
wasm = ["wasm-bindgen"]
登入後複製
登入後複製

這是我加入 src/lib.rs 檔案中的一小段程式碼,位於 wasm 功能標誌後面。 greet 函數以 #[wasm_bindgen] 修飾,使該符號在 JavaScript 中可用。

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm
登入後複製
登入後複製
登入後複製

建立 JavaScript 介面

我還向我的人工智慧助理詢問了我可以用來測試我的 Wasm 介面的盡可能小的 JavaScript 片段。當我們呼叫 init() 時,瀏覽器會載入 .wasm 文件,執行 JIT 編譯步驟以將可移植的 WebAssembly 二進位檔案轉換為本機程式碼,並初始化 WebAssembly 執行時期的記憶體。

[dependencies]
wasm-bindgen = { version = "0.2", optional = true }

[features]
wasm = ["wasm-bindgen"]
登入後複製
登入後複製

就像奇蹟中的奇蹟一樣,它確實有效。誠然,我沒有在瀏覽器中運行任何 Python 程式碼,但與我的二進位檔案互動是一個巨大的步驟,年輕人不能低估它的價值。

下一步是給它一個用 JavaScript 定義的 Python 表達式,並讓 Wasm 二進位處理數字。正如我在 REPL 文章中提到的,軟體專案中的每個入口點都是改進我的抽象的機會,這裡肯定會再次出現這種情況。當我翻閱我的 Memphis 儲存庫時,我意識到哇,我真的應該有一個更好的介面來傳遞字串並將其作為 Python 進行評估。 就像我說的,我喜歡新的入口點。

目前,我會使用我的交叉檢查適配器。 Crosscheck 是我正在進行的測試框架,用於驗證 Treewalk 解釋器和字節碼 VM 對於給定的 Python 輸入產生相同的行為。它以空服員所做的事情命名。

這是我更新的 Rust 程式碼。

#[cfg(feature = "wasm")]
mod wasm {
    use wasm_bindgen::prelude::wasm_bindgen;

    // Export a function to JavaScript
    #[wasm_bindgen]
    pub fn greet() -> String {
        "Hello from WebAssembly!".to_string()
    }
}
登入後複製

這是我更新的 JavaScript 程式碼,它呼叫新的 Rust 評估函數。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wasm Test</title>
</head>
<body>
    <script type="module">
        import init, { greet } from './pkg/memphis.js';

        async function run() {
            await init();
            console.log(greet());
        }

        run();
    </script>
</body>
</html>
登入後複製

偵錯 WebAssembly 錯誤

現在,當我運行它時,我得到了…控制台錯誤。它因未實現的錯誤而崩潰。

我查了一下,並不清楚是什麼原因造成的。您可以單擊原始程式碼,但對於 Wasm 建置來說,它只是一個彙編區塊,沒有引用原始 Rust 函數。

我進行了一些人工智慧聊天/谷歌搜索,發現了兩種有用的方法。一種是用於 Wasm 建置的 console_log,它在瀏覽器控制台中顯示來自 Rust 程式碼的日誌語句。這對一些人有幫助,但我真正想要的是堆疊追蹤。輸入console_error_panic_hook。它立即給了我 Rust 堆疊跟踪,即 CLUTCH。如果您正在建立自己的 Wasm,請立即停止閱讀並添加此箱子。我甚至不介意你永遠讀不完這篇文章。費里斯希望你使用這個箱子?以下是我將其添加到我的 Wasm 介面的方法。

#[cfg(feature = "wasm")]
mod wasm {
    use wasm_bindgen::prelude::wasm_bindgen;

    use crosscheck::{InterpreterTest, TreewalkAdapter};

    // Export a function to JavaScript
    #[wasm_bindgen]
    pub fn greet() -> String {
        "Hello from WebAssembly!".to_string()
    }

    #[wasm_bindgen]
    pub fn evaluate(code: String) -> String {
        let result = TreewalkAdapter.execute(&code);
        format!("{}", result)
    }
}
登入後複製

我的堆疊追蹤指出了罪魁禍首:我使用 std::env 來請求一些作業系統資源,這在 Wasm 運行時(即沙盒部分)中是不允許的。我將這些呼叫放在功能標誌後面(它們與我如何隨意確定 Python 標準庫在主機上的位置有關)並再次啟動我的建置。在與正確顯示我的返回類型相關的一些小失敗之後......

它成功了。這是我現在在瀏覽器控制台中看到的內容。

# wasm-pack helps compile our Rust code to WebAssembly and bundle it
# with JavaScript bindings we can call from our HTML/JavaScript page.
cargo install wasm-pack

# wasm-pack also downloads the wasm32-unknown-unknown target via
# rustup for us. If for whatever reason it does not, you can use this: 
# rustup target add wasm32-unknown-unknown
# We must specify a feature flag because our wasm_bindgen interface is
# behind the wasm feature flag.
wasm-pack build --target web --out-dir wasm_ui/pkg -- --features wasm
登入後複製
登入後複製
登入後複製

tldr 我可以在瀏覽器中執行Python。 (值得讚揚的是,RustPython 也這樣做了:https://rustpython.github.io/demo/。我沒有深入研究他們的項目,但它似乎很全面。)Python 列表理解是在JavaScript 中以字符串形式定義的,回應清單由編譯為Wasm 的Rust 程式碼評估,並轉換回可由JavaScript 顯示的字串。

此設定目前僅支援表達式。為了評估語句(並稍後讀回其結果),我需要在 Rust 端保留狀態。我也夢想建立一個 JavaScript REPL。這聽起來像是未來的我的一個問題(而且是一個無聊的夢)。

結局

我已經聊得夠久了,所以我打算推遲到下週一再討論嵌入式 Python。

對誘餌和開關表示歉意。內容日曆不等人。

需要明確的是,透過嵌入式 Python,我的意思是在孟菲斯內部嵌入 CPython 解釋器,而不是在「嵌入式系統」環境中運行 Python。那會毫無理由地困難。與孟菲斯不同,孟菲斯很難好玩。


如果您想將更多類似的貼文直接發送到您的收件匣,您可以在這裡訂閱!

別處

除了指導軟體工程師之外,我還寫了我作為成人診斷自閉症患者的經歷。更少的程式碼和相同數量的笑話。

  • 為什麼我渴望得到認同? - 來自 Scratch 點組織

以上是為 WebAssembly 構建的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板