// 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. package main import ( "bytes" "crypto/sha1" "errors" "fmt" "go/build" "go/scanner" "go/token" "io" "io/ioutil" "os" pathpkg "path" "path/filepath" "runtime" "sort" "strconv" "strings" "unicode" ) // A Package describes a single package found in a directory. type Package struct { // Note: These fields are part of the go command's public API. // See list.go. It is okay to add fields, but not to change or // remove existing ones. Keep in sync with list.go Dir string `json:",omitempty"` // directory containing package sources ImportPath string `json:",omitempty"` // import path of package in dir ImportComment string `json:",omitempty"` // path in import comment on package statement Name string `json:",omitempty"` // package name Doc string `json:",omitempty"` // package documentation string Target string `json:",omitempty"` // install path Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared) Goroot bool `json:",omitempty"` // is this package found in the Go root? Standard bool `json:",omitempty"` // is this package part of the standard Go library? Stale bool `json:",omitempty"` // would 'go install' do anything for this package? StaleReason string `json:",omitempty"` // why is Stale true? Root string `json:",omitempty"` // Go root or Go path dir containing this package ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory BinaryOnly bool `json:",omitempty"` // package cannot be recompiled // Source files GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) CgoFiles []string `json:",omitempty"` // .go sources files that import "C" IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints CFiles []string `json:",omitempty"` // .c source files CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files MFiles []string `json:",omitempty"` // .m source files HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files SFiles []string `json:",omitempty"` // .s source files SwigFiles []string `json:",omitempty"` // .swig files SwigCXXFiles []string `json:",omitempty"` // .swigcxx files SysoFiles []string `json:",omitempty"` // .syso system object files added to package // Cgo directives CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler CgoCPPFLAGS []string `json:",omitempty"` // cgo: flags for C preprocessor CgoCXXFLAGS []string `json:",omitempty"` // cgo: flags for C++ compiler CgoFFLAGS []string `json:",omitempty"` // cgo: flags for Fortran compiler CgoLDFLAGS []string `json:",omitempty"` // cgo: flags for linker CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names // Dependency information Imports []string `json:",omitempty"` // import paths used by this package Deps []string `json:",omitempty"` // all (recursively) imported dependencies // Error information Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies? Error *PackageError `json:",omitempty"` // error loading this package (not dependencies) DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies // Test information TestGoFiles []string `json:",omitempty"` // _test.go files in package TestImports []string `json:",omitempty"` // imports from TestGoFiles XTestGoFiles []string `json:",omitempty"` // _test.go files outside package XTestImports []string `json:",omitempty"` // imports from XTestGoFiles // Unexported fields are not part of the public API. build *build.Package pkgdir string // overrides build.PkgDir imports []*Package deps []*Package gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths sfiles []string allgofiles []string // gofiles + IgnoredGoFiles, absolute paths target string // installed file for this package (may be executable) fake bool // synthesized package external bool // synthesized external test package forceLibrary bool // this package is a library (even if named "main") cmdline bool // defined by files listed on command line local bool // imported via local path (./ or ../) localPrefix string // interpret ./ and ../ imports relative to this prefix exeName string // desired name for temporary executable coverMode string // preprocess Go source files with the coverage tool in this mode coverVars map[string]*CoverVar // variables created by coverage analysis omitDWARF bool // tell linker not to write DWARF information buildID string // expected build ID for generated package gobinSubdir bool // install target would be subdir of GOBIN } // vendored returns the vendor-resolved version of imports, // which should be p.TestImports or p.XTestImports, NOT p.Imports. // The imports in p.TestImports and p.XTestImports are not recursively // loaded during the initial load of p, so they list the imports found in // the source file, but most processing should be over the vendor-resolved // import paths. We do this resolution lazily both to avoid file system work // and because the eventual real load of the test imports (during 'go test') // can produce better error messages if it starts with the original paths. // The initial load of p loads all the non-test imports and rewrites // the vendored paths, so nothing should ever call p.vendored(p.Imports). func (p *Package) vendored(imports []string) []string { if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { panic("internal error: p.vendored(p.Imports) called") } seen := make(map[string]bool) var all []string for _, path := range imports { path = vendoredImportPath(p, path) if !seen[path] { seen[path] = true all = append(all, path) } } sort.Strings(all) return all } // CoverVar holds the name of the generated coverage variables targeting the named file. type CoverVar struct { File string // local file name Var string // name of count struct } func (p *Package) copyBuild(pp *build.Package) { p.build = pp if pp.PkgTargetRoot != "" && buildPkgdir != "" { old := pp.PkgTargetRoot pp.PkgRoot = buildPkgdir pp.PkgTargetRoot = buildPkgdir pp.PkgObj = filepath.Join(buildPkgdir, strings.TrimPrefix(pp.PkgObj, old)) } p.Dir = pp.Dir p.ImportPath = pp.ImportPath p.ImportComment = pp.ImportComment p.Name = pp.Name p.Doc = pp.Doc p.Root = pp.Root p.ConflictDir = pp.ConflictDir p.BinaryOnly = pp.BinaryOnly // TODO? Target p.Goroot = pp.Goroot if buildContext.Compiler == "gccgo" { p.Standard = stdpkg[p.ImportPath] } else { p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath) } p.GoFiles = pp.GoFiles p.CgoFiles = pp.CgoFiles p.IgnoredGoFiles = pp.IgnoredGoFiles p.CFiles = pp.CFiles p.CXXFiles = pp.CXXFiles p.MFiles = pp.MFiles p.HFiles = pp.HFiles p.FFiles = pp.FFiles p.SFiles = pp.SFiles p.SwigFiles = pp.SwigFiles p.SwigCXXFiles = pp.SwigCXXFiles p.SysoFiles = pp.SysoFiles p.CgoCFLAGS = pp.CgoCFLAGS p.CgoCPPFLAGS = pp.CgoCPPFLAGS p.CgoCXXFLAGS = pp.CgoCXXFLAGS p.CgoLDFLAGS = pp.CgoLDFLAGS p.CgoPkgConfig = pp.CgoPkgConfig p.Imports = pp.Imports p.TestGoFiles = pp.TestGoFiles p.TestImports = pp.TestImports p.XTestGoFiles = pp.XTestGoFiles p.XTestImports = pp.XTestImports } // isStandardImportPath reports whether $GOROOT/src/path should be considered // part of the standard distribution. For historical reasons we allow people to add // their own code to $GOROOT instead of using $GOPATH, but we assume that // code will start with a domain name (dot in the first element). func isStandardImportPath(path string) bool { i := strings.Index(path, "/") if i < 0 { i = len(path) } elem := path[:i] return !strings.Contains(elem, ".") } // A PackageError describes an error loading information about a package. type PackageError struct { ImportStack []string // shortest path from package named on command line to this one Pos string // position of error Err string // the error itself isImportCycle bool // the error is an import cycle hard bool // whether the error is soft or hard; soft errors are ignored in some places } func (p *PackageError) Error() string { // Import cycles deserve special treatment. if p.isImportCycle { return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports ")) } if p.Pos != "" { // Omit import stack. The full path to the file where the error // is the most important thing. return p.Pos + ": " + p.Err } if len(p.ImportStack) == 0 { return p.Err } return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err } // An importStack is a stack of import paths. type importStack []string func (s *importStack) push(p string) { *s = append(*s, p) } func (s *importStack) pop() { *s = (*s)[0 : len(*s)-1] } func (s *importStack) copy() []string { return append([]string{}, *s...) } // shorterThan reports whether sp is shorter than t. // We use this to record the shortest import sequence // that leads to a particular package. func (sp *importStack) shorterThan(t []string) bool { s := *sp if len(s) != len(t) { return len(s) < len(t) } // If they are the same length, settle ties using string ordering. for i := range s { if s[i] != t[i] { return s[i] < t[i] } } return false // they are equal } // packageCache is a lookup cache for loadPackage, // so that if we look up a package multiple times // we return the same pointer each time. var packageCache = map[string]*Package{} // reloadPackage is like loadPackage but makes sure // not to use the package cache. func reloadPackage(arg string, stk *importStack) *Package { p := packageCache[arg] if p != nil { delete(packageCache, p.Dir) delete(packageCache, p.ImportPath) } return loadPackage(arg, stk) } // dirToImportPath returns the pseudo-import path we use for a package // outside the Go path. It begins with _/ and then contains the full path // to the directory. If the package lives in c:\home\gopher\my\pkg then // the pseudo-import path is _/c_/home/gopher/my/pkg. // Using a pseudo-import path like this makes the ./ imports no longer // a special case, so that all the code to deal with ordinary imports works // automatically. func dirToImportPath(dir string) string { return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir))) } func makeImportValid(r rune) rune { // Should match Go spec, compilers, and ../../go/parser/parser.go:/isValidImport. const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { return '_' } return r } // Mode flags for loadImport and download (in get.go). const ( // useVendor means that loadImport should do vendor expansion // (provided the vendoring experiment is enabled). // That is, useVendor means that the import path came from // a source file and has not been vendor-expanded yet. // Every import path should be loaded initially with useVendor, // and then the expanded version (with the /vendor/ in it) gets // recorded as the canonical import path. At that point, future loads // of that package must not pass useVendor, because // disallowVendor will reject direct use of paths containing /vendor/. useVendor = 1 << iota // getTestDeps is for download (part of "go get") and indicates // that test dependencies should be fetched too. getTestDeps ) // loadImport scans the directory named by path, which must be an import path, // but possibly a local import path (an absolute file system path or one beginning // with ./ or ../). A local relative path is interpreted relative to srcDir. // It returns a *Package describing the package found in that directory. func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package { stk.push(path) defer stk.pop() // Determine canonical identifier for this package. // For a local import the identifier is the pseudo-import path // we create from the full directory to the package. // Otherwise it is the usual import path. // For vendored imports, it is the expanded form. importPath := path origPath := path isLocal := build.IsLocalImport(path) if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) } else if mode&useVendor != 0 { // We do our own vendor resolution, because we want to // find out the key to use in packageCache without the // overhead of repeated calls to buildContext.Import. // The code is also needed in a few other places anyway. path = vendoredImportPath(parent, path) importPath = path } if p := packageCache[importPath]; p != nil { if perr := disallowInternal(srcDir, p, stk); perr != p { return perr } if mode&useVendor != 0 { if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { return perr } } return reusePackage(p, stk) } p := new(Package) p.local = isLocal p.ImportPath = importPath packageCache[importPath] = p // Load package. // Import always returns bp != nil, even if an error occurs, // in order to return partial information. // // TODO: After Go 1, decide when to pass build.AllowBinary here. // See issue 3268 for mistakes to avoid. buildMode := build.ImportComment if mode&useVendor == 0 || path != origPath { // Not vendoring, or we already found the vendored path. buildMode |= build.IgnoreVendor } bp, err := buildContext.Import(path, srcDir, buildMode) bp.ImportPath = importPath if gobin != "" { bp.BinDir = gobin } if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } p.load(stk, bp, err) if p.Error != nil && p.Error.Pos == "" && len(importPos) > 0 { pos := importPos[0] pos.Filename = shortPath(pos.Filename) p.Error.Pos = pos.String() } if perr := disallowInternal(srcDir, p, stk); perr != p { return perr } if mode&useVendor != 0 { if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { return perr } } return p } var isDirCache = map[string]bool{} func isDir(path string) bool { result, ok := isDirCache[path] if ok { return result } fi, err := os.Stat(path) result = err == nil && fi.IsDir() isDirCache[path] = result return result } // vendoredImportPath returns the expansion of path when it appears in parent. // If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, // x/vendor/path, vendor/path, or else stay path if none of those exist. // vendoredImportPath returns the expanded path or, if no expansion is found, the original. func vendoredImportPath(parent *Package, path string) (found string) { if parent == nil || parent.Root == "" { return path } dir := filepath.Clean(parent.Dir) root := filepath.Join(parent.Root, "src") if !hasFilePathPrefix(dir, root) { // Look for symlinks before reporting error. dir = expandPath(dir) root = expandPath(root) } if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator { fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator)) } vpath := "vendor/" + path for i := len(dir); i >= len(root); i-- { if i < len(dir) && dir[i] != filepath.Separator { continue } // Note: checking for the vendor directory before checking // for the vendor/path directory helps us hit the // isDir cache more often. It also helps us prepare a more useful // list of places we looked, to report when an import is not found. if !isDir(filepath.Join(dir[:i], "vendor")) { continue } targ := filepath.Join(dir[:i], vpath) if isDir(targ) && hasGoFiles(targ) { importPath := parent.ImportPath if importPath == "command-line-arguments" { // If parent.ImportPath is 'command-line-arguments'. // set to relative directory to root (also chopped root directory) importPath = dir[len(root)+1:] } // We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy. // We know the import path for parent's dir. // We chopped off some number of path elements and // added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path. // Now we want to know the import path for that directory. // Construct it by chopping the same number of path elements // (actually the same number of bytes) from parent's import path // and then append /vendor/path. chopped := len(dir) - i if chopped == len(importPath)+1 { // We walked up from c:\gopath\src\foo\bar // and found c:\gopath\src\vendor\path. // We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7). // Use "vendor/path" without any prefix. return vpath } return importPath[:len(importPath)-chopped] + "/" + vpath } } return path } // hasGoFiles reports whether dir contains any files with names ending in .go. // For a vendor check we must exclude directories that contain no .go files. // Otherwise it is not possible to vendor just a/b/c and still import the // non-vendored a/b. See golang.org/issue/13832. func hasGoFiles(dir string) bool { fis, _ := ioutil.ReadDir(dir) for _, fi := range fis { if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") { return true } } return false } // reusePackage reuses package p to satisfy the import at the top // of the import stack stk. If this use causes an import loop, // reusePackage updates p's error information to record the loop. func reusePackage(p *Package, stk *importStack) *Package { // We use p.imports==nil to detect a package that // is in the midst of its own loadPackage call // (all the recursion below happens before p.imports gets set). if p.imports == nil { if p.Error == nil { p.Error = &PackageError{ ImportStack: stk.copy(), Err: "import cycle not allowed", isImportCycle: true, } } p.Incomplete = true } // Don't rewrite the import stack in the error if we have an import cycle. // If we do, we'll lose the path that describes the cycle. if p.Error != nil && !p.Error.isImportCycle && stk.shorterThan(p.Error.ImportStack) { p.Error.ImportStack = stk.copy() } return p } // disallowInternal checks that srcDir is allowed to import p. // If the import is allowed, disallowInternal returns the original package p. // If not, it returns a new package containing just an appropriate error. func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { // golang.org/s/go14internal: // An import of a path containing the element “internal” // is disallowed if the importing code is outside the tree // rooted at the parent of the “internal” directory. // There was an error loading the package; stop here. if p.Error != nil { return p } // The stack includes p.ImportPath. // If that's the only thing on the stack, we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. if len(*stk) == 1 { return p } // Check for "internal" element: three cases depending on begin of string and/or end of string. i, ok := findInternal(p.ImportPath) if !ok { return p } // Internal is present. // Map import path back to directory corresponding to parent of internal. if i > 0 { i-- // rewind over slash in ".../internal" } parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)] if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } // Look for symlinks before reporting error. srcDir = expandPath(srcDir) parent = expandPath(parent) if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } // Internal is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ ImportStack: stk.copy(), Err: "use of internal package not allowed", } perr.Incomplete = true return &perr } // findInternal looks for the final "internal" path element in the given import path. // If there isn't one, findInternal returns ok=false. // Otherwise, findInternal returns ok=true and the index of the "internal". func findInternal(path string) (index int, ok bool) { // Three cases, depending on internal at start/end of string or not. // The order matters: we must return the index of the final element, // because the final one produces the most restrictive requirement // on the importer. switch { case strings.HasSuffix(path, "/internal"): return len(path) - len("internal"), true case strings.Contains(path, "/internal/"): return strings.LastIndex(path, "/internal/") + 1, true case path == "internal", strings.HasPrefix(path, "internal/"): return 0, true } return 0, false } // disallowVendor checks that srcDir is allowed to import p as path. // If the import is allowed, disallowVendor returns the original package p. // If not, it returns a new package containing just an appropriate error. func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package { // The stack includes p.ImportPath. // If that's the only thing on the stack, we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. if len(*stk) == 1 { return p } if perr := disallowVendorVisibility(srcDir, p, stk); perr != p { return perr } // Paths like x/vendor/y must be imported as y, never as x/vendor/y. if i, ok := findVendor(path); ok { perr := *p perr.Error = &PackageError{ ImportStack: stk.copy(), Err: "must be imported as " + path[i+len("vendor/"):], } perr.Incomplete = true return &perr } return p } // disallowVendorVisibility checks that srcDir is allowed to import p. // The rules are the same as for /internal/ except that a path ending in /vendor // is not subject to the rules, only subdirectories of vendor. // This allows people to have packages and commands named vendor, // for maximal compatibility with existing source trees. func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package { // The stack includes p.ImportPath. // If that's the only thing on the stack, we started // with a name given on the command line, not an // import. Anything listed on the command line is fine. if len(*stk) == 1 { return p } // Check for "vendor" element. i, ok := findVendor(p.ImportPath) if !ok { return p } // Vendor is present. // Map import path back to directory corresponding to parent of vendor. if i > 0 { i-- // rewind over slash in ".../vendor" } truncateTo := i + len(p.Dir) - len(p.ImportPath) if truncateTo < 0 || len(p.Dir) < truncateTo { return p } parent := p.Dir[:truncateTo] if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } // Look for symlinks before reporting error. srcDir = expandPath(srcDir) parent = expandPath(parent) if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { return p } // Vendor is present, and srcDir is outside parent's tree. Not allowed. perr := *p perr.Error = &PackageError{ ImportStack: stk.copy(), Err: "use of vendored package not allowed", } perr.Incomplete = true return &perr } // findVendor looks for the last non-terminating "vendor" path element in the given import path. // If there isn't one, findVendor returns ok=false. // Otherwise, findVendor returns ok=true and the index of the "vendor". // // Note that terminating "vendor" elements don't count: "x/vendor" is its own package, // not the vendored copy of an import "" (the empty import path). // This will allow people to have packages or commands named vendor. // This may help reduce breakage, or it may just be confusing. We'll see. func findVendor(path string) (index int, ok bool) { // Two cases, depending on internal at start of string or not. // The order matters: we must return the index of the final element, // because the final one is where the effective import path starts. switch { case strings.Contains(path, "/vendor/"): return strings.LastIndex(path, "/vendor/") + 1, true case strings.HasPrefix(path, "vendor/"): return 0, true } return 0, false } type targetDir int const ( toRoot targetDir = iota // to bin dir inside package root (default) toTool // GOROOT/pkg/tool stalePath // the old import path; fail to build ) // goTools is a map of Go program import path to install target directory. var goTools = map[string]targetDir{ "cmd/addr2line": toTool, "cmd/api": toTool, "cmd/asm": toTool, "cmd/compile": toTool, "cmd/cgo": toTool, "cmd/cover": toTool, "cmd/dist": toTool, "cmd/doc": toTool, "cmd/fix": toTool, "cmd/link": toTool, "cmd/newlink": toTool, "cmd/nm": toTool, "cmd/objdump": toTool, "cmd/pack": toTool, "cmd/pprof": toTool, "cmd/trace": toTool, "cmd/vet": toTool, "cmd/yacc": toTool, "code.google.com/p/go.tools/cmd/cover": stalePath, "code.google.com/p/go.tools/cmd/godoc": stalePath, "code.google.com/p/go.tools/cmd/vet": stalePath, } // expandScanner expands a scanner.List error into all the errors in the list. // The default Error method only shows the first error. func expandScanner(err error) error { // Look for parser errors. if err, ok := err.(scanner.ErrorList); ok { // Prepare error with \n before each message. // When printed in something like context: %v // this will put the leading file positions each on // its own line. It will also show all the errors // instead of just the first, as err.Error does. var buf bytes.Buffer for _, e := range err { e.Pos.Filename = shortPath(e.Pos.Filename) buf.WriteString("\n") buf.WriteString(e.Error()) } return errors.New(buf.String()) } return err } var raceExclude = map[string]bool{ "runtime/race": true, "runtime/msan": true, "runtime/cgo": true, "cmd/cgo": true, "syscall": true, "errors": true, } var cgoExclude = map[string]bool{ "runtime/cgo": true, } var cgoSyscallExclude = map[string]bool{ "runtime/cgo": true, "runtime/race": true, "runtime/msan": true, } // load populates p using information from bp, err, which should // be the result of calling build.Context.Import. func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package { p.copyBuild(bp) // The localPrefix is the path we interpret ./ imports relative to. // Synthesized main packages sometimes override this. p.localPrefix = dirToImportPath(p.Dir) if err != nil { p.Incomplete = true err = expandScanner(err) p.Error = &PackageError{ ImportStack: stk.copy(), Err: err.Error(), } return p } useBindir := p.Name == "main" if !p.Standard { switch buildBuildmode { case "c-archive", "c-shared": useBindir = false } } if useBindir { // Report an error when the old code.google.com/p/go.tools paths are used. if goTools[p.ImportPath] == stalePath { newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath) p.Error = &PackageError{Err: e} return p } _, elem := filepath.Split(p.Dir) full := buildContext.GOOS + "_" + buildContext.GOARCH + "/" + elem if buildContext.GOOS != toolGOOS || buildContext.GOARCH != toolGOARCH { // Install cross-compiled binaries to subdirectories of bin. elem = full } if p.build.BinDir != "" { // Install to GOBIN or bin of GOPATH entry. p.target = filepath.Join(p.build.BinDir, elem) if !p.Goroot && strings.Contains(elem, "/") && gobin != "" { // Do not create $GOBIN/goos_goarch/elem. p.target = "" p.gobinSubdir = true } } if goTools[p.ImportPath] == toTool { // This is for 'go tool'. // Override all the usual logic and force it into the tool directory. if buildContext.Compiler == "gccgo" { p.target = filepath.Join(runtime.GCCGOTOOLDIR, elem) } else { p.target = filepath.Join(gorootPkg, "tool", full) } } if p.target != "" && buildContext.GOOS == "windows" { p.target += ".exe" } } else if p.local { // Local import turned into absolute path. // No permanent install target. p.target = "" } else { p.target = p.build.PkgObj if buildLinkshared { shlibnamefile := p.target[:len(p.target)-2] + ".shlibname" shlib, err := ioutil.ReadFile(shlibnamefile) if err == nil { libname := strings.TrimSpace(string(shlib)) if buildContext.Compiler == "gccgo" { p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname) } else { p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname) } } else if !os.IsNotExist(err) { fatalf("unexpected error reading %s: %v", shlibnamefile, err) } } } importPaths := p.Imports // Packages that use cgo import runtime/cgo implicitly. // Packages that use cgo also import syscall implicitly, // to wrap errno. // Exclude certain packages to avoid circular dependencies. if len(p.CgoFiles) > 0 && (!p.Standard || !cgoExclude[p.ImportPath]) { importPaths = append(importPaths, "runtime/cgo") } if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { importPaths = append(importPaths, "syscall") } // Currently build modes c-shared, pie, and -linkshared force // external linking mode, and external linking mode forces an // import of runtime/cgo. if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) { importPaths = append(importPaths, "runtime/cgo") } // Everything depends on runtime, except runtime, its internal // subpackages, and unsafe. if !p.Standard || (p.ImportPath != "runtime" && !strings.HasPrefix(p.ImportPath, "runtime/internal/") && p.ImportPath != "unsafe") { importPaths = append(importPaths, "runtime") // When race detection enabled everything depends on runtime/race. // Exclude certain packages to avoid circular dependencies. if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) { importPaths = append(importPaths, "runtime/race") } // MSan uses runtime/msan. if buildMSan && (!p.Standard || !raceExclude[p.ImportPath]) { importPaths = append(importPaths, "runtime/msan") } // On ARM with GOARM=5, everything depends on math for the link. if p.Name == "main" && goarch == "arm" { importPaths = append(importPaths, "math") } } // Runtime and its internal packages depend on runtime/internal/sys, // so that they pick up the generated zversion.go file. // This can be an issue particularly for runtime/internal/atomic; // see issue 13655. if p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal/")) && p.ImportPath != "runtime/internal/sys" { importPaths = append(importPaths, "runtime/internal/sys") } // Build list of full paths to all Go files in the package, // for use by commands like go fmt. p.gofiles = stringList(p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles) for i := range p.gofiles { p.gofiles[i] = filepath.Join(p.Dir, p.gofiles[i]) } sort.Strings(p.gofiles) p.sfiles = stringList(p.SFiles) for i := range p.sfiles { p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i]) } sort.Strings(p.sfiles) p.allgofiles = stringList(p.IgnoredGoFiles) for i := range p.allgofiles { p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i]) } p.allgofiles = append(p.allgofiles, p.gofiles...) sort.Strings(p.allgofiles) // Check for case-insensitive collision of input files. // To avoid problems on case-insensitive files, we reject any package // where two different input files have equal names under a case-insensitive // comparison. f1, f2 := foldDup(stringList( p.GoFiles, p.CgoFiles, p.IgnoredGoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles, p.TestGoFiles, p.XTestGoFiles, )) if f1 != "" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2), } return p } // Build list of imported packages and full dependency list. imports := make([]*Package, 0, len(p.Imports)) deps := make(map[string]*Package) for i, path := range importPaths { if path == "C" { continue } p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor) if !reqStdPkgSrc && p1.Standard { continue } if p1.Name == "main" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("import %q is a program, not an importable package", path), } pos := p.build.ImportPos[path] if len(pos) > 0 { p.Error.Pos = pos[0].String() } } if p1.local { if !p.local && p.Error == nil { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("local import %q in non-local package", path), } pos := p.build.ImportPos[path] if len(pos) > 0 { p.Error.Pos = pos[0].String() } } } if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("non-standard import %q in standard package %q", path, p.ImportPath), } pos := p.build.ImportPos[path] if len(pos) > 0 { p.Error.Pos = pos[0].String() } } path = p1.ImportPath importPaths[i] = path if i < len(p.Imports) { p.Imports[i] = path } deps[path] = p1 imports = append(imports, p1) for _, dep := range p1.deps { // The same import path could produce an error or not, // depending on what tries to import it. // Prefer to record entries with errors, so we can report them. if deps[dep.ImportPath] == nil || dep.Error != nil { deps[dep.ImportPath] = dep } } if p1.Incomplete { p.Incomplete = true } } p.imports = imports p.Deps = make([]string, 0, len(deps)) for dep := range deps { p.Deps = append(p.Deps, dep) } sort.Strings(p.Deps) for _, dep := range p.Deps { p1 := deps[dep] if p1 == nil { panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath) } p.deps = append(p.deps, p1) if p1.Error != nil { p.DepsErrors = append(p.DepsErrors, p1.Error) } } // unsafe is a fake package. if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { p.target = "" } p.Target = p.target // If cgo is not enabled, ignore cgo supporting sources // just as we ignore go files containing import "C". if !buildContext.CgoEnabled { p.CFiles = nil p.CXXFiles = nil p.MFiles = nil p.SwigFiles = nil p.SwigCXXFiles = nil // Note that SFiles are okay (they go to the Go assembler) // and HFiles are okay (they might be used by the SFiles). // Also Sysofiles are okay (they might not contain object // code; see issue #16050). } // The gc toolchain only permits C source files with cgo. if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")), } return p } // In the absence of errors lower in the dependency tree, // check for case-insensitive collisions of import paths. if len(p.DepsErrors) == 0 { dep1, dep2 := foldDup(p.Deps) if dep1 != "" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2), } return p } } if p.BinaryOnly { // For binary-only package, use build ID from supplied package binary. buildID, err := readBuildID(p) if err == nil { p.buildID = buildID } } else { computeBuildID(p) } return p } // usesSwig reports whether the package needs to run SWIG. func (p *Package) usesSwig() bool { return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0 } // usesCgo reports whether the package needs to run cgo func (p *Package) usesCgo() bool { return len(p.CgoFiles) > 0 } // packageList returns the list of packages in the dag rooted at roots // as visited in a depth-first post-order traversal. func packageList(roots []*Package) []*Package { seen := map[*Package]bool{} all := []*Package{} var walk func(*Package) walk = func(p *Package) { if seen[p] { return } seen[p] = true for _, p1 := range p.imports { walk(p1) } all = append(all, p) } for _, root := range roots { walk(root) } return all } // computeStale computes the Stale flag in the package dag that starts // at the named pkgs (command-line arguments). func computeStale(pkgs ...*Package) { for _, p := range packageList(pkgs) { p.Stale, p.StaleReason = isStale(p) } } // The runtime version string takes one of two forms: // "go1.X[.Y]" for Go releases, and "devel +hash" at tip. // Determine whether we are in a released copy by // inspecting the version. var isGoRelease = strings.HasPrefix(runtime.Version(), "go1") // isStale and computeBuildID // // Theory of Operation // // There is an installed copy of the package (or binary). // Can we reuse the installed copy, or do we need to build a new one? // // We can use the installed copy if it matches what we'd get // by building a new one. The hard part is predicting that without // actually running a build. // // To start, we must know the set of inputs to the build process that can // affect the generated output. At a minimum, that includes the source // files for the package and also any compiled packages imported by those // source files. The *Package has these, and we use them. One might also // argue for including in the input set: the build tags, whether the race // detector is in use, the target operating system and architecture, the // compiler and linker binaries being used, the additional flags being // passed to those, the cgo binary being used, the additional flags cgo // passes to the host C compiler, the host C compiler being used, the set // of host C include files and installed C libraries, and so on. // We include some but not all of this information. // // Once we have decided on a set of inputs, we must next decide how to // tell whether the content of that set has changed since the last build // of p. If there have been no changes, then we assume a new build would // produce the same result and reuse the installed package or binary. // But if there have been changes, then we assume a new build might not // produce the same result, so we rebuild. // // There are two common ways to decide whether the content of the set has // changed: modification times and content hashes. We use a mixture of both. // // The use of modification times (mtimes) was pioneered by make: // assuming that a file's mtime is an accurate record of when that file was last written, // and assuming that the modification time of an installed package or // binary is the time that it was built, if the mtimes of the inputs // predate the mtime of the installed object, then the build of that // object saw those versions of the files, and therefore a rebuild using // those same versions would produce the same object. In contrast, if any // mtime of an input is newer than the mtime of the installed object, a // change has occurred since the build, and the build should be redone. // // Modification times are attractive because the logic is easy to // understand and the file system maintains the mtimes automatically // (less work for us). Unfortunately, there are a variety of ways in // which the mtime approach fails to detect a change and reuses a stale // object file incorrectly. (Making the opposite mistake, rebuilding // unnecessarily, is only a performance problem and not a correctness // problem, so we ignore that one.) // // As a warmup, one problem is that to be perfectly precise, we need to // compare the input mtimes against the time at the beginning of the // build, but the object file time is the time at the end of the build. // If an input file changes after being read but before the object is // written, the next build will see an object newer than the input and // will incorrectly decide that the object is up to date. We make no // attempt to detect or solve this problem. // // Another problem is that due to file system imprecision, an input and // output that are actually ordered in time have the same mtime. // This typically happens on file systems with 1-second (or, worse, // 2-second) mtime granularity and with automated scripts that write an // input and then immediately run a build, or vice versa. If an input and // an output have the same mtime, the conservative behavior is to treat // the output as out-of-date and rebuild. This can cause one or more // spurious rebuilds, but only for 1 second, until the object finally has // an mtime later than the input. // // Another problem is that binary distributions often set the mtime on // all files to the same time. If the distribution includes both inputs // and cached build outputs, the conservative solution to the previous // problem will cause unnecessary rebuilds. Worse, in such a binary // distribution, those rebuilds might not even have permission to update // the cached build output. To avoid these write errors, if an input and // output have the same mtime, we assume the output is up-to-date. // This is the opposite of what the previous problem would have us do, // but binary distributions are more common than instances of the // previous problem. // // A variant of the last problem is that some binary distributions do not // set the mtime on all files to the same time. Instead they let the file // system record mtimes as the distribution is unpacked. If the outputs // are unpacked before the inputs, they'll be older and a build will try // to rebuild them. That rebuild might hit the same write errors as in // the last scenario. We don't make any attempt to solve this, and we // haven't had many reports of it. Perhaps the only time this happens is // when people manually unpack the distribution, and most of the time // that's done as the same user who will be using it, so an initial // rebuild on first use succeeds quietly. // // More generally, people and programs change mtimes on files. The last // few problems were specific examples of this, but it's a general problem. // For example, instead of a binary distribution, copying a home // directory from one directory or machine to another might copy files // but not preserve mtimes. If the inputs are new than the outputs on the // first machine but copied first, they end up older than the outputs on // the second machine. // // Because many other build systems have the same sensitivity to mtimes, // most programs manipulating source code take pains not to break the // mtime assumptions. For example, Git does not set the mtime of files // during a checkout operation, even when checking out an old version of // the code. This decision was made specifically to work well with // mtime-based build systems. // // The killer problem, though, for mtime-based build systems is that the // build only has access to the mtimes of the inputs that still exist. // If it is possible to remove an input without changing any other inputs, // a later build will think the object is up-to-date when it is not. // This happens for Go because a package is made up of all source // files in a directory. If a source file is removed, there is no newer // mtime available recording that fact. The mtime on the directory could // be used, but it also changes when unrelated files are added to or // removed from the directory, so including the directory mtime would // cause unnecessary rebuilds, possibly many. It would also exacerbate // the problems mentioned earlier, since even programs that are careful // to maintain mtimes on files rarely maintain mtimes on directories. // // A variant of the last problem is when the inputs change for other // reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg // into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a. // If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must // rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date. // If Go 1.5 has just been installed, perhaps the compiler will have a // newer mtime; since the compiler is considered an input, that would // trigger a rebuild. But only once, and only the last Go 1.4 build of // mypkg.a happened before Go 1.5 was installed. If a user has the two // versions installed in different locations and flips back and forth, // mtimes alone cannot tell what to do. Changing the toolchain is // changing the set of inputs, without affecting any mtimes. // // To detect the set of inputs changing, we turn away from mtimes and to // an explicit data comparison. Specifically, we build a list of the // inputs to the build, compute its SHA1 hash, and record that as the // ``build ID'' in the generated object. At the next build, we can // recompute the build ID and compare it to the one in the generated // object. If they differ, the list of inputs has changed, so the object // is out of date and must be rebuilt. // // Because this build ID is computed before the build begins, the // comparison does not have the race that mtime comparison does. // // Making the build sensitive to changes in other state is // straightforward: include the state in the build ID hash, and if it // changes, so does the build ID, triggering a rebuild. // // To detect changes in toolchain, we include the toolchain version in // the build ID hash for package runtime, and then we include the build // IDs of all imported packages in the build ID for p. // // It is natural to think about including build tags in the build ID, but // the naive approach of just dumping the tags into the hash would cause // spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag' // produce the same binaries (assuming neverusedtag is never used). // A more precise approach would be to include only tags that have an // effect on the build. But the effect of a tag on the build is to // include or exclude a file from the compilation, and that file list is // already in the build ID hash. So the build ID is already tag-sensitive // in a perfectly precise way. So we do NOT explicitly add build tags to // the build ID hash. // // We do not include as part of the build ID the operating system, // architecture, or whether the race detector is enabled, even though all // three have an effect on the output, because that information is used // to decide the install location. Binaries for linux and binaries for // darwin are written to different directory trees; including that // information in the build ID is unnecessary (although it would be // harmless). // // TODO(rsc): Investigate the cost of putting source file content into // the build ID hash as a replacement for the use of mtimes. Using the // file content would avoid all the mtime problems, but it does require // reading all the source files, something we avoid today (we read the // beginning to find the build tags and the imports, but we stop as soon // as we see the import block is over). If the package is stale, the compiler // is going to read the files anyway. But if the package is up-to-date, the // read is overhead. // // TODO(rsc): Investigate the complexity of making the build more // precise about when individual results are needed. To be fully precise, // there are two results of a compilation: the entire .a file used by the link // and the subpiece used by later compilations (__.PKGDEF only). // If a rebuild is needed but produces the previous __.PKGDEF, then // no more recompilation due to the rebuilt package is needed, only // relinking. To date, there is nothing in the Go command to express this. // // Special Cases // // When the go command makes the wrong build decision and does not // rebuild something it should, users fall back to adding the -a flag. // Any common use of the -a flag should be considered prima facie evidence // that isStale is returning an incorrect false result in some important case. // Bugs reported in the behavior of -a itself should prompt the question // ``Why is -a being used at all? What bug does that indicate?'' // // There is a long history of changes to isStale to try to make -a into a // suitable workaround for bugs in the mtime-based decisions. // It is worth recording that history to inform (and, as much as possible, deter) future changes. // // (1) Before the build IDs were introduced, building with alternate tags // would happily reuse installed objects built without those tags. // For example, "go build -tags netgo myprog.go" would use the installed // copy of package net, even if that copy had been built without netgo. // (The netgo tag controls whether package net uses cgo or pure Go for // functionality such as name resolution.) // Using the installed non-netgo package defeats the purpose. // // Users worked around this with "go build -tags netgo -a myprog.go". // // Build IDs have made that workaround unnecessary: // "go build -tags netgo myprog.go" // cannot use a non-netgo copy of package net. // // (2) Before the build IDs were introduced, building with different toolchains, // especially changing between toolchains, tried to reuse objects stored in // $GOPATH/pkg, resulting in link-time errors about object file mismatches. // // Users worked around this with "go install -a ./...". // // Build IDs have made that workaround unnecessary: // "go install ./..." will rebuild any objects it finds that were built against // a different toolchain. // // (3) The common use of "go install -a ./..." led to reports of problems // when the -a forced the rebuild of the standard library, which for some // users was not writable. Because we didn't understand that the real // problem was the bug -a was working around, we changed -a not to // apply to the standard library. // // (4) The common use of "go build -tags netgo -a myprog.go" broke // when we changed -a not to apply to the standard library, because // if go build doesn't rebuild package net, it uses the non-netgo version. // // Users worked around this with "go build -tags netgo -installsuffix barf myprog.go". // The -installsuffix here is making the go command look for packages // in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH. // Since the former presumably doesn't exist, go build decides to rebuild // everything, including the standard library. Since go build doesn't // install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf, // so repeated invocations continue to work. // // If the use of -a wasn't a red flag, the use of -installsuffix to point to // a non-existent directory in a command that installs nothing should // have been. // // (5) Now that (1) and (2) no longer need -a, we have removed the kludge // introduced in (3): once again, -a means ``rebuild everything,'' not // ``rebuild everything except the standard library.'' Only Go 1.4 had // the restricted meaning. // // In addition to these cases trying to trigger rebuilds, there are // special cases trying NOT to trigger rebuilds. The main one is that for // a variety of reasons (see above), the install process for a Go release // cannot be relied upon to set the mtimes such that the go command will // think the standard library is up to date. So the mtime evidence is // ignored for the standard library if we find ourselves in a release // version of Go. Build ID-based staleness checks still apply to the // standard library, even in release versions. This makes // 'go build -tags netgo' work, among other things. // isStale reports whether package p needs to be rebuilt, // along with the reason why. func isStale(p *Package) (bool, string) { if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { // fake, builtin package return false, "builtin package" } if p.Error != nil { return true, "errors loading package" } if p.Stale { return true, p.StaleReason } // If this is a package with no source code, it cannot be rebuilt. // If the binary is missing, we mark the package stale so that // if a rebuild is needed, that rebuild attempt will produce a useful error. // (Some commands, such as 'go list', do not attempt to rebuild.) if p.BinaryOnly { if p.target == "" { // Fail if a build is attempted. return true, "no source code for package, but no install target" } if _, err := os.Stat(p.target); err != nil { // Fail if a build is attempted. return true, "no source code for package, but cannot access install target: " + err.Error() } return false, "no source code for package" } // If the -a flag is given, rebuild everything. if buildA { return true, "build -a flag in use" } // If there's no install target, we have to rebuild. if p.target == "" { return true, "no install target" } // Package is stale if completely unbuilt. fi, err := os.Stat(p.target) if err != nil { return true, "cannot stat install target" } // Package is stale if the expected build ID differs from the // recorded build ID. This catches changes like a source file // being removed from a package directory. See issue 3895. // It also catches changes in build tags that affect the set of // files being compiled. See issue 9369. // It also catches changes in toolchain, like when flipping between // two versions of Go compiling a single GOPATH. // See issue 8290 and issue 10702. targetBuildID, err := readBuildID(p) if err == nil && targetBuildID != p.buildID { return true, "build ID mismatch" } // Package is stale if a dependency is. for _, p1 := range p.deps { if p1.Stale { return true, "stale dependency" } } // The checks above are content-based staleness. // We assume they are always accurate. // // The checks below are mtime-based staleness. // We hope they are accurate, but we know that they fail in the case of // prebuilt Go installations that don't preserve the build mtimes // (for example, if the pkg/ mtimes are before the src/ mtimes). // See the large comment above isStale for details. // If we are running a release copy of Go and didn't find a content-based // reason to rebuild the standard packages, do not rebuild them. // They may not be writable anyway, but they are certainly not changing. // This makes 'go build' skip the standard packages when // using an official release, even when the mtimes have been changed. // See issue 3036, issue 3149, issue 4106, issue 8290. // (If a change to a release tree must be made by hand, the way to force the // install is to run make.bash, which will remove the old package archives // before rebuilding.) if p.Standard && isGoRelease { return false, "standard package in Go release distribution" } // Time-based staleness. built := fi.ModTime() olderThan := func(file string) bool { fi, err := os.Stat(file) return err != nil || fi.ModTime().After(built) } // Package is stale if a dependency is, or if a dependency is newer. for _, p1 := range p.deps { if p1.target != "" && olderThan(p1.target) { return true, "newer dependency" } } // As a courtesy to developers installing new versions of the compiler // frequently, define that packages are stale if they are // older than the compiler, and commands if they are older than // the linker. This heuristic will not work if the binaries are // back-dated, as some binary distributions may do, but it does handle // a very common case. // See issue 3036. // Exclude $GOROOT, under the assumption that people working on // the compiler may want to control when everything gets rebuilt, // and people updating the Go repository will run make.bash or all.bash // and get a full rebuild anyway. // Excluding $GOROOT used to also fix issue 4106, but that's now // taken care of above (at least when the installed Go is a released version). if p.Root != goroot { if olderThan(buildToolchain.compiler()) { return true, "newer compiler" } if p.build.IsCommand() && olderThan(buildToolchain.linker()) { return true, "newer linker" } } // Note: Until Go 1.5, we had an additional shortcut here. // We built a list of the workspace roots ($GOROOT, each $GOPATH) // containing targets directly named on the command line, // and if p were not in any of those, it would be treated as up-to-date // as long as it is built. The goal was to avoid rebuilding a system-installed // $GOROOT, unless something from $GOROOT were explicitly named // on the command line (like go install math). // That's now handled by the isGoRelease clause above. // The other effect of the shortcut was to isolate different entries in // $GOPATH from each other. This had the unfortunate effect that // if you had (say), GOPATH listing two entries, one for commands // and one for libraries, and you did a 'git pull' in the library one // and then tried 'go install commands/...', it would build the new libraries // during the first build (because they wouldn't have been installed at all) // but then subsequent builds would not rebuild the libraries, even if the // mtimes indicate they are stale, because the different GOPATH entries // were treated differently. This behavior was confusing when using // non-trivial GOPATHs, which were particularly common with some // code management conventions, like the original godep. // Since the $GOROOT case (the original motivation) is handled separately, // we no longer put a barrier between the different $GOPATH entries. // // One implication of this is that if there is a system directory for // non-standard Go packages that is included in $GOPATH, the mtimes // on those compiled packages must be no earlier than the mtimes // on the source files. Since most distributions use the same mtime // for all files in a tree, they will be unaffected. People using plain // tar x to extract system-installed packages will need to adjust mtimes, // but it's better to force them to get the mtimes right than to ignore // the mtimes and thereby do the wrong thing in common use cases. // // So there is no GOPATH vs GOPATH shortcut here anymore. // // If something needs to come back here, we could try writing a dummy // file with a random name to the $GOPATH/pkg directory (and removing it) // to test for write access, and then skip GOPATH roots we don't have write // access to. But hopefully we can just use the mtimes always. srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles) for _, src := range srcs { if olderThan(filepath.Join(p.Dir, src)) { return true, "newer source file" } } return false, "" } // computeBuildID computes the build ID for p, leaving it in p.buildID. // Build ID is a hash of the information we want to detect changes in. // See the long comment in isStale for details. func computeBuildID(p *Package) { h := sha1.New() // Include the list of files compiled as part of the package. // This lets us detect removed files. See issue 3895. inputFiles := stringList( p.GoFiles, p.CgoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles, ) for _, file := range inputFiles { fmt.Fprintf(h, "file %s\n", file) } // Include the content of runtime/internal/sys/zversion.go in the hash // for package runtime. This will give package runtime a // different build ID in each Go release. if p.Standard && p.ImportPath == "runtime/internal/sys" { data, err := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go")) if err != nil { fatalf("go: %s", err) } fmt.Fprintf(h, "zversion %q\n", string(data)) } // Include the build IDs of any dependencies in the hash. // This, combined with the runtime/zversion content, // will cause packages to have different build IDs when // compiled with different Go releases. // This helps the go command know to recompile when // people use the same GOPATH but switch between // different Go releases. See issue 10702. // This is also a better fix for issue 8290. for _, p1 := range p.deps { fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID) } p.buildID = fmt.Sprintf("%x", h.Sum(nil)) } var cwd, _ = os.Getwd() var cmdCache = map[string]*Package{} // loadPackage is like loadImport but is used for command-line arguments, // not for paths found in import statements. In addition to ordinary import paths, // loadPackage accepts pseudo-paths beginning with cmd/ to denote commands // in the Go command directory, as well as paths to those directories. func loadPackage(arg string, stk *importStack) *Package { if build.IsLocalImport(arg) { dir := arg if !filepath.IsAbs(dir) { if abs, err := filepath.Abs(dir); err == nil { // interpret relative to current directory dir = abs } } if sub, ok := hasSubdir(gorootSrc, dir); ok && strings.HasPrefix(sub, "cmd/") && !strings.Contains(sub[4:], "/") { arg = sub } } if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") { if p := cmdCache[arg]; p != nil { return p } stk.push(arg) defer stk.pop() bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0) bp.ImportPath = arg bp.Goroot = true bp.BinDir = gorootBin if gobin != "" { bp.BinDir = gobin } bp.Root = goroot bp.SrcRoot = gorootSrc p := new(Package) cmdCache[arg] = p p.load(stk, bp, err) if p.Error == nil && p.Name != "main" { p.Error = &PackageError{ ImportStack: stk.copy(), Err: fmt.Sprintf("expected package main but found package %s in %s", p.Name, p.Dir), } } return p } // Wasn't a command; must be a package. // If it is a local import path but names a standard package, // we treat it as if the user specified the standard package. // This lets you run go test ./ioutil in package io and be // referring to io/ioutil rather than a hypothetical import of // "./ioutil". if build.IsLocalImport(arg) { bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly) if bp.ImportPath != "" && bp.ImportPath != "." { arg = bp.ImportPath } } return loadImport(arg, cwd, nil, stk, nil, 0) } // packages returns the packages named by the // command line arguments 'args'. If a named package // cannot be loaded at all (for example, if the directory does not exist), // then packages prints an error and does not include that // package in the results. However, if errors occur trying // to load dependencies of a named package, the named // package is still returned, with p.Incomplete = true // and details in p.DepsErrors. func packages(args []string) []*Package { var pkgs []*Package for _, pkg := range packagesAndErrors(args) { if pkg.Error != nil { errorf("can't load package: %s", pkg.Error) continue } pkgs = append(pkgs, pkg) } return pkgs } // packagesAndErrors is like 'packages' but returns a // *Package for every argument, even the ones that // cannot be loaded at all. // The packages that fail to load will have p.Error != nil. func packagesAndErrors(args []string) []*Package { if len(args) > 0 && strings.HasSuffix(args[0], ".go") { return []*Package{goFilesPackage(args)} } args = importPaths(args) var ( pkgs []*Package stk importStack seenArg = make(map[string]bool) seenPkg = make(map[*Package]bool) ) for _, arg := range args { if seenArg[arg] { continue } seenArg[arg] = true pkg := loadPackage(arg, &stk) if seenPkg[pkg] { continue } seenPkg[pkg] = true pkgs = append(pkgs, pkg) } computeStale(pkgs...) return pkgs } // packagesForBuild is like 'packages' but fails if any of // the packages or their dependencies have errors // (cannot be built). func packagesForBuild(args []string) []*Package { pkgs := packagesAndErrors(args) printed := map[*PackageError]bool{} for _, pkg := range pkgs { if pkg.Error != nil { errorf("can't load package: %s", pkg.Error) } for _, err := range pkg.DepsErrors { // Since these are errors in dependencies, // the same error might show up multiple times, // once in each package that depends on it. // Only print each once. if !printed[err] { printed[err] = true errorf("%s", err) } } } exitIfErrors() // Check for duplicate loads of the same package. // That should be impossible, but if it does happen then // we end up trying to build the same package twice, // usually in parallel overwriting the same files, // which doesn't work very well. seen := map[string]bool{} reported := map[string]bool{} for _, pkg := range packageList(pkgs) { if seen[pkg.ImportPath] && !reported[pkg.ImportPath] { reported[pkg.ImportPath] = true errorf("internal error: duplicate loads of %s", pkg.ImportPath) } seen[pkg.ImportPath] = true } exitIfErrors() return pkgs } // hasSubdir reports whether dir is a subdirectory of // (possibly multiple levels below) root. // If so, it sets rel to the path fragment that must be // appended to root to reach dir. func hasSubdir(root, dir string) (rel string, ok bool) { if p, err := filepath.EvalSymlinks(root); err == nil { root = p } if p, err := filepath.EvalSymlinks(dir); err == nil { dir = p } const sep = string(filepath.Separator) root = filepath.Clean(root) if !strings.HasSuffix(root, sep) { root += sep } dir = filepath.Clean(dir) if !strings.HasPrefix(dir, root) { return "", false } return filepath.ToSlash(dir[len(root):]), true } var ( errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain") errBuildIDMalformed = fmt.Errorf("malformed object file") errBuildIDUnknown = fmt.Errorf("lost build ID") ) var ( bangArch = []byte("!") pkgdef = []byte("__.PKGDEF") goobject = []byte("go object ") buildid = []byte("build id ") ) // readBuildID reads the build ID from an archive or binary. // It only supports the gc toolchain. // Other toolchain maintainers should adjust this function. func readBuildID(p *Package) (id string, err error) { if buildToolchain != (gcToolchain{}) { return "", errBuildIDToolchain } // For commands, read build ID directly from binary. if p.Name == "main" { return ReadBuildIDFromBinary(p.Target) } // Otherwise, we expect to have an archive (.a) file, // and we can read the build ID from the Go export data. if !strings.HasSuffix(p.Target, ".a") { return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown} } // Read just enough of the target to fetch the build ID. // The archive is expected to look like: // // ! // __.PKGDEF 0 0 0 644 7955 ` // go object darwin amd64 devel X:none // build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224" // // The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none). // Reading the first 1024 bytes should be plenty. f, err := os.Open(p.Target) if err != nil { return "", err } data := make([]byte, 1024) n, err := io.ReadFull(f, data) f.Close() if err != nil && n == 0 { return "", err } bad := func() (string, error) { return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed} } // Archive header. for i := 0; ; i++ { // returns during i==3 j := bytes.IndexByte(data, '\n') if j < 0 { return bad() } line := data[:j] data = data[j+1:] switch i { case 0: if !bytes.Equal(line, bangArch) { return bad() } case 1: if !bytes.HasPrefix(line, pkgdef) { return bad() } case 2: if !bytes.HasPrefix(line, goobject) { return bad() } case 3: if !bytes.HasPrefix(line, buildid) { // Found the object header, just doesn't have a build id line. // Treat as successful, with empty build id. return "", nil } id, err := strconv.Unquote(string(line[len(buildid):])) if err != nil { return bad() } return id, nil } } } var ( goBuildPrefix = []byte("\xff Go build ID: \"") goBuildEnd = []byte("\"\n \xff") elfPrefix = []byte("\x7fELF") machoPrefixes = [][]byte{ {0xfe, 0xed, 0xfa, 0xce}, {0xfe, 0xed, 0xfa, 0xcf}, {0xce, 0xfa, 0xed, 0xfe}, {0xcf, 0xfa, 0xed, 0xfe}, } ) var BuildIDReadSize = 32 * 1024 // changed for testing // ReadBuildIDFromBinary reads the build ID from a binary. // // ELF binaries store the build ID in a proper PT_NOTE section. // // Other binary formats are not so flexible. For those, the linker // stores the build ID as non-instruction bytes at the very beginning // of the text segment, which should appear near the beginning // of the file. This is clumsy but fairly portable. Custom locations // can be added for other binary types as needed, like we did for ELF. func ReadBuildIDFromBinary(filename string) (id string, err error) { if filename == "" { return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown} } // Read the first 32 kB of the binary file. // That should be enough to find the build ID. // In ELF files, the build ID is in the leading headers, // which are typically less than 4 kB, not to mention 32 kB. // In Mach-O files, there's no limit, so we have to parse the file. // On other systems, we're trying to read enough that // we get the beginning of the text segment in the read. // The offset where the text segment begins in a hello // world compiled for each different object format today: // // Plan 9: 0x20 // Windows: 0x600 // f, err := os.Open(filename) if err != nil { return "", err } defer f.Close() data := make([]byte, BuildIDReadSize) _, err = io.ReadFull(f, data) if err == io.ErrUnexpectedEOF { err = nil } if err != nil { return "", err } if bytes.HasPrefix(data, elfPrefix) { return readELFGoBuildID(filename, f, data) } for _, m := range machoPrefixes { if bytes.HasPrefix(data, m) { return readMachoGoBuildID(filename, f, data) } } return readRawGoBuildID(filename, data) } // readRawGoBuildID finds the raw build ID stored in text segment data. func readRawGoBuildID(filename string, data []byte) (id string, err error) { i := bytes.Index(data, goBuildPrefix) if i < 0 { // Missing. Treat as successful but build ID empty. return "", nil } j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd) if j < 0 { return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} } quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1] id, err = strconv.Unquote(string(quoted)) if err != nil { return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} } return id, nil }