go run компилирует и запускает программу за один шаг и не сохраняет бинарник. go build компилирует и оставляет исполняемый файл в текущей папке. go install компилирует и кладёт исполняемый файл в $HOME/go/bin. Все три команды компилируют в нативный машинный код; ни одна ничего не интерпретирует.
| Команда | Компилирует | Запускает | Сохраняет бинарник | Куда попадает бинарник |
|---|---|---|---|---|
go run . | да | да | нет | временная папка, потом удаляется |
go build | да | нет | да | текущая папка (или -o path) |
go install | да | нет | да | $GOBIN, иначе $GOPATH/bin |
Программа ниже используется во всех примерах этой страницы. Редактор запускает её так же, как go run.
go run
go run принимает пакет (обычно ., текущую папку) или список файлов .go:
go run .
go run main.go
go run ./cmd/server
Всё, что идёт после пакета, передаётся вашей программе как аргументы:
go run . --port 8080 verbose
version: dev
built for: linux/amd64
args: [--port 8080 verbose]
Пишите go run ., а не go run main.go. Если указать файл, скомпилируется только он, и как только в пакете появится второй файл, объявленные там функции будут считаться undefined. Подробно эта ошибка разобрана на странице о пакетах и импортах.
go run также запускает удалённую программу конкретной версии без установки, что удобно для генераторов кода:
go run golang.org/x/tools/cmd/stringer@v0.30.0 -type=Color
go build
go build компилирует пакет в текущей папке. Для пакета main он записывает исполняемый файл; библиотечный пакет компилирует, сообщает об ошибках и выбрасывает результат.
go mod init example.com/hello
go build
ls
go.mod hello main.go
Имя бинарника определяется так:
| Что вы запускаете | Имя бинарника |
|---|---|
go build в модуле example.com/hello | hello |
go build ./cmd/server | server |
go build main.go | main (по первому файлу) |
go build -o bin/app . | bin/app |
любой из вариантов выше с GOOS=windows | то же имя плюс .exe |
Ещё две формы, которыми вы будете пользоваться постоянно:
go build ./... # compile every package in the module
go vet ./... # static checks, covered below
./... означает «эта папка и все папки ниже». go build ./... с несколькими пакетами main не записывает бинарники; это быстрая проверка «компилируется ли всё».
Полезные флаги сборки
| Флаг | Что делает |
|---|---|
-o name | выходной файл или папка |
-v | печатает имена пакетов по мере компиляции |
-race | сборка с детектором гонок данных (медленнее, бинарник больше; для тестов) |
-trimpath | убирает локальные пути файловой системы из бинарника, для воспроизводимых сборок |
-ldflags "-s -w" | вырезает таблицу символов и отладочную информацию DWARF, бинарник становится меньше |
-ldflags "-X main.version=1.4.0" | задаёт строковую переменную на этапе линковки |
-tags name | включает файлы с ограничением //go:build name |
Флагом -X большинство Go-проектов вшивают версию в бинарник. Он работает только с переменными типа string уровня пакета (не с константами):
go build -o app -ldflags "-X main.version=1.4.0" .
./app
version: 1.4.0
built for: linux/amd64
args: []
Бинарник также хранит версии модулей, а начиная с Go 1.18 и коммит VCS, из которого он собран. go version -m ./app их выводит, а программа может прочитать их через runtime/debug.ReadBuildInfo.
go install
go install собирает точно так же, как go build, а затем переносит исполняемый файл в $GOBIN или в $GOPATH/bin, если GOBIN не задан (по умолчанию $HOME/go/bin):
go install .
go env GOPATH
Чаще всего так устанавливают утилиты, написанные на Go. С @version программа ставится, не трогая ваш go.mod:
go install golang.org/x/tools/gopls@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
Если после этого оболочка не находит утилиту, значит $HOME/go/bin нет в PATH. Добавьте export PATH=$PATH:$(go env GOPATH)/bin в профиль оболочки.
Кросс-компиляция через GOOS и GOARCH
Go умеет собирать под другую операционную систему или процессор с любой машины, без дополнительного тулчейна. Задайте для команды сборки две переменные окружения:
GOOS=linux GOARCH=amd64 go build -o app-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o app-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o app-macos .
GOOS=windows GOARCH=amd64 go build -o app.exe .
В PowerShell переменные окружения задаются иначе:
$env:GOOS = "linux"; $env:GOARCH = "amd64"; go build -o app-linux .
Самые частые пары:
| GOOS | GOARCH | Цель |
|---|---|---|
linux | amd64 | большинство серверов и контейнеров |
linux | arm64 | AWS Graviton, Raspberry Pi с 64-битной ОС |
darwin | arm64 | Mac на Apple Silicon |
darwin | amd64 | Mac на Intel |
windows | amd64 | 64-битная Windows |
js | wasm | WebAssembly в браузере |
go tool dist list выводит все поддерживаемые пары (в Go 1.24 их 48).
Так просто кросс-компиляция работает только для кода на чистом Go. Пакету, который использует cgo (код на C, например некоторые драйверы SQLite), нужен кросс-компилятор C для целевой платформы. При кросс-компиляции cgo по умолчанию выключен, а явное CGO_ENABLED=0 к тому же даёт полностью статический бинарник для Linux, что и нужно для минимального образа контейнера scratch или distroless.
go fmt и go vet
Две проверки должны быть в любом рабочем процессе и в CI.
go fmt переписывает файлы в едином официальном стиле: табы, выровненные поля, нормализованные пробелы. Это обёртка над gofmt -l -w:
go fmt ./...
gofmt -l . # list files that are not formatted; empty output means clean
go vet сообщает о коде, который компилируется, но почти наверняка ошибочен. Классический случай это несовпадение формата Printf:
package main
import "fmt"
func main() {
count := 3
fmt.Printf("%s items\n", count)
}
go vet ./...
# example.com/hello
# [example.com/hello]
./main.go:7:2: fmt.Printf format %s has arg count of wrong type int
Программа компилируется и печатает %!s(int=3) items, и именно такие баги vet и должен ловить. Среди других проверок vet: копирование sync.Mutex по значению, недостижимый код, теги структур с неправильным синтаксисом и context.CancelFunc, который так и не вызывается. go test автоматически запускает часть этих проверок; go build не запускает ни одной.
Другие подкоманды go
| Команда | Назначение |
|---|---|
go test ./... | запустить тесты |
go mod tidy | добавить недостающие и удалить неиспользуемые зависимости |
go get pkg@version | добавить или изменить зависимость |
go clean -cache | очистить кеш сборки |
go env | вывести конфигурацию Go |
go doc fmt.Println | показать документацию в терминале |
go list -m all | перечислить все модули сборки |
Почему повторная сборка быстрая
Go кеширует скомпилированные пакеты в кеше сборки (go env GOCACHE). При пересборке компилируются заново только пакеты, у которых изменился исходный код или зависимости, поэтому go run . на неизменённом проекте стартует почти мгновенно. Если сборка ведёт себя странно после смены версии Go или переменных окружения, go clean -cache очистит кеш; нужно это редко.
Часто задаваемые вопросы
Чем go run отличается от go build?
go run компилирует программу во временную папку, запускает её и выбрасывает бинарник. go build компилирует программу и записывает бинарник в текущую папку, чтобы его можно было запустить снова или скопировать. go run удобен во время разработки, go build нужен, когда требуется исполняемый файл.
Как задать имя выходного файла в go build?
Флагом -o: go build -o myapp . запишет myapp (на Windows пишите -o myapp.exe сами). Без -o команда go build называет бинарник по последнему элементу пути импорта пакета или по первому файлу, если вы передали файлы .go, и добавляет .exe при сборке под Windows.
Как собрать Go под Linux или Windows с другой машины?
Задайте для сборки GOOS и GOARCH: GOOS=linux GOARCH=amd64 go build -o app-linux . или GOOS=windows GOARCH=amd64 go build . (получится .exe). Для кода на чистом Go дополнительный тулчейн не нужен. go tool dist list выводит все поддерживаемые пары.
Куда go install кладёт бинарник?
В $GOBIN, если переменная задана, иначе в $GOPATH/bin, то есть по умолчанию в $HOME/go/bin. Добавьте эту папку в PATH, чтобы запускать установленные утилиты по имени. go install example.com/tool@latest ставит утилиту, не добавляя её в ваш модуль.
Запускает ли go build проверку go vet?
Нет. go build только компилирует. go test автоматически запускает часть проверок go vet, но для полного набора выполните go vet ./... сами, обычно в CI рядом с gofmt -l ..