Rust: Faça o Rust funcionar com o emscripten

Criado em 18 abr. 2012  ·  30Comentários  ·  Fonte: rust-lang/rust

Passei algum tempo investigando esse problema e agora o rustc gera código que o emscripten pode traduzir, mas o javascript compilado falha quando atinge uma função de tempo de execução. A próxima etapa é começar a construir o tempo de execução usando emcc como compilador. Elimine todas as coisas que não são construídas por trás de EMSCRIPTEN ifdefs.

Emscripten está adicionando uma maneira de tratar a montagem embutida como javascript, então todas as partes do tempo de execução que não são construídas com emscripten podem ser implementadas embutidas com javascript.

Como alternativa, poderíamos reimplementar o tempo de execução aos poucos em javascript e não nos incomodar em compilá-lo em C ++. Essa abordagem não é recomendada.

A-runtime E-hard

Comentários muito úteis

Estou fazendo um grande esforço de triagem para nos preparar para o 1.0. Como parte disso, estou movendo coisas que são como uma lista de desejos para o repositório RFCs, já que é onde as coisas novas importantes devem ser discutidas / priorizadas.

Este problema foi movido para o repositório RFCs: rust-lang / rfcs # 604

Todos 30 comentários

Veja também # 3608.

Ainda seria bom; não em qualquer marco de maturidade.

Ainda seria bom, mas não é muito importante. Isso deve ficar mais fácil, já que muito do tempo de execução está sendo reescrito em ferrugem.

Agora que o tempo de execução foi escrito em Rust, como isso muda as perspectivas desse bug? Seria muito difícil fazer um Hello World sem tempo de execução rodar por meio do emscripten?

Não deve ser particularmente difícil adicionar um suporte realmente bom para emscripten agora. Já funciona muito bem com núcleo de ferrugem. No compilador, precisamos adicionar suporte para o triplo de destino adequado, configurar os vários atributos de destino corretamente e, em seguida, isolar as poucas partes do tempo de execução que atualmente não podem funcionar em js, threading e troca de contexto.

Uma vez que o modo de agendamento 1: 1 amadurece um pouco mais, podemos até ser capazes de adicionar suporte para tarefas por meio de web workers, embora atualmente isso requeira uma solução diferente de passagem de mensagens. Dependendo de qual suporte de paralelismo é adicionado a js / emscripten, podemos eventualmente ser capazes de suportar a semântica de passagem de mensagem de rust com precisão.

@brson : Acho que # 10780 seria o maior bloqueador no momento. O Rust produzirá bases de aterrissagem com chamadas para atualizar o tamanho usado para fazer a segurança da pilha por meio do suporte de pilha segmentada do LLVM.

Graças a -Z no-landing-pads agora funciona bem! Adicionar suporte explícito para isso à biblioteca padrão é possível, mas a maioria não vai funcionar de qualquer maneira (arquivos, tcp, udp, etc.), então não acho que seja necessário. Se e quando a biblioteca padrão obter suporte independente, ela começará a funcionar e podemos abrir mais problemas com base na funcionalidade que podemos mapear para JavaScript.

Se estiver tudo bem, gostaria de deixar em aberto por enquanto. Acho que fazer isso seria um bom passo para garantir que a biblioteca padrão seja extensível e capaz de rodar em qualquer número de plataformas.

Eu concordo que a maior parte do trabalho provavelmente está concluída, e isso provavelmente precisará de libemscripten para fornecer E / S específica do emscripten, mas acho que pode haver empecilhos suficientes no caminho que vale a pena deixar o problema aberto para (ainda é um projeto interessante!)

@alexcrichton : Não será possível fornecer a simultaneidade da biblioteca padrão e o suporte de E / S para emscripten. Na melhor das hipóteses, ele pode enviar saída para o console para stdout / stderr. Não consigo pensar em nada na biblioteca padrão que seja uma boa ideia para um destino emscripten, mas não independente, além de uma implementação de alocador padrão.

Atualização de status:

@alexcrichton Refatorou a biblioteca padrão em um monte de bibliotecas menores com dependências mais compreensíveis. Deve ser quase trivial obter as bibliotecas core, aloc, rand e coleções para compilar na web agora.

Aqui está como eu sugeriria lidar com isso:

  • Faça alguns experimentos com as cadeias de ferramentas Rust e LLVM para entender como o codegen funciona para compilação cruzada para asm.js.
  • Construa manualmente a libcore com emscripten e prove que funciona na web.
  • Modifique rustc e mk / platform.mk para entender um triplo de destino específico de emscripten, produza uma cadeia de ferramentas de compilação cruzada que contém nada além de libcore.rlib
  • Enfrente o liballoc permitindo que ele funcione com o malloc do sistema (neste caso, fornecido pelo emscripten) e, em seguida, com as outras caixas livres de tempo de execução.

É um bom começo!

Ok, então tentei com os primeiros passos e obviamente tive problemas logo de cara.

Compilei libcore para o código de bits com --emit bc e, ao tentar compilá-lo com emcc -O0 , obtive:

/Users/arcnor/emscripten-fastcomp/build/bin/llvm-nm: /tmp/tmpfTkmfj/core_0.o: Invalid CMPXCHG record.
/Users/arcnor/emscripten-fastcomp/build/bin/opt: /tmp/tmpfTkmfj/core.bc: error: Invalid CMPXCHG record
Traceback (most recent call last):
  File "/Users/arcnor/emscripten/emcc", line 1573, in <module>
    shared.Building.llvm_opt(final, link_opts)
  File "/Users/arcnor/emscripten/tools/shared.py", line 1335, in llvm_opt
    assert os.path.exists(target), 'Failed to run llvm optimizations: ' + output
AssertionError: Failed to run llvm optimizations:

Não tenho certeza se posso fazer algo sobre isso, ou é porque não podemos usar a saída rustc --emit para isso.

Desculpe se este não é o lugar para comentar sobre isso ...

Também tentei com libnum , um mais simples, e bc gera corretamente, mas recebo um aviso durante o processo emcc sobre o uso do triplo errado e o resultante. js não tem nenhuma das funções dentro de libnum , então acho que estou sendo muito ingênuo aqui :)

@Arcnor Você pode perguntar a alguns daqueles que já compilaram testes simples com emscripten sobre seu processo. Eu só tenho algumas idéias.

  • O código de bits LLVM muda de versão para versão e a versão que Rust usa nem sempre é a mesma que emscripten. Conseguir os dois usando uma versão relativamente semelhante do LLVM pode melhorar a compatibilidade.
  • Pela sua mensagem de erro, você parece estar usando o novo back-end 'fastcomp' do emscripten. Isso pode ser menos testado em cargas de trabalho do Rusty do que em seu antigo back-end. Optar manualmente pelo back-end antigo pode pelo menos produzir resultados diferentes.
  • Emscripten geralmente usa seu próprio triplo de destino, então rustc pode precisar ser perseguido para usar o mesmo.

O erro ao tentar compilar libcore parece estar relacionado a este problema de emscripten. Compilar libcore para bytecode llvm gera instruções atômicas llvm, mas emscripten não suporta instruções atômicas.

Pode haver uma maneira de contornar isso do lado da ferrugem, mas com base nos comentários na edição do emscripten, acho que fazer mais sentido obter suporte para atômicos no emscripten.

Se o emscripten tiver sua própria plataforma, poderíamos talvez cfg-out de todos os atômicos para suas variantes single-threaded, mas eu concordo que seria melhor ter isso no emscripten upstream!

Se não me engano, o novo backend "fastcomp" do emscripten é um fork do LLVM (enquanto o backend anterior era apenas uma camada acima do LLVM), então a versão LLVM do fastcomp provavelmente é difícil de atualizar e não será atualizada freqüentemente.

Isso será problemático se precisar ser compatível com a saída do Rust. Por exemplo, agora a versão LLVM de fastcomp é 3.3, enquanto o LLVM usado por Rust é 3.4.

O antigo backend emscripten está obsoleto e não deve ser usado de acordo com os documentos oficiais, então provavelmente não é uma opção de usá-lo.

Parece que sou o único tentando compilar para o emscripten no momento.

Para registro, aqui estão as coisas que experimentei:

  • Compilar para bytecode (gerado pelo Rust's LLVM 3.4) e passar para fastcomp (fork do LLVM 3.3); faz com que o fastcomp falhe
  • Compilando para IR, editando manualmente até que seja compatível com LLVM 3.3 e passando para fastcomp; muito complicado, muitas coisas para modificar para qualquer código não trivial
  • Compilando Rust stage1 com --llvm-root apontado para fastcomp do emscripten; que não funcionou porque eles removeram o suporte para ARM / MIPS / etc. em seu fork (estou recebendo erros dos makefiles e durante a vinculação por causa disso)
  • Modifique o submódulo git do LLVM no código-fonte do Rust para apontar para um antigo commit da era 3.3; obtendo um segfault em algum ponto no LLVM
  • Compilar o Rust com --llvm-root apontou para um LLVM 3.3 pré-compilado (vindo do repositório oficial do Ubuntu); a obtenção de uma declaração falhou no final da compilação do stage1 e o binário rustc produzido não funciona.

A menos que alguém tenha uma ideia, minha conclusão é que precisamos esperar a atualização do emscripten.

parece que está funcionando com rum , sorta; talvez isso ajude

Atualização secundária: emscripten-fastcomp foi atualizado para LLVM 3.4 e será atualizado para LLVM 3.5 posteriormente.

@tomaka , você já tentou fazer alguma coisa com a versão 3.4? Consegui compilar o exemplo do rum com ele, mas qualquer outra coisa falhou com erros ininteligíveis.

@ibdknox 3.4 é incompatível com 3.5
Mesmo um simples hello world produz uma afirmação falhada: LLVM ERROR: 0 && "some i64 thing we can't legalize yet"

Hm. Consegui pegar a saída de rustc --emit ir foo.rust e executá-la por meio do emscripten-coming. A ferrugem está agora no LLVM 3.5?

Rust já usa o LLVM 3.5 há muito tempo. Você pode ter sorte e não gerar nada incompatível.
Por exemplo, isso compila perfeitamente:

#[start]
fn main(_: int, _: *const *const u8) -> int {}

Isso não acontece por causa de IR incompatível:

fn main() { println!("hello world"); }

@ibdknox http://www.reddit.com/r/rust_gamedev/comments/2n0x08/emscripten_experiments/
Parece que existem menos incompatibilidades do que eu pensava.

Como atualização, quando compilo hello world com emscripten que agora foi atualizado para 3.5, recebo o seguinte:

Value:   %28 = call fastcc { i8, [0 x i8], [0 x i8] } @_ZN3fmt5write20h2c56fdda0b308d94DFAE({ i8*, void (i8*)** }* noalias nocapture dereferenceable(8) %arg.i, %"struct.core::fmt::Arguments[#3]"* noalias nocapture readonly dereferenceable(24) %__args31), !noalias !22
LLVM ERROR: Unrecognized struct value
Traceback (most recent call last):
  File "/Users/chris/Downloads/emsdk_portable/emscripten/incoming/emcc", line 1259, in <module>
    shared.Building.llvm_opt(final, link_opts)
  File "/Users/chris/Downloads/emsdk_portable/emscripten/incoming/tools/shared.py", line 1401, in llvm_opt
    assert os.path.exists(target), 'Failed to run llvm optimizations: ' + output
AssertionError: Failed to run llvm optimizations:

Aqui está como estou compilando:

rustc --target i686-apple-darwin -C lto --emit ir foo.rust
emcc -v foo.ll -o test.html

Coisas que não parecem trazer fmt geralmente parecem funcionar, no entanto.

Passei meu tempo livre na semana passada investigando isso. Eu li o livro do ferrugem entre o verão e agora e gostei muito da mecânica da linguagem, mas só recentemente comecei a implementar algo com ela. Tenho tanto conhecimento sobre o compilador de ferrugem quanto o que aprendi esta semana, mas espero poder contribuir.

Portanto, acho que a primeira coisa a notar do que aprendi (mas isso me levou algumas noites para perceber) é que Rust mudou para o LLVM 3.6 em julho. Portanto, as versões atuais de Rust e emscripten-fastcomp são incompatíveis.

Tentei compilar a ferrugem com --llvm-root apontando para emscripten-fastcomp 1.29.2 e recebi este erro:

rustc: x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/libcore
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
thread 'rustc' panicked at 'assertion failed: self.raw.hash != self.hashes_end', /Users/zen/Code/rust/src/libstd/collections/hash/table.rs:776


make: *** [x86_64-apple-darwin/stage2/lib/rustlib/x86_64-apple-darwin/lib/stamp.core] Error 101

Para obter este erro, configurei e construí emscripten-fastcomp com

../configure --enable-optimized --disable-assertions --enable-targets=host,js,arm,aarch64,mips

Em vez do guia do emscripten recomendado

../configure --enable-optimized --disable-assertions --enable-targets=host,js

Embora o Rust não precise ser construído para todos os destinos, atualmente ele sempre se vincula ao LLVM com suporte de CPU compilado para todos os destinos. Esta é uma solução alternativa para um problema que pode ser corrigido no futuro, portanto, nem sempre precisamos compilar o emscripten-fastcomp com essa configuração.

Assim que descobri que o Rust havia mudado para o LLVM 3.6, pesquisei o último branch em rust-lang / llvm que era o LLVM 3.5. https://github.com/rust-lang/llvm/tree/rust-llvm-2014-07-24 Compilei contra isso em vez de emscripten-fastcomp, curioso para ver o que aconteceria. Eu obtive exatamente o mesmo erro ao compilar em relação à mudança recente do emscripton-fastcomp para o LLVM 3.5. Eu entendo que isso significa que Rust é de alguma forma incompatível com o LLVM 3.5 agora e eu realmente não esperaria o contrário.

Portanto, agora esperamos ou temos que obter emscripten-fastcomp para LLVM 3.6: wink:

Vale a pena mencionar que eu baixei uma cópia arquivada de 0,11 e fui capaz de produzir IR LLVM para hello world que emcc entendeu, mas depois cheguei ao problema de vinculação. Foi muito empolgante ver isso ultrapassar a compreensão do código de bytes, mas realmente conseguir vinculá-lo vai precisar de trabalho na base do código ferrugem.

Dei uma olhada na fusão de rust-lang / llvm em emscripten-fastcomp. Na época, havia 117 seções conflitantes em 43 arquivos.

Mencionei obter Rust 0.11 e emcc 1.29.2 para chegar ao estágio de vinculação. Este é o resultado específico:

$ emcc -v hello.ll -o hello.js
INFO     root: (Emscripten: Running sanity checks)
WARNING: Linking two modules of different data layouts: '/Users/zen/.emscripten_cache/libc.bc' is 'e-p:32:32-i64:64-v128:32:128-n32-S128' whereas '/tmp/tmpv_yB8E/hello_0.o' is 'e-p:32:32-f64:32:64-f80:128-n8:16:32'
WARNING: Linking two modules of different target triples: /Users/zen/.emscripten_cache/libc.bc' is 'asmjs-unknown-emscripten' whereas '/tmp/tmpv_yB8E/hello_0.o' is 'i686-apple-darwin'
warning: incorrect target triple 'i686-apple-darwin' (did you use emcc/em++ on all source files and not clang directly?)
warning: unresolved symbol: _ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0_11_0E
warning: unresolved symbol: _ZN10lang_start20h70f93b7d0a75f99atre7v0_11_0E

Parece que emcc / fastcomp substitui pontos em símbolos por sublinhados, enquanto Rust espera prefixar com outro sublinhado, mas não tenho certeza sobre isso. O primeiro símbolo não resolvido aparece como __ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0.11.0E em libstd na compilação i686-apple-darwin. Mesmo que eu pudesse fazer com que o emcc soubesse como encontrar esse símbolo nas bibliotecas construídas, estou supondo que as libs contêm código de máquina, enquanto o emcc precisará de códigos de byte LLVM. Acho que me lembro de alguém mencionando a necessidade de compilar a biblioteca padrão para o emscripten. Isso seria parte da necessidade disso.

Portanto, aqui estão as próximas etapas que procuro experimentar e trabalhar se alguém quiser tentar por conta própria. (Ou pode me dizer se estou certo ou errado.)

  • Merge rust-lang / llvm em emscripten-fastcomp
  • Construir ferrugem com fastcomp mesclado sem suporte de back-end JS
    Esperando que este seja um bom teste de sanidade para a fusão.
  • Adicione o triplo do emscripten ao Rust e construa-o
    Pelo que posso dizer, há uma série de arquivos que preciso alterar ou adicionar.

    • mk / cfg / asmjs-unknown-emscripten.mk

    • rt / arch / asmjs / {morestack.S, record_sp.S} (pode estar vazio?)

      Esses arquivos são necessários para construir morestack.a for Rust para suportar a pilha segmentada do LLVM. Se bem me lembro, a pilha de Emscripten também é a cabeça. Ele usa a extremidade oposta da pilha como pilha e, como para asmjs, você não pode alterar o tamanho da matriz, não é possível criar novos segmentos de pilha. Eu vi um campo em TargetOption nos arquivos de destino librustc_back que espero poder desabilitar isso.

    • librustc_trans / trans / cabi_asmjs.rs

    • librustc_trans / trans / cabi.rs

      Não tenho certeza se eles serão necessários, atualmente apenas um palpite.

    • librustc_back / target / asmjs_unknown_emscripten.rs

    • librustc_back / asmjs.rs

    • librustc_syntax / abi.rs

    • librustc_back / back / write.js configure_llvm ()

    • librustc_llvm / lib.rs static_link_hack_this_sucks ()

  • Implementar interfaces de sistema ausentes
    Eu vi em novembro que o libgreen foi removido. Uma vez que o emscripten precisa esperar por alguma forma de compartilhar com os workers nos navegadores, se isso acontecer, algo como libgreen precisaria ser restaurado ou pthread ajustado de alguma forma especificamente para emscripten como a ferrugem constrói para pthreads ou API de threads do Windows.

IO também. Provavelmente outras partes que não conheço.

"Merge rust-lang / llvm em emscripten-fastcomp"

Você pode não querer fazer isso - Emscripten é baseado em pnacl-llvm / pnacl-clang, então você está criando uma bifurcação com patches em patches, o que provavelmente será doloroso. Se estiver interessado, você pode ver alguns detalhes da ramificação na investigação que fiz para a mesclagem do Emscripten de r33 -> r34 em https://github.com/kripken/emscripten-fastcomp/issues/51#issuecomment -62323164 .

Ouvi dizer que o pnacl está planejando rastrear o upstream um pouco mais perto do que antes, mas não consigo ver nenhum problema relevante no rastreador de problemas do pnacl para atualizar para o 3.6, então pode demorar (especialmente dado o 3.6 ramificado apenas 5 dias atrás!). ..Acho que você poderia criar um problema? Se você decidir contra seu próprio fork do Emscripten, vejo duas opções - aguardar pelo pnacl ou ajudar o Emscripten a sair do pnacl e colocá-lo no upstream.

Editar: corrigido 'agora' para 'não'. Uma diferença crucial.

Estou fazendo um grande esforço de triagem para nos preparar para o 1.0. Como parte disso, estou movendo coisas que são como uma lista de desejos para o repositório RFCs, já que é onde as coisas novas importantes devem ser discutidas / priorizadas.

Este problema foi movido para o repositório RFCs: rust-lang / rfcs # 604

Esta página foi útil?
0 / 5 - 0 avaliações