GOPATH и GOROOT больше не нужны?
Так повелось, что разработчики, ещё только начинающие знакомиться с Go, часто сталкиваются с проблемой выбора рабочей директории для Go-проектов. Новые гоферы часто пугают друг друга словами GOPATH и GOROOT.
Однако, в руководствах по быстрому старту с текущей версией Go (1.13) упоминания эти двух «страшных» слов вообще нет.
Давайте посмотрим, почему так. Для чистоты эксперимента я развернула свежую Ubuntu на виртуальной машине и установила Go по инструкции из Wiki:
sudo add-apt-repository ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install golang-go
Go 1.13 установлен и готов к использованию:
$ 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
Про GOROOT уже было прекрасно написано в статье 2015 года, и эта информация до сих пор актуальна.
Забавно, что среди списка директорий, выданных последней командой (whereis go), GOROOT на самом деле нет:
$ go env GOROOT /usr/lib/go-1.13
Итак, например, если для IDE мне понадобится указать путь к файлам стандартной библиотеки Go, я укажу
GOPATH и модули
Казалось бы, в этом месте надо бежать устанавливать GOPATH, но я не буду этого делать. На самом деле GOPATH уже и так задан:
$ go env GOPATH /home/elena/go
Меня устраивает вариант с GOPATH в
Я сразу создам директорию для своего первого проекта на Go. Это можно сделать в любом месте, например, прямо в домашнем каталоге. Также я сразу начну работать с инструментом Go Modules:
$ mkdir ~/hello $ go mod init github.com/rumyantseva/hello go: creating new go.mod: module github.com/rumyantseva/hello
Для команды
После вызова команды
$ tree ~/go /home/elena/go └── pkg └── mod └── cache └── lock 3 directories, 1 file
При этом lock-файл (в самом низу дерева) пока пуст. В каталоге
module github.com/rumyantseva/hello go 1.13
Именно в
Давайте теперь напишем приложение, использующее внешнюю зависимость. В директории
package main import ( "github.com/sirupsen/logrus" ) func main() { logrus.Info("Hello, world!") }
Конечно, в реальной жизни для написания "Hello, world!" можно обойтись и без logrus, но в этом примере эта библиотека поможет нам узнать, где хранятся файлы внешних зависимостей.
Запускаю приложение самым простым способом:
$ 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!
Перед тем, как приложение было собрано и запущено, сработал инструмент
В файл
module github.com/rumyantseva/hello go 1.13 require github.com/sirupsen/logrus v1.4.2 // indirect
Также появился файл
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=
Где же сам код зависимостей? Его можно найти в
Если вы уже сталкивались с инструментом go get, знаете, что он при вытягивании зависимостей фактически клонирует репозитории (например, в случае git с помощью git clone). Но
Модули представляют собой архивы. Во время работы с зависимостями go mod явно (если вы вызывали команду
$ go env GOPROXY https://proxy.golang.org,direct
Итак, в качестве прокси при сборке моего "Hello, World!" использовался proxy.golang.org. Конечно, эту переменную можно изменить, выбрав другое хранилище модулей. Например, можно развернуть свой собственный внутренний прокси компании, где будут храниться, в том числе, внутренние библиотеки, код которых не публиковался в open source.
В общем, если я начинаю новый проект и не против использования Go Modules, мне можно ничего не знать о GOPATH. Go самостоятельно создаст директорию
Когда нужен GOPATH?
Если вы принципиально не используете Go Modules (например, в легаси-проекте), уйти от более явной работы с GOPATH может быть не так просто.
Чтобы посмотреть, что будет с моим проектом, если я решила не использовать go mod, удаляю файлы
rm -rf ~/go ~/hello/go.mod ~/hello/go.sum
В директории
$ 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)
Вот они, эти страшные GOROOT и GOPATH!
Чтобы скомпилировать приложение, мне надо подтянуть зависимость в GOPATH. Делаю это с помощью старого доброго
$ 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
Что произошло? Первым делом,
Кстати, на моей чистой установке Ubuntu до сих пор не было клиента git и, чтобы
Запускаю приложение:
$ go run main.go INFO[0000] Hello, world!
Работает!
Вот только на уровне приложения я теперь не отслеживаю версии внешних зависимостей. Что, если из-за уязвимости в какой-то момент в репозитории
Рано или поздно, мне всё-таки понадобится инструмент для работы с зависимостями, и если Go Modules по какой-то причине не подходит, придётся искать что-то другое...
Заключение
В этой статье не рассмотрены некоторые специфичные моменты, и работа с внешними зависимостями в Go по-прежнему может вызвать много вопросов. Тем не менее, новые версии Go хотя бы не накладывают ограничений на то, где могут быть созданы рабочие каталоги ваших проектов.
Если вы начинаете новый проект, попробуйте Go Modules! Возвращаться к старому подходу к работе с зависимостями имеет смысл, только если что-то пошло не так. Кстати, если вы предпочитаете хранить все зависимости внутри проекта, Go Modules поддерживает режим vendor.
Если вам нужно работать с уже существующим проектом, и по каким-то причинам его не хочется переводить на Go Modules, в документации к проекту важно указать особенности его развёртывания и управления зависимостями. Если в проект придут новички, незнакомые со старыми подходами к работе с зависимостями, им будет гораздо проще разобраться с проектом, если вся документация будет на месте.