Go 跨平台的特点
前面Go 环境变量已经介绍了Go环境变量相关的知识,本文即将介绍的Go交叉编译就是基于它来实现的.
我们知道现在的主流的高级语言几乎都支持跨平台开发.它们跨平台分为2个大的流派:
- 解释型语言
- JavaScript,Python
- 编译型语言
- Java,Scala,Groovy
- Go
不专业的大致来讲解释型语言跨平台主要是程序代码先被解释器解释,解释完的代码会被解析器转为平台相关的指令集来执行.解释型语言跨平台性很好,但是理论上性能往往低效,比不过典型的编译型语言.
编译型语言分为2个子类:
- 直接编译为具体的某种平台相关的指令集
- 先编译为中间状态的字节码,然后由具体某个平台上的虚拟机执行字节码
第一种跨平台是需要在有源代码的情况下为不同的平台编译对应的版本的,比如你为Windows编译的程序不能在Linux/Unix上运行,你需要重新编译.这种方式其实是编写一次编译多次运行多平台的设计.比如设计良好的Go,C/C++只要不用到和某种平台强绑定的特殊的特性,一般都是可以编写一次编译多次运行多平台,实现跨平台的.
第二种就是先编译成中间状态的字节码,然后通过各个平台的语言虚拟机去解释/JIT编译执行字节码. 比如依赖JVM的语言(Java,Scala,Kotlin,Groovy)等都是如此
上面2种编译型语言也互有有缺点,不严谨的讲:
- 性能/资源占用/启动速度: 第一种占优势
- 运行时反射/语言的灵活性: 第二种占优势
- 跨平台性: 第二种占优势,第一种在有些地方还是无法做到绝对的平台无关
- 运维/部署简单性: 第二种占优势
第一种需要使用交叉编译,交叉编译是用来在一个平台上生成另一个平台的可执行程序.比如我在Windows上编写程序,将程序编译为Linux可执行程序交付出去,这就是Go/C++等语言的跨平台的方式.相反Java这类JVM语言就没有这个限制,在那个平台上编译都可以在任何其他的平台上的JVM上运行.
交叉编译
Go 环境变量介绍的4个变量对Go语言交叉编译很重要
| 变量 | 描述 |
|---|---|
| GOARCH | 编译时使用,Go build时的目标CPU架构 |
| GOOS | 编译时使用,Go build时的目标操作系统 |
| GOHOSTARCH | 运行时使用,当前电脑(宿主机)的CPU架构 |
| GOHOSTOS | 运行时使用,当前电脑(宿主机)的操作系统 |
下面的图截取自 environment ,讲了交叉编译的核心:
- Go语言编译的时候会查看
GOOS和GOARCH的值,依据它们的值进行编译.比如GOARCH是AMD64,GOOS是Linux,那么编译出的程序就是在Linux/AMD64平台上运行的专版程序 - 如果没有特殊指定
GOOS和GOARCH,那么默认使用GOHOSTARCH和GOHOSTOS来编译程序.原因是我们在安装GO SDK的时候如果不自己更改那么默认GOARCH=GOHOSTARCH,GOOS=GOHOSTOS.编译出的程序默认是以宿主机为目标平台的.
Note that GOOS identify the target environment, not the environment you are running on. In effect, you are always cross-compiling
GO语言交叉编译的核心本质上是GOARCH和GOOS. GOHOSTARCH和GOHOSTOS处于辅助地位是默认值. environment也详细的列举了可以作为编译目标平台的GOARCH和GOOS组合.
我们也可以这样来查看(windows):
PS C:\Users\xxx\Desktop> go tool dist list
aix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
openbsd/mips64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm
交叉编译实践
我以在windows 10/amd64平台为linux/amd64编译gorilla为例演示
# git clone代码到本地
PS D:\workspace> git clone ssh://git@10.xxx.xxx.120:10022/xxx/gorilla.git
Cloning into 'gorilla'...
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 23 (delta 6), reused 0 (delta 0)
Receiving objects: 100% (23/23), 5.31 KiB | 5.31 MiB/s, done.
Resolving deltas: 100% (6/6), done.
PS D:\workspace> cd .\gorilla\
PS D:\workspace\gorilla> ls
目录: D:\workspace\gorilla
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2021/5/31 12:01 13 README.md
# 切换分支为feature
PS D:\workspace\gorilla> git checkout feature
Switched to a new branch 'feature'
Branch 'feature' set up to track remote branch 'feature' from 'origin'.
# 整理mod指定的依赖
PS D:\workspace\gorilla> go mod tidy
# 默认情况下交叉编译关闭,编译后.这时会默认产生windows/amd64平台的程序
PS D:\workspace\gorilla> go build .\cmd\main.go
PS D:\workspace\gorilla> ls
目录: D:\workspace\gorilla
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/5/31 12:01 cmd
-a---- 2021/5/31 12:01 5 .gitignore
-a---- 2021/5/31 12:01 922 Dockerfile
-a---- 2021/5/31 12:01 77 go.mod
-a---- 2021/5/31 12:01 5037 go.sum
# 生成了windows/amd64 可执行程序
-a---- 2021/5/31 12:01 9479168 main.exe
-a---- 2021/5/31 12:01 130 README.md
# 手动设置,开启交叉编译
# 目标系统为linux
PS D:\workspace\gorilla> $env:GOOS = "linux"
# 目标CPU架构为amd64
PS D:\workspace\gorilla> $env:GOARCH = "amd64"
# 交叉编译开始,编译
PS D:\workspace\gorilla> go build .\cmd\main.go
PS D:\workspace\gorilla> ls
目录: D:\workspace\gorilla
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2021/5/31 12:01 cmd
-a---- 2021/5/31 12:01 5 .gitignore
-a---- 2021/5/31 12:01 922 Dockerfile
-a---- 2021/5/31 12:01 77 go.mod
-a---- 2021/5/31 12:01 5037 go.sum
# 产生了linux/amd64的可执行程序
-a---- 2021/5/31 12:02 9427063 main
-a---- 2021/5/31 12:01 9479168 main.exe
-a---- 2021/5/31 12:01 130 README.md
参考: