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

    Несмотря на то, что 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
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 21
    • +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
              У меня еще появилась GOROOT_BOOTSTRAP
              Адепты собирающие tip из исходников думаю все прочувствовали)))
              • 0
                Ну, статья не для адептов )
              • 0
                Когда-то начал изучать Го, потом бросил, не понял как быть если я пишу две разные софтины? Мне потом менять GOPATH для второй софтины? Или Го сам понимает к какому скрипту какую зависимость прицепить при компиляции. То есть каждый новый проект в отдельную папку src/, потом через go get ставим пакеты, а потом каждый проект решает какой себе пакет взять, я правильно понял?

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