将 Python 编译为 WebAssembly
Compiling Python to WebAssembly
我了解到可以将 Python 2.7 代码转换为 Web Assembly,但我找不到关于如何转换的权威指南。
到目前为止,我已经使用 Emscripten 及其所有必要组件将 C 程序编译为 Web Assembly,所以我知道它正在运行(使用的指南:http://webassembly.org/getting-started/developers-guide/)
要在 Ubuntu 机器上执行此操作,我必须执行哪些步骤?我是否必须将 python 代码转换为 LLVM 位码,然后使用 Emscripten 对其进行编译?如果是这样,我将如何实现?
在 web assembly 实现垃圾收集之前,这是不可能的。您可以在此处关注进度:https://github.com/WebAssembly/proposals/issues/16
WebAssembly 与 asm.js
首先我们来看看WebAssembly和asm.js在原理上有什么区别,有没有潜力重用现有知识和工具。以下给出了很好的概述:
让我们概括一下,WebAssembly(MVP,因为 its roadmap 上还有更多内容,大致):
- 是具有静态类型的 AST 的二进制格式,可以由现有的 JavaScript 引擎执行(因此支持 JIT 或编译 AOT),
- 它比 JavaScript、
紧凑 10-20%(gzip 比较)并且解析速度快一个数量级
- 它可以表达更多不适合JavaScript语法的低级操作,阅读asm.js(例如64位整数,特殊CPU指令,SIMD等)
- 可转换(在某种程度上)to/from asm.js.
因此,目前 WebAssembly 是 asm.js 的迭代,并且仅针对 C/C++(和类似语言)。
Python 网络
看起来 GC 并不是唯一阻止 Python 代码以 WebAssembly/asm.js 为目标的东西。两者都代表低级静态类型代码,其中 Python 代码不能(实际上)被代表。由于目前WebAssembly/asm.js的工具链是基于LLVM的,所以可以将一种可以轻松编译为LLVM IR的语言转换为WebAssembly/asm.js。但遗憾的是,Python 过于动态,无法适应它,正如 PyPy 的 Unladen Swallow and several attempts 所证明的那样。
此 asm.js 演示文稿有 slides about the state of dynamic languages。这意味着目前只能将整个 VM(C/C++ 中的语言实现)编译为 WebAssembly/asm.js 并解释(尽可能使用 JIT)原始源代码。 Python 有几个现有项目:
PyPy:PyPy.js (author's talk at PyCon). Here's release repo。主 JS 文件 pypyjs.vm.js
为 13 MB(gzip -6
后为 2MB)+ Python stdlib + 其他内容。
CPython:pyodide, EmPython, CPython-Emscripten, EmCPython,等等。empython.js
是 5.8 MB(gzip -6
之后是 2.1 MB),没有标准库。
微蟒:this fork.
那里没有内置的 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,一个 Python 到 C++ 的编译器。有可能将您的 Python 应用程序构建为 C++,然后使用 Emscripten 将其与 CPython 一起编译。但实际上我不知道该怎么做。
解决方案
目前,如果您正在构建一个传统的网站或 Web 应用程序,而下载几兆字节的 JS 文件几乎是一种选择,请查看 Python-to-JavaScript 转译器(例如 Transcrypt) or JavaScript Python implementations (e.g. Brython). Or try your luck with others from list of languages that compile to JavaScript.
否则,如果下载大小不是问题,并且您已准备好解决很多问题,请在以上三个选项中进行选择。
2020 年第 3 季度更新
JavaScript 端口 was integrated 进入 MicroPython。它住在
ports/javascript.
该端口可作为名为 MicroPython.js 的 npm 包使用。
您可以在 RunKit.
中试用
在 Rust 中有一个积极开发的 Python 实现,称为
RustPython。因为 Rust 官方支持 WebAssembly 作为
编译目标,难怪demo link就在
自述文件的顶部。虽然,现在还早。他们的免责声明如下。
RustPython is in a development phase and should not be used in
production or a fault intolerant setting.
Our current build supports only a subset of Python syntax.
简而言之:有转译器,但你不能自动将任意 Python 转换为 Web Assembly,我怀疑你在未来很长一段时间内是否能够做到这一点。尽管理论上这些语言同样强大,并且总是可以进行手动翻译,但 Python 允许某些数据结构和表达模式需要非常智能的跨语言编译器(或转译器)[见下文]。解决方法可能是 Python to C to Web Assembly,因为 python-to-C 技术已经相当成熟,但这通常也行不通,因为 Python-to-C 是也很脆弱(见下文)。
WebAssembly 专门针对类 C 语言,如您在 http://webassembly.org/docs/high-level-goals/
中所见
从 Python 到 C 的转换可以使用像 PyPy 这样的工具来完成,它已经开发了很长时间,但对于任意 Python 代码仍然不起作用。这有几个原因:
- Python 有一些非常方便、抽象和漂亮的数据结构,但它们很难转化为静态代码。
- Python 取决于动态垃圾回收。
- 大多数 Python 代码在很大程度上依赖于各种库,每个库都有自己的怪癖和问题(例如用 C 甚至汇编程序编写)。
如果你更仔细地研究为什么 Python-to-C(或 Python 到 C++)如此棘手,你可以看到这个简洁答案背后的详细原因,但我认为这是超出你的问题范围。
首先想到的是PyPy和rpython,然后我发现
https://github.com/soIu/rpython
我们无法将任意 python 代码转换为 rpython。但是,如果您需要替代语言而不是 rust 或 AssemblyScript,rpython 可能是一个方向。
因此,我可以将 python/js/rust 与 wasm 作为沙箱一起使用,并使用非常 pythonic 的语言(例如 rpython)进行编码。至少我不用担心整数溢出。
Python 对于 WASM 来说太动态了,结果你只能得到在 WASM 中实现的解释器,而不是你的代码被编译的。
另一种方式,你可以尝试使用Python作为工具语言,将你自己的模型编译器写入WASM。我的意思不是 source-to-WASM 编译,而是将应用程序模型转换为 WASM 或其他 low-level 语言的编译器,例如 Rust 或 C++。
这样的模型可以作为一个数据结构来实现,该数据结构由描述应用程序部分的对象组合而成:模块、类、API 界面、GUI 元素等。此类对象必须具有代码生成g “知道”如何将其状态和行为写入 low-level 代码片段的方法。
接下来,您可以通过将此类生成的代码片段组合到可以使用 WASM-enabled 编译器或仅 WAT 文件构建的项目中来手动构建您的应用程序。
我了解到可以将 Python 2.7 代码转换为 Web Assembly,但我找不到关于如何转换的权威指南。
到目前为止,我已经使用 Emscripten 及其所有必要组件将 C 程序编译为 Web Assembly,所以我知道它正在运行(使用的指南:http://webassembly.org/getting-started/developers-guide/)
要在 Ubuntu 机器上执行此操作,我必须执行哪些步骤?我是否必须将 python 代码转换为 LLVM 位码,然后使用 Emscripten 对其进行编译?如果是这样,我将如何实现?
在 web assembly 实现垃圾收集之前,这是不可能的。您可以在此处关注进度:https://github.com/WebAssembly/proposals/issues/16
WebAssembly 与 asm.js
首先我们来看看WebAssembly和asm.js在原理上有什么区别,有没有潜力重用现有知识和工具。以下给出了很好的概述:
让我们概括一下,WebAssembly(MVP,因为 its roadmap 上还有更多内容,大致):
- 是具有静态类型的 AST 的二进制格式,可以由现有的 JavaScript 引擎执行(因此支持 JIT 或编译 AOT),
- 它比 JavaScript、 紧凑 10-20%(gzip 比较)并且解析速度快一个数量级
- 它可以表达更多不适合JavaScript语法的低级操作,阅读asm.js(例如64位整数,特殊CPU指令,SIMD等)
- 可转换(在某种程度上)to/from asm.js.
因此,目前 WebAssembly 是 asm.js 的迭代,并且仅针对 C/C++(和类似语言)。
Python 网络
看起来 GC 并不是唯一阻止 Python 代码以 WebAssembly/asm.js 为目标的东西。两者都代表低级静态类型代码,其中 Python 代码不能(实际上)被代表。由于目前WebAssembly/asm.js的工具链是基于LLVM的,所以可以将一种可以轻松编译为LLVM IR的语言转换为WebAssembly/asm.js。但遗憾的是,Python 过于动态,无法适应它,正如 PyPy 的 Unladen Swallow and several attempts 所证明的那样。
此 asm.js 演示文稿有 slides about the state of dynamic languages。这意味着目前只能将整个 VM(C/C++ 中的语言实现)编译为 WebAssembly/asm.js 并解释(尽可能使用 JIT)原始源代码。 Python 有几个现有项目:
PyPy:PyPy.js (author's talk at PyCon). Here's release repo。主 JS 文件
pypyjs.vm.js
为 13 MB(gzip -6
后为 2MB)+ Python stdlib + 其他内容。CPython:pyodide, EmPython, CPython-Emscripten, EmCPython,等等。
empython.js
是 5.8 MB(gzip -6
之后是 2.1 MB),没有标准库。微蟒:this fork.
那里没有内置的 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,一个 Python 到 C++ 的编译器。有可能将您的 Python 应用程序构建为 C++,然后使用 Emscripten 将其与 CPython 一起编译。但实际上我不知道该怎么做。
解决方案
目前,如果您正在构建一个传统的网站或 Web 应用程序,而下载几兆字节的 JS 文件几乎是一种选择,请查看 Python-to-JavaScript 转译器(例如 Transcrypt) or JavaScript Python implementations (e.g. Brython). Or try your luck with others from list of languages that compile to JavaScript.
否则,如果下载大小不是问题,并且您已准备好解决很多问题,请在以上三个选项中进行选择。
2020 年第 3 季度更新
JavaScript 端口 was integrated 进入 MicroPython。它住在 ports/javascript.
该端口可作为名为 MicroPython.js 的 npm 包使用。 您可以在 RunKit.
中试用在 Rust 中有一个积极开发的 Python 实现,称为 RustPython。因为 Rust 官方支持 WebAssembly 作为 编译目标,难怪demo link就在 自述文件的顶部。虽然,现在还早。他们的免责声明如下。
RustPython is in a development phase and should not be used in production or a fault intolerant setting.
Our current build supports only a subset of Python syntax.
简而言之:有转译器,但你不能自动将任意 Python 转换为 Web Assembly,我怀疑你在未来很长一段时间内是否能够做到这一点。尽管理论上这些语言同样强大,并且总是可以进行手动翻译,但 Python 允许某些数据结构和表达模式需要非常智能的跨语言编译器(或转译器)[见下文]。解决方法可能是 Python to C to Web Assembly,因为 python-to-C 技术已经相当成熟,但这通常也行不通,因为 Python-to-C 是也很脆弱(见下文)。
WebAssembly 专门针对类 C 语言,如您在 http://webassembly.org/docs/high-level-goals/
中所见从 Python 到 C 的转换可以使用像 PyPy 这样的工具来完成,它已经开发了很长时间,但对于任意 Python 代码仍然不起作用。这有几个原因:
- Python 有一些非常方便、抽象和漂亮的数据结构,但它们很难转化为静态代码。
- Python 取决于动态垃圾回收。
- 大多数 Python 代码在很大程度上依赖于各种库,每个库都有自己的怪癖和问题(例如用 C 甚至汇编程序编写)。
如果你更仔细地研究为什么 Python-to-C(或 Python 到 C++)如此棘手,你可以看到这个简洁答案背后的详细原因,但我认为这是超出你的问题范围。
首先想到的是PyPy和rpython,然后我发现
https://github.com/soIu/rpython
我们无法将任意 python 代码转换为 rpython。但是,如果您需要替代语言而不是 rust 或 AssemblyScript,rpython 可能是一个方向。
因此,我可以将 python/js/rust 与 wasm 作为沙箱一起使用,并使用非常 pythonic 的语言(例如 rpython)进行编码。至少我不用担心整数溢出。
Python 对于 WASM 来说太动态了,结果你只能得到在 WASM 中实现的解释器,而不是你的代码被编译的。
另一种方式,你可以尝试使用Python作为工具语言,将你自己的模型编译器写入WASM。我的意思不是 source-to-WASM 编译,而是将应用程序模型转换为 WASM 或其他 low-level 语言的编译器,例如 Rust 或 C++。
这样的模型可以作为一个数据结构来实现,该数据结构由描述应用程序部分的对象组合而成:模块、类、API 界面、GUI 元素等。此类对象必须具有代码生成g “知道”如何将其状态和行为写入 low-level 代码片段的方法。
接下来,您可以通过将此类生成的代码片段组合到可以使用 WASM-enabled 编译器或仅 WAT 文件构建的项目中来手动构建您的应用程序。