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

    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 输出编译的信息。 

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 脚步,打开这个脚步,可以看到这个脚步主要做了如下几件事情:

  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 是否存在,不存在,则提示,退出

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

  

   




你可能感兴趣的:(编译原理)