首页 > 后端开发 > Python教程 > 为 WebAssembly 构建

为 WebAssembly 构建

Mary-Kate Olsen
发布: 2024-12-02 01:26:09
原创
314 人浏览过

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中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板