从源码构建Golang的完整指南
从源码构建Golang的完整指南 我一直在进行一个涉及Go语言垃圾回收机制的研究项目。我们已经成功从源代码构建了Go。现在,我们正尝试对源代码进行微小的修改,并观察构建是否成功。作为开始,我们在mgc.go文件的gcinit函数的最开头添加了一条日志打印语句。
func gcinit() {
log.Print("In Function GCINT ")
}
添加日志打印后,构建失败并出现以下错误:
In Function GCINIT
In Function GCINIT shift.go:12:6: (i8 + 1) (8 bits) too small for shift of 8
FAIL
FAIL cmd/vet 9.460s
FAIL
go tool dist: Failed: exit status 1
我们也尝试过使用fmt.printf,但到目前为止都没有成功。如果有人能提供帮助,我们将非常感激。
更多关于从源码构建Golang的完整指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你好,我尝试使用debuglog,但还是失败了。
更多关于从源码构建Golang的完整指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
你能详细说明一下复现步骤吗?我也想从源代码构建它……看起来很有意思
谢谢。我会根据您的建议尝试使用它。如果有效,我会告诉您。
如果你找到了这个场景的解决方案,请告诉我。我确实被这个问题困住了。
你说得对,问题确实如此。我们只在 gcinit 函数中添加了一行代码,这就导致了失败。如果我们移除这行代码,构建就能正常进行。
抱歉回复晚了。恐怕我已经没有其他想法了。使用 debuglog 只是我查看源码时的一个快速想法。也许有从源码构建 Go 经验的人能提供进一步的帮助。
你好 @christophberger,感谢你的建议。它仍然失败,并显示以下信息:
--- FAIL: TestVet/rangeloop (0.46s)
vet_test.go:146: error check failed:
Unmatched Errors:
这些错误似乎来自于对 vet 命令的源代码运行 go test。
我看不出你修改的 mgc.go 与属于 vet 命令单元测试的文件 shift.go 和 vet_test.go 之间有任何联系。
我的理解是否正确:如果你在 runtime/mgc.go 的 func gcinit() 中添加一个对内置函数 println() 的调用,rangeloop 测试就会可复现地失败?
其他所有代码都是原始未修改的吗?
目前我只能确定,任何向标准输出(可能也包括标准错误)写入数据的函数都会导致多个测试失败。
我不得不进行推测,但文件 debuglog.go(位于 src/runtime 目录下)看起来很有意思。它提供了一个内存中的调试器。当应用程序发生恐慌时,日志输出会被写入标准输出。
从文件的注释来看,debuglog.go 似乎非常适合记录运行时的内部活动:
dlog 可以用于运行时的各种高度受限的场景:在信号处理程序中使用是安全的,可以在写屏障内部使用,可以在栈实现内部使用,也可以在必须递归 nosplit 的地方使用。
我出于好奇,按照从源代码安装 Go - Go 编程语言中的步骤安装了 Go 源代码。
然后我修改了 src/runtime/mgc.go,加入了 println 调用:
func gcinit() {
println("GCINIT")
// rest of gcinit
接着我在 goroot 目录下运行了 ./all.bash。编译成功了。
第一个失败的测试是:
ok regexp/syntax 1.042s
--- FAIL: TestLockRankGenerated (0.15s)
lockrank_test.go:20: exit status 1
--- FAIL: TestSUID (0.11s)
crash_test.go:138: running go build -o /var/folders/_m/dgnkqt8d3j10svk5c06px4vc0000gn/T/go-build2564578370/testsuid.exe
security_test.go:82: building testsuid []: exit status 1
# runtime
../../mgc.go:153:13: newline in string
../../mgc.go:153:13: syntax error: unexpected newline in argument list; possibly missing comma or )
../../mgc.go:154:2: syntax error: unexpected if at end of statement
其他测试以这些方式失败:
--- FAIL: TestTrampoline (1.00s)
link_test.go:690: unexpected output (default):
GCINIT
hello
--- FAIL: TestRuntimeTypeAttrInternal (0.77s)
dwarf_test.go:776: could not parse type address from program output "GCINIT\n4311591584": strconv.ParseUint: parsing "GCINIT\n4311591584": invalid syntax
--- FAIL: TestHello (27.07s)
pack_test.go:221: incorrect output: "GCINIT\nhello world\n", want "hello world\n"
FAIL
看起来首要问题是 print / println 干扰了标准输出。
从错误信息看,问题出在cmd/vet工具的编译阶段,而不是你的日志代码本身。这是因为Go的构建系统在编译标准库和工具链时,会先编译cmd/vet等工具,而mgc.go中的修改影响了这些工具的编译。
关键问题在于log.Print在runtime包的初始化阶段可能不可用。mgc.go属于runtime包,而runtime包在Go启动过程中很早被初始化,此时日志系统可能还未准备好。
以下是两种解决方案:
方案1:使用内部打印函数
使用runtime包内部的打印函数,这些函数在早期初始化阶段可用:
func gcinit() {
print("In Function GCINIT\n")
}
或者使用带时间戳的版本:
func gcinit() {
println("In Function GCINIT")
}
方案2:如果必须使用log包,需要确保正确导入 确保在文件顶部正确导入了log包,并且构建时包含必要的依赖:
package runtime
import "log"
func gcinit() {
log.Print("In Function GCINIT ")
}
但需要注意的是,即使这样可能仍然会失败,因为log包依赖于runtime包本身,可能存在循环依赖问题。
构建命令建议:
使用-a标志强制重新构建所有依赖:
cd /path/to/go/src
./make.bash -a
或者使用dist工具:
cd /path/to/go/src
./all.bash
调试建议: 如果问题仍然存在,可以尝试先构建一个最小的修改来验证构建系统:
func gcinit() {
// 先注释掉log语句,确保基础构建正常
// log.Print("In Function GCINIT ")
// 或者使用绝对安全的内部函数
if false {
print("debug")
}
}
然后逐步添加功能,观察构建何时失败。这有助于确定是代码问题还是构建系统问题。
错误信息中的shift.go:12:6提示可能还有其他文件存在编译问题,建议检查是否有其他未提交的修改影响了编译。

