Verwenden von ldflags zum Festlegen von Versionsinformationen für Go-Anwendungen

Einführung

Wenn Sie Anwendungen in einer Produktionsumgebung bereitstellen, können Sie durch Erstellen von Binärdateien mit Versionsinformationen und anderen Metadaten Ihre Überwachungs-, Protokollierungs- und Debugging-Prozesse verbessern, indem Sie Identifizierungsinformationen hinzufügen, um Ihre Builds im Laufe der Zeit zu verfolgen. Diese Versionsinformationen können häufig hochdynamische Daten enthalten, z. B. die Erstellungszeit, den Computer oder Benutzer, der die Binärdatei erstellt, die Commit-ID vonVersion Control System (VCS), für die er erstellt wurde, und vieles mehr. Da sich diese Werte ständig ändern, ist das Codieren dieser Daten direkt in den Quellcode und das Ändern vor jedem neuen Build mühsam und fehleranfällig: Quelldateien können sich verschieben undvariables/constants können während der Entwicklung die Dateien wechseln, wodurch der Erstellungsprozess unterbrochen wird .

Eine Möglichkeit, dies in Go zu lösen, besteht darin,-ldflags mit dem Befehlgo build zu verwenden, um dynamische Informationen zur Erstellungszeit in die Binärdatei einzufügen, ohne dass eine Änderung des Quellcodes erforderlich ist. In diesem Flag stehtld fürlinker, das Programm, das die verschiedenen Teile des kompilierten Quellcodes in der endgültigen Binärdatei miteinander verbindet. ldflags steht dann fürlinker flags. Dies wird genannt, weil es ein Flag an den zugrunde liegenden Go-Toolchain-Linkercmd/link übergibt, mit dem Sie die Werte importierter Pakete zur Erstellungszeit über die Befehlszeile ändern können.

In diesem Lernprogramm verwenden Sie-ldflags, um den Wert von Variablen zur Erstellungszeit zu ändern und Ihre eigenen dynamischen Informationen mithilfe einer Beispielanwendung, die Versionsinformationen auf dem Bildschirm druckt, in eine Binärdatei einzufügen.

Voraussetzungen

Um dem Beispiel in diesem Artikel zu folgen, benötigen Sie:

Erstellen Ihrer Beispielanwendung

Bevor Sieldflags verwenden können, um dynamische Daten einzuführen, benötigen Sie zunächst eine Anwendung, in die Sie die Informationen einfügen können. In diesem Schritt erstellen Sie diese Anwendung, die zu diesem Zeitpunkt nur statische Versionsinformationen ausgibt. Lassen Sie uns diese Anwendung jetzt erstellen.

Erstellen Sie in Ihrem Verzeichnissrcein Verzeichnis, das nach Ihrer Anwendung benannt ist. In diesem Tutorial wird der Anwendungsnameapp verwendet:

mkdir app

Ändern Sie Ihr Arbeitsverzeichnis in diesen Ordner:

cd app

Erstellen Sie als Nächstes mit dem Texteditor Ihrer Wahl den Einstiegspunkt Ihres Programms,main.go:

nano main.go

Lassen Sie Ihre Anwendung jetzt die Versionsinformationen ausdrucken, indem Sie die folgenden Inhalte hinzufügen:

app/main.go

package main

import (
    "fmt"
)

var Version = "development"

func main() {
    fmt.Println("Version:\t", Version)
}

Innerhalb der Funktionmain() haben Sie die VariableVersion deklariert und dann diestringVersion: gedruckt, gefolgt von einem Tabulatorzeichen, und der deklarierten Variable.

Zu diesem Zeitpunkt ist die VariableVersion alsdevelopment definiert. Dies ist die Standardversion für diese App. Später werden Sie diesen Wert in eine offizielle Versionsnummer ändern, die nachsemantic versioning format geordnet ist.

Speichern und schließen Sie die Datei. Erstellen Sie anschließend die Anwendung und führen Sie sie aus, um sicherzustellen, dass die richtige Version gedruckt wird:

go build
./app

Sie werden die folgende Ausgabe sehen:

OutputVersion:     development

Sie haben jetzt eine Anwendung, die Standardversionsinformationen druckt, aber Sie haben noch keine Möglichkeit, die aktuellen Versionsinformationen zum Zeitpunkt der Erstellung weiterzugeben. Im nächsten Schritt verwenden Sie-ldflags undgo build, um dieses Problem zu lösen.

Verwenden vonldflags mitgo build

Wie bereits erwähnt, stehtldflags fürlinker flags und wird verwendet, um Flags an den zugrunde liegenden Linker in der Go-Toolchain zu übergeben. Dies funktioniert nach folgender Syntax:

go build -ldflags="-flag"

In diesem Beispiel haben wirflag an den zugrunde liegenden Befehlgo tool link übergeben, der als Teil vongo build ausgeführt wird. Dieser Befehl verwendet doppelte Anführungszeichen um den anldflags übergebenen Inhalt, um zu vermeiden, dass darin enthaltene Zeichen oder Zeichen, die die Befehlszeile möglicherweise als etwas anderes als das von uns gewünschte interpretiert, beschädigt werden. Von hier aus können Siemany different link flags übergeben. Für die Zwecke dieses Tutorials verwenden wir das Flag-X, um Informationen zur Verknüpfungszeit in die Variable zu schreiben, gefolgt vom Pfadpackagezur Variablen und ihrem neuen Wert:

go build -ldflags="-X 'package_path.variable_name=new_value'"

In den Anführungszeichen gibt es jetzt die Option-X undkey-value pair, die die zu ändernde Variable und ihren neuen Wert darstellen. Das Zeichen.trennt den Paketpfad und den Variablennamen, und einfache Anführungszeichen werden verwendet, um zu vermeiden, dass Zeichen im Schlüssel-Wert-Paar unterbrochen werden.

Um die VariableVersionin Ihrer Beispielanwendung zu ersetzen, verwenden Sie die Syntax im letzten Befehlsblock, um einen neuen Wert zu übergeben und die neue Binärdatei zu erstellen:

go build -ldflags="-X 'main.Version=v1.0.0'"

In diesem Befehl istmain der Paketpfad der VariablenVersion, da sich diese Variable in der Dateimain.go befindet. Version ist die Variable, in die Sie schreiben, undv1.0.0 ist der neue Wert.

Umldflags verwenden zu können, muss der Wert, den Sie ändern möchten, vorhanden sein und eine Variable auf Paketebene vom Typstring sein. Diese Variable kann entweder exportiert oder nicht exportiert werden. Der Wert darf nichtconst sein oder durch das Ergebnis eines Funktionsaufrufs festgelegt werden. Glücklicherweise erfülltVersion alle diese Anforderungen: Es wurde bereits in der Dateimain.go als Variable deklariert, und der aktuelle Wert (development) und der gewünschte Wert (v1.0.0 ) sind beide Saiten.

Führen Sie die Anwendung aus, sobald die Binärdatei Ihres neuenapperstellt wurde:

./app

Sie erhalten folgende Ausgabe:

OutputVersion:     v1.0.0

Mit-ldflags haben Sie die VariableVersion erfolgreich vondevelopment inv1.0.0 geändert.

Sie haben jetzt einestring-Variable in einer einfachen Anwendung zur Erstellungszeit geändert. Mitldflags können Sie Versionsdetails, Lizenzinformationen und mehr in eine Binärdatei einbetten, die nur über die Befehlszeile zur Verteilung bereit ist.

In diesem Beispiel befand sich die von Ihnen geänderte Variable im Programmmain, wodurch die Schwierigkeit beim Ermitteln des Pfadnamens verringert wurde. Manchmal ist es jedoch komplizierter, den Pfad zu diesen Variablen zu finden. Im nächsten Schritt schreiben Sie Werte in Variablen in Unterpaketen, um die beste Methode zur Ermittlung komplexerer Paketpfade zu demonstrieren.

Targeting von Unterpaketvariablen

Im letzten Abschnitt haben Sie die VariableVersion bearbeitet, die sich im obersten Paket der Anwendung befand. Dies ist jedoch nicht immer der Fall. Oft ist es praktischer, diese Variablen in einem anderen Paket zu platzieren, damain kein importierbares Paket ist. Um dies in Ihrer Beispielanwendung zu simulieren, erstellen Sie ein neues Unterpaket,app/build, in dem Informationen zum Zeitpunkt der Erstellung der Binärdatei und zum Namen des Benutzers gespeichert werden, der den Befehl build erstellt hat.

Um ein neues Unterpaket hinzuzufügen, fügen Sie Ihrem Projekt zunächst ein neues Verzeichnis mit dem Namenbuild hinzu:

mkdir -p build

Erstellen Sie dann eine neue Datei mit dem Namenbuild.go, die die neuen Variablen enthält:

nano build/build.go

Fügen Sie in Ihrem Texteditor neue Variablen fürTime undUser hinzu:

app/build/build.go

package build

var Time string

var User string

Die VariableTime enthält eine Zeichenfolgendarstellung der Zeit, zu der die Binärdatei erstellt wurde. Die VariableUser enthält den Namen des Benutzers, der die Binärdatei erstellt hat. Da diese beiden Variablen immer Werte haben, müssen Sie diese Variablen nicht wie beiVersion mit Standardwerten initialisieren.

Speichern und schließen Sie die Datei.

Öffnen Sie als Nächstesmain.go, um diese Variablen zu Ihrer Anwendung hinzuzufügen:

nano main.go

Fügen Sie innerhalb vonmain.go die folgenden hervorgehobenen Zeilen hinzu:

main.go

package main

import (
    "app/build"
    "fmt"
)

var Version = "development"

func main() {
    fmt.Println("Version:\t", Version)
    fmt.Println("build.Time:\t", build.Time)
    fmt.Println("build.User:\t", build.User)
}

In diesen Zeilen haben Sie zuerst das Paketapp/build importiert und dannbuild.Time undbuild.User auf dieselbe Weise gedruckt, wie SieVersion gedruckt haben.

Speichern Sie die Datei und beenden Sie dann Ihren Texteditor.

Um auf diese Variablen mitldflags abzuzielen, können Sie den Importpfadapp/build gefolgt von.User oder.Time verwenden, da Sie den Importpfad bereits kennen. Um jedoch eine komplexere Situation zu simulieren, in der der Pfad zur Variablen nicht ersichtlich ist, verwenden wir stattdessen den Befehlnm in der Go-Werkzeugkette.

Der Befehlgo tool nm gibt diesymbols aus, die an einer bestimmten ausführbaren Datei, Objektdatei oder einem bestimmten Archiv beteiligt sind. In diesem Fall bezieht sich ein Symbol auf ein Objekt im Code, z. B. eine definierte oder importierte Variable oder Funktion. Durch Generieren einer Symboltabelle mitnm und Verwenden vongrep zum Suchen nach einer Variablen können Sie schnell Informationen über ihren Pfad finden.

[.note] #Note: Der Befehlnm hilft Ihnen nicht, den Pfad Ihrer Variablen zu finden, wenn der Paketname nicht https: //en.wikipedia.org/wiki/ASCII [ASCII ] Zeichen oder ein" oder% Zeichen, da dies eine Einschränkung des Werkzeugs selbst darstellt.
#

Um diesen Befehl zu verwenden, erstellen Sie zuerst die Binärdatei fürapp:

go build

Nachdemapp erstellt wurde, richten Sie das Werkzeugnm darauf und durchsuchen Sie die Ausgabe:

go tool nm ./app | grep app

Beim Ausführen gibt das Toolnmviele Daten aus. Aus diesem Grund verwendete der vorhergehende Befehl|, um die Ausgabe an den Befehlgrep weiterzuleiten, der dann nach Begriffen suchte, deren Titel die oberste Ebeneapp enthielt.

Sie erhalten eine Ausgabe ähnlich der folgenden:

Output  55d2c0 D app/build.Time
  55d2d0 D app/build.User
  4069a0 T runtime.appendIntStr
  462580 T strconv.appendEscapedRune
. . .

In diesem Fall enthalten die ersten beiden Zeilen der Ergebnismenge die Pfade zu den beiden gesuchten Variablen:app/build.Time undapp/build.User.

Nachdem Sie die Pfade kennen, erstellen Sie die Anwendung erneut. Diesmal ändern SieVersion,User undTime zur Erstellungszeit. Übergeben Sie dazu mehrere-X Flags an-ldflags:

go build -v -ldflags="-X 'main.Version=v1.0.0' -X 'app/build.User=$(id -u -n)' -X 'app/build.Time=$(date)'"

Hier haben Sie den Befehlid -u -n Bash übergeben, um den aktuellen Benutzer aufzulisten, und den Befehldate, um das aktuelle Datum aufzulisten.

Nachdem die ausführbare Datei erstellt wurde, führen Sie das Programm aus:

./app

Dieser Befehl erzeugt bei Ausführung auf einem Unix-System eine ähnliche Ausgabe wie der folgende:

OutputVersion:     v1.0.0
build.Time:  Fri Oct  4 19:49:19 UTC 2019
build.User:  sammy

Jetzt verfügen Sie über eine Binärdatei mit Versions- und Build-Informationen, die Sie bei der Lösung von Problemen in der Produktion unterstützen können.

Fazit

Dieses Tutorial hat gezeigt, wieldflags bei korrekter Anwendung ein leistungsstarkes Werkzeug zum Einfügen wertvoller Informationen in Binärdateien zur Erstellungszeit sein kann. Auf diese Weise können Sie Feature-Flags, Umgebungsinformationen, Versionsinformationen usw. steuern, ohne Änderungen an Ihrem Quellcode vornehmen zu müssen. Durch Hinzufügen vonldflags zu Ihrem aktuellen Build-Workflow können Sie die Vorteile des in sich geschlossenen binären Verteilungsformats von Go maximieren.

Wenn Sie mehr über die Programmiersprache Go erfahren möchten, lesen Sie unsere vollständigenHow To Code in Go series. Wenn Sie nach weiteren Lösungen für die Versionskontrolle suchen, lesen Sie unserHow To Use Git-Referenzhandbuch.