golang交叉編譯

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

相關文章
相關標籤/搜索