vlambda博客
学习文章列表

golang源码分析-编译(二)

本文主要介绍golang编译脚本的构建过程


接下来主要分析go1.4编译脚本的主要内容


首先来看go1.4编译脚本,$GOROOT_BOOTSTRAP/src/make.bash

114 echo '# Building C bootstrap tool.'115 echo cmd/dist116 export GOROOT="$(cd .. && pwd)"117 GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"118 DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'119120 mflag=""121 case "$GOHOSTARCH" in122 386) mflag=-m32;;123 amd64) mflag=-m64;;124 esac125 if [ "$(uname)" == "Darwin" ]; then126 # golang.org/issue/5261127 mflag="$mflag -mmacosx-version-min=10.6"128 fi129 # if gcc does not exist and $CC is not set, try clang if available.130 if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then131 export CC=clang CXX=clang++132 fi133 ${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c

这段代码最终生成一条编译指令,如下

gcc -m64 -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist -DGOROOT_FINAL="$GOROOT_FINAL" cmd/dist/*.c

通过gcc编译后生成二进制可执行程序$GOROOT_BOOTSTRAP/src/cmd/dist/dist

# 通过上一步生成的dist工具构建go_bootstrap159 ./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
# 通过go_bootstrap安装go及相关工具175 CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std

以上代码主要是通过dist生成go_bootstrap,然后通过go_bootstrap安装高版本的go及对应的工具


接下来详细分析下dist工具源码,源码文件如下:

$GOROOT_BOOTSTRAP/src/cmd/dist├── a.h├── arg.h├── arm.c├── buf.c├── build.c├── buildgc.c├── buildgo.c├── buildruntime.c├── main.c├── plan9.c├── README├── unix.c└── windows.c

plan9.c,unix.c,windows.c分别为不同移植平台的入口文件;main.c为可移植的入口文件;build.c,buildgc.c及buildruntime.c分别对应dist工具的核心功能;a.h定义了两个核心的数据结构Buf(字节缓冲区)及Vec(字符串切片),buf.c主要实现两种核心数据结构的相关操作


Buf及Vec的数据结构定义如下

// A Buf is a byte buffer, like Go's []byte.typedef struct Buf Buf;struct Buf{ char *p; int len; int cap;};
// A Vec is a string vector, like Go's []string.typedef struct Vec Vec;struct Vec{ char **p; int len; int cap;};


我们采用centos系统中的gcc进行源码编译,因此移植平台的入口文件是unix.c

main函数主要职责

1、初始化GO相关全局变量(goroot,goarch等)

2、调用可移植入口文件main.c的函数xmain


xmain的主要功能是根据dist工具获取子命令参数,执行相应的函数功能

static struct { char *name; void (*f)(int, char**);} cmdtab[] = { {"banner", cmdbanner}, {"bootstrap", cmdbootstrap}, {"clean", cmdclean}, {"env", cmdenv}, {"install", cmdinstall}, {"version", cmdversion},};

dist工具的子命令包含

  • banner(显示安装相关信息)

  • bootstrap(生成go_bootstrap)

  • clean(清理编译过程中生成的文件及目录)

  • env(显示环境变量)

  • install(安装相关目录对应的库,包及二进制可执行工具)

  • version(dist的版本)

函数cmdbootstrap主要负责生成go_bootstrap,具体实现在build.c文件中


cmdbootstrap函数主要按照buildorder顺序调用install函数进行编译,buildorder主要包含依赖的c函数库,编译器及包依赖


install函数主要功能如下

1、构建gcc编译lib9,libbio,liblink c库指令,生成.o中间文件

2、构建gcc编译6a(amd64架构汇编编译器),6c(amd64架构c语言编译器),6g(amd64架构go语言编译器),6l(amd64架构链接器)指令,生成.o中间文件

3、通过6a,6c,6g编译生成中间文件,通过6l链接中间文件生成二进制可执行文件go_bootstrap


go_bootstrap工具的源码在$GOROOT_BOOTSTRAP/src/cmd/go目录下,下一节主要分析通过go_bootstrap工具安装go标准库,自定义库及相关工具的源码