summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-08-09 18:44:00 -0400
committerRuss Cox <rsc@golang.org>2013-08-09 18:44:00 -0400
commit14d54a2c70d15573fdc409a0a423b16314c36c8c (patch)
tree02d515047fb82f47688951e53e61fbe01ecdc059 /src
parent3c0d8740d531131488e62870bdbe2357e2d0d432 (diff)
downloadgo-14d54a2c70d15573fdc409a0a423b16314c36c8c.tar.gz
cmd/api: eliminate duplicate package import work
On my Mac, cuts the API checks from 15 seconds to 6 seconds. Also clean up some tag confusion: go run list-of-files ignores tags. R=bradfitz, gri CC=golang-dev https://codereview.appspot.com/12699048
Diffstat (limited to 'src')
-rw-r--r--src/cmd/api/goapi.go58
-rw-r--r--src/cmd/api/run.go4
-rwxr-xr-xsrc/run.bash2
-rw-r--r--src/run.bat2
4 files changed, 60 insertions, 6 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 1b2862801..1138f4db0 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -1,9 +1,9 @@
-// +build api_tool
-
// Copyright 2011 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.
+// +build api_tool
+
// Binary api computes the exported API of a set of Go packages.
package main
@@ -387,6 +387,38 @@ func contains(list []string, s string) bool {
return false
}
+var (
+ pkgCache = map[string]*types.Package{} // map tagKey to package
+ pkgTags = map[string][]string{} // map import dir to list of relevant tags
+)
+
+// tagKey returns the tag-based key to use in the pkgCache.
+// It is a comma-separated string; the first part is dir, the rest tags.
+// The satisfied tags are derived from context but only those that
+// matter (the ones listed in the tags argument) are used.
+// The tags list, which came from go/build's Package.AllTags,
+// is known to be sorted.
+func tagKey(dir string, context *build.Context, tags []string) string {
+ ctags := map[string]bool{
+ context.GOOS: true,
+ context.GOARCH: true,
+ }
+ if context.CgoEnabled {
+ ctags["cgo"] = true
+ }
+ for _, tag := range context.BuildTags {
+ ctags[tag] = true
+ }
+ // TODO: ReleaseTags (need to load default)
+ key := dir
+ for _, tag := range tags {
+ if ctags[tag] {
+ key += "," + tag
+ }
+ }
+ return key
+}
+
// Importing is a sentinel taking the place in Walker.imported
// for a package that is in the process of being imported.
var importing types.Package
@@ -411,6 +443,19 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
if context == nil {
context = &build.Default
}
+
+ // Look in cache.
+ // If we've already done an import with the same set
+ // of relevant tags, reuse the result.
+ var key string
+ if tags, ok := pkgTags[dir]; ok {
+ key = tagKey(dir, context, tags)
+ if pkg := pkgCache[key]; pkg != nil {
+ w.imported[name] = pkg
+ return pkg
+ }
+ }
+
info, err := context.ImportDir(dir, 0)
if err != nil {
if _, nogo := err.(*build.NoGoError); nogo {
@@ -418,6 +463,13 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
}
log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
}
+
+ // Save tags list first time we see a directory.
+ if _, ok := pkgTags[dir]; !ok {
+ pkgTags[dir] = info.AllTags
+ key = tagKey(dir, context, info.AllTags)
+ }
+
filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...)
// Certain files only exist when building for the specified context.
@@ -463,6 +515,8 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
log.Fatalf("error typechecking package %s: %s (%s)", name, err, ctxt)
}
+ pkgCache[key] = pkg
+
w.imported[name] = pkg
return
}
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index 6e89bb734..520c56fd5 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -1,9 +1,9 @@
-// +build from_src_run
-
// Copyright 2013 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.
+// +build ignore
+
// The run program is invoked via "go run" from src/run.bash or
// src/run.bat conditionally builds and runs the cmd/api tool.
//
diff --git a/src/run.bash b/src/run.bash
index 178290327..258a4d2f9 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -182,7 +182,7 @@ time go run run.go || exit 1
echo
echo '# Checking API compatibility.'
-go run --tags=from_src_run $GOROOT/src/cmd/api/run.go
+time go run $GOROOT/src/cmd/api/run.go
echo
echo ALL TESTS PASSED
diff --git a/src/run.bat b/src/run.bat
index 36f594bb8..bf038d1a7 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -121,7 +121,7 @@ set GOMAXPROCS=%OLDGOMAXPROCS%
set OLDGOMAXPROCS=
echo # Checking API compatibility.
-go run --tags=from_src_run "%GOROOT%\src\cmd\api\run.go"
+go run "%GOROOT%\src\cmd\api\run.go"
if errorlevel 1 goto fail
echo.