Kompilieren von Python zu WebAssembly

87

Ich habe gelesen, dass es möglich ist, Python 2.7-Code in Web Assembly zu konvertieren, aber ich kann keine endgültige Anleitung dazu finden.

Bisher habe ich ein C-Programm für Web Assembly mit Emscripten und allen erforderlichen Komponenten kompiliert, damit ich weiß, dass es funktioniert (verwendete Anleitung: http://webassembly.org/getting-started/developers-guide/ ).

Welche Schritte muss ich unternehmen, um dies auf einem Ubuntu-Computer zu tun? Muss ich den Python-Code in LLVM-Bitcode konvertieren und dann mit Emscripten kompilieren? Wenn ja, wie würde ich das erreichen?

Robbie
quelle
1
@guettli github.com/pypyjs/pypyjs/issues/145
denfromufa
1
Check out pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide bringt die Python-Laufzeit über WebAssembly zum Browser: github.com/iodide-project/pyodide
guettli

Antworten:

141

WebAssembly vs asm.js.

Schauen wir uns zunächst an, wie sich WebAssembly im Prinzip von asm.js unterscheidet und ob das Potenzial besteht, vorhandenes Wissen und Tools wiederzuverwenden. Folgendes gibt einen ziemlich guten Überblick:

Fassen wir noch einmal zusammen: WebAssembly (MVP, da ungefähr mehr auf der Roadmap steht):

  • ist ein Binärformat von AST mit statischer Typisierung, das von vorhandenen JavaScript-Engines (und damit JIT-fähigen oder kompilierten AOT) ausgeführt werden kann.
  • Es ist 10-20% kompakter (komprimierter Vergleich) und um eine Größenordnung schneller zu analysieren als JavaScript.
  • Es kann mehr Operationen auf niedriger Ebene ausdrücken, die nicht in die JavaScript-Syntax passen. Lesen Sie asm.js (z. B. 64-Bit-Ganzzahlen, spezielle CPU-Anweisungen, SIMD usw.).
  • ist (bis zu einem gewissen Grad) konvertierbar zu / von asm.js.

Daher ist WebAssembly derzeit eine Iteration auf asm.js und zielt nur auf C / C ++ (und ähnliche Sprachen) ab.

Python im Web

Es sieht nicht so aus, als ob GC das einzige ist, was Python-Code davon abhält, auf WebAssembly / asm.js abzuzielen. Beide repräsentieren statisch typisierten Code auf niedriger Ebene, in dem Python-Code nicht (realistisch) dargestellt werden kann. Da die aktuelle Toolchain von WebAssembly / asm.js auf LLVM basiert, kann eine Sprache, die einfach in LLVM IR kompiliert werden kann, in WebAssembly / asm.js konvertiert werden. Aber leider ist Python zu dynamisch, um auch hinein zu passen, wie Unladen Swallow und mehrere Versuche von PyPy beweisen .

Diese Präsentation von asm.js enthält Folien zum Status dynamischer Sprachen . Dies bedeutet, dass derzeit nur die gesamte VM (Sprachimplementierung in C / C ++) in WebAssembly / asm.js kompiliert und (wenn möglich mit JIT) Originalquellen interpretiert werden können. Für Python gibt es mehrere bestehende Projekte:

  1. PyPy: PyPy.js (Autorenvortrag bei PyCon ). Hier ist Release Repo . Die Haupt-JS-Datei pypyjs.vm.jsist 13 MB (2 MB später gzip -6) + Python stdlib + anderes Zeug.

  2. CPython: Pyodid , EmPython , CPython-Emscripten , EmCPython usw. empython.jssind 5,8 MB (2,1 MB danach gzip -6), keine Standardlib.

  3. Micropython: diese Gabel .

    Da dort keine JS-Datei erstellt wurde, konnte ich sie mit trzeci/emscripten/einer vorgefertigten Emscripten-Toolchain erstellen . Etwas wie:

     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 

    Es produziert micropython.js1,1 MB (225 KB danach gzip -d). Letzteres ist bereits zu beachten, wenn Sie nur eine sehr konforme Implementierung ohne stdlib benötigen.

    Um einen WebAssembly-Build zu erstellen, können Sie Zeile 13 von Makefileto ändern

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

    Dann make -jproduziert:

     113 KB micropython.js
     240 KB micropython.wasm

    Sie können sich die HTML-Ausgabe von ansehen emcc hello.c -s WASM=1 -o hello.html, um zu sehen, wie diese Dateien verwendet werden.

    Auf diese Weise können Sie möglicherweise auch PyPy und CPython in WebAssembly erstellen, um Ihre Python-Anwendung in einem kompatiblen Browser zu interpretieren.

Eine andere potenziell interessante Sache ist hier Nuitka , ein Python-zu-C ++ - Compiler. Möglicherweise ist es möglich, Ihre Python-App in C ++ zu erstellen und sie dann zusammen mit CPython mit Emscripten zu kompilieren. Aber praktisch habe ich keine Ahnung, wie es geht.

Lösungen

Wenn Sie vorerst eine herkömmliche Website oder Web-App erstellen, bei der das Herunterladen einer JS-Datei mit mehreren Megabyte kaum möglich ist, sollten Sie sich Python-zu-JavaScript-Transpiler (z. B. Transcrypt ) oder JavaScript-Python-Implementierungen (z. B. Brython ) ansehen ). Oder versuchen Sie Ihr Glück mit anderen aus der Liste der Sprachen, die zu JavaScript kompiliert werden .

Andernfalls können Sie zwischen den drei oben genannten Optionen wählen, wenn die Downloadgröße kein Problem darstellt und Sie bereit sind, viele Ecken und Kanten zu beseitigen.

Q3 2020 Update

  1. Der JavaScript-Port wurde in MicroPython integriert . Es lebt in Ports / Javascript .

  2. Der Port ist als npm-Paket mit dem Namen MicroPython.js verfügbar . Sie können es in RunKit ausprobieren .

  3. In Rust gibt es eine aktiv entwickelte Python-Implementierung namens RustPython . Da Rust WebAssembly offiziell als Kompilierungsziel unterstützt , ist es keine Überraschung, dass sich der Demo-Link ganz oben in der Readme-Datei befindet. Es ist jedoch früh. Ihr Haftungsausschluss folgt.

    RustPython befindet sich in einer Entwicklungsphase und sollte nicht in der Produktion oder in einer Umgebung mit Fehlertoleranz verwendet werden.

    Unser aktueller Build unterstützt nur eine Teilmenge der Python-Syntax.

saaj
quelle
1
Diese .js- und .wasm-Größen sind nicht wirklich fair. Die Stream-Komprimierung wird gut unterstützt und kann verwendet werden, um die Größe beider zu reduzieren. Wie groß sind die gleichen Dateien, gezippt? Ansonsten gute Antwort.
EnigmaticPhysicist
4

Kurz gesagt: Sie können kein beliebiges Python in Web Assembly konvertieren, und ich bezweifle, dass Sie dies noch lange können. Eine Problemumgehung könnte Python to C to Web Assembly sein, aber das wird im Allgemeinen auch nicht funktionieren, da Python to C fragil ist (siehe unten).

WebAssembly richtet sich speziell an C-ähnliche Sprachen, wie Sie unter http://webassembly.org/docs/high-level-goals/ sehen können.

Die Übersetzung von Python nach C kann mit Tools wie PyPy erfolgen, das sich seit langem in der Entwicklung befindet, aber für beliebigen Python-Code immer noch nicht funktioniert. Dafür gibt es mehrere Gründe:

  1. Python hat einige sehr praktische, abstrakte und nette Datenstrukturen, die sich jedoch nur schwer in statischen Code übersetzen lassen.
  2. Python hängt von der dynamischen Speicherbereinigung ab.
  3. Der meiste Python-Code hängt stark von verschiedenen Bibliotheken ab, von denen jede ihre eigenen Macken und Probleme hat (z. B. in C geschrieben oder sogar Assembler).

Wenn Sie genauer untersuchen, warum Python-to-C (oder Python-to-C ++) so schwierig war, können Sie die detaillierten Gründe für diese knappe Antwort erkennen, aber ich denke, das liegt außerhalb des Rahmens Ihrer Frage.

GregD
quelle
3

Dies ist erst möglich, wenn die Webassemblierung die Speicherbereinigung implementiert. Sie können den Fortschritt hier verfolgen: https://github.com/WebAssembly/proposals/issues/16

Malcolm White
quelle
17
Nicht unbedingt. Sie können GC - und insbesondere Referenzzählung, wie sie von Python IIRC verwendet wird - zusätzlich zu Wasm implementieren. Grundsätzlich sollten Sie in der Lage sein, CPython mit Emscripten zu Wasm zu kompilieren.
Andreas Rossberg
1
Mein Standpunkt von OP war, dass sie vorhandene Tools verwenden wollten - die Implementierung von cpython GC auf wasm klingt wie ein Projekt für sich
Malcolm White
3
Sie sollten nichts extra tun müssen, sondern nur CPython zum Kompilieren bringen. Es enthält bereits die RC-Implementierung AFAICT.
Andreas Rossberg