1. 交叉编译与golang的编译器架构
golang是一门跨平台的编译型语言, 其支持交叉编译(across-compiling). 所谓的交叉编译就是在平台A上使用编译器产生能够在平台B上运行的目标代码.
交叉编译常见于嵌入式开发与代码移植(transplant)中, 即在linux平台上编译arm平台的目标代码. 个人认为这样做的原因是arm开发板各种硬件都过于mini, 无法运行一个完整开发环境.
go的编译系统由gccgo前端(源码地址: https://github.com/golang/gofrontend)与gcc的后端组成. gccgo将go源码转化为中间表示IR, gcc再将IR转换为目标代码. 所以gcc后端具体执行代码的编译, 优化的步骤.
这种前端对应语言, 后端对应平台架构, 中间通过IR这个桥梁连接的编译器架构使得编译器开发大大简化. golang编译器开发中只需开发go语言前端, 再复用gcc后端. 著名的编译器框架LLVM
就使用了就采用了这种架构, 其best practice => clang. clang将c/c++源码转换为LLVM IR之后, 具体工作就交由llvm后端去做了.
2. golang交叉编译参数
两个最重要的交叉编译参数: $GOARCH, $GOOS.
这两个参数都是go的内置环境变量, 具体含义见(官方文档: https://golang.org/cmd/go/).
$GOOS控制目标代码的系统, 典型的有linux, windows, darwin.
$GOARCH控制目标代码的架构, 典型的有amd64, i386, arm64, arm.
linux on amd64, linux on arm64(即嵌入式/android), darwin on amd64(即MacOS)
3. 编译实战
源码如下:
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world!")
}
a. linux on amd64
$ GOOS=linux GOARCH=amd64 go build -o main_linux_amd64
由于开发环境就是linux on amd64, 所以GOOS与GOARCH的默认值就是linux与amd64.
go env|egrep -e 'GOOS|GOARCH'
也就是说, 目标代码的平台默认就是开发环境的平台.
b. windows on amd64
$ GOOS=windows GOARCH=amd64 go build -o main_win_amd64
在linux上可编译出直接运行于windows上的代码. 这给了我一点启发, 在linux上搭建GUI开发环境显然是十分麻烦的, CLI开发效率又太低.
那就可以在windows或mac上进行go服务器端开发, release时进行交叉编译, 部署, 测试即可.
go的跨平台性简直可以与java相媲美. 对于java来说每次修改源码之后都要重新编译生成字节码.
对于go来说, 每次修改源码之后同样要重新编译, 只是交叉编译参数的问题. 但是go相比于其在c系家族的"兄弟"
c/c++来说跨平台性大大提高. 跨平台的c代码中都要封装大量平台相关的宏(marco)与类型重命名(typedef).
移植c/c++代码远比移植go代码来的复杂, 尤其是在异构架构间移植 , 如amd64到arm64.
c. linux on arm64
$ GOOS=linux GOARCH=arm64 go build -o main_linux_arm64
在linux上可编译出直接运行于arm上的代码, 这仿佛对c的"独立王国"嵌入式领域造成了一定的威胁.
就我个人观点, 只要嵌入式设备的内存能够放得下go的运行时(1~2M)加上主体代码(最多10M左右), 蚕食嵌入式开发中c的地盘也是很有可能的(go嵌入式实战).
另外还可以通过剔除(strip)符号表来减小go可执行文件的大小. 可以看到未剔除符号的可执行文件大小为2.1M, 其中大部分为运行时库, 剔除符号后估计大小为1.5M甚至更小.
5G出现之后, 物联网IoT将会加速发展, 市场对嵌入式开发的需求将会越来越大. 希望go也能乘此快车而壮大.
go亦能开发Android程序, golang官方称之为gomobile(官方文档: https://godoc.org/golang.org/x/mobile). 传统的Android开发中, 开发人员调用java api进行开发, java代码底层使用JNI调用NDK接口.
而go直接调用NDK接口. 效率固然是go高, 但是目前go生态孱弱, 不及java九牛之一毛. 并且google将gomobile作为实验性(experimental)内容. tip! 目前Android的官方开发语言是kotlin, 一种可与java兼容的JVM语言.
d. wasm on js
wasm即Web assembly, 是一种为了替换在计算密集型场景中js代码的虚拟机语言, 可由任意语言开发.
由于go的运行时太大, 估计不会成为主流.