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的運行時太大, 估計不會成爲主流.