Anpassen von Go-Binärdateien mit Build-Tags

Einführung

In Go ist einbuild tag oder eine Build-Einschränkung eine Kennung, die einem Code hinzugefügt wird, der bestimmt, wann die Datei während desbuild-Prozesses in ein Paket aufgenommen werden soll. Auf diese Weise können Sie verschiedene Versionen Ihrer Go-Anwendung aus demselben Quellcode erstellen und schnell und organisiert zwischen ihnen wechseln. Viele Entwickler verwenden Build-Tags, um den Workflow beim Erstellen plattformübergreifender kompatibler Anwendungen zu verbessern, z. B. Programme, bei denen Codeänderungen erforderlich sind, um Abweichungen zwischen verschiedenen Betriebssystemen zu berücksichtigen. Build-Tags werden auch fürintegration testing verwendet, sodass Sie schnell zwischen dem integrierten Code und dem Code mitmock service or stub wechseln können, sowie für unterschiedliche Ebenen von Funktionssätzen innerhalb einer Anwendung.

Nehmen wir als Beispiel das Problem unterschiedlicher Kundenfeatures. Wenn Sie einige Anwendungen schreiben, möchten Sie möglicherweise steuern, welche Funktionen in die Binärdatei aufgenommen werden sollen, z. B. eine Anwendung, die die StufenFree,Pro undEnterprise bietet. Wenn der Kunde sein Abonnement in diesen Anwendungen erhöht, werden mehr Funktionen freigeschaltet und verfügbar. Um dieses Problem zu lösen, können Sie separate Projekte verwalten und versuchen, sie mithilfe der Anweisungen vonimportmiteinander synchron zu halten. Während dieser Ansatz funktionieren würde, würde er mit der Zeit mühsam und fehleranfällig werden. Ein alternativer Ansatz wäre die Verwendung von Build-Tags.

In diesem Artikel werden Sie Build-Tags in Go verwenden, um verschiedene ausführbare Binärdateien zu generieren, die Free-, Pro- und Enterprise-Feature-Sets einer Beispielanwendung bieten. Für jede Version stehen unterschiedliche Funktionen zur Verfügung, wobei die kostenlose Version die Standardversion ist.

Voraussetzungen

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

Erstellen der kostenlosen Version

Beginnen wir mit der Erstellung der kostenlosen Version der Anwendung, da dies die Standardeinstellung ist, wenngo build ohne Build-Tags ausgeführt wird. Später werden wir Build-Tags verwenden, um unserem Programm selektiv andere Teile hinzuzufügen.

Erstellen Sie im Verzeichnissrc einen Ordner mit dem Namen Ihrer Anwendung. In diesem Tutorial werdenapp verwendet:

mkdir app

In diesen Ordner verschieben:

cd app

Erstellen Sie als Nächstes eine neue Textdatei in Ihrem Texteditor Ihrer Wahl mit dem Namenmain.go:

nano main.go

Jetzt definieren wir die kostenlose Version der Anwendung. Fügen Siemain.go den folgenden Inhalt hinzu:

main.go

package main

import "fmt"

var features = []string{
  "Free Feature #1",
  "Free Feature #2",
}

func main() {
  for _, f := range features {
    fmt.Println(">", f)
  }
}

In dieser Datei haben wir ein Programm erstellt, dasslice mit dem Namenfeatures deklariert und zweistrings enthält, die die Funktionen unserer kostenlosen Anwendung darstellen. Die Funktionmain() in der Anwendung verwendet einfor loop to range bis zumfeatures-Slice und druckt alle auf dem Bildschirm verfügbaren Funktionen.

Speichern und schließen Sie die Datei. Nachdem diese Datei gespeichert wurde, müssen wir sie für den Rest des Artikels nicht mehr bearbeiten. Stattdessen werden wir Build-Tags verwenden, um die Funktionen der Binärdateien zu ändern, die wir daraus erstellen werden.

Erstellen Sie das Programm und führen Sie es aus:

go build
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2

Das Programm hat unsere beiden kostenlosen Funktionen ausgedruckt und damit die kostenlose Version unserer App vervollständigt.

Bisher haben Sie eine Anwendung mit sehr grundlegenden Funktionen erstellt. Als Nächstes erstellen Sie eine Möglichkeit, der Anwendung zum Zeitpunkt der Erstellung weitere Funktionen hinzuzufügen.

Hinzufügen der Pro-Funktionen mitgo build

Wir haben bisher vermieden, Änderungen anmain.go vorzunehmen, um eine gemeinsame Produktionsumgebung zu simulieren, in der Code hinzugefügt werden muss, ohne den Hauptcode zu ändern und möglicherweise zu beschädigen. Da wir diemain.go-Datei nicht bearbeiten können, müssen wir einen anderen Mechanismus verwenden, um mithilfe von Build-Tags mehr Features in dasfeatures-Slice einzufügen.

Erstellen wir eine neue Datei mit dem Namenpro.go, die eineinit()-Funktion verwendet, um weitere Funktionen an dasfeatures-Slice anzuhängen:

nano pro.go

Nachdem der Editor die Datei geöffnet hat, fügen Sie die folgenden Zeilen hinzu:

pro.go

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

In diesem Code haben wirinit() verwendet, um Code vor dermain()-Funktion unserer Anwendung auszuführen, gefolgt vonappend(), um die Pro-Funktionen zumfeatures-Slice hinzuzufügen. Speichern und schließen Sie die Datei.

Kompilieren Sie die Anwendung und führen Sie sie mitgo build aus:

go build

Da sich jetzt zwei Dateien in unserem aktuellen Verzeichnis befinden (pro.go undmain.go), erstelltgo build aus beiden eine Binärdatei. Führe diese Binärdatei aus:

./app

Dadurch erhalten Sie die folgenden Funktionen:

Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

Die Anwendung enthält jetzt sowohl die Pro-Funktionen als auch die Free-Funktionen. Dies ist jedoch nicht wünschenswert: Da es keinen Unterschied zwischen den Versionen gibt, enthält die kostenlose Version jetzt die Funktionen, die nur in der Pro-Version verfügbar sein sollen. Um dies zu beheben, können Sie mehr Code einfügen, um die verschiedenen Ebenen der Anwendung zu verwalten, oder Sie können Build-Tags verwenden, um der Go-Toolkette mitzuteilen, welche.go-Dateien erstellt und welche ignoriert werden sollen. Lassen Sie uns im nächsten Schritt Build-Tags hinzufügen.

Build-Tags hinzufügen

Sie können jetzt Build-Tags verwenden, um die Pro-Version Ihrer Anwendung von der kostenlosen Version zu unterscheiden.

Beginnen wir damit, zu untersuchen, wie ein Build-Tag aussieht:

// +build tag_name

Indem Sie diese Codezeile als erste Zeile Ihres Pakets einfügen undtag_name durch den Namen Ihres Build-Tags ersetzen, kennzeichnen Sie dieses Paket als Code, der selektiv in die endgültige Binärdatei aufgenommen werden kann. Lassen Sie uns dies in Aktion sehen, indem Sie der Dateipro.goein Build-Tag hinzufügen, um den Befehlgo buildanzuweisen, es zu ignorieren, sofern das Tag nicht angegeben ist. Öffnen Sie die Datei in Ihrem Texteditor:

nano pro.go

Fügen Sie dann die folgende hervorgehobene Zeile hinzu:

pro.go

// +build pro

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

Am Anfang der Dateipro.go haben wir// +build pro hinzugefügt, gefolgt von einer leeren neuen Zeile. Diese nachgestellte Zeile ist erforderlich, andernfalls interpretiert Go dies als Kommentar. Build-Tag-Deklarationen müssen sich auch ganz oben in der.go-Datei befinden. Nichts, nicht einmal Kommentare, können über Build-Tags liegen.

Die Deklaration von+buildteilt dem Befehlgo buildmit, dass dies kein Kommentar, sondern ein Build-Tag ist. Der zweite Teil ist daspro-Tag. Durch Hinzufügen dieses Tags oben in derpro.go-Datei enthält der Befehlgo build nur noch diepro.go-Datei, in der daspro-Tag vorhanden ist.

Kompilieren Sie die Anwendung und führen Sie sie erneut aus:

go build
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2

Da für diepro.go-Datei einpro-Tag erforderlich sein muss, wird die Datei ignoriert und die Anwendung wird ohne sie kompiliert.

Wenn Sie den Befehlgo build ausführen, können Sie das Flag-tags verwenden, um Code bedingt in die kompilierte Quelle aufzunehmen, indem Sie das Tag selbst als Argument hinzufügen. Lassen Sie uns dies für daspro-Tag tun:

go build -tags pro

Dies gibt Folgendes aus:

Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2

Jetzt erhalten wir die zusätzlichen Funktionen nur, wenn wir die Anwendung mit dem Build-Tagproerstellen.

Dies ist in Ordnung, wenn es nur zwei Versionen gibt, aber die Dinge werden kompliziert, wenn Sie mehr Tags hinzufügen. Um im nächsten Schritt die Enterprise-Version unserer App hinzuzufügen, verwenden wir mehrere Build-Tags, die mit Boolescher Logik verbunden sind.

Build Tag Boolean Logic

Wenn ein Go-Paket mehrere Build-Tags enthält, interagieren die Tags mithilfe vonBoolean logic miteinander. Um dies zu demonstrieren, fügen wir die Enterprise-Ebene unserer Anwendung sowohl mit dem Tagproals auch mit dem Tagenterprisehinzu.

Um eine Enterprise-Binärdatei zu erstellen, müssen sowohl die Standardfunktionen als auch die Pro-Level-Funktionen und eine Reihe neuer Funktionen für Enterprise enthalten sein. Öffnen Sie zunächst einen Editor und erstellen Sie eine neue Dateienterprise.go, in der die neuen Enterprise-Funktionen hinzugefügt werden:

nano enterprise.go

Der Inhalt vonenterprise.go sieht fast identisch mitpro.go aus, enthält jedoch neue Funktionen. Fügen Sie der Datei die folgenden Zeilen hinzu:

enterprise.go

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Speichern und schließen Sie die Datei.

Derzeit enthält die Dateienterprise.go keine Build-Tags. Wie Sie beim Hinzufügen vonpro.go erfahren haben, bedeutet dies, dass diese Funktionen bei der Ausführung vongo.build zur kostenlosen Version hinzugefügt werden. Fürpro.go haben Sie// +build pro und einen Zeilenumbruch oben in die Datei eingefügt, umgo build mitzuteilen, dass es nur enthalten sein soll, wenn-tags pro verwendet wird. In dieser Situation brauchten Sie nur ein Build-Tag, um das Ziel zu erreichen. Wenn Sie die neuen Enterprise-Funktionen hinzufügen, müssen Sie jedoch zuerst über die Pro-Funktionen verfügen.

Fügen wir zuerst die Unterstützung für das Build-Tagprozuenterprise.gohinzu. Öffnen Sie die Datei mit Ihrem Texteditor:

nano enterprise.go

Fügen Sie als Nächstes das Build-Tag vor der Deklaration vonpackage mainhinzu und stellen Sie sicher, dass nach dem Build-Tag eine neue Zeile eingefügt wird:

enterprise.go

// +build pro

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Speichern und schließen Sie die Datei.

Kompilieren Sie die Anwendung und führen Sie sie ohne Tags aus:

go build
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2

Die Enterprise-Funktionen werden in der kostenlosen Version nicht mehr angezeigt. Fügen wir nun das Build-Tagprohinzu und erstellen und führen die Anwendung erneut aus:

go build -tags pro
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

Dies ist immer noch nicht genau das, was wir brauchen: Die Enterprise-Funktionen werden jetzt angezeigt, wenn wir versuchen, die Pro-Version zu erstellen. Um dies zu lösen, müssen wir ein anderes Build-Tag verwenden. Im Gegensatz zumpro-Tag müssen wir jetzt sicherstellen, dass sowohl diepro- als auch dieenterprise-Funktionen verfügbar sind.

Das Go-Build-System trägt dieser Situation Rechnung, indem es die Verwendung einiger grundlegender boolescher Logik im Build-Tag-System zulässt.

Öffnen wirenterprise.go erneut:

nano enterprise.go

Fügen Sie ein weiteres Build-Tag,enterprise, in derselben Zeile wie daspro-Tag hinzu:

enterprise.go

// +build pro enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Speichern und schließen Sie die Datei.

Kompilieren Sie nun die Anwendung und führen Sie sie mit dem neuen Build-Tagenterpriseaus.

go build -tags enterprise
./app

Dies ergibt folgendes:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2

Jetzt haben wir die Pro-Funktionen verloren. Dies liegt daran, dassgo build beim Erstellen mehrerer Build-Tags in derselben Zeile in einer.go-Datei die Verwendung derOR-Logik interpretiert. Durch Hinzufügen der Zeile// +build pro enterprise wird die Dateienterprise.goerstellt, wenneither das Build-Tagpro oder das Build-Tagenterprise vorhanden ist. Wir müssen die Build-Tags korrekt einrichten, umboth zu benötigen, und stattdessen die Logik vonANDverwenden.

Anstatt beide Tags in dieselbe Zeile zu setzen, interpretiertgo build diese Tags mithilfe der Logik vonAND, wenn wir sie in separate Zeilen setzen.

Öffnen Sieenterprise.go erneut und teilen Sie die Build-Tags in mehrere Zeilen auf.

enterprise.go

// +build pro
// +build enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

Kompilieren Sie nun die Anwendung und führen Sie sie mit dem neuen Build-Tagenterpriseaus.

go build -tags enterprise
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2

Immer noch nicht ganz da: Da für eineAND-Anweisung beide Elemente alstrue betrachtet werden müssen, müssen sowohl die Build-Tagspro als auchenterprise verwendet werden.

Lass es uns erneut versuchen:

go build -tags "enterprise pro"
./app

Sie erhalten folgende Ausgabe:

Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2

Jetzt kann unsere Anwendung auf verschiedene Arten aus demselben Quelltextbaum erstellt werden, wobei die Funktionen der Anwendung entsprechend freigeschaltet werden.

In diesem Beispiel haben wir ein neues// +build-Tag verwendet, um dieAND-Logik zu kennzeichnen. Es gibt jedoch alternative Möglichkeiten, die Boolesche Logik mit Build-Tags darzustellen. Die folgende Tabelle enthält einige Beispiele für andere syntaktische Formatierungen für Build-Tags sowie deren boolesche Entsprechung:

Tag-Syntax erstellen Tag-Beispiel erstellen Boolesche Anweisung

Durch Leerzeichen getrennte Elemente

// +build pro enterprise

pro ODERenterprise

Durch Kommas getrennte Elemente

// +build pro,enterprise

pro UNDenterprise

Ausrufezeichenelemente

// +build !pro

NICHTpro

Fazit

In diesem Lernprogramm haben Sie Build-Tags verwendet, um zu steuern, welcher Code in die Binärdatei kompiliert wurde. Zuerst haben Sie Build-Tags deklariert und mitgo build verwendet, dann haben Sie mehrere Tags mit der Booleschen Logik kombiniert. Anschließend haben Sie ein Programm erstellt, das die verschiedenen Funktionssätze einer Free-, Pro- und Enterprise-Version darstellt und die leistungsstarke Kontrolle zeigt, die Sie durch das Erstellen von Tags über Ihr Projekt erhalten können.

Wenn Sie mehr über Build-Tags erfahren möchten, schauen Sie sich dieGolang documentation on the subjectan oder erkunden Sie unsereHow To Code in Go series.