Инструментальные комплекты Go

Введение

Начиная с Go 1.21, дистрибутив Go состоит из команды go и включенного в комплект набора инструментов Go, который включает стандартную библиотеку, компилятор, ассемблер и другие инструменты. Команда go может использовать свой встроенный набор инструментов Go, а также другие версии, которые она находит в локальном PATH или загружает по мере необходимости.

Выбор используемого набора инструментов Go зависит от настройки окружения GOTOOLCHAIN и строк go и toolchain в основном модуле в файле go.mod или в текущем рабочем пространстве в файле go.work. По мере перехода между различными основными модулями и рабочими пространствами версия используемого набора инструментов может отличаться, как и версии зависимостей модулей.

В стандартной конфигурации команда go использует свой собственный встроенный набор инструментов, если этот набор инструментов не старше, чем строки go или toolchain в основном модуле или рабочем пространстве. Например, при использовании команды go, поставляемой с Go 1.21.3, в основном модуле, в котором указано go 1.21.0, команда go будет использовать Go 1.21.3. Когда строка go или toolchain указывает на более новую версию, чем встроенный набор инструментов, команда go запускает более новую версию набора инструментов. Например, при использовании команды go, поставляемой с Go 1.21.3, в основном модуле, в котором указано go 1.21.9, команда go найдёт и запустит Go 1.21.9. Сначала она ищет программу с именем go1.21.9 в PATH, иначе загружает и кэширует копию набора инструментов Go 1.21.9. Эта автоматическая смена набора инструментов может быть отключена, но в этом случае, для более точной обратной совместимости, команда go откажется запускаться в основном модуле или рабочем пространстве, где строка go требует более новую версию Go. То есть строка go устанавливает минимально необходимую версию Go, необходимую для использования модуля или рабочего пространства.

Модули, являющиеся зависимостями других модулей, могут требовать установки минимальной версии Go, ниже чем предпочтительная версия набора инструментов, используемая при прямой работе с этим модулем. В этом случае строка toolchain в go.mod или go.work устанавливает предпочтительный набор инструментов, который имеет приоритет над строкой go при принятии решения о том, какой набор инструментов использовать.

Строки go и toolchain можно рассматривать как указание требований к версии для зависимости модуля от самого набора инструментов Go, аналогично строкам require в go.mod, которые указывают требования к версии для зависимостей от других модулей. Команда go get управляет зависимостью от набора инструментов Go так же, как она управляет зависимостями от других модулей. Например, go get go@latest обновляет модуль, чтобы он требовал последнюю выпущенную версию набора инструментов Go.

Параметр среды GOTOOLCHAIN может принудительно задать определённую версию Go, перезаписывая строки go и toolchain. Например, чтобы протестировать пакет с помощью Go 1.21rc3:

<code>GOTOOLCHAIN=go1.21rc3 go test
</code>

Значение GOTOOLCHAIN по умолчанию — auto, что включает переключение инструментария, описанное выше. Альтернативная форма <name>+auto устанавливает инструментарий по умолчанию, который будет использоваться до принятия решения о дальнейшем переключении. Например, GOTOOLCHAIN=go1.21.3+auto указывает команде go начать принятие решения с использованием Go 1.21.3, но при этом использовать более новую версию инструментария, если это указано в строках go и toolchain.

Поскольку значение GOTOOLCHAIN по умолчанию можно изменить с помощью go env -w, если установлен Go 1.21.0 или новее, то

<code>go env -w GOTOOLCHAIN=go1.21.3+auto
</code>

эквивалентно замене установки Go 1.21.0 на Go 1.21.3.

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

Версии Go

Выпущенные версии Go используют синтаксис версий «1.N.P», обозначая P-й выпуск Go 1.N. Первый выпуск — это 1.N.0, например, «1.21.0». Последующие выпуски, такие как 1.N.9, часто называют патч-релизами.

Кандидаты в релизы Go 1.N, которые выпускаются до 1.N.0, используют синтаксис версий «1.NrcR». Первый кандидат в релиз для Go 1.N имеет версию 1.Nrc1, например, 1.23rc1.

Синтаксис «1.N» называется «языковой версией». Он обозначает общую семью выпусков Go, реализующих эту версию языка Go и стандартной библиотеки.

Языковая версия для версии Go — это результат усечения всего, что следует после N: 1.21, 1.21rc2 и 1.21.3 все реализуют языковую версию 1.21.

Выпущенные инструментарии Go, такие как Go 1.21.0 и Go 1.21rc1, сообщают об этой конкретной версии (например, go1.21.0 или go1.21rc1) из команды go version и runtime.Version. Неофициальные (все ещё находящиеся в разработке) инструментарии Go, собранные из репозитория разработки Go, вместо этого сообщают только языковую версию (например, go1.21).

Любые две версии Go можно сравнить, чтобы определить, меньше одна, больше или равна другой. Если языковые версии различаются, это определяет результат сравнения: 1.21.9 < 1.22. Внутри языковой версии порядок от наименьшего к наибольшему следующий: сама языковая версия, затем кандидаты в релизы, упорядоченные по R, затем релизы, упорядоченные по P.

Например, 1.21 < 1.21rc1 < 1.21rc2 < 1.21.0 < 1.21.1 < 1.21.2.

До Go 1.21 первый выпуск инструментария имел версию 1.N, а не 1.N.0, поэтому для N < 21 порядок корректируется так, чтобы 1.N находилась после кандидатов в релизы.

Например, 1.20rc1 < 1.20rc2 < 1.20rc3 < 1.20 < 1.20.1.

Ранее в Go существовали бета-релизы, с версиями вроде 1.18beta2. Бета-релизы размещаются непосредственно перед кандидатами на релиз в порядке версий.

Например, 1.18beta1 < 1.18beta2 < 1.18rc1 < 1.18 < 1.18.1.

Названия инструментов Go

Стандартные инструменты Go называются goV, где V — это версия Go, обозначающая бета-релиз, кандидата на релиз или релиз. Например, go1.21rc1 и go1.21.0 — это названия инструментов; go1.21 и go1.22 — нет (начальные релизы — это go1.21.0 и go1.22.0), но go1.20 и go1.19 — да.

Нестандартные инструменты используют названия вида goV-suffix для любого суффикса.

Инструменты сравниваются путём сравнения версии V, встроенной в название (удаляется начальный go и отбрасывается любой суффикс, начинающийся с -). Например, go1.21.0 и go1.21.0-custom считаются равными при сортировке.

Конфигурация модулей и рабочих пространств

Go модули и рабочие пространства указывают конфигурацию, связанную с версиями, в своих файлах go.mod или go.work.

Строка go объявляет минимально необходимую версию Go для использования модуля или рабочего пространства. В целях совместимости, если строка go опущена в файле go.mod, модуль считается имеющим неявную строку go 1.16, а если строка go опущена в файле go.work, рабочее пространство считается имеющим неявную строку go 1.18.

Строка toolchain объявляет предпочтительный инструмент для использования с модулем или рабочим пространством. Как описано в разделе “Выбор инструментов Go” ниже, команда go может запустить этот конкретный инструмент, если версия инструмента по умолчанию меньше версии, указанной в строке toolchain. Если строка toolchain опущена, модуль или рабочее пространство считаются имеющими неявную строку toolchain goV, где V — это версия Go из строки go.

Например, go.mod, который указывает go 1.21.0 без строки toolchain, интерпретируется как будто он имеет строку toolchain go1.21.0.

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

Например, Go 1.21.2 откажется загружать модуль или рабочее пространство с строкой go 1.21.3 или go 1.22.

Строка go модуля должна объявлять версию, большую или равную версии go, объявленной в каждом из модулей, перечисленных в инструкциях require. Строка go рабочего пространства должна объявлять версию, большую или равную версии go, объявленной в каждом из модулей, перечисленных в инструкциях use.

Например, если модуль M требует зависимость D с файлом go.mod, в котором указано go 1.22.0, тогда go.mod модуля M не может содержать go 1.21.3.

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

Например, модуль, содержащий код, использующий версию языка Go 1.21, должен иметь файл go.mod со строкой go 1.21 или go 1.21.3. Если конкретный исходный файл должен компилироваться только при использовании более новой версии инструментария Go, добавление //go:build go1.22 в этот исходный файл гарантирует, что файл будет скомпилирован только с использованием инструментария Go 1.22 и выше, а также изменяет версию языка в этом файле на Go 1.22.

Строки go и toolchain удобнее всего и безопаснее всего изменять с помощью команды go get; см. раздел, посвящённый команде go get ниже.

До версии Go 1.21 инструментарий Go рассматривал строку go как рекомендательное требование: если сборка проходила успешно, инструментарий считал, что всё в порядке, а если нет — выводил предупреждение о возможном несоответствии версий. В Go 1.21 строка go стала обязательным требованием. Это поведение частично реализовано в более ранних версиях языка: выпуски Go 1.19, начиная с Go 1.19.13, и выпуски Go 1.20, начиная с Go 1.20.8, отказываются загружать рабочие пространства или модули, объявляющие версию Go 1.22 или выше.

До Go 1.21 инструментарии не требовали, чтобы модуль или рабочее пространство имели строку go, значение которой было бы больше или равно версии go, необходимой каждому из зависимых модулей.

Настройка GOTOOLCHAIN

Команда go выбирает используемый инструментарий Go на основе настройки GOTOOLCHAIN. Чтобы определить значение GOTOOLCHAIN, команда go использует стандартные правила для любых настроек среды Go:

В стандартных наборах инструментов Go файл $GOROOT/go.env устанавливает значение по умолчанию GOTOOLCHAIN=auto, но перепакованные наборы инструментов Go могут изменить это значение.

Если файл $GOROOT/go.env отсутствует или не устанавливает значение по умолчанию, команда go предполагает GOTOOLCHAIN=local.

Запуск команды go env GOTOOLCHAIN выводит текущую настройку GOTOOLCHAIN.

Выбор набора инструментов Go

При запуске команда go выбирает, какой набор инструментов Go использовать. Она обращается к настройке GOTOOLCHAIN, которая имеет форму <name>, <name>+auto или <name>+path. GOTOOLCHAIN=auto является сокращением для GOTOOLCHAIN=local+auto; аналогично, GOTOOLCHAIN=path является сокращением для GOTOOLCHAIN=local+path. <name> задаёт набор инструментов Go по умолчанию: local указывает на встроенный набор инструментов Go (тот, который поставляется вместе с командой go, которая запускается), в противном случае <name> должен быть конкретным названием набора инструментов Go, таким как go1.21.0. Команда go предпочитает запускать набор инструментов Go по умолчанию. Как упоминалось выше, начиная с Go 1.21, наборы инструментов Go отказываются запускаться в рабочих пространствах или модулях, требующих более новых версий Go. Вместо этого они выводят сообщение об ошибке и завершаются.

Когда GOTOOLCHAIN установлено в значение local, команда go всегда запускает встроенный набор инструментов Go.

Когда GOTOOLCHAIN установлено в значение <name> (например, GOTOOLCHAIN=go1.21.0), команда go всегда запускает конкретный набор инструментов Go. Если двоичный файл с таким именем найден в системном PATH, команда go использует его. В противном случае команда go использует набор инструментов Go, который был загружен и проверен.

Когда GOTOOLCHAIN установлено в значение <name>+auto или <name>+path (или сокращения auto или path), команда go выбирает и запускает более новую версию Go по мере необходимости. Конкретно, она обращается к строкам toolchain и go в файле go.work текущего рабочего пространства или, если рабочее пространство отсутствует, в основном модуле файла go.mod. Если файл go.work или go.mod содержит строку toolchain <tname> и <tname> новее набора инструментов Go по умолчанию, то команда go запускает <tname>. Если файл содержит строку toolchain default, то команда go запускает набор инструментов Go по умолчанию, отключая любую попытку обновления сверх <name>. В противном случае, если файл содержит строку go <version> и <version> новее набора инструментов Go по умолчанию, то команда go запускает go<version>.

Чтобы запустить другую toolchain, отличную от встроенной toolchain Go, команда go ищет в пути исполняемых файлов процесса ($PATH в Unix и Plan 9, %PATH% в Windows) программу с указанным именем (например, go1.21.3) и запускает эту программу. Если такая программа не найдена, команда go скачивает и запускает указанную toolchain Go. Использование формы GOTOOLCHAIN <name>+path отключает механизм загрузки по умолчанию, заставляя команду go прекратить выполнение после поиска в пути исполняемых файлов.

Запуск команды go version выводит версию выбранной toolchain Go (путем запуска реализации команды go version выбранной toolchain).

Запуск команды GOTOOLCHAIN=local go version выводит версию встроенной toolchain Go.

Начиная с Go 1.24, можно отслеживать процесс выбора toolchain командой go, добавив toolchaintrace=1 в переменную окружения GODEBUG при запуске команды go.

Переключение toolchain Go

Для большинства команд файл go.work рабочей области или файл go.mod основного модуля будут содержать строку go, которая не менее новая, чем строка go в любом модуле-зависимости, в соответствии с требованиями конфигурации по порядку версий. В этом случае при запуске выбирается достаточно новая toolchain Go, чтобы завершить выполнение команды.

Некоторые команды включают новые версии модулей как часть своей операции: go get добавляет новые зависимости модулей в основной модуль; go work use добавляет новые локальные модули в рабочую область; go work sync синхронизирует рабочую область с локальными модулями, которые могли быть обновлены с момента создания рабочей области; go install package@version и go run package@version эффективно выполняются в пустом основном модуле и добавляют package@version как новую зависимость. Все эти команды могут столкнуться с модулем, содержащим строку go в go.mod, требующую более новой версии Go, чем текущая запущенная версия Go.

Когда команда сталкивается с модулем, требующим более новой версии Go, и GOTOOLCHAIN разрешает запуск различных toolchain (это одна из форм auto или path), команда go выбирает и переключается на соответствующую более новую toolchain, чтобы продолжить выполнение текущей команды.

В任何时候, когда команда go переключается на другую toolchain после начального выбора toolchain, она выводит сообщение, объясняющее причину переключения. Например:

<code>go: module example.com/widget@v1.2.3 requires go >= 1.24rc1; switching to go 1.27.9
</code>

Как показано в примере, команда go может переключиться на toolchain, более новую, чем требуемая. В общем случае команда go стремится переключиться на поддерживаемую toolchain Go.

Для выбора toolchain, команда go сначала получает список доступных toolchain. Для формы auto, команда go загружает список доступных toolchain. Для формы path, команда go сканирует PATH в поиске любых исполняемых файлов, названных согласно допустимым toolchain, и использует список всех найденных toolchain. Используя этот список toolchain, команда go определяет до трёх кандидатов:

Это поддерживаются релизы Go согласно политике релизов. Согласно минимальному выбору версий, команда go затем консервативно использует кандидата с минимальной (самой старой) версией, которая удовлетворяет новому требованию.

Например, предположим, что example.com/widget@v1.2.3 требует Go 1.24rc1 или более поздней. Команда go получает список доступных toolchain и находит, что последние патч-релизы двух последних toolchain Go — это Go 1.28.3 и Go 1.27.9, а также доступен release candidate Go 1.29rc2. В этой ситуации команда go выберет Go 1.27.9. Если бы widget требовал Go 1.28 или более поздней, команда go выбрали бы Go 1.28.3, потому что Go 1.27.9 слишком старая. Если бы widget требовал Go 1.29 или более поздней, команда go выбрали бы Go 1.29rc2, потому что и Go 1.27.9, и Go 1.28.3 слишком старые.

Команды, которые включают новые версии модулей, требующие новых версий Go, записывают новое минимальное требование версии go в файл go.work текущего рабочего пространства или в файл go.mod основного модуля, обновляя строку go. Для повторяемости, любая команда, обновляющая строку go, также обновляет строку toolchain, записывая имя своей toolchain. В следующий раз, когда команда go будет запускаться в этом рабочем пространстве или модуле, она будет использовать обновлённую строку toolchain во время выбора toolchain.

Например, go get example.com/widget@v1.2.3 может напечатать уведомление о переключении, подобное выше, и переключиться на Go 1.27.9. Go 1.27.9 завершит команду go get и обновит строку toolchain до toolchain go1.27.9. Следующий запуск команды go в этом модуле или рабочем пространстве выберет go1.27.9 во время запуска и не напечатает никакого сообщения о переключении.

В общем случае, если какая-либо команда go запускается дважды, и первая из них выводит сообщение о переключении, то вторая не будет его выводить, поскольку первая также обновила go.work или go.mod, чтобы выбрать нужную цепочку инструментов при запуске. Исключением являются формы go install package@version и go run package@version, которые выполняются вне рабочей области или основного модуля и не могут записать строку toolchain. Они выводят сообщение о переключении каждый раз, когда требуется переключиться на более новую цепочку инструментов.

Загрузка цепочек инструментов

При использовании GOTOOLCHAIN=auto или GOTOOLCHAIN=<name>+auto, команда go загружает более новые цепочки инструментов по мере необходимости. Эти цепочки инструментов упакованы как специальные модули с путём модуля golang.org/toolchain и версией v0.0.1-goVERSION.GOOS-GOARCH. Цепочки инструментов загружаются так же, как и любые другие модули, то есть загрузка цепочек инструментов может быть прокирована путём установки GOPROXY, а их контрольные суммы проверяются с помощью базы данных контрольных сумм Go. Поскольку конкретная используемая цепочка инструментов зависит как от собственной цепочки инструментов по умолчанию системы, так и от локальной операционной системы и архитектуры (GOOS и GOARCH), нецелесообразно записывать контрольные суммы модулей цепочек инструментов в go.sum. Вместо этого загрузка цепочек инструментов завершается неудачей из-за отсутствия проверки, если GOSUMDB=off. Шаблоны GOPRIVATE и GONOSUMDB не применяются к загрузке цепочек инструментов.

Управление требованиями версий Go модуля с помощью go get

В общем случае команда go рассматривает строки go и toolchain как объявления зависимостей цепочки инструментов с версией для основного модуля. Команда go get может управлять этими строками так же, как и управлять строками require, которые указывают зависимости модулей с версией.

Например, go get go@1.22.1 toolchain@1.24rc1 изменяет файл go.mod основного модуля на go 1.22.1 и toolchain go1.24rc1.

Команда go понимает, что зависимость go требует зависимость toolchain с версией Go, большей или равной текущей.

Продолжая пример, последующий go get go@1.25.0 обновит цепочку инструментов до go1.25.0. Когда цепочка инструментов соответствует строке go точно, она может быть опущена и подразумеваться, поэтому эта команда go get удалит строку toolchain.

То же самое требование применяется и в обратном порядке при понижении версии: если go.mod начинается с go 1.22.1 и toolchain go1.24rc1, тогда go get toolchain@go1.22.9 обновит только строку toolchain, но go get toolchain@go1.21.3 понизит строку go до go 1.21.3. В результате останется только go 1.21.3 без строки toolchain.

Специальная форма toolchain@none означает удаление любой строки toolchain, как в go get toolchain@none или go get go@1.25.0 toolchain@none.

Команда go понимает синтаксис версий для зависимостей go и toolchain, а также запросов.

Например, как go get example.com/widget@v1.2 использует последнюю версию v1.2 пакета example.com/widget (возможно, v1.2.3), так и go get go@1.22 использует последний доступный релиз версии языка Go 1.22 (возможно, 1.22rc3 или 1.22.3). То же самое относится к go get toolchain@go1.22.

Команды go get и go mod tidy поддерживают строку go таким образом, чтобы она была больше или равна строке go любого модуля зависимости.

Например, если основной модуль имеет go 1.22.1, а мы запускаем go get example.com/widget@v1.2.3, который объявляет go 1.24rc1, тогда go get обновит строку go основного модуля до go 1.24rc1.

Продолжая пример, позднее выполнение go get go@1.22.1 понизит версию example.com/widget до совместимой с Go 1.22.1 или же полностью удалит требование, как это происходит при понижении любой другой зависимости example.com/widget.

До Go 1.21 рекомендовалось обновлять модуль до новой версии Go (например, Go 1.22) с помощью команды go mod tidy -go=1.22, чтобы убедиться, что все специфичные для Go 1.22 настройки были применены к файлу go.mod одновременно с обновлением строки go. Эта форма по-прежнему допустима, но теперь предпочтительнее более простая форма go get go@1.22.

Когда команда go get запускается в модуле внутри корневой директории рабочей области, go get в основном игнорирует рабочую область, но при этом обновляет файл go.work, чтобы повысить строку go, если иначе рабочая область осталась бы с слишком старой строкой go.

Управление требованиями версии Go в рабочих областях с помощью go work

Как упоминалось в предыдущем разделе, команда go get, запущенная в директории внутри корня рабочей области, будет заботиться о том, чтобы строка go в файле go.work обновлялась соответствующим образом, чтобы быть больше или равной любой строке go модулей внутри этого корня. Однако рабочие области также могут ссылаться на модули вне корневой директории; запуск go get в этих директориях может привести к некорректной конфигурации рабочей области, при которой версия Go, объявленная в go.work, меньше, чем одна или несколько версий модулей в директивах use.

Команда go work use, которая добавляет новые директивы use, также проверяет, что версия Go в файле go.work достаточна для всех существующих директив use. Чтобы обновить рабочую область, у которой версия go не соответствует модулям, выполните go work use без аргументов.

Команды go work init и go work sync также при необходимости обновляют версию go.

Чтобы удалить строку toolchain из файла go.work, используйте команду go work edit -toolchain=none.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang