Avatar ·

Как выполнить кросс-компиляцию Go программы на macOS?

Всем привет! Я пишу на Go под macOS и хочу собрать бинарник для Linux и Windows, чтобы запускать на сервере и отдавать коллегам. Пробовал просто запустить `go build`, но он создает исполняемый файл только для macOS. Я прочитал, что в Go есть встроенная поддержка кросс-компиляции, но не могу разобраться, как правильно это сделать. Вот мой простой код (файл main.go): ```go package main import "fmt" func main() { fmt.Println("Hello, cross-compilation!") } ``` Я пробовал: ```bash GOOS=linux GOARCH=amd64 go build main.go ``` Но получил ошибку: `cannot find package "main" in any of: ...` или бинарник, который не запускается на Linux. Что я делаю не так? Нужно ли устанавливать дополнительные инструменты, как для CGo? У меня macOS Big Sur, Go версии 1.21. Буду благодарен за пошаговое объяснение для новичка. <<>>

Пошаговое решение кросс-компиляции в Go на macOS

Вы на правильном пути! Go действительно имеет встроенную поддержку кросс-компиляции без установки дополнительных тулчейнов (если не используете CGo). Ваша ошибка скорее всего связана с тем, что вы выполняете команду не в той директории или используете относительный путь. Давайте разберем всё по порядку.

1. Базовая кросс-компиляция (без CGo)

Для Go-программ, которые не используют CGo (то есть не подключают C-библиотеки), всё работает из коробки. Вот правильные команды для вашего случая:

# Перейдите в директорию с main.go
cd /path/to/your/project

# Для Linux (64-bit)
GOOS=linux GOARCH=amd64 go build -o myapp-linux main.go

# Для Windows (64-bit)
GOOS=windows GOARCH=amd64 go build -o myapp.exe main.go

# Для macOS (Intel)
GOOS=darwin GOARCH=amd64 go build -o myapp-mac main.go

# Для macOS (Apple Silicon M1/M2)
GOOS=darwin GOARCH=arm64 go build -o myapp-mac-arm64 main.go

Обратите внимание на флаг -o — он указывает имя выходного файла. Если его не указать, Go создаст файл с именем директории (или "main" для Windows). Также убедитесь, что вы находитесь в корневой папке модуля (где лежит go.mod).

2. Возможные проблемы и их решения

  • Ошибка "cannot find package" — скорее всего вы запускаете команду не из той папки. Убедитесь, что файл main.go лежит в текущей директории. Выполните ls чтобы проверить.
  • Бинарник не запускается на Linux — проверьте права доступа: chmod +x myapp-linux. Также убедитесь, что целевая система имеет ту же архитектуру (amd64).
  • Ошибки с CGo — если ваш код использует C-библиотеки (например, через import "C"), вам понадобится кросстулчейн. Для этого установите brew install FiloSottile/musl-cross/musl-cross и используйте CC=x86_64-linux-musl-gcc CGO_ENABLED=1.

3. Продвинутый вариант: Makefile для автоматизации

Чтобы не запоминать все команды, создайте Makefile в корне проекта:

.PHONY: build-all

build-all:
	GOOS=linux GOARCH=amd64 go build -o bin/myapp-linux main.go
	GOOS=windows GOARCH=amd64 go build -o bin/myapp.exe main.go
	GOOS=darwin GOARCH=amd64 go build -o bin/myapp-darwin main.go
	@echo "Build complete for all platforms!"

Теперь просто запускайте make build-all и все бинарники будут в папке bin/.

4. Проверка результата

Чтобы убедиться, что бинарник собран для нужной платформы, используйте команду file:

$ file myapp-linux
myapp-linux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped

$ file myapp.exe
myapp.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

Если видите ELF — это Linux, PE — Windows, Mach-O — macOS. Всё работает!

<<>>

Альтернативный подход: использование Docker для кросс-компиляции

Если вы столкнулись с проблемами при кросс-компиляции (например, из-за CGo или сложных зависимостей), можно использовать Docker. Это гарантирует, что сборка происходит в чистом окружении целевой платформы.

# Создайте Dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -o myapp main.go

# Для запуска (опционально)
FROM alpine:latest
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]

Затем соберите образ:

docker build -t myapp-linux .

Если вам нужен только бинарник, используйте многоступенчатую сборку и скопируйте его на хост:

docker create --name temp myapp-linux
docker cp temp:/myapp ./myapp-linux
docker rm temp

Этот метод особенно полезен, когда вы работаете с CGo, системными библиотеками или нуждаетесь в точном соответствии окружению продакшена. Docker гарантирует, что бинарник собран в тех же условиях, что и на целевом сервере.