1. 交叉编译与golang的编译器架构前端
golang是一门跨平台的编译型语言, 其支持交叉编译(across-compiling). 所谓的交叉编译就是在平台A上使用编译器产生可以在平台B上运行的目标代码.java
交叉编译常见于嵌入式开发与代码移植(transplant)中, 即在linux平台上编译arm平台的目标代码. 我的认为这样作的缘由是arm开发板各类硬件都过于mini, 没法运行一个完整开发环境.linux
go的编译系统由gccgo前端(源码地址: https://github.com/golang/gofrontend)与gcc的后端组成. gccgo将go源码转化为中间表示IR, gcc再将IR转换为目标代码. 因此gcc后端具体执行代码的编译, 优化的步骤.android
这种前端对应语言, 后端对应平台架构, 中间经过IR这个桥梁链接的编译器架构使得编译器开发大大简化. golang编译器开发中只需开发go语言前端, 再复用gcc后端. 著名的编译器框架LLVMc++
就使用了就采用了这种架构, 其best practice => clang. clang将c/c++源码转换为LLVM IR以后, 具体工做就交由llvm后端去作了.git
2. golang交叉编译参数github
两个最重要的交叉编译参数: $GOARCH, $GOOS.golang
这两个参数都是go的内置环境变量, 具体含义见(官方文档: https://golang.org/cmd/go/).windows
$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嵌入式实战: https://blog.csdn.net/yyz_1987/article/details/87714058).
另外还能够经过剔除(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的运行时太大, 估计不会成为主流.