Сборка Go-приложений в бинарник
go run vs go build
Во время разработки вы запускаете программу через go run main.go. Это удобно: Go компилирует код "на лету" и сразу запускает. Но для распространения программы это не подходит — у пользователя может не быть Go.
go build компилирует исходный код в нативный бинарник — один исполняемый файл, который:
- Не требует установленного Go
- Не требует исходного кода
- Не требует интернета или зависимостей
- Запускается на любой совместимой системе
Это одна из причин популярности Go для CLI-инструментов и серверов: Docker, Kubernetes, Terraform, Hugo — все написаны на Go и распространяются как один бинарник.
Базовая сборка
Простейший вариант
go build
Создаст бинарник с именем текущей директории (или модуля из go.mod).
Указать имя выходного файла
go build -o myapp
Создаст файл myapp (на Windows автоматически добавится .exe).
Собрать конкретный файл
go build -o myapp main.go
Проверить без создания файла
go build -n
Покажет, что будет выполнено, но ничего не создаст. Полезно для отладки процесса сборки.
Что происходит при сборке
- Парсинг — Go читает исходные файлы и строит AST (абстрактное синтаксическое дерево)
- Проверка типов — статический анализ, поиск ошибок
- Компиляция — преобразование в машинный код для целевой платформы
- Линковка — объединение кода вашей программы, стандартной библиотеки и зависимостей в один файл
Результат — статически слинкованный бинарник. Все зависимости "вшиты" внутрь. Никаких .dll или .so файлов рядом не нужно.
# Посмотреть размер бинарника ls -lh myapp # Посмотреть, от чего зависит (на Linux) ldd myapp # Вывод: "not a dynamic executable" — зависимостей нет
Кросс-компиляция
Go умеет собирать бинарники для других операционных систем и архитектур. Работаете на macOS, а нужен бинарник для Linux-сервера? Две переменные окружения:
# Для Linux (64-bit) GOOS=linux GOARCH=amd64 go build -o myapp-linux # Для Windows (64-bit) GOOS=windows GOARCH=amd64 go build -o myapp.exe # Для macOS на Apple Silicon GOOS=darwin GOARCH=arm64 go build -o myapp-mac-arm # Для Raspberry Pi (ARM) GOOS=linux GOARCH=arm64 go build -o myapp-raspi
Основные значения
GOOS (операционная система):
| Значение | ОС |
|---|---|
linux | Linux |
darwin | macOS |
windows | Windows |
freebsd | FreeBSD |
GOARCH (архитектура процессора):
| Значение | Архитектура |
|---|---|
amd64 | Intel/AMD 64-bit (большинство серверов и ПК) |
arm64 | ARM 64-bit (Apple Silicon, ARM серверы, Raspberry Pi 4) |
386 | Intel/AMD 32-bit (устаревшее) |
arm | ARM 32-bit (старые Raspberry Pi) |
# Посмотреть все поддерживаемые комбинации go tool dist list
Оптимизация размера бинарника
По умолчанию бинарник содержит отладочную информацию. Для продакшена можно её убрать:
go build -ldflags="-s -w" -o myapp
| Флаг | Что убирает | Экономия |
|---|---|---|
-s | Таблицу символов | ~20-25% |
-w | DWARF отладочную информацию | ~5-10% |
Пример: бинарник 10 MB → 7 MB.
Внедрение данных при сборке
Через -ldflags можно задать значения переменных прямо при компиляции. Это полезно для версии, даты сборки, коммита.
Пример: версия приложения
package main import "fmt" // Значение задаётся при сборке var version = "dev" func main() { fmt.Printf("myapp version %s\n", version) }
Сборка с версией:
go build -ldflags="-X main.version=1.0.0" -o myapp
Теперь ./myapp выведет myapp version 1.0.0.
Автоматизация через git
# Взять версию из git-тега VERSION=$(git describe --tags --always) go build -ldflags="-X main.version=$VERSION" -o myapp # Добавить дату сборки BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ) go build -ldflags="-X main.version=$VERSION -X main.buildTime=$BUILD_TIME" -o myapp
Комбинирование флагов
# Версия + оптимизация размера go build -ldflags="-s -w -X main.version=1.0.0" -o myapp
Сборка для продакшена
Типичная команда для production-сборки:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \ go build -ldflags="-s -w -X main.version=$(git describe --tags)" \ -o myapp
Что здесь:
CGO_ENABLED=0— отключает CGO, гарантирует полностью статический бинарникGOOS=linux GOARCH=amd64— целевая платформа-ldflags="-s -w"— убираем отладочную информацию-X main.version=...— внедряем версию
Makefile для сборки
Для повторяемой сборки удобно использовать Makefile:
VERSION := $(shell git describe --tags --always) BUILD_TIME := $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -s -w -X main.version=$(VERSION) -X main.buildTime=$(BUILD_TIME) .PHONY: build build-linux build-windows clean build: go build -ldflags="$(LDFLAGS)" -o myapp build-linux: GOOS=linux GOARCH=amd64 go build -ldflags="$(LDFLAGS)" -o myapp-linux build-windows: GOOS=windows GOARCH=amd64 go build -ldflags="$(LDFLAGS)" -o myapp.exe build-all: build build-linux build-windows clean: rm -f myapp myapp-linux myapp.exe
Использование:
make build # Собрать для текущей ОС make build-linux # Собрать для Linux make build-all # Собрать для всех платформ make clean # Удалить бинарники
Шпаргалка
# Базовая сборка go build go build -o myapp # Кросс-компиляция GOOS=linux GOARCH=amd64 go build -o myapp-linux GOOS=windows GOARCH=amd64 go build -o myapp.exe GOOS=darwin GOARCH=arm64 go build -o myapp-mac # Оптимизация размера go build -ldflags="-s -w" -o myapp # Внедрение версии go build -ldflags="-X main.version=1.0.0" -o myapp # Production-сборка CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=1.0.0" -o myapp
Полезные ресурсы
- Документация go build
- Go Linker Flags — все флаги линковщика
- Building Go Applications — официальный туториал