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.
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.
Siehe auch https://github.com/mozilla/rust/issues/7282
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:
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 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:
--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)--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.)
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
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