Go 编译过程分析(一) -- 编译脚本
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 "$@" --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如果当前是 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 1 fi如果调用脚本的时候,传递如参数 "--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 0 fi否则,就重新编译所以的代码,编译 go_bootstrap,通过执行命令 dist bootstrap
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
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。