如何用Go構建Go

Codefor發表於2013-06-08

這篇文章基於2013年4月中旬我給悉尼Go使用者組分享中描述Go構建的部分。

在郵件組和IRC頻道中,經常有人詢問有關 Go編譯器,執行時和內部實現的文件。目前關於 Go內部實現權威的文件就是原始碼,我鼓勵大家都去看原始碼。之前已經說過,自從 Go1.0釋出之後,Go構建的過程已經固定下來,所以這篇文章很可能維持一段時間。

這篇文章從原始碼開始,到充分測試的 Go安裝過程結束,講述了Go構建過程的九個步驟。為簡單起見,所有這裡提到的路徑都相對於簽出原始碼的根目錄 , $GOROOT/src 。

至於背景知識要求,你應該讀讀 golang.org上面的從原始碼安裝Go

 

第一步, all.bash

第一步有點虎頭蛇尾,因為 all.bash會呼叫另外兩個shell指令碼: make.bash和run.bash .如果你用 Windows或者Plan9 ,步驟是一樣的,只不過指令碼名稱分別以 .bat和.rc 結尾。以下敘述過程中,請用相應作業系統的副檔名進行替代。

 

第二步. make.bash

make.bash 源於 all.bash ,因此呼叫exit會正常終止構建過程.make.bash 有三個主要功能, 第一個功能是驗證正在編譯Go的環境的完整性。完整性檢查在過去幾年內建立起來,目的主要是避免用已知的損壞了的工具構建或者在構建會失敗的環境中構建。

 

第三步. cmd/dist

一旦完整性檢查完成,make.bash 會編譯 cmd/dist. cmd/dist 替代了Go1之前的基於Makefile的構建系統並管理pkg/runtime中少量的程式碼生成。cmd/dist 是一個C程式,這使得它能夠利用系統的C編譯器和標頭檔案來處理大多數的主機平臺檢測問題.cmd/dist 總是會檢測主機的作業系統和架構, $GOHOSTOS and $GOHOSTARCH. 如果你是交叉編譯,這些變數的值可能會與設定的不一樣。實際上,Go構建過程就是在建立一個交叉編譯器,但大多數情況下宿主機和目標機平臺是一致的。之後, make.bash 用引導引數呼叫 cmd/dist ,後者先編譯編譯器套件使用的支援庫 lib9, libbio 和 libmach, 然後編譯編譯器自身。 這些工具也是用c寫成的,用系統的c編譯器編譯。

cmd/dist 用編譯器套件編譯了 go 工具 go_bootstrap 的一個版本。 go_bootstrap 是一個不完整的 go 工具,比如為了避免對cgo的依賴,去掉了 pkg/net 。由於cmd/dist 工具包含將要編譯的包或者庫及其依賴的資料夾列表,所以要格外小心避免引入新的 cmd/go 的構建依賴。

 

第四步. go_bootstrap

現在go_bootstrap 已經構建完成, make.bash 的最後一步是用go_bootstrap 編譯所有的Go標準庫包括一個完整版本的go 工具。

第五步. run.bash

現在 make.bash 已經執行完了。執行控制又回到 all.bash 。接下來會呼叫run.bash 。run.bash的作用是編譯並測試標準庫、執行時和語言測試套件。

使用–no-rebuild 是因為 make.bash 和 run.bash 都會呼叫 go install -a std, 。為了避免重複呼叫,–no-rebuild 會跳過第二次 go install。

 

第六步. go test -a std

run.bash 接下來執行標準庫中所有包中的單元測試,這些單元測試用到了testing包。因為$GOPATH 和 $GOROOT 下的程式碼屬於同一個名稱空間,我們不能用go test …(這回測試$GOPATH中所有的包)。因此用一個別名std來宣告標準庫中的包,由於一些測試需要很長時間或者消耗很多記憶體,可以用-short標誌來過濾這些測試。

 

第七步. runtime and cgo tests

run.bash 下一步執行了一系列的針對支援cgo平臺的測試,少量基準測試,編譯各種各樣的和Go一起發雜項程式。慢慢地,這種雜項程式越來越多。因為我們發現,這些雜項程式在構建過程中不可或缺。

 

第八步. go run test

這是run.bash 的倒數第二個階段。呼叫位於$GOROOT test 資料夾下編譯器和執行時的測試用例。這些都是關於編譯器和執行時自己的底層細節的測試用例。在測試語言規範的同時, test/bugs 和 test/fixedbugs 子資料夾下的測試用例獨立執行以捕獲之前已經發現並修復的問題.所有這些測試的驅動是 $GOROOT/test/run.go ,它會執行test資料夾下面每一個.go檔案。一些.go檔案會在第一行包含一些指令,這些指令會指示run.go ,比如退出程式或者丟擲特定的輸出序列。

 

第九步. go tool api

run.bash 的最後一步就是呼叫 api 工具。 api工具的作用是在Go1 2012年釋出時執行Go1 API的約定,Go1 API包括匯出符號、常量、函式、變數、型別、方法等等。 Go1把這些寫在 api/go1.txt中,Go 1.1寫在api/go1.1.txt 中。Go1.1之後,一個額外的檔案 api/next.txt 指明瞭標準庫和執行時新增符號。一旦Go1.2釋出,這個檔案會成為Go1.2的約定,並且會有一個新的next.txtT。還有一個包含Go1 約定異常的小檔案 except.txt。修改這些檔案不可掉以輕心。

 

其他貼士和技巧

你可能已經發現make.bash 在不執行測試用例時構建Go很有用,而 run.bash 用來構建和測試Go執行時。區別就是:前者可以用於交叉編譯;如果你基於標準庫開發,後者很有幫助。

更新: 感謝Russ Cox 和 Andrew Gerrand的反饋和建議。

 

英文原文:Dave Cheney,感謝@Codefor 的熱心翻譯。如果其他朋友也有不錯的原創或譯文,可以嘗試推薦給伯樂線上

譯文連結:http://blog.jobbole.com/41054/

【非特殊說明,轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊,謝謝合作!】

相關文章