Idź do budowania: „Nie można znaleźć pakietu” (mimo że ustawiono GOPATH)

150

Mimo że mam GOPATHustawione prawidłowo, nadal nie mogę znaleźć własnych pakietów w trybie „go build” lub „go run”. Co ja robię źle?

$ 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
źródło
Napotykam ten sam problem, kiedy wchodzę na github.com/adonovan/gopl.io/tree/master/ch1/helloworld . Powodem może być brak pliku o nazwie helloworld.go. go uzyskać, dopasowując nazwę pakietu i nazwę pliku.
keniee van
Może się również zdarzyć, że musisz zaktualizować Go. Miałem podobny problem, gdy miałem istniejący kod przy użyciu go.mod do zdefiniowania modułu. Na maszynie testowej pobrałem kod i próbowałem go skompilować, ale Go dawał mi różnego rodzaju błędy związane z GOPATH i nie mogłem znaleźć modułów. To była wersja Go 1.7. Jak tylko zaktualizowałem Go, działało bez problemu.
KyferEz
Wpisz to jest terminal, aby uzyskać aktualne wyjaśnienie$ go help gopath
A1rPun

Odpowiedzi:

169

Nie działa, ponieważ foobar.goplik źródłowy nie znajduje się w katalogu o nazwie foobar. go buildi go installspróbuj dopasować katalogi, a nie pliki źródłowe.

  1. Ustaw $GOPATHna prawidłowy katalog, npexport GOPATH="$HOME/go"
  2. Przeprowadzka foobar.godo $GOPATH/src/foobar/foobar.goi budowanie powinno działać dobrze.

Dodatkowe zalecane kroki:

  1. Dodaj $GOPATH/bindo swojego $PATH:PATH="$GOPATH/bin:$PATH"
  2. Przejdź main.godo podfolderu $GOPATH/srcnp$GOPATH/src/test
  3. go install testpowinien teraz utworzyć plik wykonywalny, $GOPATH/binktóry można wywołać, wpisując go testw terminalu.
fasmat
źródło
1
Czy to nie jest błąd? My GOPATH=/usr/local/go-pkgs, więc Go szuka /usr/local/go-pkgs/src/<package-name>źródła, ale go getwstawia je /usr/local/go-pkgs/src/gopkg.in/<package-name>. Dlaczego po instalacji powinienem ręcznie przenosić wszystkie moje pakiety? To po prostu głupie.
josiah
3
go getnormalnie umieszcza pakiety w, $GOPATH/src/więc jeśli zadzwonisz go get domain.com/path/to/package, skończy się w $GOPATH/src/domain.com/path/to/package. Myślę, że próbujesz pobrać paczkę z gopkg.in? Jeśli tak, jest to absolutnie zamierzone zachowanie i powinieneś po prostu zaimportować je z ich pełną nazwą; np. import "gopkg.in/yaml.v1"jak również opisano w dok .
fasmat
1
Ahhhh, rozumiem. Dziękuję za rozwianie mojej ignorancji.
josiah
10

Edit: ponieważ chodziło GOPATH patrz fasmat „s odpowiedź (upvoted)

Jak wspomniano w „ Jak mam znaleźć mój pakiet? ”, Musisz umieścić pakiet xxxw katalogu xxx.

Zobacz specyfikację języka Go :

package math

Zestaw plików udostępniających taką samą PackageNamepostać jak wykonanie pakietu.
Implementacja może wymagać, aby wszystkie pliki źródłowe pakietu znajdowały się w tym samym katalogu.

Organizacja Kodeksu wspomina:

Podczas budowania programu, który importuje pakiet „ widget” te gospojrzenia na polecenie src/pkg/widgetwewnątrz korzenia Go, a wtedy, jeśli źródłem pakiet nie zostanie znaleziony tam-wyszukuje src/widgetwewnątrz każdego obszaru roboczego w porządku.

(„obszar roboczy” to wpis ścieżki w Twoim GOPATH: ta zmienna może odnosić się do wielu ścieżek, aby Twój „ src, bin, pkg” był)


(Oryginalna odpowiedź)

Powinieneś także ustawić GOPATH~ / go, a nie GOROOT, jak pokazano w „ Jak napisać kod Go ”.

Ścieżka Go służy do rozwiązywania instrukcji importu. Jest zaimplementowany i udokumentowany w pakiecie go / build.

Do GOPATHwymienia zmiennym otoczeniu miejsca szukać kodu Go.
W systemie Unix wartość jest łańcuchem rozdzielanym dwukropkami.
W systemie Windows wartość jest ciągiem rozdzielanym średnikami.
W planie 9 wartością jest lista.

To różni się od GOROOT:

Dystrybucje binarne Go zakładają, że zostaną zainstalowane w /usr/local/go(lub c:\Gopod Windows), ale można je zainstalować w innej lokalizacji.
Jeśli to zrobisz, będziesz musiał ustawić GOROOTzmienną środowiskową na ten katalog podczas korzystania z narzędzi Go.

VonC
źródło
4
Jest też krótkie wideo wprowadzające do przygotowania GOPATH
Ulf Holm Nielsen
1
Przepraszam, zredagowałem oryginalne pytanie. Wszędzie, gdzie mówiłem GOROOT, miałem na myśli GOPATH.
MitchellSalad
5

Chociaż zaakceptowana odpowiedź jest nadal poprawna, jeśli chodzi o konieczność dopasowania katalogów do nazw pakietów, naprawdę musisz przejść do używania modułów Go zamiast używania GOPATH. Nowi użytkownicy, którzy napotkają ten problem, mogą być zdezorientowani wzmiankami o używaniu GOPATH (tak jak ja), które są teraz nieaktualne. Postaram się więc wyjaśnić ten problem i udzielić wskazówek związanych z zapobieganiem temu problemowi podczas korzystania z modułów Go.

Jeśli znasz już moduły Go i masz ten problem, przejdź do moich bardziej szczegółowych sekcji poniżej, które obejmują niektóre konwencje Go, które łatwo przeoczyć lub zapomnieć.

Ten przewodnik uczy o modułach Go: https://golang.org/doc/code.html

Organizacja projektu za pomocą modułów Go

Po migracji do modułów Go, jak wspomniano w tym artykule, zorganizuj kod projektu zgodnie z opisem:

Repozytorium zawiera co najmniej jeden moduł. Moduł to zbiór powiązanych pakietów Go, które są wydawane razem. Repozytorium Go zazwyczaj zawiera tylko jeden moduł znajdujący się w katalogu głównym repozytorium. Plik o nazwie go.mod deklaruje ścieżkę modułu: prefiks ścieżki importu dla wszystkich pakietów w module. Moduł zawiera pakiety w katalogu zawierającym jego plik go.mod, a także podkatalogi tego katalogu, aż do następnego podkatalogu zawierającego inny plik go.mod (jeśli istnieje).

Ścieżka każdego modułu nie tylko służy jako prefiks ścieżki importu dla jego pakietów, ale także wskazuje, gdzie polecenie go powinno szukać, aby go pobrać. Na przykład, aby pobrać moduł golang.org/x/tools, polecenie go skonsultuje się z repozytorium wskazanym przez https://golang.org/x/tools (opisane więcej tutaj).

Ścieżka importu to ciąg znaków używany do importowania pakietu. Ścieżka importu pakietu to ścieżka jego modułu połączona z podkatalogiem w module. Na przykład moduł github.com/google/go-cmp zawiera pakiet w katalogu cmp /. Ścieżka importu tego pakietu to github.com/google/go-cmp/cmp. Pakiety w bibliotece standardowej nie mają przedrostka ścieżki modułu.

Możesz zainicjować swój moduł w następujący sposób:

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

Twój kod nie musi znajdować się na github.com, aby mógł zostać zbudowany. Jednak najlepszą praktyką jest uporządkowanie modułów w taki sposób, jakby były ostatecznie publikowane.

Zrozumienie, co się dzieje podczas próby odebrania paczki

Jest tutaj świetny artykuł, który mówi o tym, co się dzieje, gdy próbujesz uzyskać pakiet lub moduł: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Omawia, gdzie pakiet jest przechowywany i będzie pomoże Ci zrozumieć, dlaczego możesz otrzymać ten błąd, jeśli już używasz modułów Go.

Upewnij się, że zaimportowana funkcja została wyeksportowana

Zwróć uwagę, że jeśli masz problemy z dostępem do funkcji z innego pliku, musisz upewnić się, że funkcja została wyeksportowana. Jak opisano w pierwszym linku, który podałem, funkcja musi zaczynać się od dużej litery, aby można ją było wyeksportować i udostępnić do zaimportowania do innych pakietów.

Nazwy katalogów

Kolejnym krytycznym szczegółem (jak wspomniano w zaakceptowanej odpowiedzi) jest to, że nazwy katalogów definiują nazwy twoich pakietów. (Nazwy twoich pakietów muszą być zgodne z nazwami ich katalogów.) Możesz zobaczyć przykłady tutaj: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc With To powiedziawszy, plik zawierający twoją mainmetodę (tj. punkt wejścia twojej aplikacji) jest jakby zwolniony z tego wymogu.

Na przykład miałem problemy z importem, gdy korzystałem z takiej struktury:

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

Nie udało mi się zaimportować kodu utilsdo mojego mainpakietu.

Jednak po umieszczeniu main.gowe własnym podkatalogu, jak pokazano poniżej, mój import działał dobrze:

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

W tym przykładzie mój plik go.mod wygląda następująco:

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

go 1.14

Kiedy zapisałem main.go po dodaniu odwołania do utils.MyFunction(), moje IDE automatycznie pobierało odwołanie do mojego pakietu w następujący sposób:

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

(Używam VS Code z rozszerzeniem Golang).

Zwróć uwagę, że ścieżka importu zawierała podkatalog do pakietu.

Radzenie sobie z prywatnym repo

Jeśli kod jest częścią prywatnego repozytorium, musisz uruchomić polecenie git, aby umożliwić dostęp. W przeciwnym razie możesz napotkać inne błędy Ten artykuł wspomina, jak to zrobić w przypadku prywatnych repozytoriów Github, BitBucket i GitLab: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Ten problem jest również omawiany tutaj: Jaki jest właściwy sposób na „zdobycie” prywatnego repozytorium?

devinbost
źródło
3

TL; DR: konwencje Follow Go! (lekcja na własnej skórze), sprawdź starsze wersje go i usuń je. Zainstaluj najnowsze.

Dla mnie rozwiązanie było inne. Pracowałem na współdzielonym serwerze Linux i po GOPATHkilkukrotnej weryfikacji moich i innych zmiennych środowiskowych nadal nie działał. Napotkałem kilka błędów, w tym „Nie można znaleźć pakietu” i „Nierozpoznana ścieżka importu”. Po próbie ponownej instalacji tego rozwiązania zgodnie z instrukcjami na golang.org (łącznie z częścią odinstalowującą ) nadal występowały problemy.

Zajęło mi trochę czasu, zanim zdałem sobie sprawę, że wciąż istnieje stara wersja, która nie została odinstalowana ( go versiona potem uruchomiona which go... DAHH), co doprowadziło mnie do tego pytania i ostatecznie rozwiązane.

Moshisho
źródło
3

W ostatnich wersjach go, począwszy od 1.14, musimy to zrobić go mod vendorprzed budowaniem lub uruchomieniem, ponieważ domyślnie go dołącza -mod=vendordo poleceń go. Więc po wykonaniu tej czynności go mod vendor, jeśli spróbujemy budować, nie napotkamy tego problemu.

Luna Lovegood
źródło
1
Mam nadzieję, że wkrótce pojawi się to w wynikach wyszukiwania wyżej, ponieważ dokładnie to chciałem wiedzieć.
Jordan Mackie
1

Rozwiązałem ten problem, wyłączając go env GO111MODULE

go env -w  GO111MODULE=off
yuxuan li
źródło
-6

Czy próbowałeś dodać katalog bezwzględny go do swojej „ścieżki”?

export PATH=$PATH:/directory/to/go/
RobEdouard
źródło
$ PATH nie ma nic wspólnego ze ścieżką do pakietów go.
csgeek