Praktikum bei der Haxe Foundation

Ich präsentiere Ihnen die Übersetzung eines anderen Berichts von HaxeUp Sessions 2019 Linz . Ich glaube, dass er eine gute Ergänzung zum vorherigen ist , weil setzt das Thema der Änderungen in Haxe, die 2019 stattfanden, sowie ein kleines Gespräch über seine Zukunft fort.
Ein wenig über den Autor des Berichts: Aurel Bili hat sich mit Haxe getroffen , der an verschiedenen Game Jams teilgenommen hat, und er nimmt weiterhin daran teil (zum Beispiel hier ist sein Spiel aus dem letzten Ludum Dare 45 ).


Bild


Aurel absolviert derzeit ein Studium am Imperial College London, das ein obligatorisches Praktikum vorsieht. Das erste Praktikum, das er absolvierte, fand in einem abgelegenen Büro statt. Der Weg dorthin nahm viel Zeit in Anspruch. Er hoffte daher, dass das nächste Training aus der Ferne durchgeführt werden könne.


Bild


So kam es, dass die Haxe Foundation lange Zeit keinen Mitarbeiter für die Position des Compiler-Entwicklers finden konnte. Aurel beschloss, sein Glück zu versuchen und sandte einen Brief mit der Bitte um Fernarbeit. Er hatte Glück - er wurde für ein sechsmonatiges Praktikum mit der Möglichkeit angenommen, von London aus zu arbeiten.


Bild


Bei der Einrichtung des Geräts wurde das Aufgabenspektrum vereinbart, mit dem Aurel beauftragt wird (obwohl nicht alles realisiert wurde).


Bild


Was hat er gemacht


Zunächst wurde die Dokumentation , die sich in einem traurigen Zustand befand: Alle Änderungen in der Syntax, neue Funktionen der Sprache und des Compilers wurden beschrieben, Abschnitte über Strings, Literale und Konstanten wurden ergänzt.


Bild


Alle Dokumentationen wurden von LaTeX nach Markdown übersetzt !


Bild


Zweitens wurde die Formatierung des Standard-Bibliothekscodes auf einen einzigen Stil reduziert (da verschiedene Personen mit unterschiedlichen Codestilen über 10 Jahre daran gearbeitet haben). Somit belegte Aurel im Haxe-Compiler-Repository den siebten Platz in der Anzahl der hinzugefügten Codezeilen :)


Bild


Drittens arbeitete Aurel auch an der Standardbibliothek und am Compiler:
Der Map Container verfügt beispielsweise über eine neue clear() -Methode, mit der alle gespeicherten Werte entfernt werden. Dies wurde hauptsächlich durchgeführt, um die Arbeit mit Containern zu vereinfachen, die als final Variablen erstellt wurden (dh, ihnen kann kein neuer Wert zugewiesen, aber sie können geändert werden):


Bild


Für Objekte vom Typ Date wurden Methoden zum Arbeiten mit Datumsangaben im UTC-Format (Universal Universal Time) eingeführt. Die Arbeit an ihnen hat gezeigt, wie schwierig es ist, eine einzige API zu implementieren, die auf allen 11 von Haxe unterstützten Sprachen / Plattformen gleichermaßen funktioniert.


Bild


Im alten Compiler wurden die Definitionen und Meta-Tags in OCaml definiert. Jetzt werden sie im JSON-Format beschrieben, wodurch das Parsen durch externe Dienstprogramme vereinfacht werden soll (z. B. um automatisch Dokumentation zu generieren):


Bild


Möglicherweise stellen Sie auch fest, dass der Kompilierungsserver bei großen Projekten sehr viel Speicher belegt.


Bild


Um dieses Problem zu lösen, haben Simon Kraevsky und Aurel das Binärformat hxb entwickelt, mit dem der typisierte AST serialisiert wird. Jetzt kann der Kompilierungsserver das Modul in den Arbeitsspeicher laden, damit arbeiten, bis es benötigt wird, und es dann aus dem Arbeitsspeicher in eine Datei im Format hxb entladen und den belegten Arbeitsspeicher freigeben.


Bild


Die hxb-Formatspezifikation ist in einem separaten Repository verfügbar, und ihre aktuelle Implementierung im Compiler (mit Serializer / Deserializer) liegt in einem separaten Haxe-Zweig . Die Arbeit an dieser Funktion ist noch nicht abgeschlossen und wird möglicherweise in Haxe 4.1 angezeigt.


Bild


Der vierte und wichtigste Schwerpunkt der Arbeit von Aurel während des Praktikums war die Erstellung einer neuen asynchronen System-API - asys.


Bild


Die Notwendigkeit zu seiner Erstellung beruht auf der Tatsache, dass die vorhandene API keine einfachen Möglichkeiten zur asynchronen Ausführung von Systemoperationen bietet. Um beispielsweise asynchron mit Dateien zu arbeiten, müssen Sie einen separaten Thread erstellen, in dem die erforderlichen Vorgänge ausgeführt werden, und dessen Status manuell steuern. Darüber hinaus verfügt die aktuelle API nicht über alle Funktionen für die Arbeit mit UDP-Sockets, die sich in Standardbibliotheken in anderen Sprachen befinden. IPC-Sockets werden nicht unterstützt.


Bild


Beim Erstellen und Implementieren einer neuen API stellen sich viele Fragen:


Wie entwerfe ich eine API? Vielleicht lohnt es sich, ein bestehendes Beispiel zu nehmen? Schließlich wollen wir nicht alles von Grund auf neu erstellen, weil Es wird mehr Zeit in Anspruch nehmen und möglicherweise nicht dem Geschmack des restlichen Teams entsprechen und viel Debatte auslösen.


Wie bereits erwähnt, besteht das eigentliche Problem für Haxe in der Implementierung einer einzigen API für alle unterstützten Plattformen.


Bild


API Node.js. wurde als Beispiel ausgewählt. Es ist durchdacht, unterstützt die notwendigen Systemfunktionen und eignet sich gut zum Erstellen von Serveranwendungen.


Bild


Gleichzeitig ist die Node.js-API eine Javascript-API ohne starke Typisierung. Beispielsweise können Funktionen des Moduls fs für die Arbeit mit dem Dateisystem als Pfade entweder Zeichenfolgen oder Objekte wie Buffer und sogar URL . Und das ist nicht so gut für Haxe.


Bild


Node.js verwendet wiederum die in C geschriebene libuv-Bibliothek . Das direkte Arbeiten mit der libuv-API von Haxe wäre nicht so praktisch: Um beispielsweise die Datei asynchron umzubenennen, müssten Sie zusätzlich Objekte wie uv_loop_t (Struktur für die Verwaltung) erstellen event loop in libuv) und uv_fs_t (Struktur zur Beschreibung einer Anfrage an das Dateisystem):


Bild


Als Ergebnis wurden die APIs Node.js und libuv wie folgt integriert (am Beispiel der Methode eval macro interpreter and rename):


  • Sie haben die API-Methode von Node.js übernommen, in Haxe konvertiert und versucht, die Argumenttypen zu standardisieren und redundante Argumente für Haxe zu entfernen. Zum Beispiel sind FilePath (vom Typ FilePath ) Abstracts über Strings:

Bild


  • Dann erstellte OCaml-Ordner für diese Methode:

Bild


  • verknüpfte OCaml und C (unter Verwendung der CFFI-C-Fremdfunktionsschnittstelle):

Bild


  • und schrieb schließlich C-Binder, um libuv C-Funktionen von OCaml aufzurufen:

Bild


Ähnlich wurde es für HashLink und Neko gemacht (im Moment ist die asys API nur für diese drei Plattformen implementiert). Wie Sie vielleicht erraten haben, hat es eine Menge Arbeit gekostet.


Aurel zeigte einige kleine Anwendungen, die demonstrierten, wie die asys-API funktioniert.
Das erste Beispiel ist eine Demonstration des asynchronen Lesens des Inhalts einer Datei. Bisher werden im Code explizit Methoden zum Initialisieren von libuv ( hl.Uv.init() ) und Starten des Anwendungszyklus ( hl.Uv.run() ) hl.Uv.run() , da die Arbeit an der API noch nicht abgeschlossen wurde (aber in der Zukunft) sie werden automatisch hinzugefügt):


Bild


Das Ergebnis des angezeigten Codes:


Bild


Wir sehen, dass die Ergebnisse der aufgerufenen AsyncFileSystem.readFile() -Methoden in der Konsole nach der AsyncFileSystem.readFile() angezeigt werden, die im Code aufgerufen wird, nachdem versucht wurde, den Inhalt der Dateien zu lesen.


Das zweite Beispiel zeigt den asynchronen Betrieb mit DNS- und IP-Adressen.


Bild


In der neuen API wird es viel einfacher, den Hostnamen sowie Hilfsmethoden für die Arbeit mit IP-Adressen zu ermitteln.


Bild


Das dritte Beispiel ist ein einfacher TCP-Echoserver, für dessen Erstellung nur drei Codezeilen erforderlich sind:


Bild


Ein viertes Beispiel ist eine Demonstration des Informationsaustauschs zwischen Prozessen:
Die statische Methode makeFrame() in diesem Beispiel erstellt separate PNG-Bilder:


Bild


und in der main starten wir den ffmpeg-Prozess, in den wir die in makeFrame() generierten Frames makeFrame() :


Bild


und die Ausgabe wird eine Videodatei sein:


Bild


Und das fünfte Beispiel ist UDP-Video-Stream. Hier wird wie im vorherigen Beispiel der ffmpeg-Prozess gestartet, aber dieses Mal wird das Video abgespielt und die Daten werden an den Standardausgabestream ausgegeben. Es wird auch ein UDP-Socket erstellt, der Daten aus dem ffmpeg-Prozess übersetzt.


Bild


Und schließlich teilen wir die von ffmpeg empfangenen Daten in kleinere "Teile" auf und übersetzen sie in den angegebenen Port:


Bild


Als Ergebnis erhalten wir einen funktionierenden Videostream:


Bild


Zusammenfassend beinhaltet die neue asys API:


  • Methoden für die Arbeit mit dem Dateisystem, einschließlich neuer Funktionen, die sich nicht in der Standardbibliothek befanden (z. B. zum Ändern von Berechtigungen), sowie asynchrone Versionen aller in der alten Standardbibliothek verfügbaren Funktionen
  • Unterstützung für asynchronen Betrieb mit TCP / UDP / IPC-Sockets
  • Methoden für die Arbeit mit DNS (bisher 2 Methoden: lookup und reverse )
  • sowie Methoden für das asynchrone Arbeiten mit Prozessen.

Bild


Die Arbeiten an der asys-API sind noch nicht abgeschlossen, es gibt derzeit einige Probleme mit dem Garbage Collector, wenn Sie mit der libuv-Bibliothek arbeiten. Pull Request mit den entsprechenden Änderungen wurde noch nicht in den Hauptzweig von Haxe aufgenommen. Kommentare dazu begrüßen Meinungen zu den Namen der neuen Methoden, deren Signaturen und der Dokumentation.
Wie bereits erwähnt, wird die Unterstützung der asys-API nur für HashLink, Eval und Neko (in Form von drei separaten Pull-Requests) implementiert. Aurel hat bereits einen Plan für das Hinzufügen von Unterstützung für die neue API für C ++ und Lua erstellt. Die Implementierung für andere Plattformen erfordert zusätzliche Forschung.


Bild


Es ist möglich, dass die asys-API in Haxe 4.1 verfügbar wird (jedoch nur auf einigen Plattformen).


Aurel sprach auch über sein Nebenprojekt - die Ammer-Bibliothek (die dennoch mit seiner Arbeit bei der Haxe Foundation verbunden ist).


Bild


Ammers Ziel ist es, die Erstellung von Bindemitteln für C-Bibliotheken so zu automatisieren, dass sie sowohl in HashLink als auch in HXCPP verwendet werden können (im Oktober 2018 stellte Lars Duse eine Gebühr für die Lösung dieses Problems fest).


Warum war diese Aufgabe relevant? Tatsache ist, dass das Erstellen von Bindemitteln für HashLink und HXCPP zwar ähnlich ist, Sie jedoch für jede Plattform Ihren eigenen Klebercode schreiben müssen.


Aurel hat ungefähr dasselbe getan, als er die libuv-Bibliothek in Haxe integriert hat - für Eval, Neko und HashLink musste er denselben Code schreiben, der sich nur in Details unterschied (Funktionsaufrufe, Unterschiede in der Arbeit von FFI usw.):


Bild


Eine ähnliche Arbeit musste auf der Haxe-Seite ausgeführt werden, damit native Funktionen daraus aufgerufen werden konnten:


Bild


Und die Idee von ammer ist, die Haxe-Version der API zu verwenden, die nicht mit redundanten Informationen überladen ist, und diesen Code irgendwie für alle Plattformen funktionsfähig zu machen:


Bild


Was ammer jetzt benötigt, um externe C-Bibliotheken zu verwenden:


  • Erstellen Sie die Haxe-Spezifikation für die Bibliothek, die im Wesentlichen außerhalb der verwendeten Bibliothek liegt
  • Anwendungscode schreiben
  • Kompilieren Sie das Projekt, indem Sie Pfade zu Headerdateien und C-Bibliotheksdateien angeben
  • ...
  • Gewinn

Bild


Unter der Haube macht ammer Folgendes:


  • passt Typen abhängig von der Zielplattform an
  • generiert automatisch C-Code zum Aufrufen nativer Funktionen
  • generiert ein Makefile, das zum Erstellen von hdll- und ndll-Dateien verwendet wird

Bild


Ammer unterstützt derzeit:


  • einfache funktionen
  • definiere sie aus den Header-Dateien (im Hax-Code kann auf sie als Konstante zugegriffen werden)
  • Zeiger

Unterstützung geplant:


  • Rückrufe (sie sind noch Mangelware)
  • und Strukturen (sehr notwendig für die Arbeit mit der C-API)

Bild


Jetzt arbeitet ammer mit C ++, HashLink und Eval. Und Aurel ist sicher, dass er Unterstützung für andere Systemplattformen hinzufügen kann.


Bild


Um die Fähigkeiten von ammer zu demonstrieren, zeigte Aurel eine kleine Anwendung, die den Lua-Interpreter ausführt:


Bild


Die darin verwendeten Bindemittel sind wie folgt:


Bild


Wie Sie sehen, sind einige Methoden auskommentiert, weil Sie verwenden Rückrufe, deren Unterstützung noch nicht realisiert wurde, aber Aurel hofft, dass er dies bald beheben kann.


Bild


Wofür kann ammer verwendet werden:


  • Einbetten einer virtuellen Lua-Maschine
  • Erstellen von Anwendungen in SDL
  • Eine Automatisierung der Arbeit mit libuv ist möglich (wie bereits gezeigt, ist jetzt viel handgeschriebener Code erforderlich, um mit libuv zu arbeiten).
  • und natürlich wird es die Verwendung vieler anderer nützlicher C-Bibliotheken (wie OpenAL, Dear-Imgui usw.) erheblich vereinfachen.

Bild


Obwohl Aurels Praktikum bei der Haxe Foundation beendet ist, plant er, weiterhin mit Haxe, as zusammenzuarbeiten Seine Hochschulausbildung ist noch nicht abgeschlossen und er muss noch seine Abschlussarbeit schreiben. Aurel weiß bereits, wofür es gewidmet sein wird - die Arbeit des Garbage Collectors in HashLink zu verbessern. Nun, es wird interessant sein!

Source: https://habr.com/ru/post/de475226/


All Articles