Пользователь
120,7
рейтинг
2 февраля 2015 в 21:44

Разработка → Всё, что вы хотели знать про GOPATH и GOROOT

Go*
Несмотря на то, что Go считается одним из самых легких для входа языков, приходится регулярно слышать: «как-то все непонятно, какие-то переменные GOROOT и GOPATH нужно устанавливать». И хотя тема полностью раскрыта на официальном сайте Go, не будет лишним объяснить совсем простым языком.

TL;DR


Теперь чуть подробнее:

GOROOT


GOROOT — это переменная, указывающая, где лежит, собственно, вся бинарная сборка Go и исходные коды. Что-то вроде JAVA_HOME. Устанавливать эту переменную ручками нужно только в тех случаях, если вы ставите Go под Windows не с помощью MSI-инсталлера, а из zip-архива. Ну, или если вы хотите держать несколько версий Go, каждая в своей директории.

Раньше (до Go 1.0) эта переменная была нужна — её использовали скрипты сборки, равно как и GOARCH и GOOS. Но после Go 1.0 немного изменилась внутренняя логика работы go tool и сейчас значение GOROOT хардкодится на этапе сборки или инсталляции. Тоесть, go — дефолтно проинсталлированный — знает это значение и так. Его можно посмотреть с помощью команды:

go env GOROOT

В MacOS X это /usr/local/go/, в Linux тоже (хотя может зависеть от дистрибутива), в Windows — С:\Go.

GOPATH


А вот переменная GOPATH очень важна и нужна и её нужно установить обязательно, впрочем только один раз. Это ваш workspace, где будет лежать код и бинарные файлы всего с чем вы будете в Go работать. Поэтому выбирайте удобный вам путь и сохраняйте его в GOPATH. К примеру:

export GOPATH=~/go
export GOPATH=~/gocode
export GOPATH=~/Devel/go
export GOPATH=~/Projects/go

Ну и обязательно это сохраните в .profile или как вы там сохраняете переменные:

echo "export GOPATH=~/go" >> ~/.profile (или .bash_profile)

Всё, сделайте это один раз и забудьте. Создайте только эту директорию, если её еще и нет, и на этом готово. Теперь любой вызов go get github.com/someuser/somelib автоматически будет скачивать исходники в $GOPATH/src, а бинарный результат компиляции складывать в $GOPATH/pkg или $GOPATH/bin (для библиотек и исполняемых файлов соответственно).

PATH


Это опционально, но желательно сразу тоже сделать, раз уж вы взялись за настройку среды. Рано или поздно вы захотите пользоваться какими-то Go-программами, которые будут лежать в вашей GOPATH/bin. Чтобы их без лишних телодвижений использовать, добавьте к PATH директорию $GOPATH/bin:

export PATH=$PATH:$GOPATH/bin

Команда go install собирает и инсталлирует бинарник именно в эту директорию, поэтому это исключительно для удобства.

Структура Workspace


Теперь давайте посмотрим внимательно на структуру директории GOPATH. Возьму пример из официальной документации:

bin/
    hello                 # программа hello
pkg/
    linux_amd64/          # каталог этого уровня определяет ось и архитектуру для бинарных файлов
        github.com/user/
            stringutil.a  # объектный бинарный файл пакета stringutil
src/
    github.com/user/
        hello/
            hello.go      # исходный код программы hello
        stringutil/
            reverse.go    # исходный код библиотеки stringutil

Достаточно просто, не так ли? Важно понимать, что никто не обязывает называть директории в src/ по какому-то формату. Можно использовать и src/test/my_first_app/main.go и src/anyname/main.go — но если вы работаете с системами контроля версий (а вы таки работаете)), то вам это бесспорно станет удобно — утилиты go get/install используют это соглашения наименования, чтобы сделать работу с системами контроля версий безбожно простой.

Дополнительно


Переменная GOPATH аналогична стандартной PATH — можно указывать несколько директорий, через ':'. GOPATH=~/go:~/other_workspace. Это в очень редких случаях бывает полезно (например, для работы с внешними менеджерами зависимостей вроде gpm), но в 99% это не нужно, и просто так рекомендуется использовать только одну директорию в GOPATH.

В конце-концов, если вам нужны раздельные workspace-ы, всегда можно заменить переменную GOPATH на нужную (в скрипте сборки, к примеру). Так, собственно, и делают.

Ссылки


golang.org/doc/install
golang.org/doc/code.html
dave.cheney.net/2013/06/14/you-dont-need-to-set-goroot-really
divan0 @divan0
карма
128,0
рейтинг 120,7
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (19)

  • +1
    Можно начинать проект с создания репозитория (на GitHub или BitBucket), тогда вопрос какую папку создать отпадает, она будет $GOPATH/src/github.com/user/project.
    • 0
      Можно даже репозитарий не создавать. Просто сразу ему придумать имя и создать соответствующую структуру каталогов. Потом, если надо будет, сделаете репозитарий, и все запушите.
  • +1
    Есть другой вариант Workspace, который тоже применяется в «быту», обычно с использованием вместе менеджеров пакетов (gpm, gopm, etc..).
    Позволяет сделать в проекте подобие системы модулей.

    Project
    .../.godeps/… (Или любая другая папка от менеджера пакетов)
    .../bin/…
    .../pkg/…
    .../src/moduleone
    .../src/moduletwo
    ...main.go
    • +1
      Ну, имеет, конечно, право на жизнь и такой вариант — но это что обычно называют «don't fight go build system».
      • 0
        Не слышал о таком обычаи за проведенных мной 2 года в Go.
        • 0
          Почему? Это заезженная тема, по ней куча статей и топиков на golang-nuts/reddit и общая позиция (в том числе подкрепляемая официальными заявлениями Go-команды), в том, что single GOPATH — это официально поддерживаемый метод, а остальные способы активно не одобряются.
          • 0
            Потому что удобство первичного подхода заканчивается на втором проекте.
            Обычно, чтобы не скачивать все барахло и не тащить его за собой на продакшен, применяются менеджеры пакетов, а они, как правило — применяются в той самой архитектуре, что я дал выше. Исключений не видел, либо их просто нету.

            Вы можете написать, что можно составить список «go get» для себя и использовать его на продакшене, но когда речь заходит о контроле версий существующих пакетов при разработке — то он становится бесполезным.
            • 0
              Окей, с вашим примером, на самом деле, два момента:
              1) отдельный GOPATH для отдельного проекта
              2) исходники в корне GOPATH, видимо, для использования относительных путей для «модулей»

              Изолированный GOPATH — с зависимостями (как с применением менеджеров пакетов, так и без) — вобщем-то, не крамольно, и для «локинга» зависимостей — даже необходимо. Но это вполне ложится на исполнение менеджерами пакетов, не обязательно выделять отдельный GOPATH для каждого проекта. Я на самом деле стараюсь не пользоваться этими менеджерами, и поддерживать код с последними версиями всех зависимых библиотек (Go-Package-Store очень помогает). Но пока еще ни разу не пришлось, собственно, «поддерживать» — все таки «обещание backward-compatibility» достаточно хорошо и на авторов библиотек распространяется, создает некую культуру.

              Ну а второй момент — с выходом за src/ и относительными путями — это уж точно неодобрительная практика.

              В конце концов, если вы захотите завтра ваш проект заопенсорсить, и выложить на github — придется всю эту конструкцию с отдельным GOPATH и относительными именами рефакторить и менять под корень.
              • 0
                Вы видимо не работали с менеджером пакетов или не с теми работали. Не могу утверждать, но таковое ощущение создалось.
                Отдельных сущностей GOPATH не создается. Всегда есть команда, которая перенаправляет его на текущий проект с которым вы собираетесь работать.

                «Ну а второй момент — с выходом за src/ и относительными путями — это уж точно неодобрительная практика.»

                Если под «относительными путями» вы подразумеваете указание прямых директорий в импортах, то ничуть этого не происходит, из-за причины, описанной выше.
                Так же, когда проект идет в опен-сорс, то он выкладывается в полном виде с приложенным файлом для конкретного менеджера пакетов, чтобы можно было собрать быстро и без боли.

                И насчет — «backward-compatibility», не могу вешать никаких ярлыков, но вы живете в слишком прекрасной реальности. Я сам в своих библиотеках ломал зависимости и такое происходило во многих популярных, однако было заметно, когда очень долго пользуешься конкретной библиотекой.
                • 0
                  не могу вешать никаких ярлыков, но вы живете в слишком прекрасной реальности

                  Но таки повесили ярлык :) Нет, я не питаю иллюзий и прекрасно понимаю, что это происходит время от времени, но давайте будем откровенны — бОльшая часть библиотек в Go все-таки уважают принцип обратной совместимости, и, насколько это возможно, стремятся не ломать API. Или же — пишут большими жирными буквами — «unstable. possible API break in the future» или что-то вроде.
                  И это я говорю о вообще любых библиотеках, мелких и никем не используемых, в том числе. Самые же основные, популярные вещи (вроде gorilla или mysql/mgo/amqp-драйверов) — стабильны, и ломать в них API не будут, 100%.

                  Вобщем, я не отрицаю надобность dependency менеджмента, но стараюсь не использовать. В приватных проектах, где GOPATH шерится с другими разработчиками — время от времени обновляю зависимости с помощью Go-Package-Store, и это да — можно называть «GOPATH per project», но project тут в общем смысле — на самом деле там много go-программ и все используют один общий GOPATH.

                  И да, я не готов спорить сейчас по теме version/dependency-менеджмента, поскольку все варианты не пробовал, но, насколько я понимаю, все эти решения создают отдельную поддиректорию вроде _vendor или .godeps и в ней хранят все зависимости, и её же используют как (второй) GOPATH. При этом делается это автоматически, без форсирования использовать какую-то нестандартную схему GOPATH.

                  Если кто-то напишет подробный пост с различиями существующих решений — будет отлично и познавательно.
          • 0
            Пардон, из-за того, что в это время работал с продакшеном — допустил ошибки.
            Вместо продакшена, я имел ввиду локальное окружение, которое переносится куда нибудь в другое место или передается между разработчиками в своей команде.
  • 0
    Я пытался понять все это, официальную документацию читал. Но чесно говоря так и не понял, почему я не могу в любой произвольной папке создать и скомпилить программу на go. Допустим у меня есть некий проект на питоне, и вот где-то мне не хватило производительности и я решил переписать какой-то отдельный скрипт на go, почему бы мне хранить эту тулзу в внутри своего проекта. Кажется подход go предполагает, что я на любой чих буду писать какие-то универсальные тулзы или библиотеки. Но мне это не нужно. Допустим у меня есть еще другой проект в котором мне нужна аналогичная тулза с некоторыми отличиями. И вот в воркспесе go у меня появляются уже две тулзы с практически одинаковыми названиями. Тут уже придется добавлять префиксы, в каком проекте это используется.
    • 0
      Если у вас одиночная тулза, которая использует только стандартные либы, то проблем не должно быть. Вся эта идея с папками нужна для легкой и непринужденной установки чужих проектов и публикации своих. Запускать go build ./my_python_project/my_super_duper_tool.go вроде закон не запрещает (по крайней мере я попробовал и у меня получилось).
      • 0
        Нет, тулзе нужны внешние либы mgo. И возможно другие.
    • +1
      Как уже написали — вы можете «в любой произвольной папке создать и скомпилить программу на go».

      GOPATH — это что-то вроде PYTHON_PATH, переменная, указывающая, где лежат все ваши библиотеки и исходники. То, что ваш код удобнее складывать тоже в GOPATH/src — это не обязательное требование, но естественно возникающее удобство, как только вы начинаете писать код, который а) выкладывается в open-source б) начинается использоваться в других ваших или не ваших проектах. Тогда просто нет разницы — делаете вы go get драйверу mongo или своей библиотеке.

      И на самом деле GOPATH очень помогает, причем неявно, организовывать ваш код. Это просто и это удобно. С этой схемой сложно создавать хаос из исходников на компьютере. Попробуйте, и через какое-то время вы поймете, насколько это удобно. Вот тут, к примеру, один девелопер, вообще, говорит, что взял идею GOPATH на вооружение не только go-кода, но и для всего другого: mwholt.blogspot.com.es/2014/02/why-i-use-just-one-gopath.html
      • 0
        PYTHONPATH это другое, я его никогда не устанавливаю лишь в некоторых случаях для отладки, но и это обычно не нужно, к томуже в питоне есть vitrualenv.

        go get не работает вне GOPATH.
        • 0
          А для go есть go version manager (не путать с gvm aka Groovy enVironment Manager).
  • 0
    У меня еще появилась GOROOT_BOOTSTRAP
    Адепты собирающие tip из исходников думаю все прочувствовали)))
    • 0
      Ну, статья не для адептов )

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.