Go 编译过程分析(一) -- 编译脚本

http://blog.csdn.net/free2o/article/details/38417293

go 语言最近很火,与时俱进,我也看了看go 的语法。

    看起来 go 还是不错的,有很多新的feature。 就下载了代码研究了一下。

    go 的 src 目录下面存在三套编译文件:

  1. window 平台, 所有 bat 文件
  2. plan9 平台,所有 rc 文件
  3. unix 类平台,所有bash 文件

     以 unix 编译文件为例, go 的编译入口时在 src/all.bash , 这是一个bash 脚步, 这个脚步只是简单的调用了 make.bash 在脚步结束之后,调用 dist banner 输出编译的信息。 

[plain] view plaincopy
  1. set -e  
  2. if [ ! -f make.bash ]; then  
  3.         echo 'all.bash must be run from $GOROOT/src' 1>&2  
  4.         exit 1  
  5. fi  
  6. OLDPATH="$PATH"  
  7. . ./make.bash "$@" --no-banner  
  8. bash run.bash --no-rebuild  
  9. PATH="$OLDPATH"  
  10. $GOTOOLDIR/dist banner  # print build info  

    dist 是在 make.bash 中生成的一个可执行文件,go 的所有编译都是在这个文件的控制下完成的。 个人认为这并不是一个好的设计,导致维护编译系统的成功过高,如果要修改一下编译选项,往往要修改 dist 源代码。dist 的代码在目录: /src/cmd/dist 下。

  dist 这个命令行程序支持如下几个参数:   

[plain] view plaincopy
  1. "banner         print installation banner\n" ; 打印安装的一些信息  
  2. "bootstrap      rebuild everything\n"        ; 重新编译所有的 go 代码  
  3. "clean          deletes all built files\n"   ; 清楚编译的 go 代码  
  4. "env [-p]       print environment (-p: include $PATH)\n"  ; 打印编译的环境  
  5. "install [dir]  install individual directory\n"  ;安装某一个目录。会编译目录下代码,安装生成文件  
  6. "version        print Go version\n"              ;大约go版本信息  

  想要研究编译细节一定要看看这个程序的代码,后续详细分析。

  make.bash, 同样是一个 bash 脚步,打开这个脚步,可以看到这个脚步主要做了如下几件事情:

  1. 根据不同的系统,以及参数进行一些初始化的工作
  2. 编译生成 dist,调用dist 完成整个go 的编译. dist bootstrap
  3. 用编译生成的 go_bootstrap 完成整个安装过程

    很遗憾,这个script 不支持 window。 window 下调用 make.bat 去完成编译。  go 的编译系统不能很好的支持cygwin, 这是让人觉得很不爽的地方。其实整个go 的编译应该建立在Makefile 机制上,而修改go 的编译脚本,让整个源代码不依赖于dist 去完成整个编译的过程,是让go 很好的支持各种不同平台的好的入手点。

    有一些环境变量和 make.bash 结合的很紧密,也控制了编译的一些选项:

  1. GOROOT_FINAL :  这个变量用来表明 go 最终安装的路径,如果不设置,默认值为当前源代码的路径
  2. GOHOSTARCH :   设定编译 go 语音的电脑的 ARCH(架构) , 386 or amd64 or arm
  3. GOARCH : 编译生成的 go 所运行的 ARCH。
  4. GOOS : 编译生成的 go 所允许的操作系统
  5. GO_GCFLAGS: 编译 5g/6g/8g 时,额外指定的参数
  6. GO_LDFLAGS : 编译 5l/6l/8l 时, 额外指定的参数
  7. GO_CCFLAGS  :  编译 5c/6c/8c 时,额外指定的参数
  8. CGO_ENABLED:   是否支持 cgo,设置为1 的话,cgo 相关文件会被编译,设置为0 的话,则不会编译
  9. GO_EXTLINK_ENABLED : 是否使用Host 环境的 link。设置1的话,则会使用编译环境中带的连接器,0,在不会
  10. CC : 设置C编译器名字, gcc 还是 clang , 这个设置的是 host 环境的编译器
  11. CC_FOR_TARGET : 设置C编译器名字,这个设置的是 能够生成目标环境代码的编译器
  12. CXX_FOR_TARGET: 设置CXX编译器名字, g++ or clang++这个设置的是 能够生成目标环境代码的编译器
  13. GO_DISTFLAGS :  为 dist bootstrap 提供额外的参数.

   make.bash 的一些分析:

    判断 run.bash 是否存在,不存在,则提示,退出

[plain] view plaincopy
  1. if [ ! -f run.bash ]; then  
  2.         echo 'make.bash must be run from $GOROOT/src' 1>&2  
  3.         exit 1  
  4. fi  

     判断当前是否在cygwin 或者 mingw ,或者其他window 环境下运行。 这里吧 cygwin 简单的划到window 的环境,是不合适的

[html] view plaincopy
  1. case "$(uname)" in  
  2. *MINGW* | *WIN32* | *CYGWIN*)  
  3.        echo 'ERROR: Do not use make.bash to build on Windows.'  
  4.        echo 'Use make.bat instead.'  
  5.        echo  
  6.        exit 1  
  7.        ;;  
  8. esac  
  如果当前是 Darwin 系统,则在编译选项中加入设定最小 macos 版本的条件

[html] view plaincopy
  1. if [ "$(uname)" == "Darwin" ]; then  
  2.         # golang.org/issue/5261  
  3.         mflag="$mflag -mmacosx-version-min=10.6"  
  4. fi  
如果CC 没有设置,并且 gcc 在host 环境上没有, clang 确是在host 环境上存在,则设置编译器 为 clang

[html] view plaincopy
  1. # if gcc does not exist and $CC is not set, try clang if available.  
  2. if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then  
  3.         export CC=clang CXX=clang++  
  4. fi  

编译生成 dist 程序,判断是否编译成功

[html] view plaincopy
  1. ${CC:-gcc} $mflag -O2 -Wall -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c  
  2.   
  3. # -e doesn't propagate out of eval, so check success by hand.  
  4. eval $(./cmd/dist/dist env -p || echo FAIL=true)  
  5. if [ "$FAIL" = true ]; then  
  6.         exit 1  
  7. fi  
如果调用脚本的时候,传递如参数 "--dist--tool" ,那么意味着仅仅编译dist,那么生成disk 之后,安装dist,然后退出

[html] view plaincopy
  1. if [ "$1" = "--dist-tool" ]; then  
  2.         # Stop after building dist tool.  
  3.         mkdir -p "$GOTOOLDIR"  
  4.         if [ "$2" != "" ]; then  
  5.                 cp cmd/dist/dist "$2"  
  6.         fi  
  7.         mv cmd/dist/dist "$GOTOOLDIR"/dist  
  8.         exit 0  
  9. fi  
否则,就重新编译所以的代码,编译 go_bootstrap,通过执行命令 dist bootstrap

[html] view plaincopy
  1. echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."  
  2. buildall="-a"  
  3. if [ "$1" = "--no-clean" ]; then  
  4.         buildall=""  
  5.         shift  
  6. fi  
  7. ./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap  

用 go_bootstrap 完成整个编译过程

[html] view plaincopy
  1. if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then  
  2.         echo "# Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."  
  3.         # CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the host, however,  
  4.         # use the host compiler, CC, from `cmd/dist/dist env` instead.  
  5.         CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \  
  6.                 "$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std  
  7.         echo  
  8. fi  
  9.   
  10. echo "# Building packages and commands for $GOOS/$GOARCH."  
  11. CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std  
  12. echo  

  

    

本文来自:CSDN博客

感谢作者:working_brain

查看原文:Go 编译过程分析(一) -- 编译脚本

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。