很长的一段时间没有写文章了,因为忙着出版书籍,以及双减的影响有些懈怠。Golang自举这个系列还是接着之前的《【Golang源码剖析】Golang如何实现自举 – dist介绍》一文中持续写,因为linux下go1.3编译*.c文件会调用gcc,编译go文件会调用“/mnt/pkg/tool/linux_amd64/6g”,所以本篇文章次要钻研6g,以及go1.3源码编译过程。

1.g6简略回顾

  在go1.3中其实一部分go的源代码还处于c源码实现,其中一部分是go实现,在这种状况下须要采纳混合编译模式,通过dist进行编译。

<center>图1-1 dist运行过程 </center>
  如图1-1所示,在运行dist编译时进行会有两个分支,一个是编译c文件会应用gcc进行编译,另外编译go会应用lib9库进行编译,也就是应用Plan 9,精确的是plan9port包。

2.Plan 9 与 Plan9port 由来

  Plan 9 与 Plan9port 由来参考: http://t.zoukankan.com/ghj197…

2.1 Plan 9

  Plan9其实是一个操作系统,由贝尔实验室开发,其次要的负责人是Rob Pike。

  Plan 9不是一个很出名的作品,然而它的前身Unix是世人皆知的。而Plan 9是Unix的几位作者在AT&T职业生涯的一件巅峰之作,是被设计来超过Unix的。

  实际上,Plan 9在1992年第一次公布时,就同时实现了Google Docs、Dropbox、Github、Remote Desktop等目前很火爆的互联网产品的性能。

  Plan 9能做到这些,是因为它把所有内容都注册到一个称为9P的文件系统里。

2.2 Plan9port

  Plan9port的作者是Russ Cox, 也是Go的设计者之一Russ Cox是Go和Google Code Search的作者,并且是Rob Pike的师傅。他多年保持用一台老旧的Mac mini搞开发,并且甚为骄傲。

  Russ来到AT&T退出Google之后忍不住思念Plan 9,所以把Plan 9上的用户程序——包含Acme——移植到其余操作系统上,称为Plan 9 from User Space。

git 上这个源码在:https://github.com/9fans/plan…

Plan 9 from User Space这个名字很有意思——Plan 9这个名字其实来自一部1959年美国科幻电影《Plan 9 from Outer Space》。

Plan 9 from User Space反对以下操作系统:

  • Linux
  • Mac OS X
  • FreeBSD, NetBSD, OpenBSD
  • SunOS

参考地址: https://9fans.github.io/plan9…

3.g6如何如何实现编译

  其实在编译go文件阶段g6命令的主要用途是编译go文件为链接库,然而还有6l命令用于链接为可执行文件。

<center>图3-1 go1.3编译过程 </center>
  如图3-1所示,其实go命令去“go build”的时候是调用go_bootstrap命令,然而go_bootstrap命令其实是调用g6进行编译,调用6l去进行链接可执行文件。

3.1 编译示例

  能够简略筹备一名为demo.go的源代码,代码如下:

package main

func main() {
    printf("1111")
}

  文中是应用docker 运行go1.3相干源码的,有趣味能够看一下《【Golang源码剖析】Golang如何实现自举(一)》一文,docker run的时候其实是没有go对应的环境变量,所以须要筹备环境变量,对应的环境变量如下:

export PATH=/mnt/bin:$PATH
export GOROOT=/mnt
export GOPATH=/mnt/gopath

从图3-1得悉go build其实是调用go_bootstrap命令,那么能够执行应用go_bootstrap命令进行编译查看,go_bootstrap减少 -v参数能够打印对应的包,-x参数能够查看整个执行过程(注:如果须要看其余的能够-h查看下帮忙文档) 。命令如下:

#/mnt/pkg/tool/linux_amd64/go_bootstrap build -v -x demo.go


<center>图3-2 go_bootstrap执行过程 </center>

  通过图3-2得悉其实6g编译demo.go文件时会生成一个“command-line-arguments.a”的文件,6l会链接“command-line-arguments.a”文件并生成一个demo的可执行文件。

3.2 g6的编译过程

  要晓得g6都做了些什么事件,能够调试下g6。间接运行如下命令:

#gdb /mnt/pkg/tool/linux_amd64/6g

进入gdb模式后,能够输出如下参数:

(gdb) set args build demo.go

设置完参数后能够间接“b main”下一个main断点,并输出”r”运行编译过程,则进入main函数后通过“s”进入p9main函数,如图3-3所示。


<center>图3-3 p9main函数调试过程 </center>
  通过图3-3能够看到其实编译会进入lex.c文件,在该文件中其实会调用go.h与y.tab.h文件,该文件其实是通过Bison 2.3生成,用于词法解析,并且应用yacc包脚本进行语法解析。除此之外还会经验7次语法查看, 别离是:

  • 1.常量、类型以及函数的名称和类型。
  • 2.变量调配。
  • 3.类型查看办法体。
  • 4.内联。
  • 5.逃逸剖析。
  • 6.编译顶级函数。
  • 7.查看内部申明。

  最终查看实现后,调用dumpobj函数备份.a文件。整个过程如图3-4所示。

<center>图3-4 g6编译过程 </center>

总结

  总的来说在go自举过程还是相对来说比较复杂的,会存在混编状况。编译c时通过gcc、编译go时通过g6生成对应的链接库,而后通过6l进行链接。其实还有很多细节须要摸索,比方语言的runtime环境,还有liblink库inferno-os的利用等等。有工夫我还是会持续更新该系列文章,做更深刻的摸索。

  • g6是用于编译.a链接库文件。
  • 6l是用于链接.a文件,并生成可执行文件。
  • g6中蕴含Bison做词法解析,以及利用yacc做语法解析。
  • plan9port是一个可移植性操作系统。
  • go_bootstrap对应 “-v”,”-x”命令能够查看到对应的编译链接过程。