Avatar ·

Что на самом деле делает `go build`? Разбираемся с `go build` vs `go install`

Всем привет! Я только начал изучать Go и пытаюсь понять, как правильно собирать проекты. Прочитал кучу статей, но всё равно путаюсь в командах `go build` и `go install`. У меня есть простой проект с main-пакетом в корне. Когда я делаю `go build` в папке проекта, он создает бинарник прямо там же (я использую Go 1.20 на Windows). Но если я делаю `go install`, то я не вижу никакого бинарника в папке проекта, зато в `%GOPATH%/bin` появляется мой исполняемый файл. В чем тут разница? Зачем мне `go install`, если `go build` и так создает бинарник? Я слышал, что `go build` еще как-то проверяет зависимости, а `go install` их устанавливает? Или это не так? Мой код для примера: ```go package main import "fmt" func main() { fmt.Println("Hello, Go!") } ``` Я запускаю `go build` и получаю `hello.exe` в текущей папке (на Linux просто `hello`). Потом запускаю `go install` — бинарник в папке проекта исчезает, но появляется в `C:\Users\Me\go\bin\hello.exe`. Объясните, пожалуйста, на пальцах: что именно делает каждая команда с моим кодом и зависимостями? Когда какую команду использовать? Заранее спасибо! <<>>

Краткий ответ: `go build` собирает здесь и сейчас, `go install` — собирает и убирает в системную папку

Вы всё верно подметили. Разница между этими командами — в том, куда попадает результат сборки. Давайте разложим по полочкам.

Что делает `go build`?

Команда go build компилирует пакет (или пакеты) и все его зависимости. Если вы собираете main-пакет (тот, который содержит package main и функцию main()), то результатом будет исполняемый бинарный файл. Если вы собираете обычный пакет (библиотеку) — результата в виде файла вы не увидите, компилятор только проверит, что код собирается без ошибок.

По умолчанию бинарник для main-пакета создаётся в текущей рабочей директории (той, откуда вы вызвали команду). Имя файла совпадает с именем папки, в которой лежит main-пакет.

# Пример: у вас проект "myapp" с main.go
cd myapp
go build
# Результат: ./myapp (или myapp.exe на Windows)

Что делает `go install`?

Команда go install делает то же самое, что и go build, но с одним важным отличием: она устанавливает результат в стандартное место:

  • Для main-пакетов бинарник помещается в $GOPATH/bin (или $GOBIN, если эта переменная задана).
  • Для обычных пакетов (библиотек) скомпилированные объектные файлы (.a) помещаются в $GOPATH/pkg.

После go install вы не увидите бинарника в папке проекта — он «переехал» в системную директорию. Это сделано для того, чтобы ваши программы были доступны из любого места в командной строке (если $GOPATH/bin добавлен в PATH).

go install
# Результат: $GOPATH/bin/myapp (myapp.exe на Windows)
# В текущей папке бинарника нет!

А что насчёт зависимостей?

Ни go build, ни go install не устанавливают внешние зависимости. Они только компилируют уже скачанные пакеты. Если у вас в коде есть import "example.com/somepackage", то:

  • go build найдёт этот пакет в $GOPATH/pkg/mod (или в vendor) и скомпилирует его вместе с вашим кодом.
  • Если пакета нет, команда завершится с ошибкой.

Для загрузки зависимостей существует отдельная команда go mod download или go mod tidy. А go install (начиная с Go 1.16) может устанавливать конкретные версии утилит, например: go install golang.org/x/tools/cmd/goimports@latest. Но это уже другая история.

Когда что использовать?

  • go build — когда вы разрабатываете и хотите быстро проверить, что проект собирается, или получить бинарник «прямо здесь» для тестирования.
  • go install — когда вы хотите установить готовую программу в систему, чтобы вызывать её из любого места (например, утилиты командной строки вроде golangci-lint).
  • go build -o output.exe — когда нужно явно указать имя и путь для бинарника.

Итог

Представьте, что go build — это «собрать на столе», а go install — «собрать и положить на полку в инструментальный ящик». Обе команды делают одно и то же с точки зрения компиляции, но различаются местом размещения результата.

<<>>

Дополнение: флаг `-i` и исторический контекст

В более старых версиях Go (до 1.16) у команды go build был флаг -i, который заставлял её устанавливать зависимости в $GOPATH/pkg. Многие путались, думая, что go build -i — это то же самое, что go install. На самом деле нет: go build -i всё равно оставлял бинарник в текущей папке, но дополнительно кешировал скомпилированные зависимости.

Начиная с Go 1.16, флаг -i был объявлен устаревшим, а в Go 1.18 его убрали полностью. Теперь поведение чёткое:

  • go build — только компиляция в текущую директорию (для main-пакетов).
  • go install — компиляция + установка в $GOPATH/bin (для main) или $GOPATH/pkg (для библиотек).

Также стоит помнить про go run — это команда, которая компилирует и сразу запускает программу, не оставляя бинарника на диске. Идеально для быстрых экспериментов.

Если вы используете модули (Go Modules), то папка $GOPATH/pkg/mod содержит кеш всех скачанных зависимостей, и ни go build, ни go install его не трогают — они только читают оттуда готовые исходники.