Es kam vor, dass Entwickler, die sich gerade erst mit Go vertraut machen, häufig auf das Problem stoßen, ein Arbeitsverzeichnis für Go-Projekte auszuwählen. Im Chat der GolangConf-Konferenz wurde diese Frage ebenfalls gestellt. Neue Gophers erschrecken sich oft mit den Worten GOPATH und GOROOT . In den Kurzanleitungen mit der aktuellen Version von Go (1.13) werden diese beiden „beängstigenden“ Wörter jedoch überhaupt nicht erwähnt.
Mal sehen warum. Für die Reinheit des Experiments habe ich frisches Ubuntu auf einer virtuellen Maschine bereitgestellt und Go gemäß den Anweisungen aus dem Wiki installiert:
sudo add-apt-repository ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install golang-go
Go 1.13 ist installiert und einsatzbereit:
$ go version go version go1.13 linux/amd64 $ which go /usr/bin/go $ whereis go go: /usr/bin/go /usr/lib/go /usr/share/go /usr/share/man/man1/go.1.gz
GOROOT
Über GOROOT
wurde bereits in einem Artikel von 2015 perfekt geschrieben, und diese Informationen sind immer noch relevant.
Es ist lustig, dass whereis go
der Liste der Verzeichnisse, die vom letzten Befehl ausgegeben wurden ( whereis go
), eigentlich nicht:
$ go env GOROOT /usr/lib/go-1.13
Wenn ich beispielsweise für die IDE den Pfad zu den Dateien der Standard-Go-Bibliothek angeben /usr/lib/go-1.13
, /usr/lib/go-1.13
ich /usr/lib/go-1.13
. Vielleicht endet in diesem Szenario der Einsatz von GOROOT
im Alltag.
GOPATH und Module
Es scheint, dass es an dieser Stelle notwendig ist, sich zu GOPATH
, um GOPATH
zu installieren, aber ich werde dies nicht tun. Eigentlich ist GOPATH
bereits eingestellt:
$ go env GOPATH /home/elena/go
Ich bin mit der GOPATH
in ~/go
GOPATH
, was bedeutet, dass ich sie nicht ändern werde.
Ich werde sofort ein Verzeichnis für mein erstes Projekt auf Go erstellen. Dies kann überall erfolgen, beispielsweise direkt in Ihrem Home-Verzeichnis. Außerdem werde ich sofort mit dem Go-Modul- Tool arbeiten:
$ mkdir ~/hello $ go mod init github.com/rumyantseva/hello go: creating new go.mod: module github.com/rumyantseva/hello
Für den Befehl go mod init
ich einen eindeutigen Modulmodulpfad für mein Projekt angegeben. Auf diese Weise kann ein Proxy oder ein anderes Tool bei Bedarf die Dateien meines Projekts finden.
Nach dem Aufruf des Befehls go mod init
wurde das Verzeichnis go mod init
in meinem Ausgangsverzeichnis angezeigt:
$ tree ~/go /home/elena/go └── pkg └── mod └── cache └── lock 3 directories, 1 file
In diesem Fall ist die Sperrdatei (ganz unten im Baum) noch leer.
Die Datei go.mod
im go.mod
~/hello
mit folgendem Inhalt go.mod
:
module github.com/rumyantseva/hello go 1.13
In go.mod
werden anschließend alle Informationen zu den Abhängigkeiten meines Moduls gespeichert.
Schreiben wir nun eine Anwendung mit einer externen Abhängigkeit. Im Verzeichnis ~/hello
erstelle ich die Datei main.go
und schreibe den folgenden Code hinein:
package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, world!") }
Natürlich im wirklichen Leben für das Schreiben von "Hallo Welt!" Sie können auf logrus verzichten , aber in diesem Beispiel hilft uns diese Bibliothek herauszufinden, wo die Dateien externer Abhängigkeiten gespeichert sind.
Ich starte die Anwendung auf einfachste Weise:
$ go run main.go go: finding github.com/sirupsen/logrus v1.4.2 go: downloading github.com/sirupsen/logrus v1.4.2 go: extracting github.com/sirupsen/logrus v1.4.2 go: downloading golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: extracting golang.org/x/sys v0.0.0-20190422165155-953cdadca894 go: finding golang.org/x/sys v0.0.0-20190422165155-953cdadca894 INFO[0000] Hello, world!
Bevor die Anwendung erstellt und gestartet wurde, funktionierte das go mod
Tool. Er definierte meine externe Abhängigkeit github.com/sirupsen/logrus
, nahm die neueste Version v1.4.2
und entschied sich für transitive Abhängigkeiten.
go.mod
Datei go.mod
eine Zeile mit einer Beschreibung der Abhängigkeit von logrus
:
module github.com/rumyantseva/hello go 1.13 require github.com/sirupsen/logrus v1.4.2 // indirect
go.sum
Datei go.sum
, in der zusätzlich zum Hash der logrus
Abhängigkeit Informationen zu Hashes transitiver Abhängigkeiten gespeichert sind:
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Wo ist der Abhängigkeitscode selbst? Es kann in ~/go/pkg/mod
. Außerdem werden Prüfsummen und andere Overhead-Informationen für die Arbeit mit Abhängigkeiten in ~/go/pkg
gespeichert.
Wenn Sie bereits auf das go get
Tool gestoßen sind, wissen Sie, dass beim Abrufen von Abhängigkeiten die Repositorys tatsächlich geklont werden (z. B. bei Git mit git clone
). Aber go mod
funktioniert so nicht. Für go mod
ist die Hauptcodeeinheit das Modul. Module sind Archive. Wenn Sie mit go mod
Abhängigkeiten arbeiten, werden Archive explizit (wenn Sie den Befehl go mod download
aufgerufen haben) oder implizit (wenn Sie mit dem Kompilieren der Anwendung begonnen haben) über GOPROXY
heruntergeladen und GOPROXY
. Mal sehen, wie der Proxy standardmäßig in Go 1.13 eingestellt ist:
$ go env GOPROXY https://proxy.golang.org,direct
Also, als Proxy beim Erstellen meiner "Hallo Welt!" verwendet von proxy.golang.org . Natürlich kann diese Variable geändert werden, indem ein anderes Modul-Repository ausgewählt wird. Sie können beispielsweise Ihre eigene interne Proxy-Firma bereitstellen, die gespeichert wird, einschließlich interner Bibliotheken, deren Code nicht in Open Source veröffentlicht wurde.
Wenn ich ein neues Projekt GOPATH
und nichts dagegen habe, Go-Module zu verwenden, weiß ich im Allgemeinen möglicherweise nichts über GOPATH
. Go erstellt das Verzeichnis ~/go
bei Bedarf selbstständig.
Wann wird GOPATH benötigt?
Wenn Sie Go-Module grundsätzlich nicht verwenden (z. B. in einem Legacy-Projekt), ist es möglicherweise nicht so einfach, sich von einer expliziteren Arbeit mit GOPATH
zu GOPATH
.
Um zu sehen, was mit meinem Projekt passieren wird, löschen Sie die Dateien ~/hello/go.mod
und ~/hello/go.sum
, wenn ich mich gegen go mod
~/hello/go.sum
. Ich werde auch ~/go
entfernen, um zu dem Zustand des Systems zurückzukehren, den ich am Anfang hatte:
rm -rf ~/go ~/hello/go.mod ~/hello/go.sum
Nur die Datei main.go
verbleibt im main.go
~/hello
. Was passiert jetzt, wenn ich versuche, es mit go run
?
$ go run main.go main.go:4:2: cannot find package "github.com/sirupsen/logrus" in any of: /usr/lib/go-1.13/src/github.com/sirupsen/logrus (from $GOROOT) /home/elena/go/src/github.com/sirupsen/logrus (from $GOPATH)
Hier sind sie, diese gruseligen GOROOT
und GOPATH
:)
Um die Anwendung zu kompilieren, muss ich die Abhängigkeit in GOPATH
. Ich mache das mit dem guten alten go get
:
$ go get -v github.com/sirupsen/logrus github.com/sirupsen/logrus (download) created GOPATH=/home/elena/go; see 'go help gopath' get "golang.org/x/sys/unix": found meta tag get.metaImport{Prefix:"golang.org/x/sys", VCS:"git", RepoRoot:"https://go.googlesource.com/sys"} at //golang.org/x/sys/unix?go-get=1 get "golang.org/x/sys/unix": verifying non-authoritative meta tag golang.org/x/sys (download) golang.org/x/sys/unix github.com/sirupsen/logrus
Was ist passiert? Zunächst wird das Verzeichnis ~/go
(das als GOPATH
angegebene GOPATH
). Dann begann der Prozess des Klonens der Repositorys mit Abhängigkeiten. Es ist lustig, dass das Klonen von Repositorys merklich langsamer aussieht als die Option, als wir go mod
zum Herunterladen und Entpacken von Modulen verwendet haben. Der Abhängigkeitscode befindet sich jetzt jedoch in ~/go/src/
.
Übrigens gab es in meiner sauberen Ubuntu-Installation noch keinen Git-Client, und go get
Arbeit zu go get
musste ich ihn installieren.
Ich starte die Anwendung:
$ go run main.go INFO[0000] Hello, world!
Es funktioniert!
Das ist nur auf Anwendungsebene, ich verfolge jetzt nicht die Version von externen Abhängigkeiten. Was ist, wenn aufgrund einer Sicherheitsanfälligkeit irgendwann im Repository von github.com/sirupsen/logrus
nicht der von mir erwartete Logger, sondern bösartiger Code vorhanden ist? Früher oder später brauche ich noch ein Tool zum Arbeiten mit Abhängigkeiten, und wenn Go-Module aus irgendeinem Grund nicht passen, müssen Sie nach etwas anderem suchen ...
Fazit
In diesem Artikel wurden einige bestimmte Punkte nicht behandelt, und die Arbeit mit externen Abhängigkeiten in Go kann immer noch viele Fragen aufwerfen. Neue Versionen von Go legen jedoch zumindest keine Einschränkungen fest, wo die Arbeitsverzeichnisse Ihrer Projekte erstellt werden können.
Wenn Sie ein neues Projekt starten, versuchen Sie es mit Go Modules! Die Rückkehr zum alten Ansatz der Arbeit mit Abhängigkeiten ist nur dann sinnvoll, wenn etwas schief geht. Übrigens, wenn Sie alle Abhängigkeiten im Projekt speichern möchten, unterstützt Go Modules den Anbietermodus.
Wenn Sie mit einem vorhandenen Projekt arbeiten müssen und es aus irgendeinem Grund nicht in Go-Module übersetzen möchten, ist es wichtig, in der Dokumentation des Projekts die Funktionen der Bereitstellung und des Abhängigkeitsmanagements anzugeben. Wenn Neulinge, die mit den alten Ansätzen zur Arbeit mit Abhängigkeiten nicht vertraut sind, zum Projekt kommen, ist es für sie viel einfacher, mit dem Projekt umzugehen, wenn die gesamte Dokumentation vorhanden ist.
Übrigens planen wir am 7. Oktober auf der GolangConf- Konferenz als eine der besonderen Aktivitäten eine Expertenzone, in der jeder Fragen zu Go an die Mitglieder des Konferenzprogrammkomitees und Enthusiasten der russischen Go-Community stellen kann. Go installieren? Mit Sucht umgehen? Microservice schreiben? Das ist für uns!