Vet needs export data for the imports of the package it is analyzing.
Vet does not need export data for the package itself, since vet will
do its own type checking. Assuming that vet is just as good as the compiler
at detecting invalid programs, don't run the compiler unnecessarily.
This especially matters for tests without external test files or for
which the external test files do not import the test-augmented original
package. In that case, the test-augmented original package need not
be compiled at all.
Cuts time for 'go clean -cache && go vet -x cmd/compile/internal/ssa'
from 7.6r 24.3u 2.8s to 3.5r 8.5u 1.9s, by not running the compiler
on the augmented test package.
There is still more to be done here - if we do need to build a
test-augmented package, we rerun cgo unnecessarily.
But this is a big help.
Cuts time for 'go vet std cmd' by about 30%.
For #31916.
Change-Id: If6136b4d384f1da77aed90b43f1a6b95f09b5d86
Reviewed-on: https://go-review.googlesource.com/c/go/+/176438
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
if strings.Contains(os.Getenv("GODEBUG"), "gocacheverify") {
t.Skip("GODEBUG gocacheverify")
}
- if cfg.Getenv("GOCACHE") == "off" {
- tooSlow(t)
+ if testing.Short() {
+ // In short mode, reuse cache.
+ // Test failures may be masked if the cache has just the right entries already
+ // (not a concern during all.bash, which runs in a clean cache).
+ if cfg.Getenv("GOCACHE") == "off" {
+ tooSlow(t)
+ }
+ } else {
tg.makeTempdir()
tg.setenv("GOCACHE", tg.path("cache"))
}
actionID cache.ActionID // cache ID of action input
buildID string // build ID of action output
- VetxOnly bool // Mode=="vet": only being called to supply info about dependencies
- needVet bool // Mode=="build": need to fill in vet config
- vetCfg *vetConfig // vet config
- output []byte // output redirect buffer (nil means use b.Print)
+ VetxOnly bool // Mode=="vet": only being called to supply info about dependencies
+ needVet bool // Mode=="build": need to fill in vet config
+ needBuild bool // Mode=="build": need to do actual build (can be false if needVet is true)
+ vetCfg *vetConfig // vet config
+ output []byte // output redirect buffer (nil means use b.Print)
// Execution state.
pending int // number of deps yet to complete
ModeBuild BuildMode = iota
ModeInstall
ModeBuggyInstall
+
+ ModeVetOnly = 1 << 8
)
func (b *Builder) Init() {
// depMode is the action (build or install) to use when building dependencies.
// To turn package main into an executable, call b.Link instead.
func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
+ vetOnly := mode&ModeVetOnly != 0
+ mode &^= ModeVetOnly
+
if mode != ModeBuild && (p.Internal.Local || p.Module != nil) && p.Target == "" {
// Imported via local path or using modules. No permanent target.
mode = ModeBuild
return a
})
+ // Find the build action; the cache entry may have been replaced
+ // by the install action during (*Builder).installAction.
+ buildAction := a
+ switch buildAction.Mode {
+ case "build", "built-in package":
+ // ok
+ case "build-install":
+ buildAction = a.Deps[0]
+ default:
+ panic("lost build action: " + buildAction.Mode)
+ }
+ buildAction.needBuild = buildAction.needBuild || !vetOnly
+
// Construct install action.
if mode == ModeInstall || mode == ModeBuggyInstall {
a = b.installAction(a, mode)
func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
// Construct vet action.
a := b.cacheAction("vet", p, func() *Action {
- a1 := b.CompileAction(mode, depMode, p)
+ a1 := b.CompileAction(mode|ModeVetOnly, depMode, p)
// vet expects to be able to import "fmt".
var stk load.ImportStack
return 0
}
- cached := false
- need := bit(needBuild, !b.IsCmdList || b.NeedExport) |
+ cachedBuild := false
+ need := bit(needBuild, !b.IsCmdList && a.needBuild || b.NeedExport) |
bit(needCgoHdr, b.needCgoHdr(a)) |
bit(needVet, a.needVet) |
bit(needCompiledGoFiles, b.NeedCompiledGoFiles)
if b.useCache(a, p, b.buildActionID(a), p.Target) {
// We found the main output in the cache.
// If we don't need any other outputs, we can stop.
+ // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr).
+ // Remember that we might have them in cache
+ // and check again after we create a.Objdir.
+ cachedBuild = true
+ a.output = []byte{} // start saving output in case we miss any cache results
need &^= needBuild
if b.NeedExport {
p.Export = a.built
if need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
need &^= needCompiledGoFiles
}
- // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr).
- // Remember that we might have them in cache
- // and check again after we create a.Objdir.
- cached = true
- a.output = []byte{} // start saving output in case we miss any cache results
}
// Source files might be cached, even if the full action is not
// (e.g., go list -compiled -find).
- if !cached && need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
+ if !cachedBuild && need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
need &^= needCompiledGoFiles
}
}
objdir := a.Objdir
- if cached {
- if need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) {
- need &^= needCgoHdr
- }
+ // Load cached cgo header, but only if we're skipping the main build (cachedBuild==true).
+ if cachedBuild && need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) {
+ need &^= needCgoHdr
+ }
- // Load cached vet config, but only if that's all we have left
- // (need == needVet, not testing just the one bit).
- // If we are going to do a full build anyway,
- // we're going to regenerate the files below anyway.
- if need == needVet && b.loadCachedVet(a) {
- need &^= needVet
- }
- if need == 0 {
- return nil
- }
+ // Load cached vet config, but only if that's all we have left
+ // (need == needVet, not testing just the one bit).
+ // If we are going to do a full build anyway,
+ // we're going to regenerate the files below anyway.
+ if need == needVet && b.loadCachedVet(a) {
+ need &^= needVet
+ }
+ if need == 0 {
+ return nil
}
// make target directory