Go 是怎么使用 Go 来编译自身的 已翻译 100%

oschina 投递于 2013/06/04 09:27 (共 8 段, 翻译完成于 06-04)
阅读 8241
收藏 50
Go
5
加载中

在邮件列表或者IRC聊天室中经常有人问及Go编译器、运行时和内部实现的细节文档。目前,关于Go内部实现的最权威的文档还是源码本身,鼓励大家试着直接去阅读源码。 话虽如此,从Go 1.0开始,Go的build过程已经开始稳定下来,所以这里提到的内容也许会在一段时间管用。

本文介绍了Go的build过程中的9个步骤,从源码开始,到完整的测试及安装结束。简单起见,所有的路径都是相对路径,相对于源码的root路径,$GOROOT/src。

你需要阅读golang.org 从源码安装Go 了解一些相关的背景知识。

zicode
zicode
翻译于 2013/06/04 16:58
1

第一步:all.bash

% cd $GOROOT/src
% ./all.bash

第一步有些突兀,因为 all.bash 仅仅调用了其它两个 shell 脚本;make.bashrun.bash。如果你在使用 Windows 或 Plan 9,过程是一样的,只是脚本扩展名变成了.bat 或.rc。对于本文中的其它脚本,请根据你的系统适当改动。

第二步:make.bash

. ./make.bash --no-banner

main.bash 来源于 all.bash,因此调用退出将正确终止便宜进程。main.bash 有三个主要工作,第一个是验证编译 Go 的环境是否完整。完整性检查在过去几年中建立,它通常尝试避免使用已知的破损工具或必然失败的环境进行编译。

K6F
K6F
翻译于 2013/06/04 16:49
1

第三步. cmd/dist

gcc -O2 -Wall -Werror -ggdb -o cmd/dist/dist -Icmd/dist cmd/dist/*.c

一旦可用性检查完毕,make.bash 将编译产生 cmd/dist,cmd/dist取代了之前存在于Go 1 之前的Makefile 编译系统。cmd/dist用来管理少量的pkg/runtime的代码生成。cmd/dist 是C语言编写的程序,能够充分利用系统C编译器和头文件来处理大部分主机系统平台的检测。cmd/dist通常用来检测主机的操作系统和体系结构,即环境变量$GOHOSTOS和$GOHOSTARCH .如果交叉编译的话,变量 $GOOS和$GOARCH可能会由于你的设置而不同事实上,Go 通常用作跨平台编译器,只不过多数情况下,主机和目标系统一致而已。接下来,make.bash 调用cmd/dist 引导参数支持、 lib9、 libbio 和 libmach,使用编译器套件然后用自己编译器进行编译这些工具也是用 C 语言写的,但是由系统 C 编译器编译产生

echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
buildall="-a"
if [ "$1" = "--no-clean" ]; then
 buildall=""
fi
./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap

使用编译器套件 cmd/dist  编译产生一个版本gotool,go_bootstrap。但go_bootstrap并是完整得gotool,比方说 pkg/net 就是孤立的避免了依赖于 cgo编译文件列表以及它们依赖项,是由cmd/dist编译的 所以十分谨慎避免引入生成依赖项 到 cmd/go

MtrS
MtrS
翻译于 2013/06/04 21:29
1

第四步:go_bootstrap

现在, go_bootstrap 编译完成了,make.bash 的最后一部就是使用 go_bootstrap 完成 Go 标准库的编译,包括整套 gotool 的替换版。

echo "# Building packages and commands for $GOOS/$GOARCH."
"$GOTOOLDIR"/go_bootstrap install -gcflags "$GO_GCFLAGS" \
    -ldflags "$GO_LDFLAGS" -v std

第五步:run.bash

现在,make.bash 完成了,运行回到了 all.bash,它将引用 run.bash。run.bash 的工作是编译和测试标准库,运行时以及语言测试套件。

bash run.bash --no-rebuild

使用 --no-rebuild 标识是因为 make.bash 和 run.bash 可能都调用了 go install -a std,这样可以避免重复,--no-rebuild 跳过了第二个 go install。

# allow all.bash to avoid double-build of everything
rebuild=true
if [ "$1" = "--no-rebuild" ]; then
 shift
else
 echo '# Building packages and commands.'
 time go install -a -v std
 echo
fi

K6F
K6F
翻译于 2013/06/04 16:56
1

第六步:go test -a std

echo '# Testing packages.'
time go test std -short -timeout=$(expr 120 \* $timeout_scale)s
echo

下一步 run.bash z则是对标准库中的所有包进行单元测试,这是使用 testing 包编写的。由于 $GOPATH 和 $GOROOT 中的代码存在于同一个命名空间中,我们不能使用 go test,这可能会测试 $GOPATH 中的所有包,所以将创建别名std来标识标准库中的包。由于有些测试需要很长时间,或耗用大量内存,测试将会通过 -short 标识将其过滤。

第七步 runtime 和 cgo 测试

run.bash的下一节将运行大量对cgo支持的平台测试,运行一些季春测试,编译 Go 附带的一些杂项程序。随着时间的推移,这份杂项程序列表已经变长了,当它们发现自己并不包含在编译过程中时,沉默将不可避免的被打破。

K6F
K6F
翻译于 2013/06/04 17:11
1

第八步: go run test

(xcd ../test
unset GOMAXPROCS
time go run run.go
) || exit $?

run.bash的倒数第二步调用了$GOROOT目录下test文件夹中的编译器和运行时测试。这其中有描述编译器和运行时本身的低层级测试。而子目录 test/bugs 及 test/fixedbugs 中的测试对已知问题和已解决问题进行特别的测试。所有测试的测试驱动器是 $GOROOT/test/run.go,该程序很小,它调用test文件夹中的每个.go 文件。有些 .go 文件在首行上描述了预期的运行结果,例如,程序失败或是放出特定的输出队列。

K6F
K6F
翻译于 2013/06/04 17:25
1

第九步go tool api

echo '# Checking API compatibility.'
go tool api -c $GOROOT/api/go1.txt,$GOROOT/api/go1.1.txt \
    -next $GOROOT/api/next.txt -except $GOROOT/api/except.txt

run.bash的最后一部将调用API工具,API工具的作用是执行 Go 1 约定;导出的符号,常数,函数,变量,类型和方法组成2012年确认的 Go 1 API。Go 1 写在 api/go1.txt 文件,而 Go 1.1 则写在 api/go1.1.txt文件中。另一个额外的文件,api/next.txt 描述了G 1.1自后添加到标准库和运行时中的符号。当 Go 1.2 发布时,这个文件将会成为 Go 1.2 的约定,另一个新的 next.txt 文件也将被创建。这里还有一个小文件,except.txt,它包括 Go 1 约定中被批准的扩展。对文件的增添总是小心翼翼的。

K6F
K6F
翻译于 2013/06/04 17:39
1

补充提示和技巧

你可能发现了,make.bash对于建立没有运行试验的Go很有用,同样,run.bash对于构建和测试Go运行时很有用。 这种区别也可作为有用的样板用在交叉编译Go,和以后如果你用标准库工作时。

赵亮-碧海情天
赵亮-碧海情天
翻译于 2013/06/04 17:03
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(18)

灵魂架构师
灵魂架构师
不要那么纠结,世界上第一把锤子是用石头砸出来的,第二把是用第一把砸出来的!
L
Liigo

引用来自“长工”的评论

这讲的是Go1.0,不知道有没有用1.0来实现后续版本的打算,这就叫自举了。不过我觉得,自举不是必要的;各种Script(Php Python Bash)系统都不是自举的,也没人说不成熟。 C# Java C++也没听说是自举的,也没人说不成熟。

瞎说。Java SDK带的编译器就是Java开发的,C++的编译器g++/clang等都是C/C++开发的,这不是自举吗?
L
Liigo
Go语言编译器都是用C开发的,这也叫“使用Go编译自身”?所谓“自举”,是指Go的编译器是用Go语言编写的,然后用该编译器编译所有Go源代码。Go还没有做到自举。
O油菜
O油菜

引用来自“长工”的评论

这讲的是Go1.0,不知道有没有用1.0来实现后续版本的打算,这就叫自举了。不过我觉得,自举不是必要的;各种Script(Php Python Bash)系统都不是自举的,也没人说不成熟。 C# Java C++也没听说是自举的,也没人说不成熟。

这是我这一天看到最令人开心的事。。
刀哥
刀哥

引用来自“MtrS”的评论

引用来自“刀哥”的评论

还真有人在用Plan 9?

plan9port是linux及类Unix下的一个 移植 的应用程序 ,plan9 也产生了一个branch----> 9front

plan9不是一个操作系统么?
MtrS
MtrS

引用来自“刀哥”的评论

还真有人在用Plan 9?

plan9port是linux及类Unix下的一个 移植 的应用程序 ,plan9 也产生了一个branch----> 9front
刀哥
刀哥
还真有人在用Plan 9?
赵云30
赵云30
这讲的是Go1.0,不知道有没有用1.0来实现后续版本的打算,这就叫自举了。不过我觉得,自举不是必要的;各种Script(Php Python Bash)系统都不是自举的,也没人说不成熟。 C# Java C++也没听说是自举的,也没人说不成熟。
litqqs
litqqs

引用来自“阿尔法兽”的评论

一只鸡成熟的标志就是能下蛋,一门语言成熟的标志就是能自举

公鸡表示压力比较大!!1
devink
devink
@阿尔法兽 不是不能,而是为了吸引对go不熟悉的人参与go的开发
返回顶部
顶部