Compilation de Python en WebAssembly

90

J'ai lu qu'il est possible de convertir du code Python 2.7 en Web Assembly, mais je ne trouve pas de guide définitif sur la façon de le faire.

Jusqu'à présent, j'ai compilé un programme C vers Web Assembly en utilisant Emscripten et tous ses composants nécessaires, donc je sais que cela fonctionne (guide utilisé: http://webassembly.org/getting-started/developers-guide/ )

Quelles sont les étapes que je dois suivre pour faire cela sur une machine Ubuntu? Dois-je convertir le code python en bitcode LLVM puis le compiler en utilisant Emscripten? Si oui, comment pourrais-je y parvenir?

Robbie
la source
1
@guettli github.com/pypyjs/pypyjs/issues/145
denfromufa
1
Départ pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide apporte le runtime Python au navigateur via WebAssembly: github.com/iodide-project/pyodide
guettli

Réponses:

146

WebAssembly contre asm.js

Tout d'abord, voyons en quoi, en principe, WebAssembly est différent de asm.js , et s'il existe un potentiel de réutilisation des connaissances et des outils existants. Ce qui suit donne un assez bon aperçu:

Récapitulons, WebAssembly (MVP, car il y en a plus sur sa feuille de route , en gros):

  • est un format binaire d'AST avec typage statique, qui peut être exécuté par les moteurs JavaScript existants (et donc JIT-able ou compilé AOT),
  • il est 10 à 20% plus compact (comparaison gzippée) et un ordre de grandeur plus rapide à analyser que JavaScript,
  • il peut exprimer plus d'opérations de bas niveau qui ne rentrent pas dans la syntaxe JavaScript, lire asm.js (par exemple, des entiers 64 bits, des instructions CPU spéciales, SIMD, etc.)
  • est convertible (dans une certaine mesure) vers / depuis asm.js.

Ainsi, actuellement WebAssembly est une itération sur asm.js et ne cible que C / C ++ (et les langages similaires).

Python sur le Web

Il ne semble pas que GC soit la seule chose qui empêche le code Python de cibler WebAssembly / asm.js. Les deux représentent un code typé statiquement de bas niveau, dans lequel le code Python ne peut pas (de manière réaliste) être représenté. Comme la chaîne d'outils actuelle de WebAssembly / asm.js est basée sur LLVM, un langage qui peut être facilement compilé en LLVM IR peut être converti en WebAssembly / asm.js. Mais hélas, Python est trop dynamique pour s'y intégrer également, comme l'ont prouvé Unladen Swallow et plusieurs tentatives de PyPy.

Cette présentation asm.js a diapositives sur l'état des langages dynamiques . Cela signifie qu'actuellement, il est uniquement possible de compiler la VM entière (implémentation du langage en C / C ++) vers WebAssembly / asm.js et d'interpréter (avec JIT si possible) les sources originales. Pour Python, il existe plusieurs projets existants:

  1. PyPy: PyPy.js ( exposé de l' auteur à PyCon ). Voici le repo de version . Le fichier JS principal,, pypyjs.vm.jsfait 13 Mo (2 Mo aprèsgzip -6 ,, ) + Python stdlib + autres choses.

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPython , etc. empython.jsest de 5,8 Mo (2,1 Mo après gzip -6), pas de stdlib.

  3. Micropython: cette fourchette .

    Il n'y avait pas de fichier JS intégré, donc j'ai pu le construire avec trzeci/emscripten/une chaîne d'outils Emscripten prête à l'emploi. Quelque chose comme:

     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 
    

    Il produit micropython.js1,1 Mo (225 Ko après gzip -d). Ce dernier est déjà quelque chose à considérer, si vous n'avez besoin que d'une implémentation très conforme sans stdlib.

    Pour produire vous construire WebAssembly pouvez modifier la ligne 13 du Makefileà

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

    Ensuite make -jproduit:

     113 KB micropython.js
     240 KB micropython.wasm
    

    Vous pouvez consulter la sortie HTML de emcc hello.c -s WASM=1 -o hello.html, pour voir comment utiliser ces fichiers.

    De cette façon, vous pouvez également potentiellement créer PyPy et CPython dans WebAssembly pour interpréter votre application Python dans un navigateur compatible.

Une autre chose potentiellement intéressante ici est Nuitka , un compilateur Python vers C ++. Il est potentiellement possible de créer votre application Python en C ++, puis de la compiler avec CPython avec Emscripten. Mais pratiquement je ne sais pas comment faire.

Solutions

Pour le moment, si vous créez un site Web conventionnel ou une application Web où le téléchargement d'un fichier JS de plusieurs mégaoctets est à peine une option, jetez un coup d'œil aux transpileurs Python vers JavaScript (par exemple Transcrypt ) ou aux implémentations JavaScript Python (par exemple Brython ). Ou tentez votre chance avec d'autres parmi la liste des langages qui se compilent en JavaScript .

Sinon, si la taille du téléchargement n'est pas un problème et que vous êtes prêt à vous attaquer à de nombreux problèmes, choisissez entre les trois ci-dessus.

Mise à jour T3 2020

  1. Le port JavaScript a été intégré à MicroPython. Il vit dans les ports / javascript .

  2. Le port est disponible sous la forme d'un package npm appelé MicroPython.js . Vous pouvez l'essayer dans RunKit .

  3. Il existe une implémentation Python activement développée dans Rust, appelée RustPython . Parce que Rust prend officiellement en charge WebAssembly comme cible de compilation , il n'est pas surprenant qu'il y ait un lien de démonstration juste en haut du readme. Cependant, il est tôt. Leur avertissement suit.

    RustPython est en phase de développement et ne doit pas être utilisé en production ou dans un cadre intolérant aux pannes.

    Notre version actuelle ne prend en charge qu'un sous-ensemble de la syntaxe Python.

saaj
la source
1
Ces tailles .js et .wasm ne sont pas vraiment justes. La compression de flux est bien prise en charge et pourrait être utilisée pour réduire la taille des deux. Quelle est la taille des mêmes fichiers, gzippés? A part ça, bonne réponse.
énigmaticPhysicist
Je voulais donc ajouter qu'en 2020, il semble que le pyodure soit la chose la plus proche qu'OP recherche. C'est le runtime Python dans l'assembly Web (je suppose que le put C puis Python dans wasm). Il prend également en charge plusieurs bibliothèques. En outre, semble assez facile à utiliser.
David Frick
3

Cela ne sera pas possible tant que l'assembly Web n'aura pas implémenté le garbage collection. Vous pouvez suivre les progrès ici: https://github.com/WebAssembly/proposals/issues/16

Malcolm White
la source
17
Pas nécessairement. Vous pouvez implémenter GC - et en particulier le comptage de références, tel qu'il est utilisé par Python IIRC - au-dessus de Wasm. En principe, vous devriez être capable de prendre CPython et de le compiler dans Wasm en utilisant Emscripten.
Andreas Rossberg
1
Mon opinion d'OP était qu'ils voulaient utiliser des outils existants - implémenter cpython GC en plus de wasm sonne comme un projet en soi
Malcolm White
3
Vous ne devriez rien faire de plus, demandez simplement à CPython de compiler. Il contient déjà l'implémentation RC, AFAICT.
Andreas Rossberg
3

En bref: il existe des transpileurs, mais vous ne pouvez pas convertir automatiquement un Python arbitraire en assemblage Web, et je doute que vous puissiez le faire pendant longtemps. Bien que théoriquement les langages soient tout aussi puissants et que la traduction manuelle soit toujours possible, Python permet certaines structures de données et modes expressifs qui nécessitent un compilateur inter-langage très intelligent (ou transpilateur) [voir ci-dessous]. Une solution de contournement pourrait être l'assemblage Python vers C vers Web car la technologie python vers C est moyennement mature, mais cela ne fonctionnera généralement pas non plus puisque Python vers C est également fragile (voir ci-dessous).

WebAssembly est spécifiquement destiné aux langages de type C comme vous pouvez le voir sur http://webassembly.org/docs/high-level-goals/

La traduction de Python vers C peut être effectuée avec des outils comme PyPy, qui est en cours de développement depuis longtemps, mais qui ne fonctionne toujours pas pour du code Python arbitraire. Il y a plusieurs raisons à cela:

  1. Python a des structures de données très pratiques, abstraites et agréables, mais elles sont difficiles à traduire en code statique.
  2. Python dépend du garbage collection dynamique.
  3. La plupart du code Python dépend fortement de diverses bibliothèques, chacune ayant ses propres bizarreries et problèmes (comme l'écriture en C, ou même en assembleur).

Si vous regardez plus attentivement pourquoi Python-to-C (ou Python to C ++) a été si délicat, vous pouvez voir les raisons détaillées de cette réponse laconique, mais je pense que cela sort du cadre de votre question.

GregD
la source