Compilando Python para WebAssembly

95

Eu li que é possível converter o código Python 2.7 para Web Assembly, mas não consigo encontrar um guia definitivo sobre como fazer isso.

Até agora eu compilei um programa C para Web Assembly usando Emscripten e todos os seus componentes necessários, então sei que está funcionando (guia usado: http://webassembly.org/getting-started/developers-guide/ )

Quais são as etapas que devo seguir para fazer isso em uma máquina Ubuntu? Preciso converter o código Python em bitcode LLVM e depois compilá-lo usando o Emscripten? Se sim, como eu faria isso?

Robbie
fonte
1
@guettli github.com/pypyjs/pypyjs/issues/145
denfromufa
1
Confira pyodide: hacks.mozilla.org/2019/04/…
Alex
1
Pyodide traz o tempo de execução Python para o navegador via WebAssembly: github.com/iodide-project/pyodide
guettli

Respostas:

149

WebAssembly vs asm.js

Primeiro, vamos dar uma olhada em como, em princípio, WebAssembly é diferente de asm.js e se há potencial para reutilizar o conhecimento e ferramentas existentes. O seguinte fornece uma visão geral muito boa:

Vamos recapitular, WebAssembly (MVP, pois há mais em seu roteiro , aproximadamente):

  • é um formato binário de AST com tipagem estática, que pode ser executado por mecanismos JavaScript existentes (e, portanto, compatível com JIT ou AOT compilado),
  • é 10-20% mais compacto (comparação com gzip) e uma ordem de magnitude mais rápida de analisar do que JavaScript,
  • pode expressar mais operação de baixo nível que não se encaixa na sintaxe do JavaScript, leia asm.js (por exemplo, inteiros de 64 bits, instruções especiais de CPU, SIMD, etc)
  • é conversível (até certo ponto) de / para asm.js.

Portanto, atualmente WebAssembly é uma iteração em asm.js e visa apenas C / C ++ (e linguagens semelhantes).

Python na web

Não parece que o GC é a única coisa que impede o código Python de direcionar WebAssembly / asm.js. Ambos representam código digitado estaticamente de baixo nível, no qual o código Python não pode (realisticamente) ser representado. Como a cadeia de ferramentas atual do WebAssembly / asm.js é baseada no LLVM, uma linguagem que pode ser facilmente compilada para LLVM IR pode ser convertida para WebAssembly / asm.js. Mas, infelizmente, Python é muito dinâmico para caber nele também, como comprovado por Unladen Swallow e várias tentativas de PyPy.

Esta apresentação do asm.js contém slides sobre o estado das linguagens dinâmicas . O que isso significa é que atualmente só é possível compilar VM inteira (implementação de linguagem em C / C ++) para WebAssembly / asm.js e interpretar (com JIT onde possível) fontes originais. Para Python, existem vários projetos existentes:

  1. PyPy : PyPy.js ( palestra do autor na PyCon ). Aqui está o repo de lançamento . O arquivo JS principal ,, pypyjs.vm.jstem 13 MB (2 MB depois gzip -6) + Python stdlib + outras coisas.

  2. CPython: pyodide , EmPython , CPython-Emscripten , EmCPython , etc. empython.jsé 5,8 MB (2,1 MB depois gzip -6), sem stdlib.

  3. Micropython: este garfo .

    Não havia nenhum arquivo JS construído lá, então fui capaz de construí-lo com trzeci/emscripten/uma cadeia de ferramentas Emscripten pronta. Algo como:

     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 
    

    Produz micropython.jsde 1,1 MB (225 KB depois gzip -d). O último já é algo a ser considerado, se você precisar apenas de uma implementação muito compatível sem stdlib.

    Para produzir a construção WebAssembly, você pode alterar a linha 13 do Makefilepara

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

    Em seguida, make -jproduz:

     113 KB micropython.js
     240 KB micropython.wasm
    

    Você pode olhar a saída HTML de emcc hello.c -s WASM=1 -o hello.html, para ver como usar esses arquivos.

    Dessa forma, você também pode construir potencialmente PyPy e CPython em WebAssembly para interpretar seu aplicativo Python em um navegador compatível.

Outra coisa potencialmente interessante aqui é o Nuitka , um compilador de Python para C ++. Potencialmente, pode ser possível construir seu aplicativo Python para C ++ e, em seguida, compilá-lo junto com CPython com Emscripten. Mas praticamente não tenho ideia de como fazer isso.

Soluções

Por enquanto, se você estiver construindo um site ou aplicativo da web convencional em que baixar um arquivo JS de vários megabytes mal seja uma opção, dê uma olhada nos transpiladores de Python para JavaScript (por exemplo, Transcrypt ) ou implementações de Python de JavaScript (por exemplo, Brython ) Ou tente a sorte com outros na lista de linguagens que compilam para JavaScript .

Caso contrário, se o tamanho do download não for um problema e você estiver pronto para lidar com muitas arestas, escolha entre os três acima.

Atualização Q3 2020

  1. A porta JavaScript foi integrada ao MicroPython. Vive em ports / javascript .

  2. A porta está disponível como um pacote npm chamado MicroPython.js . Você pode experimentar no RunKit .

  3. Há uma implementação Python desenvolvida ativamente em Rust, chamada RustPython . Como o Rust oferece suporte oficial ao WebAssembly como destino de compilação , não é surpresa que haja um link de demonstração logo no topo do readme. Porém, ainda é cedo. Sua isenção de responsabilidade segue.

    RustPython está em uma fase de desenvolvimento e não deve ser usado na produção ou em uma configuração intolerante a falhas.

    Nosso build atual suporta apenas um subconjunto da sintaxe Python.

saaj
fonte
2
Esses tamanhos .js e .wasm não são realmente justos. A compactação de fluxo é bem suportada e pode ser usada para reduzir o tamanho de ambos. Qual o tamanho dos mesmos arquivos compactados? Fora isso, boa resposta.
enigmaticPhysicist
Então, gostaria de acrescentar que, em 2020, parece que o piodeto é a coisa mais próxima que a OP está procurando. É o tempo de execução do Python em web assembly (eu assumiria colocar C e, em seguida, Python em wasm). Ele também oferece suporte a várias bibliotecas. Além disso, parece fácil de usar.
David Frick,
3

Isso não será possível até que o web assembly implemente a coleta de lixo. Você pode acompanhar o progresso aqui: https://github.com/WebAssembly/proposals/issues/16

Malcolm White
fonte
18
Não necessariamente. Você pode implementar GC - e especialmente a contagem de referência, como é usado pelo Python IIRC - em cima do Wasm. Em princípio, você deve ser capaz de pegar o CPython e compilá-lo no Wasm usando o Emscripten.
Andreas Rossberg
1
Minha opinião sobre o OP foi que eles queriam usar as ferramentas existentes - implementar cpython GC em cima do wasm soa como um projeto em si
Malcolm White
3
Você não deve ter que fazer nada extra, apenas faça o CPython compilar. Já contém a implementação RC, AFAICT.
Andreas Rossberg
3

Resumindo: existem transpiladores, mas você não pode converter automaticamente qualquer Python arbitrário em Web Assembly, e duvido que seja capaz por muito tempo. Embora teoricamente as linguagens sejam igualmente poderosas e a tradução manual seja sempre possível, o Python permite algumas estruturas de dados e modos expressivos que requerem um compilador (ou transpiler) interlinguístico muito inteligente [veja abaixo]. Uma solução alternativa pode ser Python para C para Web Assembly, já que a tecnologia python-para-C é moderadamente madura, mas isso geralmente não vai funcionar, já que Python-para-C também é frágil (veja abaixo).

WebAssembly é direcionado especificamente para linguagens como C, como você pode ver em http://webassembly.org/docs/high-level-goals/

A tradução de Python para C pode ser feita com ferramentas como PyPy, que está em desenvolvimento há muito tempo, mas que ainda não funciona para código Python arbitrário. Há várias razões para isso:

  1. Python tem algumas estruturas de dados muito úteis, abstratas e interessantes, mas são difíceis de traduzir em código estático.
  2. Python depende da coleta de lixo dinâmica.
  3. A maior parte do código Python depende muito de várias bibliotecas, cada uma com suas peculiaridades e problemas (como ser escrito em C ou até mesmo em assembler).

Se você examinar mais cuidadosamente por que Python para C (ou Python para C ++) tem sido tão complicado, você pode ver os motivos detalhados por trás dessa resposta concisa, mas acho que isso está fora do escopo de sua pergunta.

GregD
fonte