summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/go/pkg.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/go/pkg.go')
-rw-r--r--libgo/go/cmd/go/pkg.go179
1 files changed, 122 insertions, 57 deletions
diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go
index 3270a8b5236..73ea2066561 100644
--- a/libgo/go/cmd/go/pkg.go
+++ b/libgo/go/cmd/go/pkg.go
@@ -118,7 +118,7 @@ func (p *Package) vendored(imports []string) []string {
seen := make(map[string]bool)
var all []string
for _, path := range imports {
- path, _ = vendoredImportPath(p, path)
+ path = vendoredImportPath(p, path)
if !seen[path] {
seen[path] = true
all = append(all, path)
@@ -156,7 +156,7 @@ func (p *Package) copyBuild(pp *build.Package) {
if buildContext.Compiler == "gccgo" {
p.Standard = stdpkg[p.ImportPath]
} else {
- p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
+ p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
}
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
@@ -181,6 +181,19 @@ func (p *Package) copyBuild(pp *build.Package) {
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
@@ -254,11 +267,14 @@ func reloadPackage(arg string, stk *importStack) *Package {
return loadPackage(arg, stk)
}
-// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1.
+// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1.
+// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0.
+// In Go 1.7 the variable will stop having any effect.
// The variable is obnoxiously long so that years from now when people find it in
// their profiles and wonder what it does, there is some chance that a web search
// might answer the question.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"
+// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away.
+var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0"
// dirToImportPath returns the pseudo-import path we use for a package
// outside the Go path. It begins with _/ and then contains the full path
@@ -314,11 +330,14 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
importPath := path
origPath := path
isLocal := build.IsLocalImport(path)
- var vendorSearch []string
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
} else if mode&useVendor != 0 {
- path, vendorSearch = vendoredImportPath(parent, path)
+ // 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
}
@@ -345,29 +364,12 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
//
// TODO: After Go 1, decide when to pass build.AllowBinary here.
// See issue 3268 for mistakes to avoid.
- bp, err := buildContext.Import(path, srcDir, build.ImportComment)
-
- // If we got an error from go/build about package not found,
- // it contains the directories from $GOROOT and $GOPATH that
- // were searched. Add to that message the vendor directories
- // that were searched.
- if err != nil && len(vendorSearch) > 0 {
- // NOTE(rsc): The direct text manipulation here is fairly awful,
- // but it avoids defining new go/build API (an exported error type)
- // late in the Go 1.5 release cycle. If this turns out to be a more general
- // problem we could define a real error type when the decision can be
- // considered more carefully.
- text := err.Error()
- if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") {
- old := strings.SplitAfter(text, "\n")
- lines := []string{old[0]}
- for _, dir := range vendorSearch {
- lines = append(lines, "\t"+dir+" (vendor tree)\n")
- }
- lines = append(lines, old[1:]...)
- err = errors.New(strings.Join(lines, ""))
- }
+ buildMode := build.ImportComment
+ if !go15VendorExperiment || 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
@@ -377,7 +379,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
p.load(stk, bp, err)
- if p.Error != nil && len(importPos) > 0 {
+ if p.Error != nil && p.Error.Pos == "" && len(importPos) > 0 {
pos := importPos[0]
pos.Filename = shortPath(pos.Filename)
p.Error.Pos = pos.String()
@@ -411,14 +413,11 @@ func isDir(path string) bool {
// 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 x/y/z if none of those exist.
+// 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.
-// If no expansion is found, vendoredImportPath also returns a list of vendor directories
-// it searched along the way, to help prepare a useful error message should path turn
-// out not to exist.
-func vendoredImportPath(parent *Package, path string) (found string, searched []string) {
+func vendoredImportPath(parent *Package, path string) (found string) {
if parent == nil || parent.Root == "" || !go15VendorExperiment {
- return path, nil
+ return path
}
dir := filepath.Clean(parent.Dir)
root := filepath.Join(parent.Root, "src")
@@ -438,7 +437,7 @@ func vendoredImportPath(parent *Package, path string) (found string, searched []
continue
}
targ := filepath.Join(dir[:i], vpath)
- if isDir(targ) {
+ if isDir(targ) && hasGoFiles(targ) {
// 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
@@ -453,14 +452,26 @@ func vendoredImportPath(parent *Package, path string) (found string, searched []
// 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, nil
+ return vpath
}
- return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil
+ return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath
}
- // Note the existence of a vendor directory in case path is not found anywhere.
- searched = append(searched, targ)
}
- return path, searched
+ 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
@@ -522,7 +533,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
i-- // rewind over slash in ".../internal"
}
parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
- if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+ if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
return p
}
@@ -619,7 +630,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
return p
}
parent := p.Dir[:truncateTo]
- if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+ if hasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
return p
}
@@ -712,6 +723,7 @@ func expandScanner(err error) error {
var raceExclude = map[string]bool{
"runtime/race": true,
+ "runtime/msan": true,
"runtime/cgo": true,
"cmd/cgo": true,
"syscall": true,
@@ -725,6 +737,7 @@ var cgoExclude = map[string]bool{
var cgoSyscallExclude = map[string]bool{
"runtime/cgo": true,
"runtime/race": true,
+ "runtime/msan": true,
}
// load populates p using information from bp, err, which should
@@ -829,27 +842,40 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
importPaths = append(importPaths, "syscall")
}
- // Currently build mode c-shared, or -linkshared, forces
+ // 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" || buildLinkshared) {
+ if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) {
importPaths = append(importPaths, "runtime/cgo")
}
- // Everything depends on runtime, except runtime and unsafe.
- if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
+ // 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)
@@ -931,6 +957,17 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
}
}
+ if p.Standard && !p1.Standard && p.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) {
@@ -1613,15 +1650,24 @@ func packagesAndErrors(args []string) []*Package {
}
args = importPaths(args)
- var pkgs []*Package
- var stk importStack
- var set = make(map[string]bool)
+ var (
+ pkgs []*Package
+ stk importStack
+ seenArg = make(map[string]bool)
+ seenPkg = make(map[*Package]bool)
+ )
for _, arg := range args {
- if !set[arg] {
- pkgs = append(pkgs, loadPackage(arg, &stk))
- set[arg] = true
+ if seenArg[arg] {
+ continue
+ }
+ seenArg[arg] = true
+ pkg := loadPackage(arg, &stk)
+ if seenPkg[pkg] {
+ continue
}
+ seenPkg[pkg] = true
+ pkgs = append(pkgs, pkg)
}
computeStale(pkgs...)
@@ -1792,8 +1838,17 @@ var (
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.
@@ -1808,10 +1863,11 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
}
- // Read the first 16 kB of the binary file.
+ // 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 16 kB.
+ // 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
@@ -1819,7 +1875,6 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
//
// Plan 9: 0x20
// Windows: 0x600
- // Mach-O: 0x2000
//
f, err := os.Open(filename)
if err != nil {
@@ -1827,7 +1882,7 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
}
defer f.Close()
- data := make([]byte, 16*1024)
+ data := make([]byte, BuildIDReadSize)
_, err = io.ReadFull(f, data)
if err == io.ErrUnexpectedEOF {
err = nil
@@ -1839,7 +1894,17 @@ func ReadBuildIDFromBinary(filename string) (id string, err error) {
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.