summaryrefslogtreecommitdiff
path: root/src/cmd/go/pkg.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go/pkg.go')
-rw-r--r--src/cmd/go/pkg.go183
1 files changed, 151 insertions, 32 deletions
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 30bbfad55..7fc61fd86 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -36,12 +36,15 @@ type Package struct {
Root string `json:",omitempty"` // Go root or Go path dir containing this package
// Source files
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
- CFiles []string `json:",omitempty"` // .c source files
- HFiles []string `json:",omitempty"` // .h source files
- SFiles []string `json:",omitempty"` // .s source files
- SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+ 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
+ HFiles []string `json:",omitempty"` // .h source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+ SwigFiles []string `json:",omitempty"` // .swig files
+ SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
@@ -69,12 +72,14 @@ type Package struct {
imports []*Package
deps []*Package
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
target string // installed file for this package (may be executable)
fake bool // synthesized package
forceBuild bool // this package must be rebuilt
forceLibrary bool // this package is a library (even if named "main")
local bool // imported via local path (./ or ../)
localPrefix string // interpret ./ and ../ imports relative to this prefix
+ exeName string // desired name for temporary executable
}
func (p *Package) copyBuild(pp *build.Package) {
@@ -90,10 +95,13 @@ func (p *Package) copyBuild(pp *build.Package) {
p.Standard = p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
+ p.IgnoredGoFiles = pp.IgnoredGoFiles
p.CFiles = pp.CFiles
p.HFiles = pp.HFiles
p.SFiles = pp.SFiles
p.SysoFiles = pp.SysoFiles
+ p.SwigFiles = pp.SwigFiles
+ p.SwigCXXFiles = pp.SwigCXXFiles
p.CgoCFLAGS = pp.CgoCFLAGS
p.CgoLDFLAGS = pp.CgoLDFLAGS
p.CgoPkgConfig = pp.CgoPkgConfig
@@ -117,6 +125,9 @@ func (p *PackageError) Error() string {
// 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
}
@@ -246,7 +257,7 @@ func reusePackage(p *Package, stk *importStack) *Package {
if p.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
- Err: "import loop",
+ Err: "import cycle not allowed",
}
}
p.Incomplete = true
@@ -260,13 +271,11 @@ func reusePackage(p *Package, stk *importStack) *Package {
// isGoTool is the list of directories for Go programs that are installed in
// $GOROOT/pkg/tool.
var isGoTool = map[string]bool{
- "cmd/api": true,
- "cmd/cgo": true,
- "cmd/fix": true,
- "cmd/vet": true,
- "cmd/yacc": true,
- "exp/gotype": true,
- "exp/ebnflint": true,
+ "cmd/api": true,
+ "cmd/cgo": true,
+ "cmd/fix": true,
+ "cmd/vet": true,
+ "cmd/yacc": true,
}
// expandScanner expands a scanner.List error into all the errors in the list.
@@ -316,11 +325,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
- p.target = filepath.Join(p.build.BinDir, elem)
- if p.Goroot && isGoTool[p.ImportPath] {
+ if p.build.BinDir != "" {
+ p.target = filepath.Join(p.build.BinDir, elem)
+ }
+ if p.Goroot && (isGoTool[p.ImportPath] || strings.HasPrefix(p.ImportPath, "exp/")) {
p.target = filepath.Join(gorootPkg, "tool", full)
}
- if buildContext.GOOS == "windows" {
+ if p.target != "" && buildContext.GOOS == "windows" {
p.target += ".exe"
}
} else if p.local {
@@ -340,6 +351,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// Everything depends on runtime, except runtime and unsafe.
if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
importPaths = append(importPaths, "runtime")
+ // When race detection enabled everything depends on runtime/race.
+ // Exclude runtime/cgo and cmd/cgo to avoid circular dependencies.
+ if buildRace && (!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")) {
+ importPaths = append(importPaths, "runtime/race")
+ }
}
// Build list of full paths to all Go files in the package,
@@ -350,6 +366,38 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
sort.Strings(p.gofiles)
+ 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.HFiles,
+ 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]bool)
@@ -403,11 +451,47 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
p.target = ""
}
-
p.Target = p.target
+
+ // 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
+ }
+ }
+
return p
}
+// usesSwig returns whether the package needs to run SWIG.
+func (p *Package) usesSwig() bool {
+ return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
+}
+
+// swigSoname returns the name of the shared library we create for a
+// SWIG input file.
+func (p *Package) swigSoname(file string) string {
+ return strings.Replace(p.ImportPath, "/", "-", -1) + "-" + strings.Replace(file, ".", "-", -1) + ".so"
+}
+
+// swigDir returns the name of the shared SWIG directory for a
+// package.
+func (p *Package) swigDir(ctxt *build.Context) string {
+ dir := p.build.PkgRoot
+ if ctxt.Compiler == "gccgo" {
+ dir = filepath.Join(dir, "gccgo_"+ctxt.GOOS+"_"+ctxt.GOARCH)
+ } else {
+ dir = filepath.Join(dir, ctxt.GOOS+"_"+ctxt.GOARCH)
+ }
+ return filepath.Join(dir, "swig")
+}
+
// 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 {
@@ -459,7 +543,7 @@ func isStale(p *Package, topRoot map[string]bool) bool {
// distributions of Go packages, although such binaries are
// only useful with the specific version of the toolchain that
// created them.
- if len(p.gofiles) == 0 {
+ if len(p.gofiles) == 0 && !p.usesSwig() {
return false
}
@@ -491,14 +575,19 @@ func isStale(p *Package, topRoot map[string]bool) bool {
// 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.
- if olderThan(buildToolchain.compiler()) {
- return true
- }
- if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
- return true
+ // 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.
+ // Assume code in $GOROOT is up to date, since it may not be writeable.
+ // See issue 4106.
+ if p.Root != goroot {
+ if olderThan(buildToolchain.compiler()) {
+ return true
+ }
+ if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
+ return true
+ }
}
// Have installed copy, probably built using current compilers,
@@ -522,6 +611,21 @@ func isStale(p *Package, topRoot map[string]bool) bool {
}
}
+ for _, src := range stringList(p.SwigFiles, p.SwigCXXFiles) {
+ if olderThan(filepath.Join(p.Dir, src)) {
+ return true
+ }
+ soname := p.swigSoname(src)
+ fi, err := os.Stat(soname)
+ if err != nil {
+ return true
+ }
+ fiSrc, err := os.Stat(src)
+ if err != nil || fiSrc.ModTime().After(fi.ModTime()) {
+ return true
+ }
+ }
+
return false
}
@@ -546,13 +650,24 @@ func loadPackage(arg string, stk *importStack) *Package {
arg = sub
}
}
- if strings.HasPrefix(arg, "cmd/") && !strings.Contains(arg[4:], "/") {
+ if strings.HasPrefix(arg, "cmd/") {
if p := cmdCache[arg]; p != nil {
return p
}
stk.push(arg)
defer stk.pop()
- bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
+
+ if strings.Contains(arg[4:], "/") {
+ p := &Package{
+ Error: &PackageError{
+ ImportStack: stk.copy(),
+ Err: fmt.Sprintf("invalid import path: cmd/... is reserved for Go commands"),
+ },
+ }
+ return p
+ }
+
+ bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
bp.BinDir = gorootBin
@@ -580,7 +695,7 @@ func loadPackage(arg string, stk *importStack) *Package {
// referring to io/ioutil rather than a hypothetical import of
// "./ioutil".
if build.IsLocalImport(arg) {
- bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+ bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
if bp.ImportPath != "" && bp.ImportPath != "." {
arg = bp.ImportPath
}
@@ -621,10 +736,14 @@ func packagesAndErrors(args []string) []*Package {
args = importPaths(args)
var pkgs []*Package
var stk importStack
+ var set = make(map[string]bool)
+
for _, arg := range args {
- pkgs = append(pkgs, loadPackage(arg, &stk))
+ if !set[arg] {
+ pkgs = append(pkgs, loadPackage(arg, &stk))
+ set[arg] = true
+ }
}
-
computeStale(pkgs...)
return pkgs