Go 高手(24):多平台编译——GOOS、GOARCH、build tags、条件编译
更新时间:2026-09-01。本文是
languages/go/intermediate/高手层第 24 篇,接 日志最佳实践。Go 的交叉编译是语言级别的特性,不需要配置复杂的工具链。设两个环境变量,go build就能编译出目标平台的二进制。
本文要回答的问题
- GOOS 和 GOARCH 的组合有哪些常用值?交叉编译怎么用?
- build tags 怎么用?
//go:build注释的语法是什么? - 平台特定代码的文件命名约定是什么?
- CGO 在交叉编译时有什么限制?
一、GOOS 和 GOARCH
bash
# 常用组合
GOOS=linux GOARCH=amd64 go build -o myapp-linux .
GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm64 .
GOOS=windows GOARCH=amd64 go build -o myapp.exe .
GOOS=darwin GOARCH=amd64 go build -o myapp-mac-intel .
GOOS=darwin GOARCH=arm64 go build -o myapp-mac-m1 .| GOOS | GOARCH | 说明 |
|---|---|---|
| linux | amd64 | Linux x86_64 |
| linux | arm64 | Linux ARM64(树莓派、服务器) |
| windows | amd64 | Windows x64 |
| darwin | amd64 | macOS Intel |
| darwin | arm64 | macOS Apple Silicon(M1/M2) |
| freebsd | amd64 | FreeBSD |
bash
# 查看当前平台
go env GOOS GOARCH
# 输出:windows amd64二、文件名约定:平台特定代码
Go 通过文件名约定自动选择平台相关的代码:
go
// 文件命名:filename_GOOS_GOARCH.go
// app_linux.go
package main
func init() {
fmt.Println("running on Linux")
}
// app_windows.go
package main
func init() {
fmt.Println("running on Windows")
}
// app_darwin.go
package main
func init() {
fmt.Println("running on macOS")
}Go 编译时只编译当前平台的文件。_linux.go 在 Windows 上编译时不会被编译。
go
// 通用文件名模式
// *_GOOS.go → 特定操作系统
// *_GOARCH.go → 特定架构
// *_GOOS_GOARCH.go → 特定操作系统 + 架构三、build tags:条件编译
//go:build 注释(Go 1.17+)控制编译条件:
go
//go:build linux
package main
func getHomeDir() string {
return "/home"
}go
//go:build windows
package main
func getHomeDir() string {
return os.Getenv("USERPROFILE")
}go
//go:build darwin || freebsd
package main
func getHomeDir() string {
return os.Getenv("HOME")
}build tags 语法:
//go:build linux→ 只在 Linux 编译//go:build !linux→ 不在 Linux 编译(其他平台)//go:build linux && amd64→ Linux + amd64//go:build linux || darwin→ Linux 或 macOS
自定义 build tag:
go
//go:build production
// 编译时:go build -tags=productiongo
//go:build debug
// 编译时:go build -tags=debug四、CGO 与交叉编译
CGO 允许 Go 代码调用 C 代码,但交叉编译时有限制:
go
// 需要 CGO 的代码
// #include <stdio.h>
import "C"bash
# 纯 Go 代码,交叉编译设 CGO_ENABLED=0
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build .
# 需要 CGO 的交叉编译,需要目标平台的 C 工具链
# 复杂,不常用规则:
- 纯 Go 代码:
CGO_ENABLED=0,交叉编译无限制 - 需要 CGO 的代码:交叉编译需要目标平台的 C 编译器,复杂
- 大多数 Go 项目是纯 Go 的,不依赖 CGO
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 交叉编译时忘记 CGO_ENABLED=0 | 报错:CGO 需要目标平台工具链 | 纯 Go 代码设 CGO_ENABLED=0 |
| 文件名约定和 build tags 混用混淆 | 文件被排除或重复编译 | 文件名约定用于简单场景,build tags 用于复杂条件 |
| 不测试交叉编译后的二进制 | 在目标平台运行出错 | 交叉编译后至少跑一次基本测试 |
| 条件编译导致代码不一致 | 一个平台能编译,另一个不行 | 每个平台都要测试编译 |
相关与延伸
下一篇:代码生成——go generate、stringer、自定义 generator;Go 工具链的基本用法,见 Go 工具链。
一句话总结
Go 多平台编译:GOOS 和 GOARCH 环境变量控制交叉编译目标,纯 Go 项目设 CGO_ENABLED=0 即可跨平台编译;文件名约定 _linux.go、_windows.go 按平台选择代码;//go:build linux 注释做条件编译,支持 &&、||、! 逻辑;自定义 build tag 用 -tags=production 编译时指定。