很长的一段时间没有写文章了,因为忙着出版书籍,以及双减的影响有些懈怠。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” 命令能够查看到对应的编译链接过程。