Rust: Lassen Sie Rust mit emscripten arbeiten

Erstellt am 18. Apr. 2012  ·  30Kommentare  ·  Quelle: rust-lang/rust

Ich habe einige Zeit damit verbracht, an diesem Problem herumzustochern, und rustc generiert jetzt Code, den Emscripten übersetzen kann, aber das kompilierte Javascript schlägt fehl, wenn es auf eine Laufzeitfunktion trifft. Der nächste Schritt besteht darin, mit dem Erstellen der Laufzeit mit emcc als Compiler zu beginnen. Stub all die Dinge heraus, die nicht hinter EMSCRIPTEN ifdefs aufbauen.

Emscripten fügt eine Möglichkeit hinzu, Inline-Assembly als Javascript zu behandeln, sodass alle Teile der Laufzeit, die nicht mit Emscripten erstellt werden, inline mit Javascript implementiert werden können.

Alternativ könnten wir die Laufzeit stückchenweise in Javascript neu implementieren und uns überhaupt nicht die Mühe machen, sie aus C++ zu kompilieren. Dieser Ansatz wird nicht empfohlen.

A-runtime E-hard

Hilfreichster Kommentar

Ich unternehme eine massive Triage-Anstrengung, um uns auf 1.0 vorzubereiten. Als Teil davon verschiebe ich Dinge, die einer Wunschliste ähnlich sind, in das RFCs-Repo, da dort wichtige neue Dinge diskutiert / priorisiert werden sollten.

Dieses Problem wurde in das RFCs-Repository verschoben: rust-lang/rfcs#604

Alle 30 Kommentare

Siehe auch #3608.

Wäre trotzdem schön; nicht auf einem Reifegrad-Meilenstein.

Wäre trotzdem nett, ist aber nicht sehr wichtig. Dies sollte einfacher werden, da ein Großteil der Laufzeit in Rost umgeschrieben wird.

Nun, da die Laufzeit in Rust geschrieben ist, wie ändert das die Aussichten für diesen Fehler? Wie schwer wäre es, eine laufzeitlose Hello World über emscripten zum Laufen zu bringen?

Es sollte nicht besonders schwierig sein, jetzt wirklich nette Unterstützung für Emscripten hinzuzufügen. Mit Rostkern funktioniert es schon ziemlich gut. Im Compiler müssen wir Unterstützung für das richtige Zieltripel hinzufügen, die verschiedenen Zielattribute richtig einrichten und dann die wenigen Teile der Laufzeit abgrenzen, die derzeit nicht in js, Threading und Kontextwechsel funktionieren.

Sobald der 1:1-Planungsmodus etwas ausgereift ist, können wir möglicherweise sogar Unterstützung für Aufgaben über Webarbeiter hinzufügen, obwohl dies derzeit eine andere Lösung für die Nachrichtenweitergabe erfordert. Abhängig davon, welche Parallelitätsunterstützung zu js/emscripten hinzugefügt wird, können wir möglicherweise die Message-Passing-Semantik von Rust präzise unterstützen.

@brson : Ich denke, #10780 wäre im Moment der größte Blocker. Rust gibt Landepads mit Aufrufen aus, um die Größe zu aktualisieren, die für die Stack-Sicherheit über die segmentierte Stack-Unterstützung von LLVM verwendet wird.

Dank -Z no-landing-pads funktioniert das jetzt einwandfrei! Das Hinzufügen einer expliziten Unterstützung dafür zur Standardbibliothek ist möglich, aber die meisten werden sowieso nicht funktionieren (Dateien, TCP, UDP usw.), daher glaube ich nicht, dass es notwendig ist. Wenn die Standardbibliothek freistehende Unterstützung erhält, wird sie funktionieren und wir können basierend auf der Funktionalität, die wir JavaScript zuordnen können, weitere Probleme öffnen.

Wenn es ok ist, würde ich das jetzt eigentlich gerne offen lassen. Ich denke, dies wäre ein guter Schritt, um sicherzustellen, dass die Standardbibliothek erweiterbar ist und auf einer beliebigen Anzahl von Plattformen ausgeführt werden kann.

Ich stimme zu, dass die meiste Arbeit wahrscheinlich erledigt ist, und dies wird wahrscheinlich libemscripten benötigen, um emscripten-spezifische I/O bereitzustellen, aber ich denke, dass es auf dem Weg genug Hindernisse geben könnte, die es wert sind, dies zu verlassen das Thema offen für (es ist immer noch ein interessantes Projekt!)

@alexcrichton : Es wird nicht möglich sein, die Parallelität und E/A-Unterstützung der Standardbibliothek für emscripten bereitzustellen. Bestenfalls könnte es für stdout/stderr an die Konsole ausgegeben werden. Ich kann mir keine Dinge in der Standardbibliothek vorstellen, die für ein Emscripten-Ziel eine gute Idee sind, aber keine freistehende, abgesehen von einer Standardzuordnungsimplementierung.

Status-Update:

@alexcrichton Hat die Standardbibliothek in eine Reihe kleinerer Bibliotheken mit verständlicheren Abhängigkeiten umgestaltet. Es sollte fast trivial sein, die Core-, Alloc-, Rand- und Collections-Bibliotheken jetzt ins Web zu kompilieren.

Hier ist, wie ich vorschlagen würde, dies anzugehen:

  • Führen Sie einige Experimente mit den Toolchains rust und LLVM durch, um zu verstehen, wie der Codegen für die Cross-Kompilierung in asm.js funktioniert.
  • Erstellen Sie libcore mit emscripten manuell und beweisen Sie, dass es im Web funktioniert.
  • Ändern Sie rustc und mk/platform.mk, um ein Emscripten-spezifisches Ziel-Triple zu verstehen, und erstellen Sie eine Cross-Compile-Toolchain, die nur libcore.rlib enthält
  • Bekämpfen Sie liballoc, indem Sie ihm erlauben, mit dem System (in diesem Fall dem von Emscripten bereitgestellten) malloc zu arbeiten, und dann mit den anderen laufzeitfreien Crates.

Das ist ein ziemlich guter Anfang!

Ok, also ich habe es mit den ersten Schritten versucht, und offensichtlich Probleme auf Anhieb bekommen.

Ich habe libcore mit --emit bc libcore in Bitcode kompiliert, und wenn ich versuche, es mit emcc -O0 zu kompilieren, erhalte ich:

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

Ich bin mir nicht sicher, ob ich etwas dagegen tun kann, oder weil wir die Ausgabe von rustc --emit dafür nicht verwenden können.

Entschuldigung, wenn dies nicht der richtige Ort ist, um dies zu kommentieren ...

Ich habe es auch mit libnum versucht, einem einfacheren, und das bc wird korrekt generiert, aber ich erhalte während des emcc Prozesses eine Warnung wegen der Verwendung des falschen Tripels und des resultierenden . js hat keine der Funktionen in libnum , daher denke ich, dass ich hier zu naiv bin :)

@Arcnor Vielleicht fragen Sie einige von denen, die zuvor einfache Tests mit emscripten zusammengestellt haben, zu ihrem Prozess. Ich habe nur wenige Ideen.

  • Der LLVM-Bitcode ändert sich von Version zu Version und die von Rust verwendete Version ist nicht immer dieselbe wie emscripten. Wenn Sie beide eine relativ ähnliche Version von LLVM verwenden, kann dies die Kompatibilität verbessern.
  • Aus Ihrer Fehlermeldung geht hervor, dass Sie das neue 'fastcomp'-Backend von emscripten verwenden. Dies wird möglicherweise weniger auf Rusty-Workloads getestet als auf ihrem alten Back-End. Wenn Sie sich manuell für das alte Backend entscheiden, kann dies zumindest zu anderen Ergebnissen führen.
  • Emscripten verwendet im Allgemeinen ein eigenes Zieltripel, daher muss rustc möglicherweise dazu gebracht werden, dasselbe zu verwenden.

Der Fehler beim Versuch, libcore zu kompilieren, scheint mit diesem Emscripten-Problem zusammenzuhängen. Das Kompilieren von libcore zu llvm-Bytecode erzeugt atomare llvm-Befehle, aber emscripten unterstützt keine atomaren Befehle.

Es mag eine Möglichkeit geben, dies von der Rostseite aus zu umgehen, aber basierend auf den Kommentaren in der Emscripten-Ausgabe denke ich, dass es am sinnvollsten ist, Unterstützung für Atomics in Emscripten zu bekommen.

Wenn emscripten eine eigene Plattform hat, könnten wir vielleicht alle Atomics für ihre Singlethread-Varianten cfg-out, aber ich stimme zu, dass es schöner wäre, dies in Upstream-emscripten zu haben!

Wenn ich mich nicht irre, ist das neue "fastcomp"-Backend von emscripten ein Fork von LLVM (während das vorherige Backend nur eine Schicht über LLVM war), daher ist die LLVM-Version von fastcomp wahrscheinlich schwer zu aktualisieren und wird nicht aktualisiert häufig.

Dies wird problematisch, wenn es mit der Ausgabe von Rust kompatibel sein muss. Im Moment ist zum Beispiel die LLVM-Version von fastcomp 3.3, während die von Rust verwendete LLVM 3.4 ist.

Das alte Emscripten-Backend ist veraltet und sollte gemäß den offiziellen Dokumenten nicht verwendet werden, daher ist es wahrscheinlich keine Option, es zu verwenden.

Ich scheine im Moment der einzige zu sein, der versucht, für Emscripten zu kompilieren.

Fürs Protokoll, hier sind die Dinge, die ich versucht habe:

  • Kompilieren in Bytecode (erzeugt von Rusts LLVM 3.4) und Übergabe an fastcomp (Fork von LLVM 3.3); führt zum Absturz von Fastcomp
  • In IR kompilieren, manuell bearbeiten, bis es mit LLVM 3.3 kompatibel ist, und an fastcomp übergeben; zu kompliziert, zu viele Dinge für jeden nicht trivialen Code zu ändern
  • Das Kompilieren von Rust stage1 mit --llvm-root zeigte auf Fastcomp von emscripten; das hat nicht funktioniert, weil sie die Unterstützung für ARM/MIPS/etc entfernt haben. in ihrem Fork (aus diesem Grund bekomme ich Fehler von den Makefiles und während der Verknüpfung)
  • Ändern Sie das LLVM-Git-Submodul im Quellcode von Rust so, dass es auf einen alten Commit aus der 3.3-Ära verweist; Irgendwann in LLVM einen Segfault bekommen
  • Das Kompilieren von Rust mit --llvm-root wies auf ein vorkompiliertes LLVM 3.3 (aus dem offiziellen Ubuntu-Repository) hin; Das Abrufen einer Assertion am Ende der Kompilierung von stage1 ist fehlgeschlagen und die erzeugte rustc-Binärdatei funktioniert nicht.

Sofern nicht jemand eine Idee hat, ist meine Schlussfolgerung, dass wir auf das Upgrade von Emscripten warten müssen.

Rum scheint es zu haben, irgendwie; vielleicht hilft das

Kleines Update: emscripten-fastcomp wurde auf LLVM 3.4 aktualisiert und wird später auf LLVM 3.5 aktualisiert.

@tomaka hast du versucht, etwas mit der Version 3.4 zu tun? Ich konnte das Rum-Beispiel damit kompilieren, aber alles andere scheiterte mit unverständlichen Fehlern.

@ibdknox 3.4 ist nicht kompatibel mit 3.5
Selbst eine einfache Hallo-Welt erzeugt eine fehlgeschlagene Behauptung: LLVM ERROR: 0 && "some i64 thing we can't legalize yet"

Hm. Ich konnte die Ausgabe von rustc --emit ir foo.rust und durch emscripten-incoming laufen lassen. Ist Rost jetzt auf LLVM 3.5?

Rust verwendet LLVM 3.5 schon seit langem. Sie können Glück haben und nichts Inkompatibles generieren lassen.
Das lässt sich zum Beispiel gut kompilieren:

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

Dies liegt nicht an inkompatibler IR:

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

@ibdknox http://www.reddit.com/r/rust_gamedev/comments/2n0x08/emscripten_experiments/
Es sieht so aus, als ob es weniger Inkompatibilitäten gibt, als ich dachte.

Als Update, wenn ich hello world mit emscripten kompiliere, das jetzt auf 3.5 aktualisiert wurde, erhalte ich Folgendes:

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:

So kompiliere ich:

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

Dinge, die fmt nicht zu bringen scheinen, scheinen jedoch im Allgemeinen zu funktionieren.

Ich habe letzte Woche meine Freizeit damit verbracht, mich damit zu befassen. Ich habe Rusts Buch irgendwann zwischen dem Sommer und jetzt gelesen und die Mechanik der Sprache hat mir sehr gut gefallen, aber erst vor kurzem habe ich angefangen, etwas damit zu implementieren. Ich kenne den Rost-Compiler nur so gut wie das, was ich diese Woche gelernt habe, aber ich hoffe, ich kann dazu beitragen.

Ich denke, das erste, was ich gelernt habe (aber ich habe ein paar Abende gebraucht, um es zu bemerken), ist, dass Rust im Juli auf LLVM 3.6 umgestiegen ist. Daher sind die aktuellen Versionen von Rust und emscripten-fastcomp nicht kompatibel.

Ich habe versucht, rust mit --llvm-root zu kompilieren, das auf emscripten-fastcomp 1.29.2 verweist, und habe diesen Fehler erhalten:

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

Um zu diesem Fehler zu gelangen, habe ich emscripten-fastcomp konfiguriert und gebaut mit

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

Anstelle der empfohlenen Anleitung des Emscriptens

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

Obwohl Rust nicht für alle Ziele erstellt werden muss, verknüpft es derzeit immer mit LLVM mit CPU-Unterstützung, die für alle Ziele kompiliert wurde. Dies ist eine Problemumgehung für ein Problem, das in Zukunft behoben werden könnte, sodass wir emscripten-fastcomp möglicherweise nicht immer mit dieser Konfiguration kompilieren müssen.

Als ich feststellte, dass Rust auf LLVM 3.6 umgestiegen war, suchte ich den letzten Zweig auf rust-lang/llvm nach, der LLVM 3.5 war. https://github.com/rust-lang/llvm/tree/rust-llvm-2014-07-24 Ich habe dagegen anstelle von emscripten-fastcomp kompiliert, gespannt, was dabei herauskommen würde. Ich habe genau den gleichen Fehler beim Kompilieren gegen emscripton-fastcomp, der kürzlich auf LLVM 3.5 umgestellt wurde. Ich verstehe das so, dass Rust jetzt irgendwie inkompatibel mit LLVM 3.5 ist und ich nicht wirklich etwas anderes erwarten würde.

Also warten wir jetzt oder müssen emscripten-fastcomp auf LLVM 3.6 bringen :wink:

Es ist erwähnenswert, dass ich eine archivierte 0.11-Kopie heruntergeladen habe und in der Lage war, LLVM-IR für hallo world zu erstellen, die emcc verstanden hat, aber dann das Problem der Verknüpfung erreichte. Es war ziemlich aufregend zu sehen, wie es über das Verständnis des Byte-Codes hinausging, aber die eigentliche Verknüpfung erfordert Arbeit in der Rostcode-Basis.

Ich habe einen Blick darauf geworfen, wie rust-lang/llvm in emscripten-fastcomp zusammengeführt wird. Damals gab es 117 widersprüchliche Abschnitte über 43 Dateien.

Ich habe erwähnt, dass ich Rust 0.11 und emcc 1.29.2 bekomme, um zur Linking-Phase zu gelangen. Dies ist das konkrete Ergebnis:

$ 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

Scheint, dass emcc/fastcomp Punkte in Symbolen durch Unterstriche ersetzt, während Rust erwartet, einen anderen Unterstrich voranzustellen, aber ich bin mir da nicht ganz sicher. Das erste unaufgelöste Symbol erscheint als __ZN2io5stdio12println_args20h0caae70b0e2eb347Iol7v0.11.0E in libstd im i686-apple-darwin-Build. Selbst wenn ich emcc dazu bringen könnte, dieses Symbol in den erstellten Bibliotheken zu finden, vermute ich, dass die Libs Maschinencode enthalten, während emcc LLVM-Bytecodes benötigt. Ich glaube, ich erinnere mich, dass jemand erwähnt hat, dass die Standardbibliothek für emscripten kompiliert werden muss. Dies wäre ein Teil der Notwendigkeit dafür.

Hier sind also die nächsten Schritte, die ich ausprobieren und bearbeiten möchte, wenn jemand sie selbst ausprobieren möchte. (Oder kann mir sagen, wie richtig oder falsch ich liege.)

  • Zusammenführen von rust-lang/llvm in emscripten-fastcomp
  • Bauen Sie Rost mit zusammengeführtem Fastcomp ohne JS-Backend-Unterstützung auf
    In der Hoffnung, dass dies ein guter Gesundheitstest für die Zusammenführung wird.
  • Füge das Triple von Emscripten zu Rust hinzu und baue es
    Soweit ich das beurteilen kann, muss ich eine Reihe von Dateien ändern oder hinzufügen.

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

    • rt/arch/asmjs/{morestack.S,record_sp.S} (könnte leer sein?)

      Diese Dateien werden benötigt, um morestack.a zu erstellen, damit Rust den segmentierten Stack von LLVM unterstützt. Wenn ich mich recht erinnere, ist der Stapel von Emscripten auch der Kopf. Es verwendet das entgegengesetzte Ende des Heaps als Stack und da Sie für asmjs die Größe des Arrays nicht ändern können, ist das Erstellen neuer Stack-Segmente nicht möglich. Ich habe ein Feld in TargetOption in den librustc_back-Zieldateien gesehen, das dies hoffentlich deaktivieren kann.

    • librustc_trans/trans/cabi_asmjs.rs

    • librustc_trans/trans/cabi.rs

      Ich bin mir nicht sicher, ob diese benötigt werden, derzeit nur eine Vermutung.

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

  • Implementieren fehlender Systemschnittstellen
    Ich habe im November gesehen, dass libgreen entfernt wurde. Da Emscripten warten muss, bis eine Möglichkeit besteht, sie mit Arbeitern in Browsern zu teilen, müsste etwas wie libgreen, wenn es jemals passiert, wiederhergestellt oder auf irgendeine Weise speziell für Emscripten geshimmt werden, z.

IO auch. Wahrscheinlich andere Teile, die ich nicht kenne.

"Rust-lang/llvm in emscripten-fastcomp zusammenführen"

Vielleicht möchten Sie dies nicht tun - Emscripten basiert auf pnacl-llvm/pnacl-clang, so dass Sie eine Abzweigung mit Patches auf Patches erstellen, was wahrscheinlich schmerzhaft sein wird. Wenn Sie interessiert sind, können Sie einige Details der Verzweigung in der Untersuchung sehen, die ich für die Emscripten-Zusammenführung von r33 -> r34 durchgeführt habe unter https://github.com/kripken/emscripten-fastcomp/issues/51#issuecomment -62323164 .

Ich höre, dass pnacl plant, Upstream etwas genauer zu verfolgen als zuvor, aber ich kann kein relevantes Problem im pnacl Issue Tracker sehen, um auf 3.6 zu aktualisieren, daher kann es eine Weile dauern (insbesondere angesichts der Tatsache, dass 3.6 erst vor 5 Tagen verzweigt wurde!). ..ich denke, Sie könnten ein Problem erstellen? Wenn Sie sich gegen Ihren eigenen Emscripten-Fork entscheiden, sehe ich zwei Möglichkeiten - auf pnacl warten oder Emscripten helfen, von pnacl in den Upstream zu gelangen.

Edit: 'jetzt' auf 'nicht' korrigiert. Ein entscheidender Unterschied.

Ich unternehme eine massive Triage-Anstrengung, um uns auf 1.0 vorzubereiten. Als Teil davon verschiebe ich Dinge, die einer Wunschliste ähnlich sind, in das RFCs-Repo, da dort wichtige neue Dinge diskutiert / priorisiert werden sollten.

Dieses Problem wurde in das RFCs-Repository verschoben: rust-lang/rfcs#604

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen