将 Python 编译为 WebAssembly



我已经读到可以将Python 2.7代码转换为Web Assembly,但我找不到有关如何这样做的权威指南。

到目前为止,我已经使用Emscripten及其所有必要的组件将一个C程序编译为Web汇编,所以我知道它正在工作(使用的指南:http://webassembly.org/getting-started/developers-guide/)

为了在 Ubuntu 机器上执行此操作,我必须采取哪些步骤?我是否必须将python代码转换为LLVM位码,然后使用Emscripten对其进行编译?如果是这样,我将如何实现这一目标?

WebAssembly vs asm.js

首先,让我们来看看,原则上,WebAssemblyasm.js有何不同,以及是否有可能重用现有的知识和工具。下面给出了很好的概述:

  • 当已经有asm.js时,为什么要创建一个新标准?
  • asm.js 和 Web Assembly 有什么区别?
  • 为什么 WebAssembly 比 asm 更快.js

让我们概括一下,WebAssembly(MVP,因为它的路线图上有更多内容,大致):

  • 是具有静态类型的AST的二进制格式,可以由现有的JavaScript引擎执行(因此可以JIT或编译AOT),
  • 它比 JavaScript 紧凑 10-20% (gzip 比较),解析速度快一个数量级,
  • 它可以表达更多不适合JavaScript语法的低级操作,读取asm.js(例如64位整数,特殊CPU指令,SIMD等)
  • (在某种程度上)可转换为 ASM.js。

因此,目前 WebAssembly 是 asm 的迭代.js并且仅针对 C/C++(和类似语言)。

网络上的蟒蛇

看起来GC并不是阻止Python代码以WebAssembly/asm.js为目标的唯一因素。两者都表示低级静态类型代码,其中 Python 代码无法(实际)表示。由于WebAssembly/asm的当前工具链.js是基于LLVM,因此可以轻松编译为LLVM IR的语言可以转换为WebAssembly/asm.js。但可惜的是,Python太动态了,无法适应它,正如Unladen Swallow和PyPy的几次尝试所证明的那样。

这个 asm.js 演示文稿包含有关动态语言状态的幻灯片。这意味着目前只能将整个虚拟机(C/C++ 中的语言实现)编译为 WebAssembly/asm.js并解释(在可能的情况下使用 JIT)原始源代码。对于Python,有几个现有的项目:

PyPy
  1. :PyPy.js(作者在PyCon上的演讲)。这是发布存储库。主要的JS文件,pypyjs.vm.js,是13 MB(gzip -6后2MB)+ Python stdlib +其他东西。

  2. CPython:pyodide,EmPython,CPython-Emscripten,EmCPython等。empython.js是5.8 MB(gzip -6后2.1 MB),没有stdlib。

  3. 微蟒:这个叉子。

    那里没有构建的JS文件,所以我能够使用trzeci/emscripten/构建它,一个现成的Emscripten工具链。像这样:

    git clone https://github.com/matthewelse/micropython.git
    cd micropython
    docker run --rm -it -v $(pwd):/src trzeci/emscripten bash
    apt-get update && apt-get install -y python3
    cd emscripten
    make -j
    # to run REPL: npm install && nodejs server.js 
    

    它产生 1.1 MB 的micropython.js(gzip -d后为 225 KB)。后者已经是需要考虑的事情,如果你只需要非常兼容的实现而不需要stdlib。

    要生成 WebAssembly 构建,您可以将Makefile的第 13 行更改为

    CC = emcc -s RESERVED_FUNCTION_POINTERS=20 -s WASM=1
    

    然后make -j产生:

    113 KB micropython.js
    240 KB micropython.wasm
    

    您可以查看emcc hello.c -s WASM=1 -o hello.html的 HTML 输出,了解如何使用这些文件。

    通过这种方式,您还可以在WebAssembly中构建PyPy和CPython,以在兼容的浏览器中解释Python应用程序。

这里另一个可能有趣的事情是Nuitka,一个C++编译器的Python。有可能构建你的Python应用程序来C++然后与CPython一起编译它与Emscripten。但实际上我不知道该怎么做。

解决 方案

目前,如果您正在构建一个传统的网站或Web应用程序,其中下载几兆字节的JS文件几乎不是一种选择,请查看Python到JavaScript的转译器(例如Transcrypt)或JavaScript Python实现(例如Brython)。或者从编译到 JavaScript 的语言列表中与其他人试试运气。

否则,如果下载大小不是问题,并且您已准备好解决许多粗糙的边缘,请在上述三个之间进行选择。

2020 年第 3 季度更新

  1. JavaScript 端口被集成到 MicroPython 中。它生活在 ports/javascript.

  2. 该端口可作为名为MicroPython.js的npm包使用。 您可以在 RunKit 中试用。

  3. 在 Rust 中有一个积极开发的 Python 实现,称为 RustPython。因为 Rust 正式支持 WebAssembly 作为 编译目标,毫不奇怪,在 自述文件的顶部。不过,现在还早。他们的免责声明如下。

    RustPython 处于开发阶段,不应用于 生产或容错设置。

    我们当前的构建仅支持 Python 语法的一个子集。

2023 年第 1 季度更新

Python 3.11在其文档中识别了两个WebAssembly"平台",并记录了它在Linux和Unix等其他平台上的API可用性(有关更多详细信息,请参阅此PR),并且还推荐了Pyodide(来自Mozilla)和另一个端口PyScript(来自Anaconda),基于它:

WebAssembly平台wasm32-emscripten(Emscripten) 和wasm32-wasi(WASI) 提供一个子集 的 POSIX API。WebAssembly 运行时和浏览器是沙盒化的,并且 对主机和外部资源的访问权限有限。任何蟒蛇 使用进程、线程、网络、 信号或其他形式的进程间通信 (IPC) 是 要么不可用,要么可能无法像在其他类 Unix 系统上那样工作。

[...]

对于浏览器中的Python,用户应该考虑Pyodide或 PyScript。PyScript建立在Pyodide之上,Pyodide本身就是构建的 在CPython和Emscripten之上。Pyodide 提供访问 浏览器的 JavaScript 和 DOM API 以及有限的网络 JavaScript 的 XMLHttpRequest 和 Fetch API 的功能。

简而言之:有转译器,但你不能自动将任何任意的 Python 转换为 Web Assembly,我怀疑你能在未来很长一段时间内都能做到。 虽然理论上这些语言同样强大,并且手动翻译总是可能的,但Python允许一些数据结构和表达模式,这需要一个非常智能的跨语言编译器(或转译器)[见下文]。 一种解决方法可能是Python到C到Web汇编,因为python-to-C技术已经相当成熟,但这通常也不会起作用,因为Python-to-C也很脆弱(见下文)。

WebAssembly 专门针对类 C 语言,如 http://webassembly.org/docs/high-level-goals/

从Python到C的转换可以使用像PyPy这样的工具来完成,PyPy已经开发了很长时间,但仍然不适用于任意Python代码。 这有几个原因:

  1. Python有一些非常方便,抽象和漂亮的数据结构,但它们很难转换为静态代码。
  2. Python 依赖于动态垃圾回收。
  3. 大多数Python代码严重依赖于各种库,每个库都有自己的怪癖和问题(例如用C甚至汇编程序编写)。

如果你更仔细地研究为什么Python-to-C(或Python到C++)如此棘手,你可以看到这个简短答案背后的详细原因,但我认为这超出了你的问题范围。

在 Web 程序集实现垃圾回收之前,这是不可能的。您可以在此处跟踪进度:https://github.com/WebAssembly/proposals/issues/16

我想到的第一件事是 PyPy 和 rpython,然后我发现

https://github.com/soIu/rpython

我们不能将任意的python代码转换为rpython。但是,如果您需要替代语言而不是rust或AssemblyScript,rpython可能是一个方向。

因此,我可以将python/js/rust与wasm一起使用作为沙箱,并使用非常pythonic的语言(如rpython)进行编码。至少我不需要担心整数的过度流动。

Python 对于 WASM来说太动态了,因此你只能得到在 WASM 中实现的解释器,而不能编译你的代码。

换句话说,你可以尝试使用Python作为工具语言,并将自己的模型编译器编写到WASM中。我的意思不是源到WASM编译,而是编译器,它将应用程序的模型转换为WASM或其他一些低级语言,例如Rust或C++。

这样的模型可以实现为由描述应用程序各部分的对象组合的数据结构:模块、类、API 接口、GUI 元素等。这些对象必须具有代码生成方法,这些方法"知道如何"将其状态和行为写入低级代码片段。

接下来,您可以通过将此类生成的代码片段组合到可以使用启用 WASM 的编译器或仅 WAT 文件构建的项目来手动构建应用程序。

相关内容

  • 没有找到相关文章

最新更新