Go build: «Не удается найти пакет» (даже если GOPATH установлен)

139

Несмотря на то, что я GOPATHправильно настроил, я все еще не могу получить команду «go build» или «go run», чтобы найти свои собственные пакеты. Что я делаю не так?

$ 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
источник
Я сталкиваюсь с той же проблемой, когда захожу на github.com/adonovan/gopl.io/tree/master/ch1/helloworld . Причина в том, что у него нет файла с именем helloworld.go. go get работает, сопоставляя имя пакета и имя файла.
keniee van
Также может быть, что вам нужно обновить Go. У меня была аналогичная проблема, когда у меня был существующий код, использующий go.mod для определения модуля. На тестовой машине я загрузил код и пытался его скомпилировать, но Go выдавал мне всевозможные ошибки, связанные с GOPATH и невозможностью найти модули. Это была версия Go 1.7. Как только я обновил Go, все заработало без проблем.
KyferEz
Типа, это терминал для получения актуального объяснения$ go help gopath
A1rPun

Ответы:

163

Это не работает, потому что ваш foobar.goисходный файл не находится в каталоге с именем foobar. go buildи go installпопробуйте сопоставить каталоги, а не исходные файлы.

  1. Установите $GOPATHдействительный каталог, напримерexport GOPATH="$HOME/go"
  2. Переместить foobar.goв $GOPATH/src/foobar/foobar.goи здание должно работать нормально.

Дополнительные рекомендуемые действия:

  1. Добавьте $GOPATH/binк себе $PATH:PATH="$GOPATH/bin:$PATH"
  2. Перейти main.goв подпапку $GOPATH/src, например$GOPATH/src/test
  3. go install testтеперь должен создать исполняемый файл, $GOPATH/binкоторый можно вызвать, набрав testв терминале.
fasmat
источник
1
Разве это не ошибка? Мой GOPATH=/usr/local/go-pkgs, так что Гоу ищет /usr/local/go-pkgs/src/<package-name>источник, но go getвставляет его /usr/local/go-pkgs/src/gopkg.in/<package-name>. Почему мне нужно вручную перемещать все мои пакеты после установки? Это просто глупо.
Иосия
3
go getобычно помещает пакеты в, $GOPATH/src/поэтому, если вы вызовете, go get domain.com/path/to/packageон окажется в $GOPATH/src/domain.com/path/to/package. Думаю, вы пытаетесь получить посылку gopkg.in? Если это так, это абсолютно запланированное поведение, и вам следует просто импортировать их с их полным именем; например, import "gopkg.in/yaml.v1"как также описано в документации .
fasmat
1
Аааа, понятно. Спасибо, что развеяли мое невежество.
Джозия
10

Edit: так как вы имели в виду GOPATH см fasmat «сек ответ (upvoted)

Как упоминалось в разделе « Как мне найти мой пакет? », Вам необходимо поместить пакет xxxв каталог xxx.

См. Спецификацию языка Go :

package math

Набор файлов, совместно использующих одно и то же, PackageNameформирует реализацию пакета.
Реализация может потребовать, чтобы все исходные файлы пакета находились в одном каталоге.

Организация Code упоминает:

При создании программы , которая импортирует пакет « widget» то goкоманда просматривает src/pkg/widgetвнутри корня Go, а затем, если исходный пакет не найден, он ищет src/widgetвнутри каждой рабочей области в порядке.

("рабочая область" - это запись пути в вашем GOPATH: эта переменная может ссылаться на несколько путей для вашего ' src, bin, pkg')


(Оригинальный ответ)

Вы также должны установить GOPATH~ / go, not GOROOT, как показано в разделе « Как писать код Go ».

Путь Go используется для разрешения операторов импорта. Он реализован и задокументирован в пакете go / build.

В GOPATHсписках переменных окружения места искать Go коду.
В Unix значение представляет собой строку, разделенную двоеточиями.
В Windows значение представляет собой строку, разделенную точкой с запятой.
На плане 9 значение представляет собой список.

Это отличается от GOROOT:

Бинарные дистрибутивы Go предполагают, что они будут установлены в /usr/local/go(или c:\Goпод Windows), но их можно установить в другом месте.
Если вы это сделаете, вам нужно будет установить GOROOTпеременную среды в этот каталог при использовании инструментов Go.

VonC
источник
4
Также есть короткое видео-вступление к настройке GOPATH
Ульф Холм Нильсен
1
Извините, я отредактировал исходный вопрос. Везде, где я говорил GOROOT, я имел в виду GOPATH.
MitchellSalad
3

TL; DR: соблюдайте соглашения Go! (урок усвоен на собственном горьком опыте), проверьте старые версии go и удалите их. Установите последнюю версию.

Для меня решение было другим. Я работал на общем сервере Linux, и после проверки моих GOPATHи других переменных среды несколько раз он все еще не работал. Я обнаружил несколько ошибок, включая «Не удается найти пакет» и «Неизвестный путь импорта». После попытки переустановки с помощью этого решения по инструкциям на golang.org (включая часть удаления ) все еще возникли проблемы.

Потребовалось некоторое время , чтобы понять , что есть еще старая версия , которая не была удалена (работает go versionзатем which goснова ... DAHH) , который заставил меня этим вопросом и , наконец , решена.

Moshisho
источник
2

Хотя принятый ответ по-прежнему верен в отношении необходимости сопоставления каталогов с именами пакетов, вам действительно нужно перейти на использование модулей Go вместо использования GOPATH. Новые пользователи, столкнувшиеся с этой проблемой, могут быть сбиты с толку упоминаниями об использовании GOPATH (как и я), которые сейчас устарели. Итак, я постараюсь прояснить эту проблему и дать рекомендации, связанные с предотвращением этой проблемы при использовании модулей Go.

Если вы уже знакомы с модулями Go и столкнулись с этой проблемой, перейдите к моим более конкретным разделам ниже, в которых рассматриваются некоторые соглашения Go, которые легко упустить из виду или забыть.

В этом руководстве рассказывается о модулях Go: https://golang.org/doc/code.html

Организация проекта с помощью модулей Go

После перехода на модули Go, как упоминалось в этой статье, организуйте код проекта, как описано:

Репозиторий содержит один или несколько модулей. Модуль - это набор связанных пакетов Go, которые выпускаются вместе. Репозиторий Go обычно содержит только один модуль, расположенный в корне репозитория. Файл с именем go.mod объявляет путь к модулю: префикс пути импорта для всех пакетов в модуле. Модуль содержит пакеты в каталоге, содержащем его файл go.mod, а также подкаталоги этого каталога, вплоть до следующего подкаталога, содержащего другой файл go.mod (если есть).

Путь к каждому модулю не только служит префиксом пути импорта для его пакетов, но также указывает, где команда go должна искать его для его загрузки. Например, чтобы загрузить модуль golang.org/x/tools, команда go обращается к репозиторию, указанному https://golang.org/x/tools (подробнее описано здесь).

Путь импорта - это строка, используемая для импорта пакета. Путь импорта пакета - это путь к модулю, соединенный с его подкаталогом внутри модуля. Например, модуль github.com/google/go-cmp содержит пакет в каталоге cmp /. Путь импорта этого пакета - github.com/google/go-cmp/cmp. Пакеты в стандартной библиотеке не имеют префикса пути к модулю.

Вы можете инициализировать свой модуль следующим образом:

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

Ваш код не обязательно должен находиться на github.com для его сборки. Однако лучше всего структурировать модули так, как будто они будут опубликованы.

Понимание того, что происходит при попытке получить посылку

Здесь есть отличная статья, в которой рассказывается о том, что происходит, когда вы пытаетесь получить пакет или модуль: https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 В нем обсуждается, где пакет хранится и будет поможет вам понять, почему вы можете получить эту ошибку, если вы уже используете модули Go.

Убедитесь, что импортированная функция была экспортирована

Обратите внимание: если у вас возникли проблемы с доступом к функции из другого файла, вам необходимо убедиться, что вы экспортировали свою функцию. Как описано в первой предоставленной мной ссылке, функция должна начинаться с заглавной буквы, чтобы ее можно было экспортировать и сделать доступной для импорта в другие пакеты.

Имена каталогов

Еще одна важная деталь (как упоминалось в принятом ответе) заключается в том, что имена каталогов определяют имена ваших пакетов. (Имена ваших пакетов должны совпадать с именами их каталогов.) Вы можете увидеть примеры этого здесь: https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc With при этом файл, содержащий ваш mainметод (т. е. точку входа вашего приложения), вроде как освобожден от этого требования.

Например, у меня были проблемы с импортом при использовании такой структуры:

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

Мне не удалось импортировать код в utilsсвой mainпакет.

Однако, как только я поместил main.goв отдельный подкаталог, как показано ниже, мой импорт работал нормально:

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

В этом примере мой файл go.mod выглядит так:

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

go 1.14

Когда я сохранил main.go после добавления ссылки на utils.MyFunction(), моя IDE автоматически вставила ссылку на мой пакет следующим образом:

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

(Я использую VS Code с расширением Golang.)

Обратите внимание, что путь импорта включает подкаталог пакета.

Работа с частным репо

Если код является частью частного репо, вам необходимо запустить команду git, чтобы разрешить доступ. В противном случае вы можете столкнуться с другими ошибками. В этой статье упоминается, как это сделать для частных репозиториев Github, BitBucket и GitLab: https://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 Эта проблема также обсуждается здесь: Как правильно «получить» частный репозиторий?

devinbost
источник
-6

Вы пробовали добавить абсолютный каталог перехода к своему «пути»?

export PATH=$PATH:/directory/to/go/
RobEdouard
источник
$ PATH не имеет ничего общего с вашим путем для пакетов go.
csgeek