Allez construire: "Impossible de trouver le package" (même si GOPATH est défini)

139

Même si j'ai GOPATHcorrectement configuré, je ne peux toujours pas obtenir "go build" ou "go run" pour trouver mes propres paquets. Qu'est-ce que je fais mal?

$ 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
MitchellSalade
la source
Je rencontre le même problème quand je vais chercher github.com/adonovan/gopl.io/tree/master/ch1/helloworld La raison en est qu'il n'a pas de fichier de nom helloworld.go. aller travailler en faisant correspondre le nom du package et le nom de fichier.
keniee van
Il se peut également que vous deviez mettre à niveau Go. J'ai eu un problème similaire où j'avais du code existant utilisant go.mod pour définir un module. Sur une machine de test, j'avais téléchargé le code et j'essayais de le compiler mais Go me donnait toutes sortes d'erreurs liées à GOPATH et étant incapable de trouver des modules. C'était la version 1.7 de Go. Dès que j'ai mis à niveau Go, cela a fonctionné sans problème.
KyferEz
Tapez ceci est terminal pour une explication à jour$ go help gopath
A1rPun

Réponses:

163

Cela ne fonctionne pas car votre foobar.gofichier source ne se trouve pas dans un répertoire appelé foobar. go buildet go installessayez de faire correspondre les répertoires, pas les fichiers source.

  1. Définir $GOPATHsur un répertoire valide, par exempleexport GOPATH="$HOME/go"
  2. Déplacer foobar.govers $GOPATH/src/foobar/foobar.goet la construction devrait fonctionner très bien.

Étapes supplémentaires recommandées:

  1. Ajoutez $GOPATH/binà votre $PATHpar:PATH="$GOPATH/bin:$PATH"
  2. Déplacer main.govers un sous-dossier de $GOPATH/src, par exemple$GOPATH/src/test
  3. go install testdevrait maintenant créer un exécutable $GOPATH/binqui peut être appelé en tapant testdans votre terminal.
fasmat
la source
1
N'est-ce pas un bug? Mon GOPATH=/usr/local/go-pkgs, alors Go cherche /usr/local/go-pkgs/src/<package-name>la source, mais la go getmet /usr/local/go-pkgs/src/gopkg.in/<package-name>. Pourquoi devrais-je déplacer manuellement tous mes packages après l'installation? C'est juste idiot.
josiah
3
go getmet normalement des paquets dedans $GOPATH/src/donc si vous appelez, go get domain.com/path/to/packageil finira dans $GOPATH/src/domain.com/path/to/package. Je suppose que vous essayez de récupérer un colis gopkg.in? Si c'est le cas, c'est le comportement absolument prévu et vous devez simplement les importer avec leur nom complet; par exemple, import "gopkg.in/yaml.v1"comme également décrit dans la documentation .
fasmat le
1
Ahhhh, je vois. Merci d'avoir dissipé mon ignorance.
josiah
10

Edit: depuis que vous vouliez dire GOPATH, voir fasmat de » réponse (upvoted)

Comme mentionné dans " Comment faire pour que je trouve mon paquet? ", Vous devez mettre un paquet xxxdans un répertoire xxx.

Voir les spécifications de langue Go :

package math

Un ensemble de fichiers partageant la même PackageNameforme la mise en œuvre d'un package.
Une implémentation peut exiger que tous les fichiers source d'un package se trouvent dans le même répertoire.

L' organisation du Code mentionne:

Lors de la création d'un programme qui importe le package " widget", la gocommande recherche à l' src/pkg/widgetintérieur de la racine Go, puis - si la source du package n'y est pas trouvée - elle recherche src/widgetdans chaque espace de travail dans l'ordre.

(un «espace de travail» est une entrée de chemin dans votre GOPATH: cette variable peut référencer plusieurs chemins pour que votre « src, bin, pkg» soit)


(Réponse originale)

Vous devez également définir GOPATH~ / go, non GOROOT, comme illustré dans " Comment écrire du code Go ".

Le chemin Go est utilisé pour résoudre les instructions d'importation. Il est implémenté et documenté dans le package go / build.

La GOPATHvariable d'environnement répertorie les endroits où rechercher du code Go.
Sous Unix, la valeur est une chaîne séparée par deux-points.
Sous Windows, la valeur est une chaîne séparée par des points-virgules.
Sur le plan 9, la valeur est une liste.

C'est différent de GOROOT:

Les distributions binaires Go supposent qu'elles seront installées dans /usr/local/go(ou c:\Gosous Windows), mais il est possible de les installer dans un emplacement différent.
Si vous faites cela, vous devrez définir la GOROOTvariable d'environnement sur ce répertoire lors de l'utilisation des outils Go.

VonC
la source
4
Il y a aussi une courte vidéo d'introduction à la configuration du GOPATH
Ulf Holm Nielsen
1
Désolé, j'ai modifié la question d'origine. Partout où j'ai dit GOROOT, je voulais dire GOPATH.
MitchellSalad
3

TL; DR: Suivez les conventions de Go! (leçon apprise à la dure), vérifiez les anciennes versions de go et supprimez- les. Installez le dernier.

Pour moi, la solution était différente. J'ai travaillé sur un serveur Linux partagé et après avoir vérifié GOPATHplusieurs fois mes variables d'environnement et d'autres, cela ne fonctionnait toujours pas. J'ai rencontré plusieurs erreurs, notamment "Impossible de trouver le package" et "Chemin d'importation non reconnu". Après avoir essayé de réinstaller avec cette solution en suivant les instructions sur golang.org (y compris la partie de désinstallation ), des problèmes ont encore été rencontrés.

Il m'a fallu un certain temps pour se rendre compte qu'il ya encore une ancienne version qui n'a pas été désinstallés ( en cours d' exécution , go versionpuis à which gonouveau ... DAHH) qui m'a fait cette question et enfin résolu.

Moshisho
la source
2

Bien que la réponse acceptée soit toujours correcte concernant la nécessité de faire correspondre les répertoires avec les noms de package, vous devez vraiment migrer vers les modules Go au lieu d'utiliser GOPATH. Les nouveaux utilisateurs qui rencontrent ce problème peuvent être confus sur les mentions d'utilisation de GOPATH (comme je l'étais), qui sont maintenant obsolètes. Je vais donc essayer de résoudre ce problème et de fournir des conseils associés à la prévention de ce problème lors de l'utilisation des modules Go.

Si vous êtes déjà familiarisé avec les modules Go et que vous rencontrez ce problème, passez à mes sections plus spécifiques ci-dessous qui couvrent certaines des conventions Go qu'il est facile d'oublier ou d'oublier.

Ce guide présente les modules Go: https://golang.org/doc/code.html

Organisation de projet avec les modules Go

Une fois que vous avez migré vers les modules Go, comme mentionné dans cet article, organisez le code du projet comme décrit:

Un référentiel contient un ou plusieurs modules. Un module est une collection de packages Go associés qui sont publiés ensemble. Un référentiel Go contient généralement un seul module, situé à la racine du référentiel. Un fichier nommé go.mod y déclare le chemin du module: le préfixe du chemin d'importation pour tous les packages du module. Le module contient les packages dans le répertoire contenant son fichier go.mod ainsi que les sous-répertoires de ce répertoire, jusqu'au sous-répertoire suivant contenant un autre fichier go.mod (le cas échéant).

Le chemin de chaque module sert non seulement de préfixe de chemin d'importation pour ses packages, mais indique également où la commande go doit chercher pour le télécharger. Par exemple, pour télécharger le module golang.org/x/tools, la commande go consulterait le référentiel indiqué par https://golang.org/x/tools (décrit plus en détail ici).

Un chemin d'importation est une chaîne utilisée pour importer un package. Le chemin d'importation d'un package est son chemin de module joint à son sous-répertoire dans le module. Par exemple, le module github.com/google/go-cmp contient un package dans le répertoire cmp /. Le chemin d'importation de ce package est github.com/google/go-cmp/cmp. Les packages de la bibliothèque standard n'ont pas de préfixe de chemin de module.

Vous pouvez initialiser votre module comme ceci:

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

Votre code n'a pas besoin d'être localisé sur github.com pour qu'il soit généré. Cependant, il est recommandé de structurer vos modules comme s'ils allaient éventuellement être publiés.

Comprendre ce qui se passe lorsque vous essayez d'obtenir un colis

Il y a un excellent article ici qui parle de ce qui se passe lorsque vous essayez d'obtenir un package ou un module: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 Il explique où le package est stocké et sera vous aider à comprendre pourquoi vous pourriez obtenir cette erreur si vous utilisez déjà des modules Go.

Assurez-vous que la fonction importée a été exportée

Notez que si vous rencontrez des difficultés pour accéder à une fonction à partir d'un autre fichier, vous devez vous assurer que vous avez exporté votre fonction. Comme décrit dans le premier lien que j'ai fourni, une fonction doit commencer par une lettre majuscule pour être exportée et rendue disponible pour être importée dans d'autres packages.

Noms des répertoires

Un autre détail critique (comme cela a été mentionné dans la réponse acceptée) est que les noms de répertoires définissent les noms de vos packages. (Les noms de vos packages doivent correspondre à leurs noms de répertoires.) Vous pouvez en voir des exemples ici: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc Avec Cela dit, le fichier contenant votre mainméthode (c'est-à-dire le point d'entrée de votre application) est en quelque sorte exempté de cette exigence.

À titre d'exemple, j'ai eu des problèmes avec mes importations lors de l'utilisation d'une structure comme celle-ci:

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

Je n'ai pas pu importer le code utilsdans mon mainpackage.

Cependant, une fois que j'ai mis main.godans son propre sous-répertoire, comme indiqué ci-dessous, mes importations ont très bien fonctionné:

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

Dans cet exemple, mon fichier go.mod ressemble à ceci:

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

go 1.14

Lorsque j'ai enregistré main.go après avoir ajouté une référence à utils.MyFunction(), mon IDE a automatiquement extrait la référence à mon package comme ceci:

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

(J'utilise VS Code avec l'extension Golang.)

Notez que le chemin d'importation incluait le sous-répertoire du package.

Gérer un repo privé

Si le code fait partie d'un dépôt privé, vous devez exécuter une commande git pour activer l'accès. Sinon, vous pouvez rencontrer d'autres erreurs. Cet article explique comment faire cela pour les dépôts privés Github, BitBucket et GitLab: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Ce problème est également abordé ici: Quelle est la bonne façon de «récupérer» un dépôt privé?

devinbost
la source
-6

Avez-vous essayé d'ajouter le répertoire absolu de go à votre «chemin»?

export PATH=$PATH:/directory/to/go/
RobEdouard
la source
le $ PATH n'a rien à voir avec le chemin des paquets go.
csgeek