前言
在写一篇文章之前,某位大佬勾起了我对学习这个主题的欲望。刚好那天带着病痛,后来根据一个Makefile字符集的问题,拿着开始研究。发现研究、研究不疼了,果然和周星驰电影《国产凌凌漆》一样精神麻醉才是最好的麻醉药。今年以来也没有给自己立啥学习目标,刚好研究Golang自举动,可以作为我今年的学习目标。该篇文章只是个开始,后续会继续迭代。
大家都知道在Go早起其实编译器并不是go去编写的,后期自举实现了编译。不过在学习Golang自举之前要了解一下Golang的版本发展历史。
1. Golang版本历史&研究方向
在github对比golang的历史版本之后,发现其实go在的release发布版本中go1 ~ go1.4版本都还是处于C去实现编译器。然后在go1.5版本实现了自己的编译器。
如何按照这个历程,研究go自举的话,应该是从没改变前去发起研究。那么其实是研究go1 ~ go1.4比较关键。根据我的阅读后,把目标锁定在go1.2 ~ go1.3作为主要研究,其次就是go1.4。
2. Golang编译脚本介绍&Golang编译原理介绍
在介绍Golang目录之前先来说一下go是如何编译的。
2.1 go编译过程简述
其实go编译在早起版本和现在版本都很类似。都是输入“go build ”类似这样的命令去实现对脚本的编译。但是在执行这个脚本过程中其实做了不少事情,go命令本身而言就是一个壳子,而这个壳子封装在一块去执行了其他命令。如图2-1-1所示。
然后这些命令呢,其实对应在go的环境变量GOTOOLDIR下,通过“go env”可以查看,如图2-1-2所示。
不同系统的go命令所在的目录并不一致,这里涉及到系统存在不同的PE结构。tool在的目录是根据系统版本命令,其次要学习go底层其实应该去调试compile,这样词法解析,语法解析都可以调试到。
不过编译的话不单单是这些,编译性语言会有很繁琐的编译步骤,首先编译会经过词法解析,语法解析,优化器,然后生成机器码。生成机器码后,还会经过连接器、buildid过程等等。
不过该主题的重点还不在这一块,对这一块有兴趣的可以去看看我之前的文章《【Golang源码分析】解析执行命令complie(二)词法解析》与《【Golang源码分析】深度解析执行命令(一)go build 》两篇文章。
2.2 go编译脚本介绍
经过2.1小节简单的洗礼,基本对go的编译过程有一个大致的了解。那么可以先了解下go1.3,看一下go1.3的结构是什么样的。
目录中分为api、doc、include、lib、src、misc、test七个原始目录,编译后还会生成bin、pkg两个目录。 - api目录:api目录为api Check,对应工具"go tool api"相应源码 src/cmd/api。 - doc目录:doc目录为文档,如果要编译,或者了解一些版本信息,可以看一下这个目录中html内容。 - include目录:依赖C头文件目录。 - lib目录:依赖库文件目录。 - src目录:源代码目录,其中编译文件就在该目录。 - misc目录:一些杂项脚本都在这里面。 - test目录:测试用力目录。 - bin目录:生成go、godoc、gofmt文件都在该目录。 - pkg目录:生成对应系统动态连接库,以及对应系统的工具命令都在该目录,如cgo、api、yacc等等。新版本中会有compile
3.编译Golang
在编译go1.3之前,来看一下对应go下doc的文档都说了一些啥。
文档中说:
3.1 安装gcc环境
根据上述提示,咱们可以考虑使用GCC 4.7.0或者GCC 4.7.1版本去编译go。这样兼容性会好一些。这里我使用的是gcc4.7,gcc安装过于麻烦,我直接使用docker镜像这样方便快捷。
在拉取镜像后,建议自己本地把docker执行的仅从“docker commit”一个本地镜像,方便下次使用。
3.2 编译
根据2.3小节内容概述,其实编译go比较简单,咱们如果是想全部编译的话,直接执行./all即可,命令如下:
4.解读编译文件
了解完2、3小节中内容。基本知道如何编译go,那我们可以来解析下all.bash文件。
4.1 all.bash文件解读
其实all.bash文件只是针对nix系统的系统执行的,这样linux和unix系统都可以执行。因为是bash脚本。然后windows系统的可以执行.bat文件,如图4-1-1 所示。
编译脚本文件总共有all.、clean.、make.、run.四类。分为对应全部执行脚本、清理脚本、编译脚本、测试脚本。
那么来看一下all.bash脚本内容:
可以清晰的看到,编译内容主要是在make.sh脚本中。那么主要还是看make.bash脚本。
4.2 make.bash文件解读
在看make.bash执行,咱们可以改一下脚本内容,讲“set -e”修改为“set -ex”,这样就可以清晰的看到脚本的执行内容。
图中可以看到首先make做的先设置selinux,然后就开始编译dist文件,命令如下:
编译好dist后,又开始编译go_bootstrap文件。 然后编译完成go_bootstrap后,又通过go_bootstrap编译了go文件,最终删除go_bootstrap。执行命令过程如下:
通过整个执行过程,可以看出go1.3其实是通过go_bootstrap编译出来了的。
那么后续主要研究内容就是dist和go_bootstrap。
总结
自举的内容比较杂也比较多,会有一个系列的文章去概述,先来总结下内容把。
- go1 ~ go1.4 为c实现编译器。
- go1 使用GCC 4.7.0活GCC 4.7.1最为佳。
- go1编译文件在src目录中,对应make.bash脚本。
- go命令只是一个命令的组装工具。
- go1.3中go是通过go_bootstrap编译出来的,go_bootstrap又是通过dist编译出来的。