I have read that it is possible to convert Python 2.7 code to Web Assembly, but I cannot find a definitive guide on how to to so.
So far I have compiled a C program to Web Assembly using Emscripten and all its necessary components, so I know it is working (guide used: http://webassembly.org/getting-started/developers-guide/)
What are the steps I must take in order to do this on an Ubuntu machine? Do I have to convert the python code to LLVM bitcode then compile it using Emscripten? If so, how would I achieve this?
This won’t be possible until web assembly implements garbage collection. You can follow progress here: https://github.com/WebAssembly/proposals/issues/16
First, let’s take a look how, in principle, WebAssembly is different from asm.js, and whether there’s potential to reuse existing knowledge and tooling. The following gives pretty good overview:
Let’s recapitulate, WebAssembly (MVP, as there’s more on its roadmap, roughly):
Thus, currently WebAssembly is an iteration on asm.js and targets only C/C++ (and similar languages).
It doesn’t look like GC is the only thing that stops Python code from targeting WebAssembly/asm.js. Both represent low-level statically typed code, in which Python code can’t (realistically) be represented. As current toolchain of WebAssembly/asm.js is based on LLVM, a language that can be easily compiled to LLVM IR can be converted to WebAssembly/asm.js. But alas, Python is too dynamic to fit into it as well, as proven by Unladen Swallow and several attempts of PyPy.
This asm.js presentation has slides about the state of dynamic languages. What it means is that currently it’s only possible to compile whole VM (language implementation in C/C++) to WebAssembly/asm.js and interpret (with JIT where possible) original sources. For Python there’re several existing projects:
Micropython: this fork.
There was no built JS file there, so I was able to build it with
trzeci/emscripten/, a ready-made Emscripten toolchain. Something like:
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 of 1.1 MB (225 KB after
gzip -d). The latter is already something to consider, if you need only very compliant implementation without stdlib.
To produce WebAssembly build you can change line 13 of the
CC = emcc -s RESERVED_FUNCTION_POINTERS=20 -s WASM=1
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.
This way you can also potentially build PyPy and CPython in WebAssembly to interpret your Python application in a compliant browser.
Another potentially interesting thing here is Nuitka, a Python to C++ compiler. Potentially it can be possible to build your Python app to C++ and then compile it along with CPython with Emscripten. But practically I’ve no idea how to do it.
Otherwise, if download size is not an issue, and you’re ready to tackle a lot of rough edges, choose between the three above.
There’s an actively developed Python implementation in Rust, called
RustPython. Because Rust officially supports WebAssembly as
compile target, no surprise there’s demo link right in the
top of the readme. Though, it’s early. Their disclaimer follows.
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 3.11 recognises two WebAssembly "platforms" in its documentation and documents its API availability on them among other platforms like Linux and Unix (see this PR for more details) and also recommends Pyodide (from Mozilla) and another port, PyScript (from Anaconda), based on it:
The WebAssembly platforms
wasm32-wasi(WASI) provide a subset
of POSIX APIs. WebAssembly runtimes and browsers are sandboxed and
have limited access to the host and external resources. Any Python
standard library module that uses processes, threading, networking,
signals, or other forms of inter-process communication (IPC), is
either not available or may not work as on other Unix-like systems.
For Python in the browser, users should consider Pyodide or
PyScript. PyScript is built on top of Pyodide, which itself is built
on top of CPython and Emscripten. Pyodide provides access to
In short: There are transpilers, but you can’t automatically convert any arbitrary Python to Web Assembly, and I doubt you will be able to for a long time to come. Although theoretically the languages are equally powerful, and manual translation is always possible, Python allows for some data structures and expressive modes that requires a very smart inter-language compiler (or transpiler) [see below]. A workaround might be Python to C to Web Assembly since python-to-C technology is moderately mature, but that isn’t generally going to work either since Python-to-C is also fragile (see below).
WebAssembly is specifically targeted to C-like languages as you can see at http://webassembly.org/docs/high-level-goals/
Translating from Python to C can be done with tools like PyPy, which has been under development for a long time, but which still does not work for arbitrary Python code. There are several reasons for this:
If you look more carefully into why Python-to-C (or Python to C++) has been so tricky you can see the detailed reasons behind this terse answer, but I think that’s outside the scope of your question.
The first thing comes into my mind is PyPy and rpython, then I found
We cannot turn arbitrary python code into rpython. However, if you need an alternative language rather than rust or AssemblyScript, rpython might be a direction.
Thus, I can use python/js/rust with wasm as a sandbox, and coding in a very pythonic language such as rpython. At least I don’t need to worry about over flow of integer.
Python is too dynamic for WASM, in result you can get only interpreter implemented in WASM but not your code was compiled.
In the other way, you can try to use Python as a tooling language, and write your own model compiler into WASM. I mean not source-to-WASM compiling, but compiler which transforms the model of your application into WASM or some other low-level language say Rust or C++.
Such a model can be implemented as a data structure combined from objects that describes parts of your application: modules, classes, API interfaces, GUI elements etc. Such objects must have code generationg methods which "knows" how to write its state and behaviour into fragments of low-level code.
Next, you can manually build your application by combining such generated code fragments into project can be built with WASM-enabled compiler or just WAT files.