Go 編譯過程分析(一) -- 編譯指令碼
http://blog.csdn.net/free2o/article/details/38417293
go 語言最近很火,與時俱進,我也看了看go 的語法。
看起來 go 還是不錯的,有很多新的feature。 就下載了程式碼研究了一下。
go 的 src 目錄下面存在三套編譯檔案:
- window 平臺, 所有 bat 檔案
- plan9 平臺,所有 rc 檔案
- unix 類平臺,所有bash 檔案
以 unix 編譯檔案為例, go 的編譯入口時在 src/all.bash , 這是一個bash 腳步, 這個腳步只是簡單的呼叫了 make.bash 在腳步結束之後,呼叫 dist banner 輸出編譯的資訊。
- set -e
- if [ ! -f make.bash ]; then
- echo 'all.bash must be run from $GOROOT/src' 1>&2
- exit 1
- fi
- OLDPATH="$PATH"
- . ./make.bash "[email protected]" --no-banner
- bash run.bash --no-rebuild
- PATH="$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 1
- fi
判斷當前是否在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
- if [ "$(uname)" == "Darwin" ]; then
- # golang.org/issue/5261
- mflag="$mflag -mmacosx-version-min=10.6"
- fi
- # 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=clangCXX=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 1
- fi
- 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 0
- fi
- echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
- buildall="-a"
- if [ "$1" = "--no-clean" ]; then
- buildall=""
- shift
- fi
- ./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
- echo
- fi
- echo "# 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 std
- echo