将 Python 编译成 WebAssembly

我读到过将 Python 2.7代码转换为 Web Assembly 是可能的,但是我找不到关于如何这样做的权威指南。

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

为了在 Ubuntu 机器上做到这一点,我必须采取哪些步骤?是否必须将 Python 代码转换为 LLVM 位代码,然后使用 Emscripten 编译它?如果是这样,我将如何实现这一点?

94346 次浏览

这在 Web 组装实现垃圾收集之前是不可能的。您可以在这里跟踪进度: https://github.com/WebAssembly/proposals/issues/16

WebAssembly vs asm.js

首先,让我们看看原则上 WebAssemblyAsm.js有什么不同,以及是否有重用现有知识和工具的潜力。下面给出了一个很好的概述:

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

  • is a binary format of AST with static typing, which can be executed by existing JavaScript engines (and thus JIT-able or compiled AOT),
  • 它比 JavaScript 紧凑10% -20% (gzip 比较) ,解析速度也比 JavaScript 数量级快,
  • it can express more low-level operation that won't fit into JavaScript syntax, read asm.js (e.g. 64-bit integers, special CPU instructions, SIMD, etc)
  • 是可转换的(在某种程度上)到/从 asm.js。

因此,目前 WebAssembly 是 asm.js 上的一个迭代,只针对 C/C + + (和类似的语言)。

网络上的巨蟒

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

这个 asm.js 演示文稿具有 关于动态语言状态的幻灯片。这意味着目前只能将整个 VM (C/C + + 中的语言实现)编译成 WebAssembly/asm.js 并解释(尽可能使用 JIT)原始源。对于 Python,有几个现有的项目:

  1. PyPy: PyPy.js(作者的 在 PyCon 谈话)。这是 release repo。主 JS 文件 pypyjs.vm.js是13MB (gzip -6之后是2MB) + Python stdlib + 其他东西。

  2. CPython: 尿嘧啶, EmPython, CPython-Emscripten, EmCPython, etc. empython.js is 5.8 MB (2.1 MB after gzip -6), no 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
    

    它产生的 micropython.js为1.1 MB (gzip -d之后为225 KB)。如果您只需要非常符合标准的、不需要 stdlib 的实现,那么后者已经是需要考虑的问题。

    To produce WebAssembly build you can change line 13 of the Makefile to

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

    Then make -j produces:

     113 KB micropython.js
    240 KB micropython.wasm
    

    You can look at HTML output of emcc hello.c -s WASM=1 -o hello.html, to see how to use these files.

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

这里另一个可能有趣的东西是 努伊特卡,一个 Python 到 C + + 的编译器。有可能将 Python 应用程序构建到 C + + ,然后使用 Emscripten 与 CPython 一起编译它。但实际上我不知道该怎么做。

解决方案

目前,如果你正在构建一个传统的网站或网络应用,下载几兆字节的 JS 文件几乎是不可能的,看看 Python-to-JavaScript 转换器(例如 Transcrypt)或 JavaScript Python 实现(例如 布莱森)。或者和 编译成 JavaScript 的语言列表的其他人碰碰运气。

否则,如果下载大小不是问题,并且您已经准备好处理许多粗糙的边缘,那么可以在以上三种方法中进行选择。

Q32020最新情况

  1. JavaScript 将 被整合了移植到 MicroPython 中 Ports/javascript .

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

  3. 在 Rust 中有一个积极开发的 Python 实现,名为 因为 Rust 官方支持 WebAssembly 作为 compile target, no surprise there's 演示链接 right in the 尽管现在还为时尚早,他们的免责声明如下。

    RustPython 正处于开发阶段,不应该在 生产或不容错的设置。

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

简而言之: 有一些传输程序,但是您不能自动地将任何任意的 Python 转换为 Web Assembly,我怀疑您在很长一段时间内都不能做到这一点。尽管理论上这些语言同样强大,而且手动翻译总是可能的,但 Python 允许一些数据结构和表达模式,这需要一个非常智能的中间语言编译器(或传输器)[见下文]。一个解决方案可能是 Python 到 C 到 Web Assembly,因为 Python 到 C 的技术还算成熟,但是这通常也不会起作用,因为 Python 到 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 to C + +)如此棘手,你就能看到这个简洁答案背后的详细原因,但我认为这超出了你的问题的范围。

首先映入我脑海的是 PyPy 和 rpython,然后我发现

Https://github.com/soiu/rpython

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

因此,我可以使用 python/js/ust 和 wasm 作为沙箱,并使用非常 Python 化的语言(如 rpython)进行编码。至少我不需要担心整数的过流。

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

另一方面,您可以尝试使用 Python 作为工具语言,并将您自己的模型编译器编写到 WASM 中。我指的不是源代码到 WASM 的编译,而是将应用程序模型转换为 WASM 或其他低级语言(比如 Rust 或 C + +)的编译器。

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

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