Go build: "Paket kann nicht gefunden werden" (obwohl GOPATH gesetzt ist)

138

Obwohl ich GOPATHrichtig eingestellt habe, kann ich immer noch nicht "go build" oder "go run" bekommen, um meine eigenen Pakete zu finden. Was mache ich falsch?

$ echo $GOROOT
/usr/local/go

$ echo $GOPATH
/home/mitchell/go

$ cat ~/main.go
package main
import "foobar"
func main() { }

$ cat /home/mitchell/go/src/foobar.go
package foobar

$ go build main.go
main.go:3:8: import "foobar": cannot find package
MitchellSalad
quelle
Ich stoße auf das gleiche Problem, wenn ich github.com/adonovan/gopl.io/tree/master/ch1/helloworld abrufe. Der Grund dafür ist, dass es keine Datei mit dem Namen helloworld.go gibt. Holen Sie sich Werke, indem Sie Paketname und Dateiname abgleichen.
Keniee van
Es kann auch sein, dass Sie Go aktualisieren müssen. Ich hatte ein ähnliches Problem, bei dem ich vorhandenen Code hatte, der go.mod zum Definieren eines Moduls verwendete. Auf einem Testcomputer hatte ich den Code heruntergeladen und versuchte ihn zu kompilieren, aber Go gab mir alle möglichen Fehler im Zusammenhang mit GOPATH und konnte keine Module finden. Es war Go Version 1.7. Sobald ich Go aktualisiert habe, hat es ohne Probleme funktioniert.
KyferEz
$ go help gopath
Geben Sie

Antworten:

161

Es funktioniert nicht, da sich Ihre foobar.goQuelldatei nicht in einem Verzeichnis namens befindet foobar. go buildund go installversuchen Sie, Verzeichnisse abzugleichen, nicht Quelldateien.

  1. Auf $GOPATHein gültiges Verzeichnis setzen, zexport GOPATH="$HOME/go"
  2. Bewegen Sie foobar.gozu $GOPATH/src/foobar/foobar.gound Gebäude sollte gut funktionieren.

Zusätzliche empfohlene Schritte:

  1. Hinzufügen $GOPATH/binzu Ihrem $PATHvon:PATH="$GOPATH/bin:$PATH"
  2. Wechseln Sie main.goin einen Unterordner von $GOPATH/srcz$GOPATH/src/test
  3. go install testsollte nun eine ausführbare Datei erstellen $GOPATH/bin, die durch Eingabe testin Ihr Terminal aufgerufen werden kann .
Fasmat
quelle
1
Ist das nicht ein Fehler? Meine Güte GOPATH=/usr/local/go-pkgs, also sucht Go nach /usr/local/go-pkgs/src/<package-name>der Quelle, go getlegt sie aber ein /usr/local/go-pkgs/src/gopkg.in/<package-name>. Warum sollte ich alle meine Pakete nach der Installation manuell verschieben müssen? Das ist einfach albern.
Josiah
3
go getnormalerweise setzt Pakete in $GOPATH/src/so , wenn Sie nennen go get domain.com/path/to/packagees in enden wird $GOPATH/src/domain.com/path/to/package. Ich denke du versuchst ein Paket von zu holen gopkg.in? Wenn ja, ist das absolut beabsichtigtes Verhalten und Sie sollten sie einfach mit ihrem vollständigen Namen importieren. zB import "gopkg.in/yaml.v1"wie auch in den Dokumenten beschrieben .
Fasmat
1
Ahhhh, ich verstehe. Danke, dass du meine Unwissenheit zerstreut hast.
Josiah
10

Edit: da Sie GOPATH gemeint, siehe fasmat ‚s Antwort (upvoted)

Wie unter " Wie kann ich mein Paket finden? " Erwähnt , müssen Sie ein Paket xxxin ein Verzeichnis stellen xxx.

Siehe die Go-Sprachspezifikation :

package math

Eine Reihe von Dateien, die dieselbe PackageNameForm haben, bilden die Implementierung eines Pakets.
Eine Implementierung erfordert möglicherweise, dass sich alle Quelldateien für ein Paket im selben Verzeichnis befinden.

Die Kodex-Organisation erwähnt:

Wenn Sie ein Programm erstellen, das das Paket " widget" importiert, gosucht der Befehl src/pkg/widgetim Go-Stammverzeichnis und sucht dann - wenn die Paketquelle dort nicht gefunden wird - src/widgetin jedem Arbeitsbereich nacheinander.

(Ein "Arbeitsbereich" ist ein Pfadeintrag in Ihrem GOPATH: Diese Variable kann auf mehrere Pfade verweisen, damit Ihr ' src, bin, pkg' sein soll.)


(Ursprüngliche Antwort)

Sie sollten auch GOPATH~ / go einstellen , nicht GOROOTwie in " So schreiben Sie Go-Code " dargestellt.

Der Go-Pfad wird zum Auflösen von Importanweisungen verwendet. Es wird von dem Paket go / build implementiert und dokumentiert.

Die GOPATHUmgebungsvariable listet Orte auf, an denen nach Go-Code gesucht werden soll.
Unter Unix ist der Wert eine durch Doppelpunkte getrennte Zeichenfolge.
Unter Windows ist der Wert eine durch Semikolons getrennte Zeichenfolge.
In Plan 9 ist der Wert eine Liste.

Das ist anders als GOROOT:

Die Go-Binärdistributionen gehen davon aus, dass sie unter /usr/local/go(oder c:\Gounter Windows) installiert werden. Es ist jedoch möglich, sie an einem anderen Speicherort zu installieren.
Wenn Sie dies tun, müssen Sie die GOROOTUmgebungsvariable auf dieses Verzeichnis setzen, wenn Sie die Go-Tools verwenden.

VonC
quelle
4
Es gibt auch ein kurzes Video-Intro zum Aufbau des GOPATH
Ulf Holm Nielsen
1
Entschuldigung, ich habe die ursprüngliche Frage bearbeitet. Überall , sagte ich GOROOT ich gemeint GOPATH.
MitchellSalad
3

TL; DR: Befolgen Sie die Go-Konventionen! (Lektion auf die harte Tour gelernt), suchen Sie nach alten Go-Versionen und entfernen Sie sie. Neueste installieren.

Für mich war die Lösung anders. Ich habe auf einem gemeinsam genutzten Linux-Server gearbeitet und nachdem ich meine GOPATHund andere Umgebungsvariablen mehrmals überprüft hatte, funktionierte es immer noch nicht. Ich habe mehrere Fehler festgestellt, darunter "Paket kann nicht gefunden werden" und "Nicht erkannter Importpfad". Nach dem Versuch, diese Lösung anhand der Anweisungen auf golang.org (einschließlich des Deinstallationsteils ) neu zu installieren, traten immer noch Probleme auf.

Ich habe einige Zeit gebraucht, um festzustellen , dass es noch eine alte Version gibt, die nicht deinstalliert wurde (läuft go versiondann which gowieder ... DAHH), was mich zu dieser Frage gebracht und schließlich gelöst hat.

Moshisho
quelle
2

Obwohl die akzeptierte Antwort immer noch richtig ist, wenn Verzeichnisse mit Paketnamen abgeglichen werden müssen, müssen Sie wirklich zur Verwendung von Go-Modulen migrieren, anstatt GOPATH zu verwenden. Neue Benutzer, die auf dieses Problem stoßen, sind möglicherweise verwirrt über die Erwähnungen der Verwendung von GOPATH (wie ich), die jetzt veraltet sind. Daher werde ich versuchen, dieses Problem zu beheben und Anleitungen zur Vermeidung dieses Problems bei der Verwendung von Go-Modulen bereitzustellen.

Wenn Sie bereits mit Go-Modulen vertraut sind und dieses Problem auftritt, fahren Sie mit meinen spezifischeren Abschnitten fort, in denen einige der Go-Konventionen behandelt werden, die leicht zu übersehen oder zu vergessen sind.

Dieses Handbuch enthält Informationen zu Go-Modulen: https://golang.org/doc/code.html

Projektorganisation mit Go-Modulen

Organisieren Sie nach der Migration zu Go-Modulen, wie in diesem Artikel erwähnt, den Projektcode wie folgt:

Ein Repository enthält ein oder mehrere Module. Ein Modul ist eine Sammlung verwandter Go-Pakete, die zusammen veröffentlicht werden. Ein Go-Repository enthält normalerweise nur ein Modul, das sich im Stammverzeichnis des Repositorys befindet. Eine Datei mit dem Namen go.mod deklariert dort den Modulpfad: das Importpfadpräfix für alle Pakete innerhalb des Moduls. Das Modul enthält die Pakete im Verzeichnis, das die Datei go.mod enthält, sowie die Unterverzeichnisse dieses Verzeichnisses bis zum nächsten Unterverzeichnis, das eine andere Datei go.mod enthält (falls vorhanden).

Der Pfad jedes Moduls dient nicht nur als Importpfadpräfix für seine Pakete, sondern gibt auch an, wo der Befehl go suchen soll, um es herunterzuladen. Um beispielsweise das Modul golang.org/x/tools herunterzuladen, konsultiert der Befehl go das unter https://golang.org/x/tools angegebene Repository (hier näher beschrieben).

Ein Importpfad ist eine Zeichenfolge, die zum Importieren eines Pakets verwendet wird. Der Importpfad eines Pakets ist sein Modulpfad, der mit seinem Unterverzeichnis innerhalb des Moduls verknüpft ist. Das Modul github.com/google/go-cmp enthält beispielsweise ein Paket im Verzeichnis cmp /. Der Importpfad dieses Pakets lautet github.com/google/go-cmp/cmp. Pakete in der Standardbibliothek haben kein Modulpfadpräfix.

Sie können Ihr Modul folgendermaßen initialisieren:

$ go mod init github.com/mitchell/foo-app

Ihr Code muss sich nicht auf github.com befinden, damit er erstellt werden kann. Es wird jedoch empfohlen, Ihre Module so zu strukturieren, als würden sie irgendwann veröffentlicht.

Verstehen, was passiert, wenn versucht wird, ein Paket zu erhalten

Es gibt hier einen großartigen Artikel, der darüber spricht, was passiert, wenn Sie versuchen, ein Paket oder Modul zu erhalten: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Er beschreibt, wo das Paket gespeichert ist und wird helfen Ihnen zu verstehen, warum dieser Fehler möglicherweise auftritt, wenn Sie bereits Go-Module verwenden.

Stellen Sie sicher, dass die importierte Funktion exportiert wurde

Beachten Sie, dass Sie sicherstellen müssen, dass Sie Ihre Funktion exportiert haben, wenn Sie Probleme beim Zugriff auf eine Funktion aus einer anderen Datei haben. Wie im ersten Link beschrieben, muss eine Funktion mit einem Großbuchstaben beginnen, der exportiert und für den Import in andere Pakete verfügbar gemacht werden soll.

Namen von Verzeichnissen

Ein weiteres wichtiges Detail (wie in der akzeptierten Antwort erwähnt) ist, dass Namen von Verzeichnissen die Namen Ihrer Pakete definieren. (Ihre Paketnamen müssen mit ihren Verzeichnisnamen übereinstimmen.) Beispiele hierfür finden Sie hier: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc With Die Datei mit Ihrer mainMethode (dh dem Einstiegspunkt Ihrer Anwendung) ist jedoch von dieser Anforderung ausgenommen.

Als Beispiel hatte ich Probleme mit meinen Importen, wenn ich eine Struktur wie diese verwendete:

/my-app
├── go.mod
├── /src
   ├── main.go
   └── /utils
      └── utils.go

Ich konnte den Code nicht utilsin mein mainPaket importieren .

Sobald ich jedoch main.goein eigenes Unterverzeichnis erstellt habe, wie unten gezeigt, funktionierten meine Importe einwandfrei:

/my-app
├── go.mod
├── /src
   ├── /app
   |  └── main.go
   └── /utils
      └── utils.go

In diesem Beispiel sieht meine go.mod-Datei folgendermaßen aus:

module git.mydomain.com/path/to/repo/my-app

go 1.14

Wenn ich main.go nach dem Hinzufügen eines Verweises auf gespeichert habe utils.MyFunction(), hat meine IDE den Verweis auf mein Paket automatisch wie folgt abgerufen :

import "git.mydomain.com/path/to/repo/my-app/src/my-app"

(Ich verwende VS-Code mit der Golang-Erweiterung.)

Beachten Sie, dass der Importpfad das Unterverzeichnis zum Paket enthielt.

Umgang mit einem privaten Repo

Wenn der Code Teil eines privaten Repos ist, müssen Sie einen git-Befehl ausführen, um den Zugriff zu aktivieren. Andernfalls können andere Fehler auftreten. In diesem Artikel wird erwähnt, wie dies für private Github-, BitBucket- und GitLab-Repos durchgeführt wird: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Dieses Problem wird auch hier behandelt: Wie kann man ein privates Repository richtig " abrufen "?

Devinbost
quelle
-6

Haben Sie versucht, das absolute Verzeichnis von go zu Ihrem 'Pfad' hinzuzufügen ?

export PATH=$PATH:/directory/to/go/
RobEdouard
quelle
Der $ PATH hat nichts mit dem Pfad für Go-Pakete zu tun.
csgeek