快速掌握 Go 二進制文件的靜態(tài)和動態(tài)鏈接
大家好,我是煎魚。
在編寫 Go 應(yīng)用程序時,Go 本身提供了跨平臺編譯,提供了非常大的便利。但內(nèi)部其實有許多靜態(tài)和動態(tài)鏈接的相關(guān)知識點。
今天給大家分享這一塊的基本知識。
如何選擇?Go 團隊的討論
Go 核心團隊在創(chuàng)造這門編程語言時已經(jīng)做了大量的討論和權(quán)衡。
圖片
“靜態(tài)鏈接有很多優(yōu)點。部署簡單是其中之一。沒有版本問題是另一個優(yōu)點(升級可能永遠不會破壞您的 go 二進制文件。但動態(tài)鏈接或解釋語言則不然,因為依賴關(guān)系可能會中斷)。啟動時間更快也是另一個優(yōu)點。
不過,動態(tài)鏈接也有很好的理由。真實原因是:因為 go 作者已經(jīng)研究了靜態(tài)鏈接與動態(tài)鏈接的權(quán)衡,并決定靜態(tài)鏈接更適合他們的用例。而且 go 社區(qū)中的大多數(shù)人都同意這一點。”
靜態(tài)和動態(tài)鏈接是什么?
靜態(tài)和動態(tài)鏈接是兩種不同的程序鏈接方式,一般會根據(jù)實際的程序運行情況進行選擇。
圖片
靜態(tài)鏈接
在編譯時,鏈接器將程序所需的所有庫文件直接復(fù)制到可執(zhí)行文件中,生成一個完整的可執(zhí)行文件。
一旦生成后,執(zhí)行時不再依賴外部庫。
- 優(yōu)點:簡單且不需要額外的庫文件。
 - 缺點:可執(zhí)行文件較大,更新庫時需要重新編譯。
 
動態(tài)鏈接
在程序運行時,操作系統(tǒng)根據(jù)需要加載共享庫到內(nèi)存中。
這使得可執(zhí)行文件更小,因為它不包含所有的庫代碼,但程序執(zhí)行時依賴于外部庫的存在。
- 優(yōu)點:在于節(jié)省內(nèi)存和便于庫的更新。
 - 缺點:可能存在一些版本兼容性問題等。
 
快速例子
靜態(tài)鏈接
對于 Go 這一門編程語言而言,靜態(tài)鏈接是他大力宣傳的一個招牌:只需要編譯一個二進制文件,哪里都可以部署。
示例代碼如下:
package main
import (
 "fmt"
)
func main() {
 fmt.Println("腦子進煎魚了!")
}輸出結(jié)果:
腦子進煎魚了!強制指定 CGO_ENABLED=0 來進行編譯:
CGO_ENABLED=0 go build main.go使用 file 工具查看目標(biāo)文件信息:
$ file greet
greet: Mach-O 64-bit executable arm64結(jié)合查看 fmt.Println 是否固定地址:
圖片
結(jié)合來看,可以確定 Go 程序本身的依賴是靜態(tài)鏈接的。而編譯出來的二進制程序到底有沒有動態(tài)鏈接庫,取決于你所編寫的程序。
動態(tài)鏈接
Go 應(yīng)用程序在進行 go build 的時候,可以加入 -buildmode 參數(shù)來指定構(gòu)建模式,以此實現(xiàn)動態(tài)鏈接的目的。
以下是可用的 buildmode 選項:
- archive: 將非 main 包構(gòu)建成 .a 文件,main 包將被排除。
 - c-archive: 構(gòu)建 main 包及其依賴的所有包為 C 歸檔文件。
 - c-shared: 構(gòu)建指定的 main 包及其所有依賴為 C 動態(tài)庫。
 - shared: 將所有非 main 包整合到一個動態(tài)庫中。
 - exe: 構(gòu)建指定的 main 包及其依賴為可執(zhí)行文件,未命名為 main 的包將被忽略。
 
默認(rèn)情況下,main 包會被內(nèi)置到可執(zhí)行文件中,非 main 包則會被內(nèi)置到 .a 文件中。
這塊我們寫 Web 程序的用的不多,如果是寫 C 庫或者調(diào)第三方語言的動態(tài)庫時用得多。此時需要在編譯時指定 CGO_ENABLED=1 才可以。
有興趣的話,CGO 例子可以參考:andreiavrammsd/cgo-examples[1],這里不展開。
總結(jié)
今天我們快速的介紹了 Go 語言中的靜態(tài)和動態(tài)鏈接的基本概念,打了個底。靜態(tài)鏈接會實現(xiàn) ALL IN ONE 的效果,確保編譯出來的二進制文件能夠在標(biāo)準(zhǔn)的環(huán)境下運行。而動態(tài)鏈接則相反。
這是 Go 這門編程語言設(shè)計時的一個招牌特性,而我們做 Web 開發(fā)的話,一般都是以靜態(tài)鏈接為主。
如果有涉及到第三方調(diào)用才會用到動態(tài)鏈接等。我見過用 CGO 逐步重構(gòu) C 服務(wù)的,甚至要慎防內(nèi)存泄露。這時候又是另外一套邏輯、體系了,要進一步進修!















 
 
 








 
 
 
 