这篇文章主要介绍如何编译Go的源码,学习后可以自己为Go添加一些定制化的功能,或许也可以为Go贡献自己的代码(仅仅会编译是不够的,还必须深入理解Go的运行机制和源码实现)。这里将通过修改Go的源码添加一个获取Goroutine编号的函数为例,介绍如何编译。
一般编程语言中都有线程,通过给线程分配编号,我们可以记录与某线程有关的数据,比如Java中的ThreadLocal。Golang没有提供线程,而是使用了更轻量化的Goroutine,同时Go也给每个Goroutine分配了一个编号,但是并没有提供获取Goroutine编号的函数。
这里注意目的是介绍如何修改和编译Go的源码,而不是为了给Go添加暴露Goroutine编号的函数,因为一般Go开发的应用中会存在大量的goroutine,很多的Goroutine运行时间较为短暂,所以获取到goroutine id后的意义并不大。
准备工作
- Go: Go编译的工具链是用Go编写的。但是早期Go语言的编译器用C语言写的,Go1.4是最后一个C语言的版本,之后的版本是使用Go编写的工具编译Go。所以编译Golang源码之前需要安装好一个版本的Go,可以使用基于C语言的Go1.4或使用之后基于Golang的其它版本。之外还需要设置环境变量GOROOT_BOOTSTRAP指向go所在的目录。
- C语言编译器: 需要安装gcc或clang。由于Go支持cgo,需要导入C语言的库,所以需要安装C语言的编译器。windows下可以安装mingw,注意32位还是64位。若不需要cgo,可以设置环境变量 CGO_ENABLED=0。
- Git: 需要安装Git。
- Go的源码。
开始编译
做完以上准备后,可以开始编译:
1
2
3
4
5
git clone [email protected]:golang/go.git # 下载源码
cd go
git checkout -b go1.17.2 go1.17.2 # 某分支或tag的版本
cd src
./all.bat # 执行编译,Linux、MacOS上为all.bash,Windows下为 all.bat
如果一切正常,会看到以下输出:
1
2
3
4
5
6
ALL TESTS PASSED
---
Installed Go for windows/amd64 in D:\workspace\go
Installed commands in D:\workspace\go\bin
*** You need to add D:\workspace\go\bin to your PATH.
编译好的二进制文件会生成在bin目录下。
可以写一段简单的代码测试一下编译好的go能否正常运行。创建一个hello.go文件:
1
2
3
4
5
6
7
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
直接使用go来运行:
1
2
$ go run hello.go
hello, world
增加goroutine id
其实每个goroutine都有一个id,只是Go没有将它暴露出来。Go开发的应用中一般存在大量的goroutine,大多数goroutine生命周期比较短暂,所以暴露出goroutine id意义并不大,它并不能给追踪问题带来较大帮助,这里只是演示和测试。
在源码src/runtime/proc.go中添加以下代码:
1
2
3
func GetGoroutineID() int64 {
return getg().goid
}
上面getg()函数为获得当前执行的g对象,它包含了当前goroutine相关的信息。然后重新执行编译:
1
.\all.bat
编译成功后,写代码测试一下。新建一个goid.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import (
"fmt"
"runtime"
"sync"
)
func PrintGoroutineID(wg *sync.WaitGroup) {
fmt.Println("hello, goroutine id:", runtime.GetGoroutineID())
wg.Done()
}
func main() {
wg := sync.WaitGroup{}
wg.Add(2)
go PrintGoroutineID(&wg)
go PrintGoroutineID(&wg)
wg.Wait()
}
然后执行:
1
2
3
$ go run ./goid.go
hello, goroutine id: 7
hello, goroutine id: 6
可以看到已经可以获取到并输出goroutine id了。