go build是如何工作的

看了下go在執(zhí)行g(shù)o build的時(shí)候可以加上-x選項(xiàng)來(lái)輸出詳細(xì)的編譯選項(xiàng)

大概流程是先把第三方用的庫(kù)進(jìn)行打包 然后再編譯項(xiàng)目文件 最后生成最終的目標(biāo)文件

下面這篇文字大概介紹了流程:

轉(zhuǎn):http://mikespook.com/2013/11/%E7%BF%BB%E8%AF%91-go-build-%E5%91%BD%E4%BB%A4%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9F/

之前 Dave Cheney 已經(jīng)為我們講解過了Go 是如何用 go 編譯自己的。這里,他繼續(xù)給大家講解一下go build 命令是如何工作的(原文)骡湖。

————翻譯分隔線————

go build 命令是如何工作的随珠?

本文以 Go 的標(biāo)準(zhǔn)庫(kù)為例,介紹了 Go 編譯過程的工作原理歧沪。

gc 工具鏈

本文將關(guān)注 gc 工具鏈碳褒。gc 工具鏈的名字來(lái)自 Go 的前端編譯器 cmd/gc折砸,這主要是為了與 gccgo 工具鏈進(jìn)行區(qū)分。當(dāng)人們討論 Go 編譯器的時(shí)候骤视,多半是指 gc 工具鏈鞍爱。本文不關(guān)注 gccgo 工具鏈。

gc 工具鏈?zhǔn)侵苯訌?Plan 9 的工具鏈剝離出來(lái)的专酗。該工具鏈由一個(gè) Go 編譯器、一個(gè) C 編譯器盗扇、一個(gè)匯編器和一個(gè)鏈接器組成祷肯。可以在 Go 代碼的 src/cmd/ 子目錄找到這些工具疗隶,包括在所有實(shí)現(xiàn)下共用的前端佑笋,和在不同處理器架構(gòu)下特定的后端。后端用特定的字母標(biāo)識(shí)斑鼻,這也是 Plan 9 的一個(gè)傳統(tǒng)蒋纬。命令包括:

5g、6g 和 8g 是 .go 文件的對(duì)應(yīng) arm坚弱、amd64 和 386 的編譯器蜀备;

5c、6c 和 8c 是 .c 文件的對(duì)應(yīng) arm荒叶、amd64 和 386 的編譯器碾阁;

5a、6a 和 8a 是 .s 文件的對(duì)應(yīng) arm些楣、amd64 和 386 的編譯器脂凶;

5l宪睹、6l 和 8l 是用于上面命令產(chǎn)生的文件的鏈接器,同樣對(duì)應(yīng) arm蚕钦、amd64 和 386亭病。

需要注意的是,每個(gè)命令都可以在任何被支持的平臺(tái)上進(jìn)行編譯嘶居,這也是 Go 的交叉編譯能力的一種體現(xiàn)罪帖。你可以在這篇文章里了解到更多關(guān)于交叉編譯的情況。

構(gòu)建包

構(gòu)建一個(gè) Go 包至少包含兩個(gè)步驟食听,編譯 .go 文件胸蛛,然后將編譯結(jié)果打包∮1ǎ考慮到 crypto/hmac 很小葬项,只有一個(gè)源文件和測(cè)試文件,所以用其舉例說(shuō)明迹蛤。使用 -x 選項(xiàng)以告訴 go build 打印出它所執(zhí)行的每一步

% go build -x crypto/hmac

WORK=/tmp/go-build249279931

mkdir-p $WORK/crypto/hmac/_obj/

mkdir-p $WORK/crypto/

cd/home/dfc/go/src/pkg/crypto/hmac

/home/dfc/go/pkg/tool/linux_arm/5g -o $WORK/crypto/hmac/_obj/_go_.5 -p crypto/hmac -complete -D _/home/dfc/go/src/pkg/crypto/hmac -I $WORK ./hmac.go

/home/dfc/go/pkg/tool/linux_arm/pack grcP $WORK $WORK/crypto/hmac.a $WORK/crypto/hmac/_obj/_go_.5

逐一了解這些步驟

WORK=/tmp/go-build249279931

mkdir-p $WORK/crypto/hmac/_obj/

mkdir-p $WORK/crypto/

go build 創(chuàng)建了一個(gè)臨時(shí)目錄 /tmp/go-build249279931 并且填充一些框架性的子目錄用于保存編譯的結(jié)果民珍。第二個(gè) mkdir 可能是多余的,已經(jīng)創(chuàng)建了issue 6538來(lái)跟蹤這個(gè)問題盗飒。

cd/home/dfc/go/src/pkg/crypto/hmac

/home/dfc/go/pkg/tool/linux_arm/5g -o $WORK/crypto/hmac/_obj/_go_.5 -p crypto/hmac -complete -D _/home/dfc/go/src/pkg/crypto/hmac -I $WORK ./hmac.go

go 工具切換 crypto/hmac 的源代碼目錄嚷量,并且調(diào)用架構(gòu)對(duì)應(yīng)的 go 編譯器,在本例中是 5g逆趣。實(shí)際上是沒有 cd 的蝶溶,當(dāng) 5g 執(zhí)行時(shí) /home/dfc/go/src/pkg/crypto/hmac 作為 exec.Command.Dir 的參數(shù)傳遞。這意味著為了讓命令行更加精簡(jiǎn)宣渗,.go 源文件可以使用對(duì)應(yīng)其源代碼目錄的相對(duì)路徑抖所。

編譯器生成唯一的一個(gè)臨時(shí)文件 $WORK/crypto/hmac/_obj/_go_.5 將在最后一步中使用。

/home/dfc/go/pkg/tool/linux_arm/pack grcP $WORK $WORK/crypto/hmac.a $WORK/crypto/hmac/_obj/_go_.5

最后一步是打包目標(biāo)文件到將被鏈接器和編譯器使用的歸檔文件 .a 中痕囱。

由于在包上調(diào)用了 go build 田轧,$WORK 中的結(jié)果將在編譯結(jié)束后刪除。如果調(diào)用 go install -x 將會(huì)輸出額外的兩行

mkdir-p /home/dfc/go/pkg/linux_arm/crypto/

cp$WORK/crypto/hmac.a /home/dfc/go/pkg/linux_arm/crypto/hmac.a

這演示了 go build 與 install 的不同之處鞍恢; build 構(gòu)建傻粘,install 構(gòu)建并且安裝,以便用于其他構(gòu)建帮掉。

構(gòu)建更加復(fù)雜的包

你可能正在思考前面例子中的打包步驟弦悉。這里的編譯器和鏈接器僅接受了單一的文件作為包的內(nèi)容,如果包含多個(gè)目標(biāo)文件旭寿,在使用它們之前警绩,必須將其打包到一個(gè)單一的 .a 歸檔文件中。

cgo 是一個(gè)常見的產(chǎn)生超過一個(gè)中間目標(biāo)文件的例子盅称,不過它對(duì)于本文來(lái)說(shuō)太過復(fù)雜了肩祥,這里用包含 .s 匯編文件的情況作為替代的例子后室,例如 crypto/md5。

% go build -x crypto/md5

WORK=/tmp/go-build870993883

mkdir-p $WORK/crypto/md5/_obj/

mkdir-p $WORK/crypto/

cd/home/dfc/go/src/pkg/crypto/md5

/home/dfc/go/pkg/tool/linux_amd64/6g -o $WORK/crypto/md5/_obj/_go_.6 -p crypto/md5 -D _/home/dfc/go/src/pkg/crypto/md5 -I $WORK ./md5.go ./md5block_decl.go

/home/dfc/go/pkg/tool/linux_amd64/6a -I $WORK/crypto/md5/_obj/ -o $WORK/crypto/md5/_obj/md5block_amd64.6 -D GOOS_linux -D GOARCH_amd64 ./md5block_amd64.s

/home/dfc/go/pkg/tool/linux_amd64/pack grcP $WORK $WORK/crypto/md5.a $WORK/crypto/md5/_obj/_go_.6 $WORK/crypto/md5/_obj/md5block_amd64.6

這個(gè)例子執(zhí)行在 linux/amd64 主機(jī)上混狠,6g 被調(diào)用以編譯兩個(gè) .go 文件:md5.go 和 md5block_decl.go岸霹。后面這個(gè)包含一些用匯編實(shí)現(xiàn)的函數(shù)的聲明。

這時(shí) 6a 被調(diào)用以匯編 md5block_amd64.s将饺。選擇哪個(gè) .s 來(lái)編譯的邏輯在我之前的關(guān)于條件編譯的文章中進(jìn)行了說(shuō)明贡避。

最后調(diào)用 pack 來(lái)打包 Go 的目標(biāo)文件 _go_.6,以及匯編目標(biāo)文件 md5block_amd64.6 到單一的一個(gè)歸檔文件中予弧。

構(gòu)建命令

一個(gè) Go 命令是一個(gè)命名為 main 的包刮吧。main 包,或者說(shuō)命令的編譯方式與其他包一致掖蛤,不過它們會(huì)在內(nèi)部經(jīng)過一些額外的步驟來(lái)鏈接成最終的可執(zhí)行文件杀捻。讓我們通過 cmd/gofmt 來(lái)研究一下這個(gè)過程

% go build -x cmd/gofmt

WORK=/tmp/go-build979246884

mkdir-p $WORK/cmd/gofmt/_obj/

mkdir-p $WORK/cmd/gofmt/_obj/exe/

cd/home/dfc/go/src/cmd/gofmt

/home/dfc/go/pkg/tool/linux_amd64/6g -o $WORK/cmd/gofmt/_obj/_go_.6 -p cmd/gofmt -complete -D _/home/dfc/go/src/cmd/gofmt -I $WORK ./doc.go ./gofmt.go ./rewrite.go ./simplify.go

/home/dfc/go/pkg/tool/linux_amd64/pack grcP $WORK $WORK/cmd/gofmt.a $WORK/cmd/gofmt/_obj/_go_.6

cd.

/home/dfc/go/pkg/tool/linux_amd64/6l -o $WORK/cmd/gofmt/_obj/exe/a.out -L $WORK $WORK/cmd/gofmt.a

cp$WORK/cmd/gofmt/_obj/exe/a.out gofmt

前面的六行應(yīng)該已經(jīng)熟悉了,main 包會(huì)向其他 Go 包一樣編譯和打包蚓庭。

不同之處在于倒數(shù)第二行致讥,調(diào)用鏈接器生成二進(jìn)制的可執(zhí)行文件。

/home/dfc/go/pkg/tool/linux_amd64/6l -o $WORK/cmd/gofmt/_obj/exe/a.out -L $WORK $WORK/cmd/gofmt.a

最后一行復(fù)制并重命名編譯后的二進(jìn)制文件到其最終的位置和名稱器赞。如果使用了 go install垢袱,二進(jìn)制也會(huì)被復(fù)制到 $GOPATH/bin(如果設(shè)置了 $GOBIN,則為 $GOBIN)港柜。

歷史原因

如果你回到足夠久遠(yuǎn)的時(shí)代请契,回到 go tool 之前,回到 Makefiles 的時(shí)代夏醉,你可以找到 Go 編譯過程的核心姚糊。這個(gè)例子來(lái)自release.r60的文檔

$cat>hello.go <

package main

import"fmt"

func main() {

fmt.Printf("hello, world\n")

}

EOF

$ 6g hello.go

$ 6l hello.6

$ ./6.out

hello, world

也就是這些,6g 編譯了 .go 文件到 .6 目標(biāo)文件授舟,6l 鏈接目標(biāo)文件以及 fmt (和運(yùn)行時(shí))包來(lái)生成二進(jìn)制文件 6.out。

結(jié)束語(yǔ)

在本文中贸辈,我們討論了 go build 的工作原理释树,并了解了 go install 對(duì)編譯結(jié)果處理的不同方式。

現(xiàn)在你已經(jīng)知道 go build 是如何工作的了擎淤,以及如何通過 -x 展示編譯過程奢啥,可以嘗試傳遞這個(gè)標(biāo)識(shí)到 go test 并且觀察其結(jié)果。

另外嘴拢,如果已經(jīng)在系統(tǒng)中安裝了 gccgo桩盲,可以向 go build 傳遞 -compiler gccgo,然后使用 -x 來(lái)了解 Go 代碼是如何用這個(gè)編譯器進(jìn)行編譯的席吴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赌结,一起剝皮案震驚了整個(gè)濱河市捞蛋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柬姚,老刑警劉巖拟杉,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異量承,居然都是意外死亡搬设,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門撕捍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拿穴,“玉大人,你說(shuō)我怎么就攤上這事忧风∧” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵阀蒂,是天一觀的道長(zhǎng)该窗。 經(jīng)常有香客問我,道長(zhǎng)蚤霞,這世上最難降的妖魔是什么酗失? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮昧绣,結(jié)果婚禮上规肴,老公的妹妹穿的比我還像新娘。我一直安慰自己夜畴,他們只是感情好拖刃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贪绘,像睡著了一般兑牡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上税灌,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天均函,我揣著相機(jī)與錄音,去河邊找鬼菱涤。 笑死苞也,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的粘秆。 我是一名探鬼主播如迟,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了殷勘?” 一聲冷哼從身側(cè)響起此再,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劳吠,沒想到半個(gè)月后引润,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痒玩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年淳附,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蠢古。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奴曙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出草讶,到底是詐尸還是另有隱情洽糟,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布堕战,位于F島的核電站坤溃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嘱丢。R本人自食惡果不足惜薪介,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望越驻。 院中可真熱鬧汁政,春花似錦、人聲如沸缀旁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)并巍。三九已至目木,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懊渡,已是汗流浹背嘶窄。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留距贷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓吻谋,卻偏偏與公主長(zhǎng)得像忠蝗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子漓拾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容