"cmd/go/internal/modload"
"cmd/go/internal/par"
"cmd/go/internal/search"
- "cmd/go/internal/str"
"cmd/go/internal/trace"
+ "cmd/internal/str"
"cmd/internal/sys"
"golang.org/x/mod/modfile"
CgoFiles []string `json:",omitempty"` // .go source files that import "C"
CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
+ InvalidGoFiles []string `json:",omitempty"` // .go source files with detected problems (parse error, wrong package name, and so on)
IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints
CFiles []string `json:",omitempty"` // .c source files
CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
p.CgoFiles,
// no p.CompiledGoFiles, because they are from GoFiles or generated by us
p.IgnoredGoFiles,
+ // no p.InvalidGoFiles, because they are from GoFiles
p.IgnoredOtherFiles,
p.CFiles,
p.CXXFiles,
// Unexported fields are not part of the public API.
Build *build.Package
Imports []*Package // this package's direct imports
- CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library)
- RawImports []string // this package's original imports as they appear in the text of the program
+ CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library); 1:1 with the end of PackagePublic.Imports
+ RawImports []string // this package's original imports as they appear in the text of the program; 1:1 with the end of PackagePublic.Imports
ForceLibrary bool // this package is a library (even if named "main")
CmdlineFiles bool // package built from files listed on command line
CmdlinePkg bool // package listed on command line
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
+ p.InvalidGoFiles = pp.InvalidGoFiles
p.IgnoredOtherFiles = pp.IgnoredOtherFiles
p.CFiles = pp.CFiles
p.CXXFiles = pp.CXXFiles
buildMode = build.ImportComment
}
data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
- if data.p.Root == "" && cfg.ModulesEnabled {
+ if cfg.ModulesEnabled {
+ // Override data.p.Root, since ImportDir sets it to $GOPATH, if
+ // the module is inside $GOPATH/src.
if info := modload.PackageModuleInfo(ctx, path); info != nil {
data.p.Root = info.Dir
}
}
}
- // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
- // except for certain packages, to avoid circular dependencies.
- if p.UsesCgo() {
- addImport("unsafe", true)
- }
- if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
- addImport("runtime/cgo", true)
- }
- if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
- addImport("syscall", true)
- }
-
- // SWIG adds imports of some standard packages.
- if p.UsesSwig() {
- addImport("unsafe", true)
- if cfg.BuildContext.Compiler != "gccgo" {
+ if !opts.IgnoreImports {
+ // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall",
+ // except for certain packages, to avoid circular dependencies.
+ if p.UsesCgo() {
+ addImport("unsafe", true)
+ }
+ if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
addImport("runtime/cgo", true)
}
- addImport("syscall", true)
- addImport("sync", true)
+ if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
+ addImport("syscall", true)
+ }
- // TODO: The .swig and .swigcxx files can use
- // %go_import directives to import other packages.
- }
+ // SWIG adds imports of some standard packages.
+ if p.UsesSwig() {
+ addImport("unsafe", true)
+ if cfg.BuildContext.Compiler != "gccgo" {
+ addImport("runtime/cgo", true)
+ }
+ addImport("syscall", true)
+ addImport("sync", true)
+
+ // TODO: The .swig and .swigcxx files can use
+ // %go_import directives to import other packages.
+ }
- // The linker loads implicit dependencies.
- if p.Name == "main" && !p.Internal.ForceLibrary {
- for _, dep := range LinkerDeps(p) {
- addImport(dep, false)
+ // The linker loads implicit dependencies.
+ if p.Name == "main" && !p.Internal.ForceLibrary {
+ for _, dep := range LinkerDeps(p) {
+ addImport(dep, false)
+ }
}
}
// PackageOpts control the behavior of PackagesAndErrors and other package
// loading functions.
type PackageOpts struct {
- // IgnoreImports controls whether we ignore imports when loading packages.
+ // IgnoreImports controls whether we ignore explicit and implicit imports
+ // when loading packages. Implicit imports are added when supporting Cgo
+ // or SWIG and when linking main packages.
IgnoreImports bool
// ModResolveTests indicates whether calls to the module loader should also
}
if opts.MainOnly {
- pkgs = mainPackagesOnly(pkgs, patterns)
+ pkgs = mainPackagesOnly(pkgs, matches)
}
// Now that CmdlinePkg is set correctly,
// mainPackagesOnly filters out non-main packages matched only by arguments
// containing "..." and returns the remaining main packages.
//
+// Packages with missing, invalid, or ambiguous names may be treated as
+// possibly-main packages.
+//
// mainPackagesOnly sets a non-main package's Error field and returns it if it
// is named by a literal argument.
//
// mainPackagesOnly prints warnings for non-literal arguments that only match
// non-main packages.
-func mainPackagesOnly(pkgs []*Package, patterns []string) []*Package {
- matchers := make([]func(string) bool, len(patterns))
- for i, p := range patterns {
- if strings.Contains(p, "...") {
- matchers[i] = search.MatchPattern(p)
+func mainPackagesOnly(pkgs []*Package, matches []*search.Match) []*Package {
+ treatAsMain := map[string]bool{}
+ for _, m := range matches {
+ if m.IsLiteral() {
+ for _, path := range m.Pkgs {
+ treatAsMain[path] = true
+ }
}
}
- matchedPkgs := make([]*Package, 0, len(pkgs))
- mainCount := make([]int, len(patterns))
- nonMainCount := make([]int, len(patterns))
+ var mains []*Package
for _, pkg := range pkgs {
- if pkg.Name == "main" || (pkg.Incomplete && pkg.Name == "") {
- matchedPkgs = append(matchedPkgs, pkg)
- for i := range patterns {
- if matchers[i] != nil && matchers[i](pkg.ImportPath) {
- mainCount[i]++
- }
- }
- } else {
- for i := range patterns {
- if matchers[i] == nil && patterns[i] == pkg.ImportPath {
- if pkg.Error == nil {
- pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
- }
- matchedPkgs = append(matchedPkgs, pkg)
- } else if matchers[i] != nil && matchers[i](pkg.ImportPath) {
- nonMainCount[i]++
- }
+ if pkg.Name == "main" {
+ treatAsMain[pkg.ImportPath] = true
+ mains = append(mains, pkg)
+ continue
+ }
+
+ if len(pkg.InvalidGoFiles) > 0 { // TODO(#45999): && pkg.Name == "", but currently go/build sets pkg.Name arbitrarily if it is ambiguous.
+ // The package has (or may have) conflicting names, and we can't easily
+ // tell whether one of them is "main". So assume that it could be, and
+ // report an error for the package.
+ treatAsMain[pkg.ImportPath] = true
+ }
+ if treatAsMain[pkg.ImportPath] {
+ if pkg.Error == nil {
+ pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
}
+ mains = append(mains, pkg)
}
}
- for i, p := range patterns {
- if matchers[i] != nil && mainCount[i] == 0 && nonMainCount[i] > 0 {
- fmt.Fprintf(os.Stderr, "go: warning: %q matched no main packages\n", p)
+
+ for _, m := range matches {
+ if m.IsLiteral() || len(m.Pkgs) == 0 {
+ continue
+ }
+ foundMain := false
+ for _, path := range m.Pkgs {
+ if treatAsMain[path] {
+ foundMain = true
+ break
+ }
+ }
+ if !foundMain {
+ fmt.Fprintf(os.Stderr, "go: warning: %q matched only non-main packages\n", m.Pattern())
}
}
- return matchedPkgs
+ return mains
}
type mainPackageError struct {