//
// Usage:
//
-// go list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages]
+// go list [-cgo] [-deps] [-e] [-f format] [-json] [-list] [-test] [build flags] [packages]
//
// List lists the packages named by the import paths, one per line.
//
// Root string // Go root or Go path dir containing this package
// ConflictDir string // this directory shadows Dir in $GOPATH
// BinaryOnly bool // binary-only package: cannot be recompiled from sources
+// ForTest string // package is only for use in named test
+// DepOnly bool // package is only a dependency, not explicitly listed
+// Export string // file containing export data (when using -export)
//
// // Source files
// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
// The -json flag causes the package data to be printed in JSON format
// instead of using the template format.
//
+// The -cgo flag causes list to set CgoFiles not to the original *.go files
+// importing "C" but instead to the translated files generated by the cgo
+// command.
+//
// The -deps flag causes list to iterate over not just the named packages
// but also all their dependencies. It visits them in a depth-first post-order
// traversal, so that a package is listed only after all its dependencies.
+// Packages not explicitly listed on the command line will have the DepOnly
+// field set to true.
//
// The -e flag changes the handling of erroneous packages, those that
// cannot be found or are malformed. By default, the list command
// a non-nil Error field; other information may or may not be missing
// (zeroed).
//
+// The -export flag causes list to set the package's Export field to
+// the name of a file containing up-to-date export information for
+// the given package.
+//
// The -test flag causes list to report not only the named packages
// but also their test binaries (for packages with tests), to convey to
// source code analysis tools exactly how test binaries are constructed.
// package itself). The reported import path of a package recompiled
// for a particular test binary is followed by a space and the name of
// the test binary in brackets, as in "math/rand [math/rand.test]"
-// or "regexp [sort.test]".
+// or "regexp [sort.test]". The ForTest field is also set to the name
+// of the package being tested ("math/rand" or "sort" in the previous
+// examples).
+//
+// The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
+// are all absolute paths.
+//
+// By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
+// (that is, paths relative to Dir, not absolute paths).
+// The extra entries added by the -cgo and -test flags are absolute paths
+// referring to cached copies of generated Go source files.
+// Although they are Go source files, the paths may not end in ".go".
//
// For more about build flags, see 'go help build'.
//
tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo")
}
+func TestGoListCgo(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.tempdir)
+
+ tg.run("list", "-f", `{{join .CgoFiles "\n"}}`, "net")
+ if tg.stdout.String() == "" {
+ t.Skip("net does not use cgo")
+ }
+ if strings.Contains(tg.stdout.String(), tg.tempdir) {
+ t.Fatalf(".CgoFiles without -cgo unexpectedly mentioned cache %s", tg.tempdir)
+ }
+ tg.run("list", "-cgo", "-f", `{{join .CgoFiles "\n"}}`, "net")
+ if !strings.Contains(tg.stdout.String(), tg.tempdir) {
+ t.Fatalf(".CgoFiles with -cgo did not mention cache %s", tg.tempdir)
+ }
+ for _, file := range strings.Split(tg.stdout.String(), "\n") {
+ if file == "" {
+ continue
+ }
+ if _, err := os.Stat(file); err != nil {
+ t.Fatalf("cannot find .CgoFiles result %s: %v", file, err)
+ }
+ }
+}
+
+func TestGoListExport(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOCACHE", tg.tempdir)
+
+ tg.run("list", "-f", "{{.Export}}", "strings")
+ if tg.stdout.String() != "" {
+ t.Fatalf(".Export without -export unexpectedly set")
+ }
+ tg.run("list", "-export", "-f", "{{.Export}}", "strings")
+ file := strings.TrimSpace(tg.stdout.String())
+ if file == "" {
+ t.Fatalf(".Export with -export was empty")
+ }
+ if _, err := os.Stat(file); err != nil {
+ t.Fatalf("cannot find .Export result %s: %v", file, err)
+ }
+}
+
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
tg := testgo(t)
)
var CmdList = &base.Command{
- UsageLine: "list [-deps] [-e] [-f format] [-json] [-test] [build flags] [packages]",
+ UsageLine: "list [-cgo] [-deps] [-e] [-f format] [-json] [-list] [-test] [build flags] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
Root string // Go root or Go path dir containing this package
ConflictDir string // this directory shadows Dir in $GOPATH
BinaryOnly bool // binary-only package: cannot be recompiled from sources
+ ForTest string // package is only for use in named test
+ DepOnly bool // package is only a dependency, not explicitly listed
+ Export string // file containing export data (when using -export)
// Source files
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
The -json flag causes the package data to be printed in JSON format
instead of using the template format.
+The -cgo flag causes list to set CgoFiles not to the original *.go files
+importing "C" but instead to the translated files generated by the cgo
+command.
+
The -deps flag causes list to iterate over not just the named packages
but also all their dependencies. It visits them in a depth-first post-order
traversal, so that a package is listed only after all its dependencies.
+Packages not explicitly listed on the command line will have the DepOnly
+field set to true.
The -e flag changes the handling of erroneous packages, those that
cannot be found or are malformed. By default, the list command
a non-nil Error field; other information may or may not be missing
(zeroed).
+The -export flag causes list to set the package's Export field to
+the name of a file containing up-to-date export information for
+the given package.
+
The -test flag causes list to report not only the named packages
but also their test binaries (for packages with tests), to convey to
source code analysis tools exactly how test binaries are constructed.
package itself). The reported import path of a package recompiled
for a particular test binary is followed by a space and the name of
the test binary in brackets, as in "math/rand [math/rand.test]"
-or "regexp [sort.test]".
+or "regexp [sort.test]". The ForTest field is also set to the name
+of the package being tested ("math/rand" or "sort" in the previous
+examples).
+
+The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
+are all absolute paths.
+
+By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
+(that is, paths relative to Dir, not absolute paths).
+The extra entries added by the -cgo and -test flags are absolute paths
+referring to cached copies of generated Go source files.
+Although they are Go source files, the paths may not end in ".go".
For more about build flags, see 'go help build'.
work.AddBuildFlags(CmdList)
}
+var listCgo = CmdList.Flag.Bool("cgo", false, "")
var listDeps = CmdList.Flag.Bool("deps", false, "")
var listE = CmdList.Flag.Bool("e", false, "")
+var listExport = CmdList.Flag.Bool("export", false, "")
var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
var listJson = CmdList.Flag.Bool("json", false, "")
var listTest = CmdList.Flag.Bool("test", false, "")
pkgs = load.Packages(args)
}
- if *listTest {
- c := cache.Default()
- if c == nil {
+ if cache.Default() == nil {
+ // These flags return file names pointing into the build cache,
+ // so the build cache must exist.
+ if *listCgo {
+ base.Fatalf("go list -cgo requires build cache")
+ }
+ if *listExport {
+ base.Fatalf("go list -export requires build cache")
+ }
+ if *listTest {
base.Fatalf("go list -test requires build cache")
}
+ }
+
+ if *listTest {
+ c := cache.Default()
// Add test binaries to packages to be listed.
for _, p := range pkgs {
if p.Error != nil {
pkgs = load.PackageList(pkgs)
}
- // Estimate whether staleness information is needed,
- // since it's a little bit of work to compute.
+ // Do we need to run a build to gather information?
needStale := *listJson || strings.Contains(*listFmt, ".Stale")
- if needStale {
+ if needStale || *listExport || *listCgo {
var b work.Builder
b.Init()
- b.ComputeStaleOnly = true
+ b.IsCmdList = true
+ b.NeedExport = *listExport
+ b.NeedCgoFiles = *listCgo
a := &work.Action{}
// TODO: Use pkgsFilter?
for _, p := range pkgs {
BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
ForTest string `json:",omitempty"` // package is only for use in named test
DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed
+ Export string `json:",omitempty"` // file containing export data (set by go list -export)
// Stale and StaleReason remain here *only* for the list command.
// They are only initialized in preparation for list execution.
flagCache map[[2]string]bool // a cache of supported compiler flags
Print func(args ...interface{}) (int, error)
- ComputeStaleOnly bool // compute staleness for go list; no actual build
+ IsCmdList bool // running as part of go list; set p.Stale and additional fields below
+ NeedError bool // list needs p.Error
+ NeedExport bool // list needs p.Export
+ NeedCgoFiles bool // list needs p.CgoFiles to cgo-generated files, not originals
objdirSeq int // counter for NewObjdir
pkgSeq int
// already up-to-date, then to avoid a rebuild, report the package
// as up-to-date as well. See "Build IDs" comment above.
// TODO(rsc): Rewrite this code to use a TryCache func on the link action.
- if target != "" && !cfg.BuildA && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" {
+ if target != "" && !cfg.BuildA && !b.NeedExport && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" {
buildID, err := buildid.ReadFile(target)
if err == nil {
id := strings.Split(buildID, buildIDSeparator)
return true
}
- if b.ComputeStaleOnly {
- // Invoked during go list only to compute and record staleness.
+ if b.IsCmdList {
+ // Invoked during go list to compute and record staleness.
if p := a.Package; p != nil && !p.Stale {
p.Stale = true
if cfg.BuildA {
a.output = []byte{}
}
- if b.ComputeStaleOnly {
- return true
- }
-
return false
}
panic("internal error: a.output not set")
}
outputID, _, err := c.Put(a.actionID, r)
+ r.Close()
if err == nil && cfg.BuildX {
b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID))))
}
+ if b.NeedExport {
+ if err != nil {
+ return err
+ }
+ a.Package.Export = c.OutputFile(outputID)
+ }
c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output)
- r.Close()
}
}
// do runs the action graph rooted at root.
func (b *Builder) Do(root *Action) {
- if c := cache.Default(); c != nil && !b.ComputeStaleOnly {
+ if c := cache.Default(); c != nil && !b.IsCmdList {
// If we're doing real work, take time at the end to trim the cache.
defer c.Trim()
}
return h.Sum()
}
-// needCgoHeader reports whether the actions triggered by this one
+// needCgoHdr reports whether the actions triggered by this one
// expect to be able to access the cgo-generated header file.
-func needCgoHeader(a *Action) bool {
+func (b *Builder) needCgoHdr(a *Action) bool {
// If this build triggers a header install, run cgo to get the header.
- if (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
+ if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
for _, t1 := range a.triggers {
if t1.Mode == "install header" {
return true
return false
}
+const (
+ needBuild uint32 = 1 << iota
+ needCgoHdr
+ needVet
+ needCgoFiles
+ needStale
+)
+
// build is the action for building a single package.
// Note that any new influence on this logic must be reported in b.buildActionID above as well.
func (b *Builder) build(a *Action) (err error) {
p := a.Package
+
+ bit := func(x uint32, b bool) uint32 {
+ if b {
+ return x
+ }
+ return 0
+ }
+
cached := false
- needCgo := needCgoHeader(a)
+ need := bit(needBuild, !b.IsCmdList || b.NeedExport) |
+ bit(needCgoHdr, b.needCgoHdr(a)) |
+ bit(needVet, a.needVet) |
+ bit(needCgoFiles, b.NeedCgoFiles && (p.UsesCgo() || p.UsesSwig()))
+
+ // Save p.CgoFiles now, because we may modify it for go list.
+ cgofiles := append([]string{}, p.CgoFiles...)
if !p.BinaryOnly {
if b.useCache(a, p, b.buildActionID(a), p.Target) {
- if b.ComputeStaleOnly || !needCgo && !a.needVet {
- return nil
+ // We found the main output in the cache.
+ // If we don't need any other outputs, we can stop.
+ need &^= needBuild
+ if b.NeedExport {
+ p.Export = a.built
}
+ if need&needCgoFiles != 0 && b.loadCachedCgoFiles(a) {
+ need &^= needCgoFiles
+ }
+ // 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
+ }
+ if need == 0 {
+ return nil
}
defer b.flushOutput(a)
}
if err != nil && err != errPrintedOutput {
err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
}
+ if err != nil && b.IsCmdList && b.NeedError && p.Error == nil {
+ p.Error = &load.PackageError{Err: err.Error()}
+ }
}()
if cfg.BuildN {
// In -n mode, print a banner between packages.
if err == nil {
a.built = a.Package.Target
a.Target = a.Package.Target
+ if b.NeedExport {
+ a.Package.Export = a.Package.Target
+ }
a.buildID = b.fileHash(a.Package.Target)
a.Package.Stale = false
a.Package.StaleReason = "binary-only package"
return nil
}
- if b.ComputeStaleOnly {
- a.Package.Stale = true
- a.Package.StaleReason = "missing or invalid binary-only package"
- return nil
- }
+ a.Package.Stale = true
+ a.Package.StaleReason = "missing or invalid binary-only package"
return fmt.Errorf("missing or invalid binary-only package")
}
}
objdir := a.Objdir
- if cached && (!needCgo || b.loadCachedCgo(a)) && (!a.needVet || b.loadCachedVet(a)) {
- return nil
+ if cached {
+ if 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
+ }
}
// make target directory
}
}
- var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+ var gofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.Package.GoFiles...)
- cgofiles = append(cgofiles, a.Package.CgoFiles...)
cfiles = append(cfiles, a.Package.CFiles...)
sfiles = append(sfiles, a.Package.SFiles...)
cxxfiles = append(cxxfiles, a.Package.CXXFiles...)
}
b.cacheGofiles(a, gofiles)
+ // Running cgo generated the cgo header.
+ need &^= needCgoHdr
+
// Sanity check only, since Package.load already checked as well.
if len(gofiles) == 0 {
return &load.NoGoError{Package: a.Package}
}
// Prepare Go vet config if needed.
- if a.needVet {
+ if need&needVet != 0 {
buildVetConfig(a, gofiles)
+ need &^= needVet
}
- if cached {
- // The cached package file is OK, so we don't need to run the compile.
- // We've only gone this far in order to prepare the vet configuration
- // or cgo header, and now we have.
+ if need&needCgoFiles != 0 {
+ if !b.loadCachedCgoFiles(a) {
+ return fmt.Errorf("failed to cache translated CgoFiles")
+ }
+ need &^= needCgoFiles
+ }
+ if need == 0 {
+ // Nothing left to do.
return nil
}
return err
}
-func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error {
+func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) {
entry, err := c.Get(cache.Subkey(a.actionID, name))
if err != nil {
- return err
+ return "", err
}
out := c.OutputFile(entry.OutputID)
info, err := os.Stat(out)
if err != nil || info.Size() != entry.Size {
- return fmt.Errorf("not in cache")
+ return "", fmt.Errorf("not in cache")
+ }
+ return out, nil
+}
+
+func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error {
+ cached, err := b.findCachedObjdirFile(a, c, name)
+ if err != nil {
+ return err
}
- return b.copyFile(a.Objdir+name, out, 0666, true)
+ return b.copyFile(a.Objdir+name, cached, 0666, true)
}
func (b *Builder) cacheCgoHdr(a *Action) {
b.cacheObjdirFile(a, c, "_cgo_install.h")
}
-func (b *Builder) loadCachedCgo(a *Action) bool {
+func (b *Builder) loadCachedCgoHdr(a *Action) bool {
c := cache.Default()
if c == nil {
return false
return true
}
+func (b *Builder) loadCachedCgoFiles(a *Action) bool {
+ c := cache.Default()
+ if c == nil {
+ return false
+ }
+ list, _, err := c.GetBytes(cache.Subkey(a.actionID, "gofiles"))
+ if err != nil {
+ return false
+ }
+ var files []string
+ for _, name := range strings.Split(string(list), "\n") {
+ if name == "" { // end of list
+ continue
+ }
+ if strings.HasPrefix(name, "./") {
+ continue
+ }
+ file, err := b.findCachedObjdirFile(a, c, name)
+ if err != nil {
+ return false
+ }
+ files = append(files, file)
+ }
+ a.Package.CgoFiles = files
+ return true
+}
+
type vetConfig struct {
Compiler string
Dir string
// link is the action for linking a single command.
// Note that any new influence on this logic must be reported in b.linkActionID above as well.
func (b *Builder) link(a *Action) (err error) {
- if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) {
+ if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
}
func (b *Builder) linkShared(a *Action) (err error) {
- if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) {
+ if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList {
return nil
}
defer b.flushOutput(a)
// We want to hide that awful detail as much as possible, so don't
// advertise it by touching the mtimes (usually the libraries are up
// to date).
- if !a.buggyInstall && !b.ComputeStaleOnly {
+ if !a.buggyInstall && !b.IsCmdList {
now := time.Now()
os.Chtimes(a.Target, now, now)
}
return nil
}
- if b.ComputeStaleOnly {
+
+ // If we're building for go list -export,
+ // never install anything; just keep the cache reference.
+ if b.IsCmdList {
+ a.built = a1.built
return nil
}