mirror of
https://github.com/golang/go
synced 2024-11-23 09:20:05 -07:00
7dea509703
This CL changes the go command to base all its rebuilding decisions on the content of the files being processed and not their file system modification times. It also eliminates the special handling of release toolchains, which were previously considered always up-to-date because modification time order could not be trusted when unpacking a pre-built release. The go command previously tracked "build IDs" as a backup to modification times, to catch changes not reflected in modification times. For example, if you remove one .go file in a package with multiple .go files, there is no modification time remaining in the system that indicates that the installed package is out of date. The old build ID was the hash of a list of file names and a few other factors, expected to change if those factors changed. This CL moves to using this kind of build ID as the only way to detect staleness, making sure that the build ID hash includes all possible factors that need to influence the rebuild decision. One such factor is the compiler flags. As of this CL, if you run go build -gcflags -N cmd/gofmt you will get a gofmt where every package is built with -N, regardless of what may or may not be installed already. Another such factor is the linker flags. As of this CL, if you run go install myprog go install -ldflags=-s myprog the second go install will now correctly build a new myprog with the updated linker flags. (Previously the installed myprog appeared up-to-date, because the ldflags were not included in the build ID.) Because we have more precise information we can also validate whether the target of a "go test -c" operation is already the right binary and therefore can avoid a rebuild. This CL sets us up for having a more general build artifact cache, maybe even a step toward not having a pkg directory with .a files, but this CL does not take that step. For now the result of go install is the same as it ever was; we just do a better job of what needs to be installed. This CL does slow down builds a small amount by reading all the dependent source files in full. (The go command already read the beginning of every dependent source file to discover build tags and imports.) On my MacBook Pro, before this CL all.bash takes 3m58s, while after this CL and a few optimizations stacked above it all.bash takes 4m28s. Given that CL 73850 cut 1m43s off the all.bash time earlier today, we can afford adding 30s back for now. More optimizations are planned that should make the go command more efficient than it was even before this CL. Fixes #15799. Fixes #18369. Fixes #19340. Fixes #21477. Change-Id: I10d7ca0e31ca3f58aabb9b1f11e2e3d9d18f0bc9 Reviewed-on: https://go-review.googlesource.com/73212 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Crawshaw <crawshaw@golang.org>
96 lines
1.9 KiB
Go
96 lines
1.9 KiB
Go
// run -gcflags -l=4
|
|
|
|
// Copyright 2017 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
)
|
|
|
|
var skip int
|
|
var npcs int
|
|
var pcs = make([]uintptr, 32)
|
|
|
|
func f() {
|
|
g()
|
|
}
|
|
|
|
func g() {
|
|
h()
|
|
}
|
|
|
|
func h() {
|
|
npcs = runtime.Callers(skip, pcs)
|
|
}
|
|
|
|
func testCallers(skp int) (frames []string) {
|
|
skip = skp
|
|
f()
|
|
for i := 0; i < npcs; i++ {
|
|
fn := runtime.FuncForPC(pcs[i])
|
|
frames = append(frames, fn.Name())
|
|
if fn.Name() == "main.main" {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func testCallersFrames(skp int) (frames []string) {
|
|
skip = skp
|
|
f()
|
|
callers := pcs[:npcs]
|
|
ci := runtime.CallersFrames(callers)
|
|
for {
|
|
frame, more := ci.Next()
|
|
frames = append(frames, frame.Function)
|
|
if !more || frame.Function == "main.main" {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
var expectedFrames [][]string = [][]string{
|
|
0: {"main.testCallers", "main.main"},
|
|
1: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
|
|
2: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
|
|
3: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
|
|
4: {"main.testCallers", "runtime.skipPleaseUseCallersFrames", "main.main"},
|
|
5: {"main.main"},
|
|
}
|
|
|
|
var allFrames = []string{"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallersFrames", "main.main"}
|
|
|
|
func same(xs, ys []string) bool {
|
|
if len(xs) != len(ys) {
|
|
return false
|
|
}
|
|
for i := range xs {
|
|
if xs[i] != ys[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func main() {
|
|
for i := 0; i <= 5; i++ {
|
|
frames := testCallers(i)
|
|
expected := expectedFrames[i]
|
|
if !same(frames, expected) {
|
|
fmt.Printf("testCallers(%d):\n got %v\n want %v", i, frames, expected)
|
|
}
|
|
|
|
frames = testCallersFrames(i)
|
|
expected = allFrames[i:]
|
|
if !same(frames, expected) {
|
|
fmt.Printf("testCallersFrames(%d):\n got %v\n want %v", i, frames, expected)
|
|
}
|
|
}
|
|
}
|