Rust: Haga que Rust funcione con emscripten

Creado en 18 abr. 2012  ·  30Comentarios  ·  Fuente: rust-lang/rust

Pasé algún tiempo analizando este problema y rustc ahora genera código que emscripten puede traducir, pero el javascript compilado falla cuando llega a una función de tiempo de ejecución. El siguiente paso es comenzar a construir el tiempo de ejecución usando emcc como compilador. Elimine todas las cosas que no se construyen detrás de EMSCRIPTEN ifdefs.

Emscripten está agregando una forma de tratar el ensamblaje en línea como javascript, por lo que todas las partes del tiempo de ejecución que no se compilan con emscripten se pueden implementar en línea con javascript.

Alternativamente, podríamos volver a implementar el tiempo de ejecución por partes en javascript y no molestarnos en compilarlo desde C ++ en absoluto. No se recomienda este enfoque.

A-runtime E-hard

Comentario más útil

Estoy haciendo un gran esfuerzo de clasificación para prepararnos para la versión 1.0. Como parte de esto, estoy moviendo cosas que son similares a una lista de deseos al repositorio de RFC, ya que ahí es donde las principales cosas nuevas deben discutirse / priorizarse.

Este problema se ha trasladado al repositorio de RFC: rust-lang / rfcs # 604

Todos 30 comentarios

Vea también # 3608.

Todavía estaría bien; no en ningún hito de madurez.

Aún así estaría bien, pero no es muy importante. Esto debería ser más fácil, ya que gran parte del tiempo de ejecución se está reescribiendo en óxido.

Ahora que el tiempo de ejecución está escrito en Rust, ¿cómo cambia eso las perspectivas de este error? ¿Qué tan difícil sería hacer que un Hello World sin tiempo de ejecución se ejecutara a través de emscripten?

No debería ser particularmente difícil agregar un soporte realmente bueno para emscripten ahora. Ya funciona prácticamente con núcleo de óxido. En el compilador, necesitamos agregar soporte para el triple de destino adecuado, configurar los diversos atributos de destino correctamente, luego delimitar las pocas partes del tiempo de ejecución que actualmente no pueden funcionar en js, subprocesos y cambio de contexto.

Una vez que el modo de programación 1: 1 madure un poco más, es posible que incluso podamos agregar soporte para tareas a través de trabajadores web, aunque actualmente requeriría una solución de paso de mensajes diferente. Dependiendo de qué soporte de paralelismo se agregue a js / emscripten, eventualmente podemos admitir la semántica de paso de mensajes de rust con precisión.

@brson : Creo que el # 10780 sería el mayor bloqueador en este momento. Rust generará plataformas de aterrizaje con llamadas para actualizar el tamaño utilizado para hacer la seguridad de la pila a través del soporte de pila segmentado de LLVM.

¡Gracias a -Z no-landing-pads esto ahora funciona bien! Es posible agregar soporte explícito para esto a la biblioteca estándar, pero la mayoría no funcionará de todos modos (archivos, tcp, udp, etc.), por lo que no creo que sea necesario. Si la biblioteca estándar adquiere soporte independiente, comenzará a funcionar y podremos abrir más problemas basados ​​en la funcionalidad que podamos asignar a JavaScript.

Si está bien, me gustaría dejar esto abierto por ahora. Creo que hacer esto sería un buen paso adelante para garantizar que la biblioteca estándar sea extensible y pueda ejecutarse en cualquier cantidad de plataformas.

Estoy de acuerdo en que la mayor parte del trabajo probablemente esté hecho, y esto probablemente necesitará libemscripten para proporcionar E / S específicas de emscripten, pero creo que puede haber suficientes inconvenientes en el camino que vale la pena dejar el tema abierto para (¡sigue siendo un proyecto interesante!)

@alexcrichton : no será posible proporcionar la concurrencia de la biblioteca estándar y el soporte de E / S para emscripten. En el mejor de los casos, podría salir a la consola para stdout / stderr. No puedo pensar en nada en la biblioteca estándar que vaya a ser una buena idea para un objetivo emscripten pero no para uno independiente, más allá de una implementación de asignador predeterminada.

Actualización de estado:

@alexcrichton Ha refactorizado la biblioteca estándar en un grupo de bibliotecas más pequeñas con dependencias más comprensibles. Debería ser casi trivial conseguir que las bibliotecas core, alloc, rand y colecciones se compilen ahora en la web.

Así es como sugeriría abordar esto:

  • Realice algunos experimentos con las cadenas de herramientas rust y LLVM para comprender cómo funciona el codegen para la compilación cruzada en asm.js.
  • Cree libcore con emscripten manualmente y demuestre que funciona en la web.
  • Modifique rustc y mk / platform.mk para comprender un triple objetivo específico de emscripten, produzca una cadena de herramientas de compilación cruzada que no contenga nada más que libcore.rlib
  • Aborde liballoc permitiéndole trabajar con el sistema (en este caso provisto por emscripten) malloc, luego con las otras cajas libres de tiempo de ejecución.

¡Ese es un buen comienzo!

Ok, lo intenté con los primeros pasos y obviamente tuve problemas desde el principio.

Compilé libcore en bitcode con --emit bc , y al intentar compilarlo con emcc -O0 , obtengo:

/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:

No estoy seguro de si puedo hacer algo al respecto, o es porque no podemos usar la salida rustc --emit para esto.

Lo siento si este no es el lugar para comentar sobre esto ...

También probé con libnum , uno más simple, y el bc genera correctamente, pero recibo una advertencia durante el proceso emcc sobre el uso del triple incorrecto y el resultado. js no tiene ninguna de las funciones dentro de libnum , así que creo que estoy siendo demasiado ingenuo aquí :)

@Arcnor Puede preguntar a algunos de los que previamente han compilado pruebas simples con emscripten sobre su proceso. Solo tengo algunas ideas.

  • El código de bits de LLVM cambia de una versión a otra y la versión que usa Rust no siempre es la misma que emscripten. Hacer que ambos utilicen una versión relativamente similar de LLVM puede mejorar la compatibilidad.
  • A partir de su mensaje de error, parece que está utilizando el nuevo backend 'fastcomp' de emscripten. Esto puede estar menos probado en cargas de trabajo de Rusty que en su antiguo backend. Optar manualmente por el backend antiguo puede producir al menos resultados diferentes.
  • Emscripten generalmente usa su propio triple objetivo, por lo que es posible que deba persuadir a rustc para que use el mismo.

El error al intentar compilar libcore parece estar relacionado con este problema de emscripten. La compilación de libcore en el bytecode llvm genera instrucciones atómicas de llvm, pero emscripten no admite instrucciones atómicas.

Puede haber una manera de solucionar esto desde el lado del óxido, pero según los comentarios en el número de emscripten, creo que obtener soporte para atomics en emscripten tiene más sentido.

Si emscripten tiene su propia plataforma, tal vez podríamos eliminar todos los atómicos para sus variantes de un solo subproceso, ¡pero estoy de acuerdo en que sería mejor tener esto en emscripten ascendente!

Si no me equivoco, el nuevo backend "fastcomp" de emscripten es una bifurcación de LLVM (mientras que el backend anterior era solo una capa por encima de LLVM), por lo que la versión LLVM de fastcomp probablemente sea difícil de actualizar y no se actualizará frecuentemente.

Esto será problemático si necesita ser compatible con la salida de Rust. Por ejemplo, en este momento, la versión LLVM de fastcomp es 3.3, mientras que la LLVM utilizada por Rust es 3.4.

El antiguo backend emscripten está obsoleto y no debería usarse de acuerdo con los documentos oficiales, por lo que probablemente no sea una opción para usarlo.

Parece que soy el único que intenta compilar para emscripten por el momento.

Para que conste, estas son las cosas que probé:

  • Compilar en código de bytes (generado por LLVM 3.4 de Rust) y pasarlo a fastcomp (bifurcación de LLVM 3.3); hace que fastcomp se bloquee
  • Compilar a IR, editarlo manualmente hasta que sea compatible con LLVM 3.3 y pasarlo a fastcomp; demasiado complicado, demasiadas cosas para modificar para cualquier código no trivial
  • La compilación de Rust stage1 con --llvm-root apuntó al fastcomp de emscripten; eso no funcionó porque eliminaron el soporte para ARM / MIPS / etc. en su bifurcación (obtengo errores de los archivos MAKE y durante el enlace debido a esto)
  • Modifique el submódulo git LLVM en el código fuente de Rust para que apunte a una confirmación anterior de la era 3.3; obteniendo una segfault en algún momento en LLVM
  • La compilación de Rust con --llvm-root apuntó a un LLVM 3.3 precompilado (procedente del repositorio oficial de ubuntu); la obtención de una aserción falló al final de la compilación de stage1 y el binario rustc producido no funciona.

A menos que alguien tenga una idea, mi conclusión es que debemos esperar a que emscripten se actualice.

el ron parece tenerlo funcionando, más o menos; tal vez esto ayude

Actualización menor: emscripten-fastcomp se actualizó a LLVM 3.4 y se actualizará a LLVM 3.5 más adelante.

@tomaka, ¿has intentado hacer algo con la versión 3.4? Pude compilar el ejemplo de ron con él, pero cualquier otra cosa falló con errores ininteligibles.

@ibdknox 3.4 es incompatible con 3.5
Incluso un simple hola mundo produce una afirmación fallida: LLVM ERROR: 0 && "some i64 thing we can't legalize yet"

Hm. Pude tomar la salida de rustc --emit ir foo.rust y ejecutarla a través de emscripten-entrante. ¿El óxido ahora está en LLVM 3.5?

Rust ha estado usando LLVM 3.5 durante mucho tiempo. Puede tener suerte y no generar nada incompatible.
Por ejemplo, esto se compila muy bien:

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

Esto no se debe a un IR incompatible:

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

@ibdknox http://www.reddit.com/r/rust_gamedev/comments/2n0x08/emscripten_experiments/
Parece que hay menos incompatibilidades de las que pensaba.

Como actualización, cuando compilo hello world con emscripten que ahora se ha actualizado a 3.5, obtengo lo siguiente:

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:

Así es como lo estoy compilando:

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

Sin embargo, las cosas que no parecen dar buenos resultados en general parecen funcionar.

He pasado mi tiempo libre esta última semana investigando esto. Leí el libro de rust en algún momento entre el verano y ahora y realmente me gustó la mecánica del lenguaje, pero recientemente comencé a implementar algo con él. Soy tan conocedor del compilador de rust como de lo que aprendí esta semana, pero espero poder contribuir.

Así que supongo que lo primero que debo notar de lo que aprendí (pero me tomó algunas noches darme cuenta) es que Rust se mudó a LLVM 3.6 en julio. Por tanto, las versiones actuales de Rust y emscripten-fastcomp son incompatibles.

Intenté compilar rust con --llvm-root apuntando a emscripten-fastcomp 1.29.2 y obtuve este error:

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 llegar a este error configuré y construí emscripten-fastcomp con

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

En lugar de los recomendados por la guía de emscripten

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

Aunque no es necesario crear Rust para todos los objetivos, actualmente siempre se vincula con LLVM con soporte de CPU compilado para todos los objetivos. Esta es una solución para un problema que podría solucionarse en el futuro, por lo que es posible que no necesitemos compilar siempre emscripten-fastcomp con esa configuración.

Una vez que descubrí que Rust se había movido a LLVM 3.6, busqué la última rama en rust-lang / llvm que era LLVM 3.5. https://github.com/rust-lang/llvm/tree/rust-llvm-2014-07-24 Compilé contra eso en lugar de emscripten-fastcomp, curioso por ver qué resultaría. Obtuve exactamente el mismo error al compilar contra el movimiento reciente de emscripton-fastcomp a LLVM 3.5. Entiendo que esto significa que Rust es de alguna manera incompatible con LLVM 3.5 ahora y realmente no esperaría lo contrario.

Así que ahora esperamos o tenemos que obtener emscripten-fastcomp a LLVM 3.6: wink:

Vale la pena mencionar que descargué una copia archivada 0.11 y pude producir LLVM IR para hola mundo que emcc entendió pero luego llegué al problema de la vinculación. Fue muy emocionante verlo pasar de la comprensión del código de bytes, pero realmente lograr que se vincule va a necesitar trabajar en la base del código rust.

Eché un vistazo a la fusión de rust-lang / llvm en emscripten-fastcomp. En ese momento, hay 117 secciones en conflicto sobre 43 archivos.

Mencioné obtener Rust 0.11 y emcc 1.29.2 para llegar a la etapa de vinculación. Este es el 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 reemplaza los puntos en los símbolos con guiones bajos, mientras que Rust espera prefijar otro guión bajo, pero no estoy muy seguro de esto. El primer símbolo sin resolver aparece como __ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0.11.0E en libstd en la compilación i686-apple-darwin. Incluso si pudiera hacer que emcc supiera cómo encontrar este símbolo en las bibliotecas compiladas, supongo que las bibliotecas contienen código de máquina, mientras que emcc necesitará códigos de bytes LLVM. Creo recordar a alguien que mencionó la necesidad de compilar la biblioteca estándar para emscripten. Esto sería parte de la necesidad de eso.

Así que aquí están los próximos pasos en los que estoy tratando de trabajar si alguien quiere intentarlo por sí mismo. (O puede hacerme saber si estoy bien o mal).

  • Fusionar rust-lang / llvm en emscripten-fastcomp
  • Construya rust con fastcomp combinado sin soporte de backend JS
    Espero que esta sea una buena prueba de cordura para la fusión.
  • Agregue el triple de emscripten a Rust y constrúyalo
    Por lo que puedo decir, hay varios archivos que necesito cambiar o agregar.

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

    • rt / arch / asmjs / {morestack.S, record_sp.S} (¿podría estar vacío?)

      Estos archivos son necesarios para construir morestack.a para que Rust admita la pila segmentada de LLVM. Si recuerdo correctamente, la pila de Emscripten también es la cabeza. Utiliza el extremo opuesto del montón como pila y, dado que para asmjs, no puede cambiar el tamaño de la matriz, no es posible crear nuevos segmentos de pila. Vi un campo en TargetOption en los archivos de destino librustc_back que, con suerte, puede desactivar esto.

    • librustc_trans / trans / cabi_asmjs.rs

    • librustc_trans / trans / cabi.rs

      No estoy seguro de si serán necesarios, actualmente solo una suposición.

    • 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 faltantes
    Vi en noviembre que se eliminó libgreen. Dado que emscripten necesita esperar alguna forma de compartir con los trabajadores en los navegadores, si alguna vez sucede, algo como libgreen necesitaría ser restaurado o pthread shimmed de alguna manera específicamente para emscripten como cómo rust construye para pthreads o windows threads api.

IO también. Probablemente otras partes que desconozco.

"Fusionar rust-lang / llvm en emscripten-fastcomp"

Es posible que no desee hacer esto: Emscripten se basa en pnacl-llvm / pnacl-clang, por lo que está creando una bifurcación con parches en parches, lo que probablemente será doloroso. Si está interesado, puede ver algunos detalles de la ramificación en la investigación que hice para la fusión de Emscripten de r33 -> r34 en https://github.com/kripken/emscripten-fastcomp/issues/51#issuecomment -62323164 .

Escuché que pnacl planea rastrear el flujo ascendente un poco más cerca que antes, pero no puedo ver ningún problema relevante en el rastreador de problemas de pnacl para actualizar a 3.6, por lo que puede pasar un tiempo (¡especialmente dado que 3.6 solo se ramificó hace 5 días!). .. ¿Supongo que podría crear un problema? Si decide no utilizar su propia bifurcación de Emscripten, veo dos opciones: esperar a pnacl o ayudar a Emscripten a salir de pnacl y pasar a la corriente ascendente.

Editar: se corrigió 'ahora' a 'no'. Una diferencia crucial.

Estoy haciendo un gran esfuerzo de clasificación para prepararnos para la versión 1.0. Como parte de esto, estoy moviendo cosas que son similares a una lista de deseos al repositorio de RFC, ya que ahí es donde las principales cosas nuevas deben discutirse / priorizarse.

Este problema se ha trasladado al repositorio de RFC: rust-lang / rfcs # 604

¿Fue útil esta página
0 / 5 - 0 calificaciones