In diesem Tutorial sehen wir uns an, wie ein Go-Entwickler ein Makefile verwenden kann, um seine eigenen Anwendungen zu entwickeln.
Was sind Makefiles?
Makefile ist ein unglaublich nützliches Automatisierungstool, mit dem Sie Anwendungen nicht nur unter Go, sondern auch in den meisten anderen Programmiersprachen ausführen und erstellen können.
Es ist häufig im Stammverzeichnis vieler Go-Apps auf Github und Gitlab zu sehen. Es wird häufig als Werkzeug zur Automatisierung von Aufgaben verwendet, die häufig von Entwicklern begleitet werden.
Wenn Sie zum Erstellen von Webdiensten Go verwenden, hilft das Makefile bei der Lösung der folgenden Aufgaben:
- Automatisieren Sie den Aufruf einfacher Befehle wie Kompilieren, Starten, Stoppen, Beobachten usw.
- Projektspezifische Umgebungsvariablen verwalten. Es sollte die .env-Datei enthalten.
- Ein Entwicklungsmodus, der bei Änderungen automatisch kompiliert wird.
- Ein Entwicklungsmodus, der Kompilierungsfehler anzeigt.
- Definieren von GOPATH für ein bestimmtes Projekt, damit Abhängigkeiten im Lieferantenordner gespeichert werden können.
- Durch die vereinfachte Dateiüberwachung wird beispielsweise watch run = „go test“ ausgeführt. / ... "
Hier ist eine typische Verzeichnisstruktur für ein Projekt:
.env Makefile main.go bin/ src/ vendor/
Wenn wir den Befehl make in diesem Verzeichnis aufrufen, erhalten wir die folgende Ausgabe:
$ make Choose a command run in my-web-server: install Install missing dependencies. Runs `go get` internally. start Start in development mode. Auto-starts when code changes. stop Stop development mode. compile Compile the binary. watch Run given command when code changes. eg; make watch run="go test ./..." exec Run given command, wrapped with custom GOPATH. eg; make exec run="go test ./..." clean Clean build files. Runs `go clean` internally.
Umgebungsvariablen
Das erste, was wir vom Makefile erwarten, ist, die Umgebungsvariablen einzuschließen, die wir für das Projekt definiert haben. Daher sieht die erste Zeile folgendermaßen aus:
include .env
Als nächstes definieren wir den Projektnamen, Ordner / Dateien, Pfade zu PID ...
PROJECTNAME=$(shell basename "$(PWD)")
Im Rest des Makefiles verwenden wir häufig die Variable GOPATH. Alle unsere Teams müssen mit dem GOPATH eines bestimmten Projekts verbunden sein, sonst funktionieren sie nicht. Dies sorgt für eine saubere Isolation unserer Projekte, erschwert aber gleichzeitig die Arbeit. Um die Aufgabe zu vereinfachen, können wir einen exec-Befehl hinzufügen, der jeden Befehl mit unserem GOPATH ausführt.
Beachten Sie jedoch, dass Sie exec nur verwenden müssen, wenn Sie etwas tun möchten, das nicht in das Makefile geschrieben werden kann.
Entwicklungsmodus
Der Entwicklungsmodus sollte:
- Löschen Sie den Build-Cache
- Code kompilieren
- Führen Sie den Dienst im Hintergrund aus
- Wiederholen Sie diese Schritte, wenn sich der Code ändert.
Das klingt einfach. Die Schwierigkeit liegt jedoch in der Tatsache, dass wir gleichzeitig den Dienst und den Datei-Watcher ausführen. Bevor wir einen neuen Prozess starten, müssen wir sicherstellen, dass er korrekt gestoppt wird und dass wir nicht das übliche Befehlszeilenverhalten verletzen, wenn wir Strg-C oder Strg-D drücken.
start: bash -c "trap 'make stop' EXIT; $(MAKE) compile start-server watch run='make compile start-server'" stop: stop-server
Der oben beschriebene Code löst die folgenden Aufgaben:
- Kompiliert und führt den Dienst im Hintergrund aus.
- Der Hauptprozess läuft nicht im Hintergrund, daher können wir ihn mit Control-C unterbrechen.
- Stoppt Hintergrundprozesse, wenn der Hauptprozess unterbrochen wird. Falle wird nur dafür benötigt.
- Kompiliert den Server neu und startet ihn neu, wenn sich der Code ändert.
In den folgenden Abschnitten werde ich diese Befehle genauer erläutern.
Zusammenstellung
Der Befehl compile ruft nicht nur go compile im Hintergrund auf, sondern löscht die Fehlerausgabe und druckt eine vereinfachte Version.
So sieht die Befehlszeilenausgabe aus, als wir wichtige Änderungen vorgenommen haben:

compile: @-touch $(STDERR) @-rm $(STDERR) @-$(MAKE) -s go-compile 2> $(STDERR) @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2
Server starten / stoppen
start-server startet eine im Hintergrund kompilierte Binärdatei und speichert deren PID in einer temporären Datei. stop-server liest die PID und beendet den Prozess bei Bedarf.
start-server: @echo " > $(PROJECTNAME) is available at $(ADDR)" @-$(GOBIN)/$(PROJECTNAME) 2>&1 & echo $$! > $(PID) @cat $(PID) | sed "/^/s/^/ \> PID: /" stop-server: @-touch $(PID) @-kill `cat $(PID)` 2> /dev/null || true @-rm $(PID) restart-server: stop-server start-server
Änderungsüberwachung
Wir benötigen eine Überwachungsdatei, um Änderungen zu verfolgen. Ich habe viele ausprobiert, konnte aber kein passendes finden, also habe ich mein eigenes Tool zur
Dateiüberwachung geschrieben -
yolo . Installieren Sie es mit dem folgenden Befehl:
$ go get github.com/azer/yolo
Nach der Installation können wir Änderungen im Projektverzeichnis beobachten, mit Ausnahme der Hersteller- und Bin-Ordner.
Wir haben jetzt einen Überwachungsbefehl, der Änderungen am Projektverzeichnis mit Ausnahme des Herstellerverzeichnisses rekursiv verfolgt. Wir können einfach jeden Befehl zum Ausführen übergeben.
Beispiel: Start ruft make-start-server auf, wenn sich der Code ändert:
make watch run="make compile start-server"
Wir können damit Tests durchführen oder die Rennbedingungen automatisch überprüfen. Umgebungsvariablen werden zur Laufzeit festgelegt, sodass Sie sich keine Gedanken über GOPATH machen müssen:
make watch run="go test ./..."
Ein schönes Feature von
Yolo ist das Webinterface. Wenn Sie es aktivieren, können Sie die Ausgabe Ihres Befehls sofort in der Weboberfläche sehen. Alles was Sie tun müssen, ist die Option -a zu übergeben:
yolo -i . -e vendor -e bin -c "go run foobar.go" -a localhost:9001
Öffnen Sie localhost: 9001 in einem Browser und sehen Sie sofort das Ergebnis der Arbeit:

Abhängigkeitsinstallation
Wenn wir Änderungen am Code vornehmen, möchten wir, dass die fehlenden Abhängigkeiten vor dem Kompilieren geladen werden. Der Installationsbefehl erledigt die Aufgabe für uns:
install: go-get
Wir werden den Installationsaufruf automatisieren, wenn sich die Datei vor dem Kompilieren ändert, sodass die Abhängigkeiten automatisch installiert werden. Wenn Sie die Abhängigkeit manuell installieren möchten, können Sie Folgendes ausführen:
make install get="github.com/foo/bar"
Intern wird dieser Befehl konvertiert in:
$ GOPATH=~/my-web-server GOBIN=~/my-web-server/bin go get github.com/foo/bar
Wie funktioniert es Im nächsten Abschnitt fügen wir reguläre Go-Befehle hinzu, um Befehle höherer Ebene zu implementieren.
Gehe zu Befehlen
Da wir GOPATH im Projektverzeichnis installieren möchten, um das Abhängigkeitsmanagement zu vereinfachen, das im Go-Ökosystem noch nicht offiziell gelöst wurde, müssen wir alle Go-Befehle in ein Makefile einschließen.
go-compile: go-clean go-get go-build go-build: @echo " > Building binary..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) go-generate: @echo " > Generating dependency files..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) go-get: @echo " > Checking if there is any missing dependencies..." @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) go-install: @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) go-clean: @echo " > Cleaning build cache" @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean
Hilfe
Schließlich benötigen wir den Befehl help, um eine Liste der verfügbaren Befehle anzuzeigen. Mit den Befehlen sed und column können wir automatisch schön formatierte Hilfeausgaben generieren:
help: Makefile @echo " Choose a command run in "$(PROJECTNAME)":" @sed -n 's/^
Der folgende Befehl durchsucht das Makefile nach Zeilen, die mit ## beginnen, und zeigt sie an. Auf diese Weise können Sie einfach bestimmte Befehle kommentieren, und Kommentare werden mit dem Hilfebefehl angezeigt.
Wenn wir ein paar Kommentare hinzufügen:
Wir werden bekommen:
$ make help Choose a command run in my-web-server: install Install missing dependencies. Runs `go get` internally. start Start in development mode. Auto-starts when code changes. stop Stop development mode.
Endgültige Version
include .env PROJECTNAME=$(shell basename "$(PWD)")