這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
go 語言最近很火,與時俱進,我也看了看go 的文法。
看起來 go 還是不錯的,有很多新的feature。 就下載了代碼研究了一下。
go 的 src 目錄下面存在三套編譯檔案:
- window 平台, 所有 bat 檔案
- plan9 平台,所有 rc 檔案
- unix 類平台,所有bash 檔案
以 unix 編譯檔案為例, go 的編譯入口時在 src/all.bash , 這是一個bash 腳步, 這個腳步只是簡單的調用了 make.bash 在腳步結束之後,調用 dist banner 輸出編譯的資訊。
set -eif [ ! -f make.bash ]; then echo 'all.bash must be run from $GOROOT/src' 1>&2 exit 1fiOLDPATH="$PATH". ./make.bash "$@" --no-bannerbash run.bash --no-rebuildPATH="$OLDPATH"$GOTOOLDIR/dist banner # print build info
dist 是在 make.bash 中產生的一個可執行檔,go 的所有編譯都是在這個檔案的控制下完成的。 個人認為這並不是一個好的設計,導致維護編譯系統的成功過高,如果要修改一下編譯選項,往往要修改 dist 原始碼。dist 的代碼在目錄: /src/cmd/dist 下。
dist 這個命令列程式支援如下幾個參數:
"banner print installation banner\n" ; 列印安裝的一些資訊 "bootstrap rebuild everything\n" ; 重新編譯所有的 go 代碼 "clean deletes all built files\n" ; 清楚編譯的 go 代碼 "env [-p] print environment (-p: include $PATH)\n" ; 列印編譯的環境 "install [dir] install individual directory\n" ;安裝某一個目錄。會編譯目錄下代碼,安裝組建檔案 "version print Go version\n" ;大約go版本資訊
想要研究編譯細節一定要看看這個程式的代碼,後續詳細分析。
make.bash, 同樣是一個 bash 腳步,開啟這個腳步,可以看到這個腳步主要做了如下幾件事情:
- 根據不同的系統,以及參數進行一些初始化的工作
- 編譯產生 dist,調用dist 完成整個go 的編譯. dist bootstrap
- 用編譯產生的 go_bootstrap 完成整個安裝過程
很遺憾,這個script 不支援 window。 window 下調用 make.bat 去完成編譯。 go 的編譯系統不能很好的支援cygwin, 這是讓人覺得很不爽的地方。其實整個go 的編譯應該建立在Makefile 機制上,而修改go 的編譯指令碼,讓整個原始碼不依賴於dist 去完成整個編譯的過程,是讓go 很好的支援各種不同平台的好的入手點。
有一些環境變數和 make.bash 結合的很緊密,也控制了編譯的一些選項:
- GOROOT_FINAL : 這個變數用來表明 go 最終安裝的路徑,如果不設定,預設值為當前原始碼的路徑
- GOHOSTARCH : 設定編譯 go 語音的電腦的 ARCH(架構) , 386 or amd64 or arm
- GOARCH : 編譯產生的 go 所啟動並執行 ARCH。
- GOOS : 編譯產生的 go 所允許的作業系統
- GO_GCFLAGS: 編譯 5g/6g/8g 時,額外指定的參數
- GO_LDFLAGS : 編譯 5l/6l/8l 時, 額外指定的參數
- GO_CCFLAGS : 編譯 5c/6c/8c 時,額外指定的參數
- CGO_ENABLED: 是否支援 cgo,設定為1 的話,cgo 相關檔案會被編譯,設定為0 的話,則不會編譯
- GO_EXTLINK_ENABLED : 是否使用Host 環境的 link。設定1的話,則會使用編譯環境中帶的連接器,0,在不會
- CC : 設定C編譯器名字, gcc 還是 clang , 這個設定的是 host 環境的編譯器
- CC_FOR_TARGET : 設定C編譯器名字,這個設定的是 能夠產生目標環境代碼的編譯器
- CXX_FOR_TARGET: 設定CXX編譯器名字, g++ or clang++這個設定的是 能夠產生目標環境代碼的編譯器
- GO_DISTFLAGS : 為 dist bootstrap 提供額外的參數.
make.bash 的一些分析:
判斷 run.bash 是否存在,不存在,則提示,退出
if [ ! -f run.bash ]; then echo 'make.bash must be run from $GOROOT/src' 1>&2 exit 1fi
判斷當前是否在cygwin 或者 mingw ,或者其他window 環境下運行。 這裡吧 cygwin 簡單的划到window 的環境,是不合適的
case "$(uname)" in*MINGW* | *WIN32* | *CYGWIN*) echo 'ERROR: Do not use make.bash to build on Windows.' echo 'Use make.bat instead.' echo exit 1 ;;esac
如果當前是 Darwin 系統,則在編譯選項中加入設定最小 macos 版本的條件
if [ "$(uname)" == "Darwin" ]; then # golang.org/issue/5261 mflag="$mflag -mmacosx-version-min=10.6"fi
如果CC 沒有設定,並且 gcc 在host 環境上沒有, clang 確是在host 環境上存在,則設定編譯器 為 clang
# if gcc does not exist and $CC is not set, try clang if available.if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then export CC=clang CXX=clang++fi
編譯產生 dist 程式,判斷是否編譯成功
${CC:-gcc} $mflag -O2 -Wall -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c# -e doesn't propagate out of eval, so check success by hand.eval $(./cmd/dist/dist env -p || echo FAIL=true)if [ "$FAIL" = true ]; then exit 1fi
如果呼叫指令碼的時候,傳遞如參數 "--dist--tool" ,那麼意味著僅僅編譯dist,那麼產生disk 之後,安裝dist,然後退出
if [ "$1" = "--dist-tool" ]; then # Stop after building dist tool. mkdir -p "$GOTOOLDIR" if [ "$2" != "" ]; then cp cmd/dist/dist "$2" fi mv cmd/dist/dist "$GOTOOLDIR"/dist exit 0fi
否則,就重新編譯所以的代碼,編譯 go_bootstrap,通過執行命令 dist bootstrap
echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."buildall="-a"if [ "$1" = "--no-clean" ]; then buildall="" shiftfi./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
用 go_bootstrap 完成整個編譯過程
if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH." # CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however, # use the host compiler, CC, from `cmd/dist/dist env` instead. CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \ "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std echofiecho "# Building packages and commands for $GOOS/$GOARCH."CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v stdecho