在 Windows、Linux、MacOS 下交叉编译 Golang
目录
从Golang 1.5
开始,交叉编译变得非常便捷:
- 对于没有使用
CGO
的程序,只需设置GOOS
、GOARCH
、CGO_ENABLED
这几个环境变量,即可直接利用编译器自带的跨平台特性实现跨平台编译 - 对于使用
CGO
的程序,大部分情况下可以通过配置CC
环境变量使用自行准备的交叉编译工具进行编译
关于使用
CGO
情况下的交叉编译,参见 交叉编译 Go 程序 | Holmesian Blog
1. 查看当前 Go 版本支持的编译平台
> go version
go version go1.13 windows/amd64
> go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/386 # Mac i386
darwin/amd64 # Mac amd64
darwin/arm
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
illumos/amd64
js/wasm
linux/386 # Linux i386
linux/amd64 # Linux amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/s390x
nacl/386
nacl/amd64p32
nacl/arm
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386 # Windows i386
windows/amd64 # Windows amd64
windows/arm
> go env
set GOHOSTARCH=amd64 # 本机的架构
set GOHOSTOS=windows # 本机的系统
set GOARCH=amd64 # 目标平台的架构,交叉编译时需要设置
set GOOS=windows # 目标平台的系统,交叉编译时需要设置
set CGO_ENABLED=0 # 是否启用 CGO
...
最常用的大概是x86
和amd64
架构:
darwin/386
:对应 Mac x86darwin/amd64
:对应 Mac amd64linux/386
:对应 Linux x86linux/amd64
:对应 Linux amd64Windows/386
:对应 Windows x86Windows/amd64
:对应 Windows amd64
2. 设置环境变量并交叉编译
2.1 Windows
在 Windows 下编译 MacOS 和 Linux 的 64 位程序:
# For MacOS/amd64
set CGO_ENABLED=0
set GOOS=darwin
set GOARCH=amd64
go build main.go
# For Linux/amd64
set CGO_ENABLED=0
set GOOS=linux
set GOARCH=amd64
go build main.go
2.2 Linux
在 Linux 下编译 MacOS 和 Windows 的 64 位程序:
# For MacOS/amd64
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go
# For Windows/amd64
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
2.3 MacOS
在 MacOS 下编译 Windows 和 Linux 的 64 位程序:
# For Windows/amd64
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
# For Linux/amd64
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
3. 选择性编译
虽然 Golang 可以跨平台编译,但系统之间的差异性仍然存在。有些时候我们会直接调用操作系统函数,不同操作系统下的库可能会有不同的实现,比如syscall
库。
命令go build
没有内置#define
或者预处理器之类的处理平台相关的代码取舍,而是采用 Tag 标记和文件后缀的方式实现选择性编译。
3.1 构建标记:build tag
为了实现根据不同的目标平台编译对应的源文件,需要在文件顶部添加构建标记build tag
:
// +build
标记遵循以下规则:
- A build tag is evaluated as the OR of space-separated options
- Each option evaluates as the AND of its comma-separated terms
- Each term is an alphanumeric word or, preceded by !, its negation
简单翻译一下:
- 空格
- 逗号
,
为且 - 叹号
!
为非
例如:
// +build A,B !C,D
// (A && B) || ((!C) && D)
再例如:
// +build !windows,386
//此文件在非 Windows 操作系统,且为 x86 处理器时编译
构建标记必须出现在文件顶部,可以有多个build tag
,之间是AND
的关系:
// +build linux darwin
// +build 386
另外需要注意build tag
和package xxx
语句之间需要有空行分隔,也就是:
// +build linux darwin
// +build 386
package mypkg
3.2 文件后缀:_$GOOS.go
以_$GOOS.go
为后缀的文件只在此平台上编译,其他平台上编译时就当此文件不存在,完整的后缀如:
_$GOOS_$GOARCH.go
例如:
syscall_linux_amd64.go
:只在 Linux/amd64 下编译syscall_windows_386.go
:只在 Windows/i386 下编译syscall_windows.go
:只在 Windows 下编译
4. 示例程序
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("OS: %s\nArchitecture: %s\n", runtime.GOOS, runtime.GOARCH)
}
Windows/amd64 下为 Windows/amd64 与 Linux/amd64 编译:
# For Windows/amd64
> go build cross.go
# For Linux/amd64
> set CGO_ENABLED=0
> set GOOS=linux
> set GOARCH=amd64
> go build cross.go
# Cmder
> ls -hl
total 3.0M
-rw-r--r-- 1 abelsu7 197609 1014K 10月 24 17:26 cross
-rwxr-xr-x 1 abelsu7 197609 2.0M 10月 24 17:15 cross.exe*
-rw-r--r-- 1 abelsu7 197609 140 10月 24 17:12 cross.go
-rw-r--r-- 1 abelsu7 197609 198 10月 23 17:58 go.mod
-rw-r--r-- 1 abelsu7 197609 1.5K 10月 23 17:57 go.sum
-rw-r--r-- 1 abelsu7 197609 1.9K 10月 24 15:48 main.go
Windows 下运行:
> .\cross.exe
OS: windows
Architecture: amd64
WSL 下运行:
> ./cross
OS: linux
Architecture: amd64
参考文章
- 交叉编译 Go 程序 | Holmesian Blog
- 交叉编译 Go 程序 | 鸟窝
- Golang 交叉编译与选择性编译 | CSDN
- Golang 在 Mac、Linux、Windows 下如何交叉编译 | CSDN
- Golang 交叉编译中的那些坑 | CSDN
- Cross compilation with Go 1,5 | Dave Cheney
- Building windows go programs on linux - golang/go | Github
- Cross Compile in Go (Golang) | Medium.com
- TinyGo Brings Go To Arduino | Hackaday
- Better way to install Golang (Go) on Raspberry Pi | E-Tinkers
- Recipe: Cross Compliling | The Go Cookbook
- Gin 实践 番外:Golang 交叉编译 - 煎鱼 | SegmentFault
- Gin 实践 番外:请入门 Makefile - 煎鱼 | SegmentFault