Go 语言编译为 Windows、macOS、Linux 的正确方法
wxk1991 Lv5

Go 语言编译为 Windows、macOS、Linux 的正确方法

Go 的跨平台编译非常方便,但真正发布软件时,不能只记住 GOOSGOARCH。你还要考虑 CGO、动态库、CPU 架构、文件路径、证书和 CI 构建环境。

这篇文章整理一套更稳的构建方法。


一、最基本的交叉编译

Go 通过 GOOSGOARCH 指定目标平台。

构建 Linux:

1
GOOS=linux GOARCH=amd64 go build -o dist/myapp-linux-amd64 ./cmd/server

构建 Windows:

1
GOOS=windows GOARCH=amd64 go build -o dist/myapp-windows-amd64.exe ./cmd/server

构建 macOS:

1
GOOS=darwin GOARCH=arm64 go build -o dist/myapp-darwin-arm64 ./cmd/server

Windows 可执行文件通常要带 .exe 后缀。


二、常见 GOOS 和 GOARCH

常用系统:

1
2
3
GOOS=linux
GOOS=windows
GOOS=darwin

常用架构:

1
2
GOARCH=amd64
GOARCH=arm64

现在服务器和桌面环境里,amd64arm64 都很常见。不要只发一个架构版本。


三、CGO 会让交叉编译变复杂

纯 Go 项目交叉编译最轻松。如果项目使用了 CGO,例如依赖 SQLite C 库、系统 OpenSSL、某些图像处理库,跨平台编译会明显复杂。

可以先尝试关闭 CGO:

1
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o dist/myapp ./cmd/server

但如果依赖必须使用 CGO,就不要硬凑命令。更稳的方式是在目标平台原生构建,或者用 CI matrix 分别在 Linux、Windows、macOS 上构建。


四、减少二进制体积

发布命令行工具或服务端程序时,可以去掉部分调试符号:

1
go build -ldflags="-s -w" -o dist/myapp ./cmd/server

这会减小体积,但调试信息也会减少。线上排查困难的项目,可以保留一份未裁剪版本。


五、写入版本信息

发布软件时,最好把版本号、Git commit、构建时间写进二进制:

1
2
3
go build \
-ldflags="-X main.version=v1.2.3 -X main.commit=$(git rev-parse --short HEAD)" \
-o dist/myapp ./cmd/server

代码里定义变量:

1
2
var version = "dev"
var commit = "unknown"

这样线上执行 myapp version 时,就能知道当前运行的是哪一版。


六、macOS 要区分 Intel 和 Apple Silicon

macOS 至少要考虑两个架构:

1
2
GOOS=darwin GOARCH=amd64 go build -o dist/myapp-darwin-amd64 ./cmd/server
GOOS=darwin GOARCH=arm64 go build -o dist/myapp-darwin-arm64 ./cmd/server

如果面向普通用户分发,还会涉及签名、公证和 Gatekeeper。那是发布流程问题,不只是 Go 编译问题。


七、推荐使用 CI 构建

最稳的方式是让 CI 在不同平台上构建:

1
2
3
4
5
6
7
8
9
10
11
12
strategy:
matrix:
include:
- os: ubuntu-latest
goos: linux
goarch: amd64
- os: windows-latest
goos: windows
goarch: amd64
- os: macos-latest
goos: darwin
goarch: arm64

纯 Go 项目可以本机交叉编译。有 CGO 或系统依赖时,CI 原生构建会省很多麻烦。


八、实践建议

Go 跨平台编译的正确姿势是:纯 Go 项目用 GOOSGOARCH 快速构建,有 CGO 的项目让目标平台自己构建。

发布前至少在目标系统上启动一次,检查配置路径、日志路径、证书访问、权限和命令行参数。跨平台不是只改环境变量,真正可靠要靠构建和验证流程一起兜住。