[committed] [RISC-V] Fix false-positive uninitialized variable
[official-gcc.git] / libgo / go / go / build / build.go
blob1e91e6eb08b4ec4d4333e1ccc6e551b4d28b0938
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package build
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "go/ast"
12 "go/build/constraint"
13 "go/doc"
14 "go/token"
15 "internal/buildcfg"
16 exec "internal/execabs"
17 "internal/goroot"
18 "internal/goversion"
19 "io"
20 "io/fs"
21 "io/ioutil"
22 "os"
23 pathpkg "path"
24 "path/filepath"
25 "runtime"
26 "sort"
27 "strconv"
28 "strings"
29 "unicode"
30 "unicode/utf8"
33 // A Context specifies the supporting context for a build.
34 type Context struct {
35 GOARCH string // target architecture
36 GOOS string // target operating system
37 GOROOT string // Go root
38 GOPATH string // Go path
40 // Dir is the caller's working directory, or the empty string to use
41 // the current directory of the running process. In module mode, this is used
42 // to locate the main module.
44 // If Dir is non-empty, directories passed to Import and ImportDir must
45 // be absolute.
46 Dir string
48 CgoEnabled bool // whether cgo files are included
49 UseAllFiles bool // use files regardless of +build lines, file names
50 Compiler string // compiler to assume when computing target paths
52 // The build, tool, and release tags specify build constraints
53 // that should be considered satisfied when processing +build lines.
54 // Clients creating a new context may customize BuildTags, which
55 // defaults to empty, but it is usually an error to customize ToolTags or ReleaseTags.
56 // ToolTags defaults to build tags appropriate to the current Go toolchain configuration.
57 // ReleaseTags defaults to the list of Go releases the current release is compatible with.
58 // BuildTags is not set for the Default build Context.
59 // In addition to the BuildTags, ToolTags, and ReleaseTags, build constraints
60 // consider the values of GOARCH and GOOS as satisfied tags.
61 // The last element in ReleaseTags is assumed to be the current release.
62 BuildTags []string
63 ToolTags []string
64 ReleaseTags []string
66 // The install suffix specifies a suffix to use in the name of the installation
67 // directory. By default it is empty, but custom builds that need to keep
68 // their outputs separate can set InstallSuffix to do so. For example, when
69 // using the race detector, the go command uses InstallSuffix = "race", so
70 // that on a Linux/386 system, packages are written to a directory named
71 // "linux_386_race" instead of the usual "linux_386".
72 InstallSuffix string
74 // By default, Import uses the operating system's file system calls
75 // to read directories and files. To read from other sources,
76 // callers can set the following functions. They all have default
77 // behaviors that use the local file system, so clients need only set
78 // the functions whose behaviors they wish to change.
80 // JoinPath joins the sequence of path fragments into a single path.
81 // If JoinPath is nil, Import uses filepath.Join.
82 JoinPath func(elem ...string) string
84 // SplitPathList splits the path list into a slice of individual paths.
85 // If SplitPathList is nil, Import uses filepath.SplitList.
86 SplitPathList func(list string) []string
88 // IsAbsPath reports whether path is an absolute path.
89 // If IsAbsPath is nil, Import uses filepath.IsAbs.
90 IsAbsPath func(path string) bool
92 // IsDir reports whether the path names a directory.
93 // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
94 IsDir func(path string) bool
96 // HasSubdir reports whether dir is lexically a subdirectory of
97 // root, perhaps multiple levels below. It does not try to check
98 // whether dir exists.
99 // If so, HasSubdir sets rel to a slash-separated path that
100 // can be joined to root to produce a path equivalent to dir.
101 // If HasSubdir is nil, Import uses an implementation built on
102 // filepath.EvalSymlinks.
103 HasSubdir func(root, dir string) (rel string, ok bool)
105 // ReadDir returns a slice of fs.FileInfo, sorted by Name,
106 // describing the content of the named directory.
107 // If ReadDir is nil, Import uses ioutil.ReadDir.
108 ReadDir func(dir string) ([]fs.FileInfo, error)
110 // OpenFile opens a file (not a directory) for reading.
111 // If OpenFile is nil, Import uses os.Open.
112 OpenFile func(path string) (io.ReadCloser, error)
115 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
116 func (ctxt *Context) joinPath(elem ...string) string {
117 if f := ctxt.JoinPath; f != nil {
118 return f(elem...)
120 return filepath.Join(elem...)
123 // splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
124 func (ctxt *Context) splitPathList(s string) []string {
125 if f := ctxt.SplitPathList; f != nil {
126 return f(s)
128 return filepath.SplitList(s)
131 // isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs.
132 func (ctxt *Context) isAbsPath(path string) bool {
133 if f := ctxt.IsAbsPath; f != nil {
134 return f(path)
136 return filepath.IsAbs(path)
139 // isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
140 func (ctxt *Context) isDir(path string) bool {
141 if f := ctxt.IsDir; f != nil {
142 return f(path)
144 fi, err := os.Stat(path)
145 return err == nil && fi.IsDir()
148 // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
149 // the local file system to answer the question.
150 func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
151 if f := ctxt.HasSubdir; f != nil {
152 return f(root, dir)
155 // Try using paths we received.
156 if rel, ok = hasSubdir(root, dir); ok {
157 return
160 // Try expanding symlinks and comparing
161 // expanded against unexpanded and
162 // expanded against expanded.
163 rootSym, _ := filepath.EvalSymlinks(root)
164 dirSym, _ := filepath.EvalSymlinks(dir)
166 if rel, ok = hasSubdir(rootSym, dir); ok {
167 return
169 if rel, ok = hasSubdir(root, dirSym); ok {
170 return
172 return hasSubdir(rootSym, dirSym)
175 // hasSubdir reports if dir is within root by performing lexical analysis only.
176 func hasSubdir(root, dir string) (rel string, ok bool) {
177 const sep = string(filepath.Separator)
178 root = filepath.Clean(root)
179 if !strings.HasSuffix(root, sep) {
180 root += sep
182 dir = filepath.Clean(dir)
183 if !strings.HasPrefix(dir, root) {
184 return "", false
186 return filepath.ToSlash(dir[len(root):]), true
189 // readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
190 func (ctxt *Context) readDir(path string) ([]fs.FileInfo, error) {
191 if f := ctxt.ReadDir; f != nil {
192 return f(path)
194 // TODO: use os.ReadDir
195 return ioutil.ReadDir(path)
198 // openFile calls ctxt.OpenFile (if not nil) or else os.Open.
199 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
200 if fn := ctxt.OpenFile; fn != nil {
201 return fn(path)
204 f, err := os.Open(path)
205 if err != nil {
206 return nil, err // nil interface
208 return f, nil
211 // isFile determines whether path is a file by trying to open it.
212 // It reuses openFile instead of adding another function to the
213 // list in Context.
214 func (ctxt *Context) isFile(path string) bool {
215 f, err := ctxt.openFile(path)
216 if err != nil {
217 return false
219 f.Close()
220 return true
223 // gopath returns the list of Go path directories.
224 func (ctxt *Context) gopath() []string {
225 var all []string
226 for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
227 if p == "" || p == ctxt.GOROOT {
228 // Empty paths are uninteresting.
229 // If the path is the GOROOT, ignore it.
230 // People sometimes set GOPATH=$GOROOT.
231 // Do not get confused by this common mistake.
232 continue
234 if strings.HasPrefix(p, "~") {
235 // Path segments starting with ~ on Unix are almost always
236 // users who have incorrectly quoted ~ while setting GOPATH,
237 // preventing it from expanding to $HOME.
238 // The situation is made more confusing by the fact that
239 // bash allows quoted ~ in $PATH (most shells do not).
240 // Do not get confused by this, and do not try to use the path.
241 // It does not exist, and printing errors about it confuses
242 // those users even more, because they think "sure ~ exists!".
243 // The go command diagnoses this situation and prints a
244 // useful error.
245 // On Windows, ~ is used in short names, such as c:\progra~1
246 // for c:\program files.
247 continue
249 all = append(all, p)
251 return all
254 // SrcDirs returns a list of package source root directories.
255 // It draws from the current Go root and Go path but omits directories
256 // that do not exist.
257 func (ctxt *Context) SrcDirs() []string {
258 var all []string
259 if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
260 dir := ctxt.joinPath(ctxt.GOROOT, "src")
261 if ctxt.isDir(dir) {
262 all = append(all, dir)
265 for _, p := range ctxt.gopath() {
266 dir := ctxt.joinPath(p, "src")
267 if ctxt.isDir(dir) {
268 all = append(all, dir)
271 return all
274 // Default is the default Context for builds.
275 // It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
276 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
277 var Default Context = defaultContext()
279 func defaultGOPATH() string {
280 env := "HOME"
281 if runtime.GOOS == "windows" {
282 env = "USERPROFILE"
283 } else if runtime.GOOS == "plan9" {
284 env = "home"
286 if home := os.Getenv(env); home != "" {
287 def := filepath.Join(home, "go")
288 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
289 // Don't set the default GOPATH to GOROOT,
290 // as that will trigger warnings from the go tool.
291 return ""
293 return def
295 return ""
298 var defaultToolTags, defaultReleaseTags []string
300 func defaultContext() Context {
301 var c Context
303 c.GOARCH = buildcfg.GOARCH
304 c.GOOS = buildcfg.GOOS
305 c.GOROOT = pathpkg.Clean(runtime.GOROOT())
306 c.GOPATH = envOr("GOPATH", defaultGOPATH())
307 c.Compiler = runtime.Compiler
309 // For each experiment that has been enabled in the toolchain, define a
310 // build tag with the same name but prefixed by "goexperiment." which can be
311 // used for compiling alternative files for the experiment. This allows
312 // changes for the experiment, like extra struct fields in the runtime,
313 // without affecting the base non-experiment code at all.
314 for _, exp := range buildcfg.EnabledExperiments() {
315 c.ToolTags = append(c.ToolTags, "goexperiment."+exp)
317 defaultToolTags = append([]string{}, c.ToolTags...) // our own private copy
319 // Each major Go release in the Go 1.x series adds a new
320 // "go1.x" release tag. That is, the go1.x tag is present in
321 // all releases >= Go 1.x. Code that requires Go 1.x or later
322 // should say "+build go1.x", and code that should only be
323 // built before Go 1.x (perhaps it is the stub to use in that
324 // case) should say "+build !go1.x".
325 // The last element in ReleaseTags is the current release.
326 for i := 1; i <= goversion.Version; i++ {
327 c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i))
330 defaultReleaseTags = append([]string{}, c.ReleaseTags...) // our own private copy
332 env := os.Getenv("CGO_ENABLED")
333 // No defaultCGO_ENABLED in gccgo.
334 // if env == "" {
335 // env = defaultCGO_ENABLED
336 // }
337 switch env {
338 case "1":
339 c.CgoEnabled = true
340 case "0":
341 c.CgoEnabled = false
342 default:
343 // cgo must be explicitly enabled for cross compilation builds
344 if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
345 // Always enabled for gccgo.
346 c.CgoEnabled = true
347 break
349 c.CgoEnabled = false
352 return c
355 func envOr(name, def string) string {
356 s := os.Getenv(name)
357 if s == "" {
358 return def
360 return s
363 // An ImportMode controls the behavior of the Import method.
364 type ImportMode uint
366 const (
367 // If FindOnly is set, Import stops after locating the directory
368 // that should contain the sources for a package. It does not
369 // read any files in the directory.
370 FindOnly ImportMode = 1 << iota
372 // If AllowBinary is set, Import can be satisfied by a compiled
373 // package object without corresponding sources.
375 // Deprecated:
376 // The supported way to create a compiled-only package is to
377 // write source code containing a //go:binary-only-package comment at
378 // the top of the file. Such a package will be recognized
379 // regardless of this flag setting (because it has source code)
380 // and will have BinaryOnly set to true in the returned Package.
381 AllowBinary
383 // If ImportComment is set, parse import comments on package statements.
384 // Import returns an error if it finds a comment it cannot understand
385 // or finds conflicting comments in multiple source files.
386 // See golang.org/s/go14customimport for more information.
387 ImportComment
389 // By default, Import searches vendor directories
390 // that apply in the given source directory before searching
391 // the GOROOT and GOPATH roots.
392 // If an Import finds and returns a package using a vendor
393 // directory, the resulting ImportPath is the complete path
394 // to the package, including the path elements leading up
395 // to and including "vendor".
396 // For example, if Import("y", "x/subdir", 0) finds
397 // "x/vendor/y", the returned package's ImportPath is "x/vendor/y",
398 // not plain "y".
399 // See golang.org/s/go15vendor for more information.
401 // Setting IgnoreVendor ignores vendor directories.
403 // In contrast to the package's ImportPath,
404 // the returned package's Imports, TestImports, and XTestImports
405 // are always the exact import paths from the source files:
406 // Import makes no attempt to resolve or check those paths.
407 IgnoreVendor
410 // A Package describes the Go package found in a directory.
411 type Package struct {
412 Dir string // directory containing package sources
413 Name string // package name
414 ImportComment string // path in import comment on package statement
415 Doc string // documentation synopsis
416 ImportPath string // import path of package ("" if unknown)
417 Root string // root of Go tree where this package lives
418 SrcRoot string // package source root directory ("" if unknown)
419 PkgRoot string // package install root directory ("" if unknown)
420 PkgTargetRoot string // architecture dependent install root directory ("" if unknown)
421 BinDir string // command install directory ("" if unknown)
422 Goroot bool // package found in Go root
423 PkgObj string // installed .a file
424 AllTags []string // tags that can influence file selection in this directory
425 ConflictDir string // this directory shadows Dir in $GOPATH
426 BinaryOnly bool // cannot be rebuilt from source (has //go:binary-only-package comment)
428 // Source files
429 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
430 CgoFiles []string // .go source files that import "C"
431 IgnoredGoFiles []string // .go source files ignored for this build (including ignored _test.go files)
432 InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on)
433 IgnoredOtherFiles []string // non-.go source files ignored for this build
434 CFiles []string // .c source files
435 CXXFiles []string // .cc, .cpp and .cxx source files
436 MFiles []string // .m (Objective-C) source files
437 HFiles []string // .h, .hh, .hpp and .hxx source files
438 FFiles []string // .f, .F, .for and .f90 Fortran source files
439 SFiles []string // .s source files
440 SwigFiles []string // .swig files
441 SwigCXXFiles []string // .swigcxx files
442 SysoFiles []string // .syso system object files to add to archive
444 // Cgo directives
445 CgoCFLAGS []string // Cgo CFLAGS directives
446 CgoCPPFLAGS []string // Cgo CPPFLAGS directives
447 CgoCXXFLAGS []string // Cgo CXXFLAGS directives
448 CgoFFLAGS []string // Cgo FFLAGS directives
449 CgoLDFLAGS []string // Cgo LDFLAGS directives
450 CgoPkgConfig []string // Cgo pkg-config directives
452 // Test information
453 TestGoFiles []string // _test.go files in package
454 XTestGoFiles []string // _test.go files outside package
456 // Dependency information
457 Imports []string // import paths from GoFiles, CgoFiles
458 ImportPos map[string][]token.Position // line information for Imports
459 TestImports []string // import paths from TestGoFiles
460 TestImportPos map[string][]token.Position // line information for TestImports
461 XTestImports []string // import paths from XTestGoFiles
462 XTestImportPos map[string][]token.Position // line information for XTestImports
464 // //go:embed patterns found in Go source files
465 // For example, if a source file says
466 // //go:embed a* b.c
467 // then the list will contain those two strings as separate entries.
468 // (See package embed for more details about //go:embed.)
469 EmbedPatterns []string // patterns from GoFiles, CgoFiles
470 EmbedPatternPos map[string][]token.Position // line information for EmbedPatterns
471 TestEmbedPatterns []string // patterns from TestGoFiles
472 TestEmbedPatternPos map[string][]token.Position // line information for TestEmbedPatterns
473 XTestEmbedPatterns []string // patterns from XTestGoFiles
474 XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
477 // IsCommand reports whether the package is considered a
478 // command to be installed (not just a library).
479 // Packages named "main" are treated as commands.
480 func (p *Package) IsCommand() bool {
481 return p.Name == "main"
484 // ImportDir is like Import but processes the Go package found in
485 // the named directory.
486 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
487 return ctxt.Import(".", dir, mode)
490 // NoGoError is the error used by Import to describe a directory
491 // containing no buildable Go source files. (It may still contain
492 // test files, files hidden by build tags, and so on.)
493 type NoGoError struct {
494 Dir string
497 func (e *NoGoError) Error() string {
498 return "no buildable Go source files in " + e.Dir
501 // MultiplePackageError describes a directory containing
502 // multiple buildable Go source files for multiple packages.
503 type MultiplePackageError struct {
504 Dir string // directory containing files
505 Packages []string // package names found
506 Files []string // corresponding files: Files[i] declares package Packages[i]
509 func (e *MultiplePackageError) Error() string {
510 // Error string limited to two entries for compatibility.
511 return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", e.Packages[0], e.Files[0], e.Packages[1], e.Files[1], e.Dir)
514 func nameExt(name string) string {
515 i := strings.LastIndex(name, ".")
516 if i < 0 {
517 return ""
519 return name[i:]
522 // Import returns details about the Go package named by the import path,
523 // interpreting local import paths relative to the srcDir directory.
524 // If the path is a local import path naming a package that can be imported
525 // using a standard import path, the returned package will set p.ImportPath
526 // to that path.
528 // In the directory containing the package, .go, .c, .h, and .s files are
529 // considered part of the package except for:
531 // - .go files in package documentation
532 // - files starting with _ or . (likely editor temporary files)
533 // - files with build constraints not satisfied by the context
535 // If an error occurs, Import returns a non-nil error and a non-nil
536 // *Package containing partial information.
538 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
539 p := &Package{
540 ImportPath: path,
542 if path == "" {
543 return p, fmt.Errorf("import %q: invalid import path", path)
546 var pkgtargetroot string
547 var pkga string
548 var pkgerr error
549 suffix := ""
550 if ctxt.InstallSuffix != "" {
551 suffix = "_" + ctxt.InstallSuffix
553 switch ctxt.Compiler {
554 case "gccgo":
555 pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
556 case "gc":
557 pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
558 default:
559 // Save error for end of function.
560 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
562 setPkga := func() {
563 switch ctxt.Compiler {
564 case "gccgo":
565 dir, elem := pathpkg.Split(p.ImportPath)
566 pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
567 case "gc":
568 pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
571 setPkga()
573 binaryOnly := false
574 if IsLocalImport(path) {
575 pkga = "" // local imports have no installed path
576 if srcDir == "" {
577 return p, fmt.Errorf("import %q: import relative to unknown directory", path)
579 if !ctxt.isAbsPath(path) {
580 p.Dir = ctxt.joinPath(srcDir, path)
582 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
583 // Determine canonical import path, if any.
584 // Exclude results where the import path would include /testdata/.
585 inTestdata := func(sub string) bool {
586 return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
588 if ctxt.GOROOT != "" {
589 root := ctxt.joinPath(ctxt.GOROOT, "src")
590 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
591 p.Goroot = true
592 p.ImportPath = sub
593 p.Root = ctxt.GOROOT
594 setPkga() // p.ImportPath changed
595 goto Found
598 all := ctxt.gopath()
599 for i, root := range all {
600 rootsrc := ctxt.joinPath(root, "src")
601 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
602 // We found a potential import path for dir,
603 // but check that using it wouldn't find something
604 // else first.
605 if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
606 if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
607 p.ConflictDir = dir
608 goto Found
611 for _, earlyRoot := range all[:i] {
612 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
613 p.ConflictDir = dir
614 goto Found
618 // sub would not name some other directory instead of this one.
619 // Record it.
620 p.ImportPath = sub
621 p.Root = root
622 setPkga() // p.ImportPath changed
623 goto Found
626 // It's okay that we didn't find a root containing dir.
627 // Keep going with the information we have.
628 } else {
629 if strings.HasPrefix(path, "/") {
630 return p, fmt.Errorf("import %q: cannot import absolute path", path)
633 if err := ctxt.importGo(p, path, srcDir, mode); err == nil {
634 goto Found
635 } else if err != errNoModules {
636 return p, err
639 gopath := ctxt.gopath() // needed twice below; avoid computing many times
641 // tried records the location of unsuccessful package lookups
642 var tried struct {
643 vendor []string
644 goroot string
645 gopath []string
648 // Vendor directories get first chance to satisfy import.
649 if mode&IgnoreVendor == 0 && srcDir != "" {
650 searchVendor := func(root string, isGoroot bool) bool {
651 sub, ok := ctxt.hasSubdir(root, srcDir)
652 if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
653 return false
655 for {
656 vendor := ctxt.joinPath(root, sub, "vendor")
657 if ctxt.isDir(vendor) {
658 dir := ctxt.joinPath(vendor, path)
659 if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) {
660 p.Dir = dir
661 p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
662 p.Goroot = isGoroot
663 p.Root = root
664 setPkga() // p.ImportPath changed
665 return true
667 tried.vendor = append(tried.vendor, dir)
669 i := strings.LastIndex(sub, "/")
670 if i < 0 {
671 break
673 sub = sub[:i]
675 return false
677 if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) {
678 goto Found
680 for _, root := range gopath {
681 if searchVendor(root, false) {
682 goto Found
687 // Determine directory from import path.
688 if ctxt.GOROOT != "" {
689 // If the package path starts with "vendor/", only search GOROOT before
690 // GOPATH if the importer is also within GOROOT. That way, if the user has
691 // vendored in a package that is subsequently included in the standard
692 // distribution, they'll continue to pick up their own vendored copy.
693 gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
694 if !gorootFirst {
695 _, gorootFirst = ctxt.hasSubdir(ctxt.GOROOT, srcDir)
697 if gorootFirst {
698 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
699 if ctxt.Compiler != "gccgo" {
700 isDir := ctxt.isDir(dir)
701 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
702 if isDir || binaryOnly {
703 p.Dir = dir
704 p.Goroot = true
705 p.Root = ctxt.GOROOT
706 goto Found
709 tried.goroot = dir
712 if ctxt.Compiler == "gccgo" && goroot.IsStandardPackage(ctxt.GOROOT, ctxt.Compiler, path) {
713 p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path)
714 p.Goroot = true
715 p.Root = ctxt.GOROOT
716 goto Found
718 for _, root := range gopath {
719 dir := ctxt.joinPath(root, "src", path)
720 isDir := ctxt.isDir(dir)
721 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
722 if isDir || binaryOnly {
723 p.Dir = dir
724 p.Root = root
725 goto Found
727 tried.gopath = append(tried.gopath, dir)
730 // If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
731 // That way, the user can still get useful results from 'go list' for
732 // standard-vendored paths passed on the command line.
733 if ctxt.GOROOT != "" && tried.goroot == "" {
734 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
735 if ctxt.Compiler != "gccgo" {
736 isDir := ctxt.isDir(dir)
737 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
738 if isDir || binaryOnly {
739 p.Dir = dir
740 p.Goroot = true
741 p.Root = ctxt.GOROOT
742 goto Found
745 tried.goroot = dir
748 // package was not found
749 var paths []string
750 format := "\t%s (vendor tree)"
751 for _, dir := range tried.vendor {
752 paths = append(paths, fmt.Sprintf(format, dir))
753 format = "\t%s"
755 if tried.goroot != "" {
756 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
757 } else {
758 paths = append(paths, "\t($GOROOT not set)")
760 format = "\t%s (from $GOPATH)"
761 for _, dir := range tried.gopath {
762 paths = append(paths, fmt.Sprintf(format, dir))
763 format = "\t%s"
765 if len(tried.gopath) == 0 {
766 paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
768 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
771 Found:
772 if p.Root != "" {
773 p.SrcRoot = ctxt.joinPath(p.Root, "src")
774 p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
775 p.BinDir = ctxt.joinPath(p.Root, "bin")
776 if pkga != "" {
777 p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
778 p.PkgObj = ctxt.joinPath(p.Root, pkga)
782 // If it's a local import path, by the time we get here, we still haven't checked
783 // that p.Dir directory exists. This is the right time to do that check.
784 // We can't do it earlier, because we want to gather partial information for the
785 // non-nil *Package returned when an error occurs.
786 // We need to do this before we return early on FindOnly flag.
787 if IsLocalImport(path) && !ctxt.isDir(p.Dir) {
788 if ctxt.Compiler == "gccgo" && p.Goroot {
789 // gccgo has no sources for GOROOT packages.
790 return p, nil
793 // package was not found
794 return p, fmt.Errorf("cannot find package %q in:\n\t%s", p.ImportPath, p.Dir)
797 if mode&FindOnly != 0 {
798 return p, pkgerr
800 if binaryOnly && (mode&AllowBinary) != 0 {
801 return p, pkgerr
804 if ctxt.Compiler == "gccgo" && p.Goroot {
805 // gccgo has no sources for GOROOT packages.
806 return p, nil
809 dirs, err := ctxt.readDir(p.Dir)
810 if err != nil {
811 return p, err
814 var badGoError error
815 badFiles := make(map[string]bool)
816 badFile := func(name string, err error) {
817 if badGoError == nil {
818 badGoError = err
820 if !badFiles[name] {
821 p.InvalidGoFiles = append(p.InvalidGoFiles, name)
822 badFiles[name] = true
826 var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
827 var firstFile, firstCommentFile string
828 embedPos := make(map[string][]token.Position)
829 testEmbedPos := make(map[string][]token.Position)
830 xTestEmbedPos := make(map[string][]token.Position)
831 importPos := make(map[string][]token.Position)
832 testImportPos := make(map[string][]token.Position)
833 xTestImportPos := make(map[string][]token.Position)
834 allTags := make(map[string]bool)
835 fset := token.NewFileSet()
836 for _, d := range dirs {
837 if d.IsDir() {
838 continue
840 if d.Mode()&fs.ModeSymlink != 0 {
841 if ctxt.isDir(ctxt.joinPath(p.Dir, d.Name())) {
842 // Symlinks to directories are not source files.
843 continue
847 name := d.Name()
848 ext := nameExt(name)
850 info, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly, fset)
851 if err != nil {
852 badFile(name, err)
853 continue
855 if info == nil {
856 if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
857 // not due to build constraints - don't report
858 } else if ext == ".go" {
859 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
860 } else if fileListForExt(p, ext) != nil {
861 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
863 continue
865 data, filename := info.header, info.name
867 // Going to save the file. For non-Go files, can stop here.
868 switch ext {
869 case ".go":
870 // keep going
871 case ".S", ".sx":
872 // special case for cgo, handled at end
873 Sfiles = append(Sfiles, name)
874 continue
875 default:
876 if list := fileListForExt(p, ext); list != nil {
877 *list = append(*list, name)
879 continue
882 if info.parseErr != nil {
883 badFile(name, info.parseErr)
884 // Fall through: we might still have a partial AST in info.parsed,
885 // and we want to list files with parse errors anyway.
888 var pkg string
889 if info.parsed != nil {
890 pkg = info.parsed.Name.Name
891 if pkg == "documentation" {
892 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
893 continue
897 isTest := strings.HasSuffix(name, "_test.go")
898 isXTest := false
899 if isTest && strings.HasSuffix(pkg, "_test") && p.Name != pkg {
900 isXTest = true
901 pkg = pkg[:len(pkg)-len("_test")]
904 if p.Name == "" {
905 p.Name = pkg
906 firstFile = name
907 } else if pkg != p.Name {
908 // TODO(#45999): The choice of p.Name is arbitrary based on file iteration
909 // order. Instead of resolving p.Name arbitrarily, we should clear out the
910 // existing name and mark the existing files as also invalid.
911 badFile(name, &MultiplePackageError{
912 Dir: p.Dir,
913 Packages: []string{p.Name, pkg},
914 Files: []string{firstFile, name},
917 // Grab the first package comment as docs, provided it is not from a test file.
918 if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest {
919 p.Doc = doc.Synopsis(info.parsed.Doc.Text())
922 if mode&ImportComment != 0 {
923 qcom, line := findImportComment(data)
924 if line != 0 {
925 com, err := strconv.Unquote(qcom)
926 if err != nil {
927 badFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
928 } else if p.ImportComment == "" {
929 p.ImportComment = com
930 firstCommentFile = name
931 } else if p.ImportComment != com {
932 badFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
937 // Record imports and information about cgo.
938 isCgo := false
939 for _, imp := range info.imports {
940 if imp.path == "C" {
941 if isTest {
942 badFile(name, fmt.Errorf("use of cgo in test %s not supported", filename))
943 continue
945 isCgo = true
946 if imp.doc != nil {
947 if err := ctxt.saveCgo(filename, p, imp.doc); err != nil {
948 badFile(name, err)
954 var fileList *[]string
955 var importMap, embedMap map[string][]token.Position
956 switch {
957 case isCgo:
958 allTags["cgo"] = true
959 if ctxt.CgoEnabled {
960 fileList = &p.CgoFiles
961 importMap = importPos
962 embedMap = embedPos
963 } else {
964 // Ignore imports and embeds from cgo files if cgo is disabled.
965 fileList = &p.IgnoredGoFiles
967 case isXTest:
968 fileList = &p.XTestGoFiles
969 importMap = xTestImportPos
970 embedMap = xTestEmbedPos
971 case isTest:
972 fileList = &p.TestGoFiles
973 importMap = testImportPos
974 embedMap = testEmbedPos
975 default:
976 fileList = &p.GoFiles
977 importMap = importPos
978 embedMap = embedPos
980 *fileList = append(*fileList, name)
981 if importMap != nil {
982 for _, imp := range info.imports {
983 importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
986 if embedMap != nil {
987 for _, emb := range info.embeds {
988 embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
993 for tag := range allTags {
994 p.AllTags = append(p.AllTags, tag)
996 sort.Strings(p.AllTags)
998 p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
999 p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
1000 p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
1002 p.Imports, p.ImportPos = cleanDecls(importPos)
1003 p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
1004 p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
1006 // add the .S/.sx files only if we are using cgo
1007 // (which means gcc will compile them).
1008 // The standard assemblers expect .s files.
1009 if len(p.CgoFiles) > 0 {
1010 p.SFiles = append(p.SFiles, Sfiles...)
1011 sort.Strings(p.SFiles)
1012 } else {
1013 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
1014 sort.Strings(p.IgnoredOtherFiles)
1017 if badGoError != nil {
1018 return p, badGoError
1020 if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1021 return p, &NoGoError{p.Dir}
1023 return p, pkgerr
1026 func fileListForExt(p *Package, ext string) *[]string {
1027 switch ext {
1028 case ".c":
1029 return &p.CFiles
1030 case ".cc", ".cpp", ".cxx":
1031 return &p.CXXFiles
1032 case ".m":
1033 return &p.MFiles
1034 case ".h", ".hh", ".hpp", ".hxx":
1035 return &p.HFiles
1036 case ".f", ".F", ".for", ".f90":
1037 return &p.FFiles
1038 case ".s", ".S", ".sx":
1039 return &p.SFiles
1040 case ".swig":
1041 return &p.SwigFiles
1042 case ".swigcxx":
1043 return &p.SwigCXXFiles
1044 case ".syso":
1045 return &p.SysoFiles
1047 return nil
1050 func uniq(list []string) []string {
1051 if list == nil {
1052 return nil
1054 out := make([]string, len(list))
1055 copy(out, list)
1056 sort.Strings(out)
1057 uniq := out[:0]
1058 for _, x := range out {
1059 if len(uniq) == 0 || uniq[len(uniq)-1] != x {
1060 uniq = append(uniq, x)
1063 return uniq
1066 var errNoModules = errors.New("not using modules")
1068 // importGo checks whether it can use the go command to find the directory for path.
1069 // If using the go command is not appropriate, importGo returns errNoModules.
1070 // Otherwise, importGo tries using the go command and reports whether that succeeded.
1071 // Using the go command lets build.Import and build.Context.Import find code
1072 // in Go modules. In the long term we want tools to use go/packages (currently golang.org/x/tools/go/packages),
1073 // which will also use the go command.
1074 // Invoking the go command here is not very efficient in that it computes information
1075 // about the requested package and all dependencies and then only reports about the requested package.
1076 // Then we reinvoke it for every dependency. But this is still better than not working at all.
1077 // See golang.org/issue/26504.
1078 func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode) error {
1079 // To invoke the go command,
1080 // we must not being doing special things like AllowBinary or IgnoreVendor,
1081 // and all the file system callbacks must be nil (we're meant to use the local file system).
1082 if mode&AllowBinary != 0 || mode&IgnoreVendor != 0 ||
1083 ctxt.JoinPath != nil || ctxt.SplitPathList != nil || ctxt.IsAbsPath != nil || ctxt.IsDir != nil || ctxt.HasSubdir != nil || ctxt.ReadDir != nil || ctxt.OpenFile != nil || !equal(ctxt.ToolTags, defaultToolTags) || !equal(ctxt.ReleaseTags, defaultReleaseTags) {
1084 return errNoModules
1087 // Predict whether module aware mode is enabled by checking the value of
1088 // GO111MODULE and looking for a go.mod file in the source directory or
1089 // one of its parents. Running 'go env GOMOD' in the source directory would
1090 // give a canonical answer, but we'd prefer not to execute another command.
1091 go111Module := os.Getenv("GO111MODULE")
1092 switch go111Module {
1093 case "off":
1094 return errNoModules
1095 default: // "", "on", "auto", anything else
1096 // Maybe use modules.
1099 if srcDir != "" {
1100 var absSrcDir string
1101 if filepath.IsAbs(srcDir) {
1102 absSrcDir = srcDir
1103 } else if ctxt.Dir != "" {
1104 return fmt.Errorf("go/build: Dir is non-empty, so relative srcDir is not allowed: %v", srcDir)
1105 } else {
1106 // Find the absolute source directory. hasSubdir does not handle
1107 // relative paths (and can't because the callbacks don't support this).
1108 var err error
1109 absSrcDir, err = filepath.Abs(srcDir)
1110 if err != nil {
1111 return errNoModules
1115 // If the source directory is in GOROOT, then the in-process code works fine
1116 // and we should keep using it. Moreover, the 'go list' approach below doesn't
1117 // take standard-library vendoring into account and will fail.
1118 if _, ok := ctxt.hasSubdir(filepath.Join(ctxt.GOROOT, "src"), absSrcDir); ok {
1119 return errNoModules
1123 // For efficiency, if path is a standard library package, let the usual lookup code handle it.
1124 if ctxt.GOROOT != "" {
1125 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
1126 if ctxt.isDir(dir) {
1127 return errNoModules
1131 // If GO111MODULE=auto, look to see if there is a go.mod.
1132 // Since go1.13, it doesn't matter if we're inside GOPATH.
1133 if go111Module == "auto" {
1134 var (
1135 parent string
1136 err error
1138 if ctxt.Dir == "" {
1139 parent, err = os.Getwd()
1140 if err != nil {
1141 // A nonexistent working directory can't be in a module.
1142 return errNoModules
1144 } else {
1145 parent, err = filepath.Abs(ctxt.Dir)
1146 if err != nil {
1147 // If the caller passed a bogus Dir explicitly, that's materially
1148 // different from not having modules enabled.
1149 return err
1152 for {
1153 if f, err := ctxt.openFile(ctxt.joinPath(parent, "go.mod")); err == nil {
1154 buf := make([]byte, 100)
1155 _, err := f.Read(buf)
1156 f.Close()
1157 if err == nil || err == io.EOF {
1158 // go.mod exists and is readable (is a file, not a directory).
1159 break
1162 d := filepath.Dir(parent)
1163 if len(d) >= len(parent) {
1164 return errNoModules // reached top of file system, no go.mod
1166 parent = d
1170 cmd := exec.Command("go", "list", "-e", "-compiler="+ctxt.Compiler, "-tags="+strings.Join(ctxt.BuildTags, ","), "-installsuffix="+ctxt.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n{{if .Error}}{{.Error}}{{end}}\n", "--", path)
1172 if ctxt.Dir != "" {
1173 cmd.Dir = ctxt.Dir
1176 var stdout, stderr strings.Builder
1177 cmd.Stdout = &stdout
1178 cmd.Stderr = &stderr
1180 cgo := "0"
1181 if ctxt.CgoEnabled {
1182 cgo = "1"
1184 cmd.Env = append(os.Environ(),
1185 "GOOS="+ctxt.GOOS,
1186 "GOARCH="+ctxt.GOARCH,
1187 "GOROOT="+ctxt.GOROOT,
1188 "GOPATH="+ctxt.GOPATH,
1189 "CGO_ENABLED="+cgo,
1192 if err := cmd.Run(); err != nil {
1193 return fmt.Errorf("go/build: go list %s: %v\n%s\n", path, err, stderr.String())
1196 f := strings.SplitN(stdout.String(), "\n", 5)
1197 if len(f) != 5 {
1198 return fmt.Errorf("go/build: importGo %s: unexpected output:\n%s\n", path, stdout.String())
1200 dir := f[0]
1201 errStr := strings.TrimSpace(f[4])
1202 if errStr != "" && dir == "" {
1203 // If 'go list' could not locate the package (dir is empty),
1204 // return the same error that 'go list' reported.
1205 return errors.New(errStr)
1208 // If 'go list' did locate the package, ignore the error.
1209 // It was probably related to loading source files, and we'll
1210 // encounter it ourselves shortly if the FindOnly flag isn't set.
1211 p.Dir = dir
1212 p.ImportPath = f[1]
1213 p.Root = f[2]
1214 p.Goroot = f[3] == "true"
1215 return nil
1218 func equal(x, y []string) bool {
1219 if len(x) != len(y) {
1220 return false
1222 for i, xi := range x {
1223 if xi != y[i] {
1224 return false
1227 return true
1230 // hasGoFiles reports whether dir contains any files with names ending in .go.
1231 // For a vendor check we must exclude directories that contain no .go files.
1232 // Otherwise it is not possible to vendor just a/b/c and still import the
1233 // non-vendored a/b. See golang.org/issue/13832.
1234 func hasGoFiles(ctxt *Context, dir string) bool {
1235 ents, _ := ctxt.readDir(dir)
1236 for _, ent := range ents {
1237 if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") {
1238 return true
1241 return false
1244 func findImportComment(data []byte) (s string, line int) {
1245 // expect keyword package
1246 word, data := parseWord(data)
1247 if string(word) != "package" {
1248 return "", 0
1251 // expect package name
1252 _, data = parseWord(data)
1254 // now ready for import comment, a // or /* */ comment
1255 // beginning and ending on the current line.
1256 for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') {
1257 data = data[1:]
1260 var comment []byte
1261 switch {
1262 case bytes.HasPrefix(data, slashSlash):
1263 comment, _, _ = bytes.Cut(data[2:], newline)
1264 case bytes.HasPrefix(data, slashStar):
1265 var ok bool
1266 comment, _, ok = bytes.Cut(data[2:], starSlash)
1267 if !ok {
1268 // malformed comment
1269 return "", 0
1271 if bytes.Contains(comment, newline) {
1272 return "", 0
1275 comment = bytes.TrimSpace(comment)
1277 // split comment into `import`, `"pkg"`
1278 word, arg := parseWord(comment)
1279 if string(word) != "import" {
1280 return "", 0
1283 line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline)
1284 return strings.TrimSpace(string(arg)), line
1287 var (
1288 slashSlash = []byte("//")
1289 slashStar = []byte("/*")
1290 starSlash = []byte("*/")
1291 newline = []byte("\n")
1294 // skipSpaceOrComment returns data with any leading spaces or comments removed.
1295 func skipSpaceOrComment(data []byte) []byte {
1296 for len(data) > 0 {
1297 switch data[0] {
1298 case ' ', '\t', '\r', '\n':
1299 data = data[1:]
1300 continue
1301 case '/':
1302 if bytes.HasPrefix(data, slashSlash) {
1303 i := bytes.Index(data, newline)
1304 if i < 0 {
1305 return nil
1307 data = data[i+1:]
1308 continue
1310 if bytes.HasPrefix(data, slashStar) {
1311 data = data[2:]
1312 i := bytes.Index(data, starSlash)
1313 if i < 0 {
1314 return nil
1316 data = data[i+2:]
1317 continue
1320 break
1322 return data
1325 // parseWord skips any leading spaces or comments in data
1326 // and then parses the beginning of data as an identifier or keyword,
1327 // returning that word and what remains after the word.
1328 func parseWord(data []byte) (word, rest []byte) {
1329 data = skipSpaceOrComment(data)
1331 // Parse past leading word characters.
1332 rest = data
1333 for {
1334 r, size := utf8.DecodeRune(rest)
1335 if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' {
1336 rest = rest[size:]
1337 continue
1339 break
1342 word = data[:len(data)-len(rest)]
1343 if len(word) == 0 {
1344 return nil, nil
1347 return word, rest
1350 // MatchFile reports whether the file with the given name in the given directory
1351 // matches the context and would be included in a Package created by ImportDir
1352 // of that directory.
1354 // MatchFile considers the name of the file and may use ctxt.OpenFile to
1355 // read some or all of the file's content.
1356 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
1357 info, err := ctxt.matchFile(dir, name, nil, nil, nil)
1358 return info != nil, err
1361 var dummyPkg Package
1363 // fileInfo records information learned about a file included in a build.
1364 type fileInfo struct {
1365 name string // full name including dir
1366 header []byte
1367 fset *token.FileSet
1368 parsed *ast.File
1369 parseErr error
1370 imports []fileImport
1371 embeds []fileEmbed
1372 embedErr error
1375 type fileImport struct {
1376 path string
1377 pos token.Pos
1378 doc *ast.CommentGroup
1381 type fileEmbed struct {
1382 pattern string
1383 pos token.Position
1386 // matchFile determines whether the file with the given name in the given directory
1387 // should be included in the package being constructed.
1388 // If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
1389 // Non-nil errors are reserved for unexpected problems.
1391 // If name denotes a Go program, matchFile reads until the end of the
1392 // imports and returns that section of the file in the fileInfo's header field,
1393 // even though it only considers text until the first non-comment
1394 // for +build lines.
1396 // If allTags is non-nil, matchFile records any encountered build tag
1397 // by setting allTags[tag] = true.
1398 func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
1399 if strings.HasPrefix(name, "_") ||
1400 strings.HasPrefix(name, ".") {
1401 return nil, nil
1404 i := strings.LastIndex(name, ".")
1405 if i < 0 {
1406 i = len(name)
1408 ext := name[i:]
1410 if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
1411 return nil, nil
1414 if ext != ".go" && fileListForExt(&dummyPkg, ext) == nil {
1415 // skip
1416 return nil, nil
1419 info := &fileInfo{name: ctxt.joinPath(dir, name), fset: fset}
1420 if ext == ".syso" {
1421 // binary, no reading
1422 return info, nil
1425 f, err := ctxt.openFile(info.name)
1426 if err != nil {
1427 return nil, err
1430 if strings.HasSuffix(name, ".go") {
1431 err = readGoInfo(f, info)
1432 if strings.HasSuffix(name, "_test.go") {
1433 binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
1435 } else {
1436 binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
1437 info.header, err = readComments(f)
1439 f.Close()
1440 if err != nil {
1441 return nil, fmt.Errorf("read %s: %v", info.name, err)
1444 // Look for +build comments to accept or reject the file.
1445 ok, sawBinaryOnly, err := ctxt.shouldBuild(info.header, allTags)
1446 if err != nil {
1447 return nil, fmt.Errorf("%s: %v", name, err)
1449 if !ok && !ctxt.UseAllFiles {
1450 return nil, nil
1453 if binaryOnly != nil && sawBinaryOnly {
1454 *binaryOnly = true
1457 return info, nil
1460 func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
1461 all := make([]string, 0, len(m))
1462 for path := range m {
1463 all = append(all, path)
1465 sort.Strings(all)
1466 return all, m
1469 // Import is shorthand for Default.Import.
1470 func Import(path, srcDir string, mode ImportMode) (*Package, error) {
1471 return Default.Import(path, srcDir, mode)
1474 // ImportDir is shorthand for Default.ImportDir.
1475 func ImportDir(dir string, mode ImportMode) (*Package, error) {
1476 return Default.ImportDir(dir, mode)
1479 var (
1480 bSlashSlash = []byte(slashSlash)
1481 bStarSlash = []byte(starSlash)
1482 bSlashStar = []byte(slashStar)
1483 bPlusBuild = []byte("+build")
1485 goBuildComment = []byte("//go:build")
1487 errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
1488 errMultipleGoBuild = errors.New("multiple //go:build comments")
1491 func isGoBuildComment(line []byte) bool {
1492 if !bytes.HasPrefix(line, goBuildComment) {
1493 return false
1495 line = bytes.TrimSpace(line)
1496 rest := line[len(goBuildComment):]
1497 return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
1500 // Special comment denoting a binary-only package.
1501 // See https://golang.org/design/2775-binary-only-packages
1502 // for more about the design of binary-only packages.
1503 var binaryOnlyComment = []byte("//go:binary-only-package")
1505 // shouldBuild reports whether it is okay to use this file,
1506 // The rule is that in the file's leading run of // comments
1507 // and blank lines, which must be followed by a blank line
1508 // (to avoid including a Go package clause doc comment),
1509 // lines beginning with '// +build' are taken as build directives.
1511 // The file is accepted only if each such line lists something
1512 // matching the file. For example:
1514 // // +build windows linux
1516 // marks the file as applicable only on Windows and Linux.
1518 // For each build tag it consults, shouldBuild sets allTags[tag] = true.
1520 // shouldBuild reports whether the file should be built
1521 // and whether a //go:binary-only-package comment was found.
1522 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) (shouldBuild, binaryOnly bool, err error) {
1523 // Identify leading run of // comments and blank lines,
1524 // which must be followed by a blank line.
1525 // Also identify any //go:build comments.
1526 content, goBuild, sawBinaryOnly, err := parseFileHeader(content)
1527 if err != nil {
1528 return false, false, err
1531 // If //go:build line is present, it controls.
1532 // Otherwise fall back to +build processing.
1533 switch {
1534 case goBuild != nil:
1535 x, err := constraint.Parse(string(goBuild))
1536 if err != nil {
1537 return false, false, fmt.Errorf("parsing //go:build line: %v", err)
1539 shouldBuild = ctxt.eval(x, allTags)
1541 default:
1542 shouldBuild = true
1543 p := content
1544 for len(p) > 0 {
1545 line := p
1546 if i := bytes.IndexByte(line, '\n'); i >= 0 {
1547 line, p = line[:i], p[i+1:]
1548 } else {
1549 p = p[len(p):]
1551 line = bytes.TrimSpace(line)
1552 if !bytes.HasPrefix(line, bSlashSlash) || !bytes.Contains(line, bPlusBuild) {
1553 continue
1555 text := string(line)
1556 if !constraint.IsPlusBuild(text) {
1557 continue
1559 if x, err := constraint.Parse(text); err == nil {
1560 if !ctxt.eval(x, allTags) {
1561 shouldBuild = false
1567 return shouldBuild, sawBinaryOnly, nil
1570 func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
1571 end := 0
1572 p := content
1573 ended := false // found non-blank, non-// line, so stopped accepting // +build lines
1574 inSlashStar := false // in /* */ comment
1576 Lines:
1577 for len(p) > 0 {
1578 line := p
1579 if i := bytes.IndexByte(line, '\n'); i >= 0 {
1580 line, p = line[:i], p[i+1:]
1581 } else {
1582 p = p[len(p):]
1584 line = bytes.TrimSpace(line)
1585 if len(line) == 0 && !ended { // Blank line
1586 // Remember position of most recent blank line.
1587 // When we find the first non-blank, non-// line,
1588 // this "end" position marks the latest file position
1589 // where a // +build line can appear.
1590 // (It must appear _before_ a blank line before the non-blank, non-// line.
1591 // Yes, that's confusing, which is part of why we moved to //go:build lines.)
1592 // Note that ended==false here means that inSlashStar==false,
1593 // since seeing a /* would have set ended==true.
1594 end = len(content) - len(p)
1595 continue Lines
1597 if !bytes.HasPrefix(line, slashSlash) { // Not comment line
1598 ended = true
1601 if !inSlashStar && isGoBuildComment(line) {
1602 if goBuild != nil {
1603 return nil, nil, false, errMultipleGoBuild
1605 goBuild = line
1607 if !inSlashStar && bytes.Equal(line, binaryOnlyComment) {
1608 sawBinaryOnly = true
1611 Comments:
1612 for len(line) > 0 {
1613 if inSlashStar {
1614 if i := bytes.Index(line, starSlash); i >= 0 {
1615 inSlashStar = false
1616 line = bytes.TrimSpace(line[i+len(starSlash):])
1617 continue Comments
1619 continue Lines
1621 if bytes.HasPrefix(line, bSlashSlash) {
1622 continue Lines
1624 if bytes.HasPrefix(line, bSlashStar) {
1625 inSlashStar = true
1626 line = bytes.TrimSpace(line[len(bSlashStar):])
1627 continue Comments
1629 // Found non-comment text.
1630 break Lines
1634 return content[:end], goBuild, sawBinaryOnly, nil
1637 // saveCgo saves the information from the #cgo lines in the import "C" comment.
1638 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
1639 // that affect the way cgo's C code is built.
1640 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
1641 text := cg.Text()
1642 for _, line := range strings.Split(text, "\n") {
1643 orig := line
1645 // Line is
1646 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
1648 line = strings.TrimSpace(line)
1649 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
1650 continue
1653 // Split at colon.
1654 line, argstr, ok := strings.Cut(strings.TrimSpace(line[4:]), ":")
1655 if !ok {
1656 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1659 // Parse GOOS/GOARCH stuff.
1660 f := strings.Fields(line)
1661 if len(f) < 1 {
1662 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1665 cond, verb := f[:len(f)-1], f[len(f)-1]
1666 if len(cond) > 0 {
1667 ok := false
1668 for _, c := range cond {
1669 if ctxt.matchAuto(c, nil) {
1670 ok = true
1671 break
1674 if !ok {
1675 continue
1679 args, err := splitQuoted(argstr)
1680 if err != nil {
1681 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1683 for i, arg := range args {
1684 if arg, ok = expandSrcDir(arg, di.Dir); !ok {
1685 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
1687 args[i] = arg
1690 switch verb {
1691 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS":
1692 // Change relative paths to absolute.
1693 ctxt.makePathsAbsolute(args, di.Dir)
1696 switch verb {
1697 case "CFLAGS":
1698 di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
1699 case "CPPFLAGS":
1700 di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
1701 case "CXXFLAGS":
1702 di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
1703 case "FFLAGS":
1704 di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
1705 case "LDFLAGS":
1706 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
1707 case "pkg-config":
1708 di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
1709 default:
1710 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
1713 return nil
1716 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure
1717 // the result is safe for the shell.
1718 func expandSrcDir(str string, srcdir string) (string, bool) {
1719 // "\" delimited paths cause safeCgoName to fail
1720 // so convert native paths with a different delimiter
1721 // to "/" before starting (eg: on windows).
1722 srcdir = filepath.ToSlash(srcdir)
1724 chunks := strings.Split(str, "${SRCDIR}")
1725 if len(chunks) < 2 {
1726 return str, safeCgoName(str)
1728 ok := true
1729 for _, chunk := range chunks {
1730 ok = ok && (chunk == "" || safeCgoName(chunk))
1732 ok = ok && (srcdir == "" || safeCgoName(srcdir))
1733 res := strings.Join(chunks, srcdir)
1734 return res, ok && res != ""
1737 // makePathsAbsolute looks for compiler options that take paths and
1738 // makes them absolute. We do this because through the 1.8 release we
1739 // ran the compiler in the package directory, so any relative -I or -L
1740 // options would be relative to that directory. In 1.9 we changed to
1741 // running the compiler in the build directory, to get consistent
1742 // build results (issue #19964). To keep builds working, we change any
1743 // relative -I or -L options to be absolute.
1745 // Using filepath.IsAbs and filepath.Join here means the results will be
1746 // different on different systems, but that's OK: -I and -L options are
1747 // inherently system-dependent.
1748 func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) {
1749 nextPath := false
1750 for i, arg := range args {
1751 if nextPath {
1752 if !filepath.IsAbs(arg) {
1753 args[i] = filepath.Join(srcDir, arg)
1755 nextPath = false
1756 } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
1757 if len(arg) == 2 {
1758 nextPath = true
1759 } else {
1760 if !filepath.IsAbs(arg[2:]) {
1761 args[i] = arg[:2] + filepath.Join(srcDir, arg[2:])
1768 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
1769 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
1770 // See golang.org/issue/6038.
1771 // The @ is for OS X. See golang.org/issue/13720.
1772 // The % is for Jenkins. See golang.org/issue/16959.
1773 // The ! is because module paths may use them. See golang.org/issue/26716.
1774 // The ~ and ^ are for sr.ht. See golang.org/issue/32260.
1775 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%! ~^"
1777 func safeCgoName(s string) bool {
1778 if s == "" {
1779 return false
1781 for i := 0; i < len(s); i++ {
1782 if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 {
1783 return false
1786 return true
1789 // splitQuoted splits the string s around each instance of one or more consecutive
1790 // white space characters while taking into account quotes and escaping, and
1791 // returns an array of substrings of s or an empty list if s contains only white space.
1792 // Single quotes and double quotes are recognized to prevent splitting within the
1793 // quoted region, and are removed from the resulting substrings. If a quote in s
1794 // isn't closed err will be set and r will have the unclosed argument as the
1795 // last element. The backslash is used for escaping.
1797 // For example, the following string:
1799 // a b:"c d" 'e''f' "g\""
1801 // Would be parsed as:
1803 // []string{"a", "b:c d", "ef", `g"`}
1805 func splitQuoted(s string) (r []string, err error) {
1806 var args []string
1807 arg := make([]rune, len(s))
1808 escaped := false
1809 quoted := false
1810 quote := '\x00'
1811 i := 0
1812 for _, rune := range s {
1813 switch {
1814 case escaped:
1815 escaped = false
1816 case rune == '\\':
1817 escaped = true
1818 continue
1819 case quote != '\x00':
1820 if rune == quote {
1821 quote = '\x00'
1822 continue
1824 case rune == '"' || rune == '\'':
1825 quoted = true
1826 quote = rune
1827 continue
1828 case unicode.IsSpace(rune):
1829 if quoted || i > 0 {
1830 quoted = false
1831 args = append(args, string(arg[:i]))
1832 i = 0
1834 continue
1836 arg[i] = rune
1839 if quoted || i > 0 {
1840 args = append(args, string(arg[:i]))
1842 if quote != 0 {
1843 err = errors.New("unclosed quote")
1844 } else if escaped {
1845 err = errors.New("unfinished escaping")
1847 return args, err
1850 // matchAuto interprets text as either a +build or //go:build expression (whichever works),
1851 // reporting whether the expression matches the build context.
1853 // matchAuto is only used for testing of tag evaluation
1854 // and in #cgo lines, which accept either syntax.
1855 func (ctxt *Context) matchAuto(text string, allTags map[string]bool) bool {
1856 if strings.ContainsAny(text, "&|()") {
1857 text = "//go:build " + text
1858 } else {
1859 text = "// +build " + text
1861 x, err := constraint.Parse(text)
1862 if err != nil {
1863 return false
1865 return ctxt.eval(x, allTags)
1868 func (ctxt *Context) eval(x constraint.Expr, allTags map[string]bool) bool {
1869 return x.Eval(func(tag string) bool { return ctxt.matchTag(tag, allTags) })
1872 // matchTag reports whether the name is one of:
1874 // cgo (if cgo is enabled)
1875 // $GOOS
1876 // $GOARCH
1877 // ctxt.Compiler
1878 // linux (if GOOS = android)
1879 // solaris (if GOOS = illumos)
1880 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags)
1882 // It records all consulted tags in allTags.
1883 func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
1884 if allTags != nil {
1885 allTags[name] = true
1888 // special tags
1889 if ctxt.CgoEnabled && name == "cgo" {
1890 return true
1892 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
1893 return true
1895 if ctxt.GOOS == "android" && name == "linux" {
1896 return true
1898 if ctxt.GOOS == "illumos" && name == "solaris" {
1899 return true
1901 if ctxt.GOOS == "ios" && name == "darwin" {
1902 return true
1905 // other tags
1906 for _, tag := range ctxt.BuildTags {
1907 if tag == name {
1908 return true
1911 for _, tag := range ctxt.ToolTags {
1912 if tag == name {
1913 return true
1916 for _, tag := range ctxt.ReleaseTags {
1917 if tag == name {
1918 return true
1922 return false
1925 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
1926 // suffix which does not match the current system.
1927 // The recognized name formats are:
1929 // name_$(GOOS).*
1930 // name_$(GOARCH).*
1931 // name_$(GOOS)_$(GOARCH).*
1932 // name_$(GOOS)_test.*
1933 // name_$(GOARCH)_test.*
1934 // name_$(GOOS)_$(GOARCH)_test.*
1936 // Exceptions:
1937 // if GOOS=android, then files with GOOS=linux are also matched.
1938 // if GOOS=illumos, then files with GOOS=solaris are also matched.
1939 // if GOOS=ios, then files with GOOS=darwin are also matched.
1940 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
1941 name, _, _ = strings.Cut(name, ".")
1943 // Before Go 1.4, a file called "linux.go" would be equivalent to having a
1944 // build tag "linux" in that file. For Go 1.4 and beyond, we require this
1945 // auto-tagging to apply only to files with a non-empty prefix, so
1946 // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
1947 // systems, such as android, to arrive without breaking existing code with
1948 // innocuous source code in "android.go". The easiest fix: cut everything
1949 // in the name before the initial _.
1950 i := strings.Index(name, "_")
1951 if i < 0 {
1952 return true
1954 name = name[i:] // ignore everything before first _
1956 l := strings.Split(name, "_")
1957 if n := len(l); n > 0 && l[n-1] == "test" {
1958 l = l[:n-1]
1960 n := len(l)
1961 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
1962 return ctxt.matchTag(l[n-1], allTags) && ctxt.matchTag(l[n-2], allTags)
1964 if n >= 1 && (knownOS[l[n-1]] || knownArch[l[n-1]]) {
1965 return ctxt.matchTag(l[n-1], allTags)
1967 return true
1970 var knownOS = make(map[string]bool)
1971 var knownArch = make(map[string]bool)
1973 func init() {
1974 for _, v := range strings.Fields(goosList) {
1975 knownOS[v] = true
1977 for _, v := range strings.Fields(goarchList) {
1978 knownArch[v] = true
1982 // ToolDir is the directory containing build tools.
1983 var ToolDir = getToolDir()
1985 // IsLocalImport reports whether the import path is
1986 // a local import path, like ".", "..", "./foo", or "../foo".
1987 func IsLocalImport(path string) bool {
1988 return path == "." || path == ".." ||
1989 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
1992 // ArchChar returns "?" and an error.
1993 // In earlier versions of Go, the returned string was used to derive
1994 // the compiler and linker tool names, the default object file suffix,
1995 // and the default linker output name. As of Go 1.5, those strings
1996 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
1997 func ArchChar(goarch string) (string, error) {
1998 return "?", errors.New("architecture letter no longer used")