Rust: Faire fonctionner Rust avec emscripten

Créé le 18 avr. 2012  ·  30Commentaires  ·  Source: rust-lang/rust

J'ai passé un certain temps à creuser ce problème et rustc génère maintenant du code qu'emscripten peut traduire, mais le javascript compilé échoue lorsqu'il atteint une fonction d'exécution. L'étape suivante consiste à commencer à construire le runtime en utilisant emcc comme compilateur. Supprimez tout ce qui ne se construit pas derrière EMSCRIPTEN ifdefs.

Emscripten ajoute un moyen de traiter l'assemblage en ligne comme du javascript, de sorte que toutes les parties du runtime qui ne sont pas construites avec emscripten peuvent être implémentées en ligne avec javascript.

Alternativement, nous pourrions réimplémenter le runtime au coup par coup en javascript et ne pas du tout prendre la peine de le compiler à partir de C++. Cette approche n'est pas recommandée.

A-runtime E-hard

Commentaire le plus utile

Je fais un effort de triage massif pour nous préparer pour la 1.0. Dans le cadre de cela, je déplace des éléments de type liste de souhaits vers le référentiel RFC, car c'est là que les nouvelles choses majeures devraient être discutées/priorisées.

Ce problème a été déplacé vers le référentiel RFC : rust-lang/rfcs#604

Tous les 30 commentaires

Voir aussi #3608.

Ce serait toujours sympa ; pas sur un jalon de maturité.

Ce serait quand même bien, mais ce n'est pas très important. Cela devrait devenir plus facile, car une grande partie du runtime est réécrite en rouille.

Maintenant que le runtime est écrit en Rust, en quoi cela change-t-il les perspectives de ce bogue ? À quel point serait-il difficile d'obtenir un Hello World indémodable sur emscripten ?

Il ne devrait pas être particulièrement difficile d'ajouter un support vraiment sympa pour emscripten maintenant. Cela fonctionne déjà à peu près avec le noyau de rouille. Dans le compilateur, nous devons ajouter la prise en charge du triple cible approprié, configurer correctement les divers attributs cibles, puis clôturer les quelques parties du runtime qui ne peuvent actuellement pas fonctionner en js, en threading et en commutation de contexte.

Une fois que le mode de planification 1:1 arrivera à maturité un peu plus, nous pourrons peut-être même ajouter une prise en charge des tâches via les travailleurs Web, bien qu'actuellement, cela nécessite une solution de transmission de messages différente. En fonction de la prise en charge du parallélisme ajoutée à js/emscripten, nous pourrions éventuellement être en mesure de prendre en charge avec précision la sémantique de transmission du message de Rust.

@brson : Je pense que le #10780 serait le plus gros bloqueur du moment. Rust produira des plates-formes d'atterrissage avec des appels pour mettre à jour la taille utilisée pour assurer la sécurité de la pile via la prise en charge de la pile segmentée de LLVM.

Grâce à -Z no-landing-pads cela fonctionne maintenant très bien ! L'ajout d'un support explicite pour cela à la bibliothèque standard est possible, mais la plupart ne fonctionneront pas de toute façon (fichiers, tcp, udp, etc.), donc je ne pense pas que ce soit nécessaire. Si et quand la bibliothèque standard prend en charge le support autonome, elle commencera à fonctionner et nous pourrons ouvrir plus de problèmes en fonction des fonctionnalités que nous pouvons mapper sur JavaScript.

Si tout va bien, j'aimerais en fait laisser cela ouvert pour le moment. Je pense que faire cela serait un bon pas en avant pour s'assurer que la bibliothèque standard est extensible et capable de s'exécuter sur n'importe quel nombre de plates-formes.

Je suis d'accord que la plupart du travail est probablement fait, et cela nécessitera probablement libemscripten pour fournir des E/S spécifiques à emscripten, mais je pense qu'il peut y avoir suffisamment d'accrocs en cours de route que cela vaut la peine de partir la question ouverte pour (ça reste un projet intéressant !)

@alexcrichton : Il ne sera pas possible de fournir la simultanéité de la bibliothèque standard et la prise en charge des E/S pour emscripten. Au mieux, il pourrait sortir sur la console pour stdout/stderr. Je ne vois rien dans la bibliothèque standard qui soit une bonne idée pour une cible emscripten mais pas une cible autonome, au-delà d'une implémentation d'allocateur par défaut.

Mise à jour du statut:

@alexcrichton A refactorisé la bibliothèque standard en un ensemble de bibliothèques plus petites avec des dépendances plus compréhensibles. Il devrait être presque trivial de compiler les bibliothèques core, alloc, rand et collections sur le Web maintenant.

Voici comment je suggérerais d'aborder cela:

  • Faites quelques expériences avec les chaînes d'outils rust et LLVM pour comprendre comment le codegen fonctionne pour la compilation croisée vers asm.js.
  • Construisez manuellement libcore avec emscripten et prouvez que cela fonctionne sur le Web.
  • Modifier rustc et mk/platform.mk pour comprendre un triple cible spécifique à emscripten, produire une chaîne d'outils de compilation croisée qui ne contient rien d'autre que libcore.rlib
  • Attaquez-vous à liballoc en lui permettant de fonctionner avec le système (dans ce cas fourni par emscripten) malloc, puis les autres caisses sans runtime.

C'est un très bon début !

D'accord, j'ai donc essayé avec les premières étapes et j'ai évidemment eu des problèmes dès le départ.

J'ai compilé libcore en bitcode avec --emit bc , et en essayant de le compiler avec emcc -O0 , j'obtiens :

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

Je ne sais pas si je peux faire quelque chose à ce sujet, ou c'est parce que nous ne pouvons pas utiliser la sortie rustc --emit pour cela.

Désolé si ce n'est pas l'endroit pour commenter ça...

J'ai également essayé avec libnum , un plus simple, et le bc génère correctement, mais je reçois un avertissement pendant le processus emcc concernant l'utilisation du mauvais triple et le résultat . js n'a aucune des fonctions dans libnum , donc je pense que je suis trop naïf ici :)

@Arcnor Vous pouvez demander à certains de ceux qui ont déjà compilé des tests simples avec emscripten sur leur processus. Je n'ai que quelques idées.

  • Le bitcode LLVM change d'une version à l'autre et la version utilisée par Rust n'est pas toujours la même que emscripten. Les obtenir tous les deux à l'aide d'une version relativement similaire de LLVM peut améliorer la compatibilité.
  • D'après votre message d'erreur, vous semblez utiliser le nouveau backend 'fastcomp' d'emscripten. Cela peut être moins testé sur les charges de travail Rusty que leur ancien backend. L'activation manuelle de l'ancien backend peut au moins produire des résultats différents.
  • Emscripten utilise généralement son propre triple cible, il peut donc être nécessaire d'inciter Rustc à utiliser le même.

L'erreur lors de la tentative de compilation de libcore semble être liée à ce problème d'emscripten. La compilation de libcore en bytecode llvm génère des instructions atomiques llvm, mais emscripten ne prend pas en charge les instructions atomiques.

Il existe peut-être un moyen de contourner ce problème du côté de la rouille, mais sur la base des commentaires dans le numéro d'emscripten, je pense que la prise en charge des atomes dans emscripten est la plus logique.

Si emscripten a sa propre plate-forme, nous pourrions peut-être cfg-out tous les atomes pour leurs variantes monothread, mais je suis d'accord qu'il serait plus agréable d'avoir cela dans emscripten en amont !

Si je ne me trompe pas, le nouveau backend "fastcomp" d'emscripten est un fork de LLVM (alors que le backend précédent n'était qu'une couche au-dessus de LLVM), donc la version LLVM de fastcomp est probablement difficile à mettre à niveau et ne sera pas mise à niveau souvent.

Ce sera problématique s'il doit être compatible avec la sortie de Rust. Par exemple, la version LLVM de fastcomp est actuellement 3.3, tandis que la version LLVM utilisée par Rust est 3.4.

L'ancien backend emscripten est obsolète et ne devrait pas être utilisé selon la documentation officielle, ce n'est donc probablement pas une option pour l'utiliser.

Je semble être le seul à essayer de compiler pour emscripten pour le moment.

Pour info, voici les trucs que j'ai essayé :

  • Compilation en bytecode (généré par le LLVM 3.4) de Rust et passage à fastcomp (fork de LLVM 3.3) ; fait planter fastcomp
  • Compilation en IR, édition manuelle jusqu'à ce qu'elle soit compatible avec LLVM 3.3 et passage à fastcomp ; trop compliqué, trop de choses à modifier pour un code non trivial
  • Compilation de Rust stage1 avec --llvm-root pointé sur le fastcomp d'emscripten ; cela n'a pas fonctionné car ils ont supprimé la prise en charge d'ARM/MIPS/etc. dans leur fourche (je reçois des erreurs des makefiles et lors de la liaison à cause de cela)
  • Modifier le sous-module LLVM git dans le code source de Rust pour pointer vers un ancien commit de l'ère 3.3 ; obtenir une erreur de segmentation à un moment donné dans LLVM
  • Compiler Rust avec --llvm-root pointait vers un LLVM 3.3 précompilé (provenant du référentiel officiel d'ubuntu) ; l'obtention d'une assertion a échoué à la fin de la compilation de stage1 et le binaire rustc produit ne fonctionne pas.

À moins que quelqu'un n'ait une idée, ma conclusion est que nous devons attendre la mise à niveau d'emscripten.

le rhum semble fonctionner, en quelque sorte ; peut-être que cela aidera

Mise à jour mineure : emscripten-fastcomp a été mis à jour vers LLVM 3.4, et sera mis à jour vers LLVM 3.5 plus tard.

@tomaka avez-vous essayé de faire quelque chose avec la version 3.4 ? J'ai pu obtenir l'exemple de rhum en le compilant, mais rien de plus n'a échoué avec des erreurs inintelligibles.

@ibdknox 3.4 est incompatible avec 3.5
Même un simple bonjour au monde produit une affirmation ratée : LLVM ERROR: 0 && "some i64 thing we can't legalize yet"

Hum. J'ai pu prendre la sortie de rustc --emit ir foo.rust et l'exécuter via emscripten-incoming. La rouille est-elle maintenant sur LLVM 3.5 ?

Rust utilise LLVM 3.5 depuis longtemps maintenant. Vous pouvez avoir de la chance et ne rien générer d'incompatible.
Par exemple, cela se compile très bien :

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

Ce n'est pas le cas à cause de l'IR incompatible :

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

@ibdknox http://www.reddit.com/r/rust_gamedev/comments/2n0x08/emscripten_experiments/
Il semble qu'il y ait moins d'incompatibilités que je ne le pensais.

En guise de mise à jour, lorsque je compile hello world avec emscripten qui a maintenant été mis à jour à 3.5, j'obtiens ce qui suit :

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:

Voici comment je compile :

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

Les choses qui ne semblent pas apporter de fmt semblent généralement fonctionner, cependant.

J'ai passé mon temps libre la semaine dernière à étudier cela. J'ai lu le livre de Rust entre l'été et maintenant et j'ai vraiment aimé la mécanique du langage, mais ce n'est que récemment que j'ai commencé à implémenter quelque chose avec. Je connais aussi bien le compilateur rouille que ce que j'ai appris cette semaine, mais j'espère pouvoir y contribuer.

Donc, je suppose que la première chose à noter de ce que j'ai appris (mais cela m'a pris quelques soirées pour le remarquer) est que Rust est passé à LLVM 3.6 en juillet. Les versions actuelles de Rust et emscripten-fastcomp sont donc incompatibles.

J'ai essayé de compiler rust avec --llvm-root pointant vers emscripten-fastcomp 1.29.2 et j'ai obtenu cette erreur :

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

Pour obtenir cette erreur, j'ai configuré et construit emscripten-fastcomp avec

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

Au lieu du guide d'emscripten recommandé

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

Bien que Rust n'ait pas besoin d'être construit pour toutes les cibles, il est actuellement toujours lié à LLVM avec un support CPU compilé pour toutes les cibles. Il s'agit d'une solution de contournement pour un problème qui pourrait être résolu à l'avenir, nous n'aurons donc peut-être pas besoin de toujours compiler emscripten-fastcomp avec cette configuration.

Une fois que j'ai découvert que Rust était passé à LLVM 3.6, j'ai recherché la dernière branche sur rust-lang/llvm qui était LLVM 3.5. https://github.com/rust-lang/llvm/tree/rust-llvm-2014-07-24 J'ai compilé contre cela au lieu d'emscripten-fastcomp, curieux de voir ce qui se passerait. J'ai eu exactement la même erreur lors de la compilation avec le récent passage à LLVM 3.5 d'emscripton-fastcomp. Je suppose que cela signifie que Rust est en quelque sorte incompatible avec LLVM 3.5 maintenant et je ne m'attendrais pas vraiment à le contraire.

Alors maintenant, nous attendons ou devons obtenir emscripten-fastcomp à LLVM 3.6 :wink:

Il convient de mentionner que j'ai téléchargé une copie archivée 0.11 et que j'ai pu produire LLVM IR pour hello world que emcc compris mais a ensuite atteint le problème de la liaison. C'était assez excitant de le voir dépasser la compréhension du byte code, mais en fait, il faudra travailler dans la base du code rouille pour le lier.

J'ai jeté un coup d'œil à la fusion de rust-lang/llvm dans emscripten-fastcomp. À l'époque, il y avait 117 sections en conflit sur 43 fichiers.

J'ai mentionné l'obtention de Rust 0.11 et emcc 1.29.2 pour accéder à l'étape de liaison. Voici le résultat spécifique :

$ 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

Il semble que emcc/fastcomp remplace les points dans les symboles par des traits de soulignement tandis que Rust s'attend à préfixer avec un autre trait de soulignement, mais je n'en suis pas trop sûr. Le premier symbole non résolu apparaît sous la forme __ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0.11.0E dans libstd dans la version i686-apple-darwin. Même si je pouvais faire en sorte qu'emcc sache comment trouver ce symbole dans les bibliothèques construites, je suppose que les bibliothèques contiennent du code machine alors qu'emcc aura besoin de codes d'octets LLVM. Je pense que je me souviens de quelqu'un qui a mentionné avoir besoin de compiler la bibliothèque standard pour emscripten. Cela ferait partie de la nécessité de cela.

Voici donc les prochaines étapes sur lesquelles je cherche à essayer de travailler si quelqu'un veut se lancer lui-même. (Ou peut me faire savoir à quel point j'ai raison ou tort.)

  • Fusionner rust-lang/llvm dans emscripten-fastcomp
  • Construire la rouille avec fastcomp fusionné sans prise en charge du backend JS
    En espérant que ce sera un bon test de santé mentale pour la fusion.
  • Ajoutez le triple d'emscripten à Rust et construisez-le
    D'après ce que je peux dire, il y a un certain nombre de fichiers que je dois modifier ou ajouter.

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

    • rt/arch/asmjs/{morestack.S,record_sp.S} (peut-être vide ?)

      Ces fichiers sont nécessaires pour créer morestack.a pour que Rust prenne en charge la pile segmentée de LLVM. Si je me souviens bien, la pile d'Emscripten est aussi la tête. Il utilise l'extrémité opposée du tas comme pile et comme pour asmjs, vous ne pouvez pas modifier la taille du tableau, la création de nouveaux segments de pile n'est pas possible. J'ai vu un champ dans TargetOption dans les fichiers cibles librustc_back qui, espérons-le, peut désactiver cela.

    • librustc_trans/trans/cabi_asmjs.rs

    • librustc_trans/trans/cabi.rs

      Je ne sais pas si ceux-ci seront nécessaires, actuellement juste une supposition.

    • 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()

  • Implémenter les interfaces système manquantes
    J'ai vu en novembre que libgreen avait été supprimé. Étant donné qu'emscripten doit attendre un moyen de partager avec les travailleurs dans les navigateurs, si cela se produit, quelque chose comme libgreen devrait être restauré ou pthread calé d'une certaine manière spécifiquement pour emscripten, comme la façon dont rouille se construit pour les pthreads ou les threads Windows api.

OI aussi. Probablement d'autres parties que je ne connais pas.

"Fusionner rust-lang/llvm dans emscripten-fastcomp"

Vous ne voudrez peut-être pas faire cela - Emscripten est basé sur pnacl-llvm/pnacl-clang, vous créez donc un fork avec des correctifs sur des correctifs, ce qui sera probablement douloureux. Si vous êtes intéressé, vous pouvez voir quelques détails du branchement dans l'enquête que j'ai effectuée pour la fusion Emscripten de r33 -> r34 à l' adresse https://github.com/kripken/emscripten-fastcomp/issues/51#issuecomment -62323164 .

J'ai entendu dire que pnacl prévoit de suivre un peu plus en amont qu'avant, mais je ne vois aucun problème pertinent dans le suivi des problèmes pnacl pour mettre à jour vers la 3.6, donc cela peut prendre un certain temps (surtout étant donné que la 3.6 n'a été branchée qu'il y a 5 jours !). ..Je suppose que vous pourriez créer un problème ? Si vous décidez de ne pas utiliser votre propre fork Emscripten, je vois deux options - attendre pnacl ou aider Emscripten à quitter pnacl et à remonter en amont.

Edit : corrigé 'maintenant' en 'pas'. Une différence cruciale.

Je fais un effort de triage massif pour nous préparer pour la 1.0. Dans le cadre de cela, je déplace des éléments de type liste de souhaits vers le référentiel RFC, car c'est là que les nouvelles choses majeures devraient être discutées/priorisées.

Ce problème a été déplacé vers le référentiel RFC : rust-lang/rfcs#604

Cette page vous a été utile?
0 / 5 - 0 notes