Die meisten Artikel und Bücher über Erlang I könnten den Schwerpunkt auf die Erstellung lang laufender serverähnlicher Anwendungen legen, die den Prozess der Erstellung von Befehlszeilentools nicht abdecken.
Ich habe ein rebar3-Projekt mit mehreren Anwendungen, das aus drei Anwendungen besteht:
myweb
- ein cowboy
basierter Webservice; mycli
- ein Befehlszeilenwerkzeug zum Vorbereiten von Assets für myweb
; mylib
- Eine Bibliothek, die von myweb
und mycli
verwendet wird, hängt von einem NIF ab. Als Ergebnis des Builds möchte ich solche Artefakte erhalten:
Eine der Möglichkeiten, die ich in freier Wildbahn gesehen habe, ist das Erstellen einer eigenständigen Escript-Datei. Mindestens rebar
und relx
tun dies. Also habe ich es versucht.
Vorteile:
Nachteile:
mylib
; *.so
-Dateien in die resultierende Escript-Datei eingebettet werden, können sie zur Laufzeit nicht geladen werden, daher funktionieren NIFs nicht (siehe Erlang Rebar escriptize & amp; nifs ); rebar3 escriptize
behandelt Abhängigkeiten nicht gut (siehe Fehler 1139 ). Unbekannte:
Eine andere Möglichkeit zum Erstellen eines Befehlszeilenwerkzeugs wurde in einem Wie starte ich: Erlang Artikel von Fred Hebert beschrieben / p>
Vorteile:
Nachteile:
main/1
; Unbekannte:
Keiner der obigen Ansätze scheint bei mir zu funktionieren.
Es wäre das Beste aus beiden Welten: Holen Sie sich die Infrastruktur, die von escript zur Verfügung gestellt wird, wie% Co_de% Einstiegspunkt, Kommandozeilenparameter und Exit-Code-Behandlung, während immer noch eine schöne Verzeichnisstruktur, die einfach zu verpacken ist behindert nicht die Verwendung von NIFs.
Unabhängig davon, ob Sie eine lange Daemon-ähnliche Anwendung in Erlang oder einen CLI-Befehl starten, benötigen Sie immer Folgendes:
erts
application - die VM und der Kernel in einer bestimmten Version Dann muss der CLI-Einstiegspunkt in jedem Fall die Erlang-VM starten und den Code ausführen, den er in einer bestimmten Situation ausführen soll. Dann wird es entweder beendet oder weiter ausgeführt - das spätere für eine lang laufende Anwendung.
Der CLI-Einstiegspunkt kann alles sein, was eine Erlang-VM startet, z. Ein escript
script, sh
, bash
, usw. Der offensichtliche Vorteil von escript
gegenüber generischer Shell ist, dass escript
bereits im Kontext einer Erlang VM ausgeführt wird. Stoppen der VM.
Sie können Erlang VM auf zwei Arten starten:
Im ersten Fall liefern Sie weder erts
noch irgendeine OTP-Anwendung mit Ihrem Paket, Sie machen nur eine bestimmte Erlang-Version zu einer Abhängigkeit für Ihre Anwendung. Im zweiten Fall liefern Sie erts
und alle erforderlichen OTP-Anwendungen zusammen mit den Abhängigkeiten Ihrer Anwendung in Ihrem Paket.
Im zweiten Fall müssen Sie auch den Code-Stamm richtig einstellen, wenn Sie das Programm starten VM. Aber das ist ziemlich einfach, siehe das Skript erl
, mit dem Erlang die systemweite VM startet:
Dies kann durch Skripte gehandhabt werden, zum Beispiel das node_package
Werkzeug, mit dem Basho seine Riak-Datenbank für alle wichtigen Pakete paketiert Betriebssysteme. Ich behalte meine eigene Gabel , die ich mit meinem eigenen Build-Tool namens builderl
. Ich sage das nur, damit Sie wissen, dass Sie das auch gut können, wenn ich es anpassen konnte:)
Sobald die Erlang-VM gestartet wurde, sollte Ihre Anwendung in der Lage sein, alle Anwendungen zu laden und zu starten, die entweder mit Erlang oder mit Ihrer Anwendung geliefert werden (einschließlich der von Ihnen erwähnten Bibliothek mylib
). Hier einige Beispiele, wie dies erreicht werden könnte:
escript
Beispiel
Siehe dieses Beispiel für builderl.esh
, wie ich das Laden anderer handhabe Erlange Anwendungen von builderl
. Das Skript escript
setzt voraus, dass die Erlang-Installation relativ zu dem Ordner ist, aus dem sie ausgeführt wird. Wenn es Teil einer anderen Anwendung ist, wie zum Beispiel humbundee
, ist das load_builderl.hrl
include Datei kompiliert und lädt bld_load
, was wiederum alle verbleibenden Module mit %Co_de% . Beachten Sie, wie ich Standard-OTP-Anwendungen verwenden kann, ohne anzugeben, wo sie sich befinden - bld_load:boot/3
wird von builderl
ausgeführt und alle Anwendungen werden von dem Ort aus, an dem sie installiert wurden, geladen ( escript
auf meinem System). Wenn von Ihrer Anwendung verwendete Bibliotheken, z. /usr/local/lib/erlang/lib/
, werden woanders installiert, alles, was Sie tun müssen, ist, diesen Ort dem Erlang-Pfad hinzuzufügen, z. mit mylib
. Erlang lädt Module, die im Code verwendet werden, automatisch aus Ordnern, die der Codepfadliste hinzugefügt wurden.
eingebettetes Erlang
Dasselbe gilt jedoch, wenn es sich bei der Anwendung um eine ordnungsgemäße OTP-Version handelte, die unabhängig von der systemweiten Erlang-Installation installiert wurde. Das liegt daran, dass in diesem Fall das Skript von code:add_path
ausgeführt wird, das zu dieser eingebetteten Erlang-Version gehört, und nicht zur systemweiten Version (selbst wenn es installiert ist). Daher kennt es den Speicherort aller Anwendungen, die zu dieser Version gehören (einschließlich Ihrer Anwendungen). Zum Beispiel macht escript
genau das - in ihrem Paket enthalten sie eine eingebettete Erlang-Version , die ihr eigenes% co_de enthält % und alle abhängigen Erlang-Anwendungen. Auf diese Weise kann riak
gestartet werden, ohne dass Erlang sogar auf dem Host-Betriebssystem installiert wird. Dies ist ein Auszug aus einem erts
Paket auf FreeBSD:
riak
/ riak
Dies unterscheidet sich nicht wesentlich von dem oben Gesagten, abgesehen davon, dass Sie explizit die Funktion aufrufen müssen, die beim Starten der Erlang-VM ausgeführt werden soll (der Einstiegspunkt oder die sh
-Funktion, wie Sie es genannt haben).
Betrachten Sie dieses Skript, das bash
erzeugt, um eine Erlang-Anwendung zu starten, nur um eine bestimmte Aufgabe auszuführen (erzeugen Sie die Datei main
), nach der der Knoten heruntergefahren wird:
Dies ist ein ähnliches Skript, startet jedoch keinen spezifischen Code oder eine bestimmte Anwendung. Stattdessen wird eine korrekte OTP-Version gestartet. Welche Anwendungen gestartet werden und in welcher Reihenfolge, hängt von der Version ab (angegeben durch die Option builderl
).
In der Datei RELEASES
können Sie bei Bedarf zusätzliche Pfade zu Ihren Anwendungen bereitstellen, z. B .:
In diesem Beispiel sind diese relativ, könnten aber absolut sein, wenn Ihre Anwendung an einem bekannten Standardstandort installiert wird. Dies ist auch nur erforderlich, wenn Sie die systemweite Erlang-Installation verwenden und zusätzliche Pfade hinzufügen müssen, um Ihre Erlang-Anwendungen zu lokalisieren, oder wenn sich Ihre Erlang-Anwendungen an einem nicht standardmäßigen Speicherort befinden (z. B. nicht im Ordner -boot
) , wie Erlang OTP erfordert). In einer ordnungsgemäß eingebetteten Erlang-Version, in der sich die Anwendungen im Code-Stammverzeichnis / vm.args
befinden Ordner kann Erlang diese Anwendungen laden, ohne zusätzliche Pfade anzugeben.
Zusammenfassung und andere Überlegungen
Die Bereitstellung von Erlang-Anwendungen unterscheidet sich nicht wesentlich von anderen in Skriptsprachen geschriebenen Projekten, z. Ruby- oder Python-Projekte. All diese Projekte müssen sich mit ähnlichen Problemen befassen, und ich glaube, dass die Paketverwaltung jedes Betriebssystems auf die eine oder andere Weise damit zu tun hat:
Erfahren Sie, wie Ihr Betriebssystem Pakete mit Laufzeitabhängigkeiten verarbeitet.
Sehen Sie, wie andere Erlang-Anwendungen für Ihr Betriebssystem gepackt werden. Es gibt viele davon, die normalerweise von allen wichtigen Systemen verteilt werden: RabbitMQ, Ejabberd, Riak und andere. Laden Sie einfach das Paket herunter und entpacken Sie es in einen Ordner. Dann sehen Sie, wo alle Dateien abgelegt sind.
BEARBEITEN - Referenzieren Sie die Anforderungen
Zurück zu Ihren Anforderungen, haben Sie die folgenden Möglichkeiten:
Installiere Erlang als OTP-Release systemweit, als eingebettetes Erlang oder als Tasche mit Anwendungen in einigen zufälligen Ordnern (sorry Rebar)
Sie können mehrere Einstiegspunkte in Form von lib
oder lib
scripts haben, die eine Auswahl von Anwendungen aus der installierten Version ausführen. Beide funktionieren so lange, wie Sie den Code-Root und die Pfade zu diesen Anwendungen korrekt konfiguriert haben (wie oben beschrieben).
Dann müsste jede Ihrer Anwendungen: sh
und escript
in ihrem eigenen neuen Kontext ausgeführt werden, z. Starten Sie eine neue VM-Instanz und führen Sie die gewünschte Anwendung aus (aus der gleichen Erlang-Version). Im Falle von myweb
kann der Einstiegspunkt ein mycli
Skript sein, das einen neuen Knoten entsprechend der Version startet (ähnlich wie Riak). Im Fall von myweb
kann der Einstiegspunkt ein sh
sein, der die Ausführung beendet, sobald die Aufgabe abgeschlossen ist.
Es ist jedoch durchaus möglich, eine Aufgabe mit kurzer Laufzeit zu erstellen, die die VM auch dann verlässt, wenn sie von mycli
gestartet wurde - siehe Beispiel oben. In diesem Fall benötigt escript
separate Release-Dateien - die sh
und mycli
, um die VM zu booten. Und natürlich ist es auch möglich, eine langlaufende Erlang VM von script
zu starten.
Ich habe ein Beispielprojekt zur Verfügung gestellt, das alle diese Methoden auf einmal verwendet: humbundee . Sobald es kompiliert ist, bietet es drei Zugriffspunkte:
boot
release. escript
release. cmd
humbundee
. Der erste wird verwendet, um den Knoten für die Installation zu starten und dann herunterzufahren. Die zweite wird verwendet, um eine lang laufende Erlang-Anwendung zu starten. Die dritte ist ein Build-Tool zum Installieren / Konfigurieren des Knotens. So sieht das Projekt nach der Erstellung der Freigabe aus:
%Vor% Der Einstiegspunkt builder.esh
verwendet die Programme escript
und cmd
sowie die Dateien deploy-0.0.1
, builderl-0.2.7
und einige OTP-Anwendungen. Der Standardeintrag cmd.boot
verwendet alle Anwendungen außer cmd.script
und humbundee
. Dann verwendet das builderl
escript die Anwendung deploy
und builderl.esh
. Alles aus derselben eingebetteten Erlang OTP-Installation.
Ein kleines Skript, das dann von "herkömmlichen" Modulen in den Code geht, könnte eine Lösung sein.
Als Beispiel wird erwartet, dass Concuerror als Befehlszeilenwerkzeug verwendet wird und ein Escript als Einstiegspunkt verwendet. Es behandelt Befehlszeilenargumente über getopt . Der Hauptcode befindet sich in regulären Erlang-Modulen, die im Pfad mit einfachen Argumenten zum Skript enthalten sind.
Soweit ich weiß, können NIFs dann mit regulären -onload
-Attributen geladen werden (Concuerror verwendet keine NIFs).