]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/build/build.go
cmd/go, go/build: parse directives in file headers
[gostls13.git] / src / go / build / build.go
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.
4
5 package build
6
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         "internal/godebug"
17         "internal/goroot"
18         "internal/goversion"
19         "io"
20         "io/fs"
21         "os"
22         "os/exec"
23         pathpkg "path"
24         "path/filepath"
25         "runtime"
26         "sort"
27         "strconv"
28         "strings"
29         "unicode"
30         "unicode/utf8"
31 )
32
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 paths
39
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.
43         //
44         // If Dir is non-empty, directories passed to Import and ImportDir must
45         // be absolute.
46         Dir string
47
48         CgoEnabled  bool   // whether cgo files are included
49         UseAllFiles bool   // use files regardless of go:build lines, file names
50         Compiler    string // compiler to assume when computing target paths
51
52         // The build, tool, and release tags specify build constraints
53         // that should be considered satisfied when processing go: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
65
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
73
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.
79
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
83
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
87
88         // IsAbsPath reports whether path is an absolute path.
89         // If IsAbsPath is nil, Import uses filepath.IsAbs.
90         IsAbsPath func(path string) bool
91
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
95
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)
104
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 os.ReadDir.
108         ReadDir func(dir string) ([]fs.FileInfo, error)
109
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)
113 }
114
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...)
119         }
120         return filepath.Join(elem...)
121 }
122
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)
127         }
128         return filepath.SplitList(s)
129 }
130
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)
135         }
136         return filepath.IsAbs(path)
137 }
138
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)
143         }
144         fi, err := os.Stat(path)
145         return err == nil && fi.IsDir()
146 }
147
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)
153         }
154
155         // Try using paths we received.
156         if rel, ok = hasSubdir(root, dir); ok {
157                 return
158         }
159
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)
165
166         if rel, ok = hasSubdir(rootSym, dir); ok {
167                 return
168         }
169         if rel, ok = hasSubdir(root, dirSym); ok {
170                 return
171         }
172         return hasSubdir(rootSym, dirSym)
173 }
174
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
181         }
182         dir = filepath.Clean(dir)
183         after, found := strings.CutPrefix(dir, root)
184         if !found {
185                 return "", false
186         }
187         return filepath.ToSlash(after), true
188 }
189
190 // readDir calls ctxt.ReadDir (if not nil) or else os.ReadDir.
191 func (ctxt *Context) readDir(path string) ([]fs.DirEntry, error) {
192         // TODO: add a fs.DirEntry version of Context.ReadDir
193         if f := ctxt.ReadDir; f != nil {
194                 fis, err := f(path)
195                 if err != nil {
196                         return nil, err
197                 }
198                 des := make([]fs.DirEntry, len(fis))
199                 for i, fi := range fis {
200                         des[i] = fs.FileInfoToDirEntry(fi)
201                 }
202                 return des, nil
203         }
204         return os.ReadDir(path)
205 }
206
207 // openFile calls ctxt.OpenFile (if not nil) or else os.Open.
208 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
209         if fn := ctxt.OpenFile; fn != nil {
210                 return fn(path)
211         }
212
213         f, err := os.Open(path)
214         if err != nil {
215                 return nil, err // nil interface
216         }
217         return f, nil
218 }
219
220 // isFile determines whether path is a file by trying to open it.
221 // It reuses openFile instead of adding another function to the
222 // list in Context.
223 func (ctxt *Context) isFile(path string) bool {
224         f, err := ctxt.openFile(path)
225         if err != nil {
226                 return false
227         }
228         f.Close()
229         return true
230 }
231
232 // gopath returns the list of Go path directories.
233 func (ctxt *Context) gopath() []string {
234         var all []string
235         for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
236                 if p == "" || p == ctxt.GOROOT {
237                         // Empty paths are uninteresting.
238                         // If the path is the GOROOT, ignore it.
239                         // People sometimes set GOPATH=$GOROOT.
240                         // Do not get confused by this common mistake.
241                         continue
242                 }
243                 if strings.HasPrefix(p, "~") {
244                         // Path segments starting with ~ on Unix are almost always
245                         // users who have incorrectly quoted ~ while setting GOPATH,
246                         // preventing it from expanding to $HOME.
247                         // The situation is made more confusing by the fact that
248                         // bash allows quoted ~ in $PATH (most shells do not).
249                         // Do not get confused by this, and do not try to use the path.
250                         // It does not exist, and printing errors about it confuses
251                         // those users even more, because they think "sure ~ exists!".
252                         // The go command diagnoses this situation and prints a
253                         // useful error.
254                         // On Windows, ~ is used in short names, such as c:\progra~1
255                         // for c:\program files.
256                         continue
257                 }
258                 all = append(all, p)
259         }
260         return all
261 }
262
263 // SrcDirs returns a list of package source root directories.
264 // It draws from the current Go root and Go path but omits directories
265 // that do not exist.
266 func (ctxt *Context) SrcDirs() []string {
267         var all []string
268         if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
269                 dir := ctxt.joinPath(ctxt.GOROOT, "src")
270                 if ctxt.isDir(dir) {
271                         all = append(all, dir)
272                 }
273         }
274         for _, p := range ctxt.gopath() {
275                 dir := ctxt.joinPath(p, "src")
276                 if ctxt.isDir(dir) {
277                         all = append(all, dir)
278                 }
279         }
280         return all
281 }
282
283 // Default is the default Context for builds.
284 // It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
285 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
286 var Default Context = defaultContext()
287
288 func defaultGOPATH() string {
289         env := "HOME"
290         if runtime.GOOS == "windows" {
291                 env = "USERPROFILE"
292         } else if runtime.GOOS == "plan9" {
293                 env = "home"
294         }
295         if home := os.Getenv(env); home != "" {
296                 def := filepath.Join(home, "go")
297                 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
298                         // Don't set the default GOPATH to GOROOT,
299                         // as that will trigger warnings from the go tool.
300                         return ""
301                 }
302                 return def
303         }
304         return ""
305 }
306
307 var defaultToolTags, defaultReleaseTags []string
308
309 func defaultContext() Context {
310         var c Context
311
312         c.GOARCH = buildcfg.GOARCH
313         c.GOOS = buildcfg.GOOS
314         if goroot := runtime.GOROOT(); goroot != "" {
315                 c.GOROOT = filepath.Clean(goroot)
316         }
317         c.GOPATH = envOr("GOPATH", defaultGOPATH())
318         c.Compiler = runtime.Compiler
319         c.ToolTags = append(c.ToolTags, buildcfg.ToolTags...)
320
321         defaultToolTags = append([]string{}, c.ToolTags...) // our own private copy
322
323         // Each major Go release in the Go 1.x series adds a new
324         // "go1.x" release tag. That is, the go1.x tag is present in
325         // all releases >= Go 1.x. Code that requires Go 1.x or later
326         // should say "go:build go1.x", and code that should only be
327         // built before Go 1.x (perhaps it is the stub to use in that
328         // case) should say "go:build !go1.x".
329         // The last element in ReleaseTags is the current release.
330         for i := 1; i <= goversion.Version; i++ {
331                 c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i))
332         }
333
334         defaultReleaseTags = append([]string{}, c.ReleaseTags...) // our own private copy
335
336         env := os.Getenv("CGO_ENABLED")
337         if env == "" {
338                 env = defaultCGO_ENABLED
339         }
340         switch env {
341         case "1":
342                 c.CgoEnabled = true
343         case "0":
344                 c.CgoEnabled = false
345         default:
346                 // cgo must be explicitly enabled for cross compilation builds
347                 if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
348                         c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
349                         break
350                 }
351                 c.CgoEnabled = false
352         }
353
354         return c
355 }
356
357 func envOr(name, def string) string {
358         s := os.Getenv(name)
359         if s == "" {
360                 return def
361         }
362         return s
363 }
364
365 // An ImportMode controls the behavior of the Import method.
366 type ImportMode uint
367
368 const (
369         // If FindOnly is set, Import stops after locating the directory
370         // that should contain the sources for a package. It does not
371         // read any files in the directory.
372         FindOnly ImportMode = 1 << iota
373
374         // If AllowBinary is set, Import can be satisfied by a compiled
375         // package object without corresponding sources.
376         //
377         // Deprecated:
378         // The supported way to create a compiled-only package is to
379         // write source code containing a //go:binary-only-package comment at
380         // the top of the file. Such a package will be recognized
381         // regardless of this flag setting (because it has source code)
382         // and will have BinaryOnly set to true in the returned Package.
383         AllowBinary
384
385         // If ImportComment is set, parse import comments on package statements.
386         // Import returns an error if it finds a comment it cannot understand
387         // or finds conflicting comments in multiple source files.
388         // See golang.org/s/go14customimport for more information.
389         ImportComment
390
391         // By default, Import searches vendor directories
392         // that apply in the given source directory before searching
393         // the GOROOT and GOPATH roots.
394         // If an Import finds and returns a package using a vendor
395         // directory, the resulting ImportPath is the complete path
396         // to the package, including the path elements leading up
397         // to and including "vendor".
398         // For example, if Import("y", "x/subdir", 0) finds
399         // "x/vendor/y", the returned package's ImportPath is "x/vendor/y",
400         // not plain "y".
401         // See golang.org/s/go15vendor for more information.
402         //
403         // Setting IgnoreVendor ignores vendor directories.
404         //
405         // In contrast to the package's ImportPath,
406         // the returned package's Imports, TestImports, and XTestImports
407         // are always the exact import paths from the source files:
408         // Import makes no attempt to resolve or check those paths.
409         IgnoreVendor
410 )
411
412 // A Package describes the Go package found in a directory.
413 type Package struct {
414         Dir           string   // directory containing package sources
415         Name          string   // package name
416         ImportComment string   // path in import comment on package statement
417         Doc           string   // documentation synopsis
418         ImportPath    string   // import path of package ("" if unknown)
419         Root          string   // root of Go tree where this package lives
420         SrcRoot       string   // package source root directory ("" if unknown)
421         PkgRoot       string   // package install root directory ("" if unknown)
422         PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
423         BinDir        string   // command install directory ("" if unknown)
424         Goroot        bool     // package found in Go root
425         PkgObj        string   // installed .a file
426         AllTags       []string // tags that can influence file selection in this directory
427         ConflictDir   string   // this directory shadows Dir in $GOPATH
428         BinaryOnly    bool     // cannot be rebuilt from source (has //go:binary-only-package comment)
429
430         // Source files
431         GoFiles           []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
432         CgoFiles          []string // .go source files that import "C"
433         IgnoredGoFiles    []string // .go source files ignored for this build (including ignored _test.go files)
434         InvalidGoFiles    []string // .go source files with detected problems (parse error, wrong package name, and so on)
435         IgnoredOtherFiles []string // non-.go source files ignored for this build
436         CFiles            []string // .c source files
437         CXXFiles          []string // .cc, .cpp and .cxx source files
438         MFiles            []string // .m (Objective-C) source files
439         HFiles            []string // .h, .hh, .hpp and .hxx source files
440         FFiles            []string // .f, .F, .for and .f90 Fortran source files
441         SFiles            []string // .s source files
442         SwigFiles         []string // .swig files
443         SwigCXXFiles      []string // .swigcxx files
444         SysoFiles         []string // .syso system object files to add to archive
445
446         // Cgo directives
447         CgoCFLAGS    []string // Cgo CFLAGS directives
448         CgoCPPFLAGS  []string // Cgo CPPFLAGS directives
449         CgoCXXFLAGS  []string // Cgo CXXFLAGS directives
450         CgoFFLAGS    []string // Cgo FFLAGS directives
451         CgoLDFLAGS   []string // Cgo LDFLAGS directives
452         CgoPkgConfig []string // Cgo pkg-config directives
453
454         // Test information
455         TestGoFiles  []string // _test.go files in package
456         XTestGoFiles []string // _test.go files outside package
457
458         // Go directive comments (//go:zzz...) found in source files.
459         Directives      []Directive
460         TestDirectives  []Directive
461         XTestDirectives []Directive
462
463         // Dependency information
464         Imports        []string                    // import paths from GoFiles, CgoFiles
465         ImportPos      map[string][]token.Position // line information for Imports
466         TestImports    []string                    // import paths from TestGoFiles
467         TestImportPos  map[string][]token.Position // line information for TestImports
468         XTestImports   []string                    // import paths from XTestGoFiles
469         XTestImportPos map[string][]token.Position // line information for XTestImports
470
471         // //go:embed patterns found in Go source files
472         // For example, if a source file says
473         //      //go:embed a* b.c
474         // then the list will contain those two strings as separate entries.
475         // (See package embed for more details about //go:embed.)
476         EmbedPatterns        []string                    // patterns from GoFiles, CgoFiles
477         EmbedPatternPos      map[string][]token.Position // line information for EmbedPatterns
478         TestEmbedPatterns    []string                    // patterns from TestGoFiles
479         TestEmbedPatternPos  map[string][]token.Position // line information for TestEmbedPatterns
480         XTestEmbedPatterns   []string                    // patterns from XTestGoFiles
481         XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
482 }
483
484 // A Directive is a Go directive comment (//go:zzz...) found in a source file.
485 type Directive struct {
486         Text string         // full line comment including leading slashes
487         Pos  token.Position // position of comment
488 }
489
490 // IsCommand reports whether the package is considered a
491 // command to be installed (not just a library).
492 // Packages named "main" are treated as commands.
493 func (p *Package) IsCommand() bool {
494         return p.Name == "main"
495 }
496
497 // ImportDir is like Import but processes the Go package found in
498 // the named directory.
499 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
500         return ctxt.Import(".", dir, mode)
501 }
502
503 // NoGoError is the error used by Import to describe a directory
504 // containing no buildable Go source files. (It may still contain
505 // test files, files hidden by build tags, and so on.)
506 type NoGoError struct {
507         Dir string
508 }
509
510 func (e *NoGoError) Error() string {
511         return "no buildable Go source files in " + e.Dir
512 }
513
514 // MultiplePackageError describes a directory containing
515 // multiple buildable Go source files for multiple packages.
516 type MultiplePackageError struct {
517         Dir      string   // directory containing files
518         Packages []string // package names found
519         Files    []string // corresponding files: Files[i] declares package Packages[i]
520 }
521
522 func (e *MultiplePackageError) Error() string {
523         // Error string limited to two entries for compatibility.
524         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)
525 }
526
527 func nameExt(name string) string {
528         i := strings.LastIndex(name, ".")
529         if i < 0 {
530                 return ""
531         }
532         return name[i:]
533 }
534
535 var installgoroot = godebug.New("installgoroot")
536
537 // Import returns details about the Go package named by the import path,
538 // interpreting local import paths relative to the srcDir directory.
539 // If the path is a local import path naming a package that can be imported
540 // using a standard import path, the returned package will set p.ImportPath
541 // to that path.
542 //
543 // In the directory containing the package, .go, .c, .h, and .s files are
544 // considered part of the package except for:
545 //
546 //   - .go files in package documentation
547 //   - files starting with _ or . (likely editor temporary files)
548 //   - files with build constraints not satisfied by the context
549 //
550 // If an error occurs, Import returns a non-nil error and a non-nil
551 // *Package containing partial information.
552 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
553         p := &Package{
554                 ImportPath: path,
555         }
556         if path == "" {
557                 return p, fmt.Errorf("import %q: invalid import path", path)
558         }
559
560         var pkgtargetroot string
561         var pkga string
562         var pkgerr error
563         suffix := ""
564         if ctxt.InstallSuffix != "" {
565                 suffix = "_" + ctxt.InstallSuffix
566         }
567         switch ctxt.Compiler {
568         case "gccgo":
569                 pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
570         case "gc":
571                 pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
572         default:
573                 // Save error for end of function.
574                 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
575         }
576         setPkga := func() {
577                 switch ctxt.Compiler {
578                 case "gccgo":
579                         dir, elem := pathpkg.Split(p.ImportPath)
580                         pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
581                 case "gc":
582                         pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
583                 }
584         }
585         setPkga()
586
587         binaryOnly := false
588         if IsLocalImport(path) {
589                 pkga = "" // local imports have no installed path
590                 if srcDir == "" {
591                         return p, fmt.Errorf("import %q: import relative to unknown directory", path)
592                 }
593                 if !ctxt.isAbsPath(path) {
594                         p.Dir = ctxt.joinPath(srcDir, path)
595                 }
596                 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
597                 // Determine canonical import path, if any.
598                 // Exclude results where the import path would include /testdata/.
599                 inTestdata := func(sub string) bool {
600                         return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
601                 }
602                 if ctxt.GOROOT != "" {
603                         root := ctxt.joinPath(ctxt.GOROOT, "src")
604                         if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
605                                 p.Goroot = true
606                                 p.ImportPath = sub
607                                 p.Root = ctxt.GOROOT
608                                 setPkga() // p.ImportPath changed
609                                 goto Found
610                         }
611                 }
612                 all := ctxt.gopath()
613                 for i, root := range all {
614                         rootsrc := ctxt.joinPath(root, "src")
615                         if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
616                                 // We found a potential import path for dir,
617                                 // but check that using it wouldn't find something
618                                 // else first.
619                                 if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
620                                         if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
621                                                 p.ConflictDir = dir
622                                                 goto Found
623                                         }
624                                 }
625                                 for _, earlyRoot := range all[:i] {
626                                         if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
627                                                 p.ConflictDir = dir
628                                                 goto Found
629                                         }
630                                 }
631
632                                 // sub would not name some other directory instead of this one.
633                                 // Record it.
634                                 p.ImportPath = sub
635                                 p.Root = root
636                                 setPkga() // p.ImportPath changed
637                                 goto Found
638                         }
639                 }
640                 // It's okay that we didn't find a root containing dir.
641                 // Keep going with the information we have.
642         } else {
643                 if strings.HasPrefix(path, "/") {
644                         return p, fmt.Errorf("import %q: cannot import absolute path", path)
645                 }
646
647                 if err := ctxt.importGo(p, path, srcDir, mode); err == nil {
648                         goto Found
649                 } else if err != errNoModules {
650                         return p, err
651                 }
652
653                 gopath := ctxt.gopath() // needed twice below; avoid computing many times
654
655                 // tried records the location of unsuccessful package lookups
656                 var tried struct {
657                         vendor []string
658                         goroot string
659                         gopath []string
660                 }
661
662                 // Vendor directories get first chance to satisfy import.
663                 if mode&IgnoreVendor == 0 && srcDir != "" {
664                         searchVendor := func(root string, isGoroot bool) bool {
665                                 sub, ok := ctxt.hasSubdir(root, srcDir)
666                                 if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
667                                         return false
668                                 }
669                                 for {
670                                         vendor := ctxt.joinPath(root, sub, "vendor")
671                                         if ctxt.isDir(vendor) {
672                                                 dir := ctxt.joinPath(vendor, path)
673                                                 if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) {
674                                                         p.Dir = dir
675                                                         p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
676                                                         p.Goroot = isGoroot
677                                                         p.Root = root
678                                                         setPkga() // p.ImportPath changed
679                                                         return true
680                                                 }
681                                                 tried.vendor = append(tried.vendor, dir)
682                                         }
683                                         i := strings.LastIndex(sub, "/")
684                                         if i < 0 {
685                                                 break
686                                         }
687                                         sub = sub[:i]
688                                 }
689                                 return false
690                         }
691                         if ctxt.Compiler != "gccgo" && ctxt.GOROOT != "" && searchVendor(ctxt.GOROOT, true) {
692                                 goto Found
693                         }
694                         for _, root := range gopath {
695                                 if searchVendor(root, false) {
696                                         goto Found
697                                 }
698                         }
699                 }
700
701                 // Determine directory from import path.
702                 if ctxt.GOROOT != "" {
703                         // If the package path starts with "vendor/", only search GOROOT before
704                         // GOPATH if the importer is also within GOROOT. That way, if the user has
705                         // vendored in a package that is subsequently included in the standard
706                         // distribution, they'll continue to pick up their own vendored copy.
707                         gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
708                         if !gorootFirst {
709                                 _, gorootFirst = ctxt.hasSubdir(ctxt.GOROOT, srcDir)
710                         }
711                         if gorootFirst {
712                                 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
713                                 if ctxt.Compiler != "gccgo" {
714                                         isDir := ctxt.isDir(dir)
715                                         binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
716                                         if isDir || binaryOnly {
717                                                 p.Dir = dir
718                                                 p.Goroot = true
719                                                 p.Root = ctxt.GOROOT
720                                                 goto Found
721                                         }
722                                 }
723                                 tried.goroot = dir
724                         }
725                         if ctxt.Compiler == "gccgo" && goroot.IsStandardPackage(ctxt.GOROOT, ctxt.Compiler, path) {
726                                 // TODO(bcmills): Setting p.Dir here is misleading, because gccgo
727                                 // doesn't actually load its standard-library packages from this
728                                 // directory. See if we can leave it unset.
729                                 p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path)
730                                 p.Goroot = true
731                                 p.Root = ctxt.GOROOT
732                                 goto Found
733                         }
734                 }
735                 for _, root := range gopath {
736                         dir := ctxt.joinPath(root, "src", path)
737                         isDir := ctxt.isDir(dir)
738                         binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
739                         if isDir || binaryOnly {
740                                 p.Dir = dir
741                                 p.Root = root
742                                 goto Found
743                         }
744                         tried.gopath = append(tried.gopath, dir)
745                 }
746
747                 // If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
748                 // That way, the user can still get useful results from 'go list' for
749                 // standard-vendored paths passed on the command line.
750                 if ctxt.GOROOT != "" && tried.goroot == "" {
751                         dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
752                         if ctxt.Compiler != "gccgo" {
753                                 isDir := ctxt.isDir(dir)
754                                 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
755                                 if isDir || binaryOnly {
756                                         p.Dir = dir
757                                         p.Goroot = true
758                                         p.Root = ctxt.GOROOT
759                                         goto Found
760                                 }
761                         }
762                         tried.goroot = dir
763                 }
764
765                 // package was not found
766                 var paths []string
767                 format := "\t%s (vendor tree)"
768                 for _, dir := range tried.vendor {
769                         paths = append(paths, fmt.Sprintf(format, dir))
770                         format = "\t%s"
771                 }
772                 if tried.goroot != "" {
773                         paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
774                 } else {
775                         paths = append(paths, "\t($GOROOT not set)")
776                 }
777                 format = "\t%s (from $GOPATH)"
778                 for _, dir := range tried.gopath {
779                         paths = append(paths, fmt.Sprintf(format, dir))
780                         format = "\t%s"
781                 }
782                 if len(tried.gopath) == 0 {
783                         paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
784                 }
785                 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
786         }
787
788 Found:
789         if p.Root != "" {
790                 p.SrcRoot = ctxt.joinPath(p.Root, "src")
791                 p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
792                 p.BinDir = ctxt.joinPath(p.Root, "bin")
793                 if pkga != "" {
794                         // Always set PkgTargetRoot. It might be used when building in shared
795                         // mode.
796                         p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
797
798                         // Set the install target if applicable.
799                         if !p.Goroot || (installgoroot.Value() == "all" && p.ImportPath != "unsafe" && p.ImportPath != "builtin") {
800                                 if p.Goroot {
801                                         installgoroot.IncNonDefault()
802                                 }
803                                 p.PkgObj = ctxt.joinPath(p.Root, pkga)
804                         }
805                 }
806         }
807
808         // If it's a local import path, by the time we get here, we still haven't checked
809         // that p.Dir directory exists. This is the right time to do that check.
810         // We can't do it earlier, because we want to gather partial information for the
811         // non-nil *Package returned when an error occurs.
812         // We need to do this before we return early on FindOnly flag.
813         if IsLocalImport(path) && !ctxt.isDir(p.Dir) {
814                 if ctxt.Compiler == "gccgo" && p.Goroot {
815                         // gccgo has no sources for GOROOT packages.
816                         return p, nil
817                 }
818
819                 // package was not found
820                 return p, fmt.Errorf("cannot find package %q in:\n\t%s", p.ImportPath, p.Dir)
821         }
822
823         if mode&FindOnly != 0 {
824                 return p, pkgerr
825         }
826         if binaryOnly && (mode&AllowBinary) != 0 {
827                 return p, pkgerr
828         }
829
830         if ctxt.Compiler == "gccgo" && p.Goroot {
831                 // gccgo has no sources for GOROOT packages.
832                 return p, nil
833         }
834
835         dirs, err := ctxt.readDir(p.Dir)
836         if err != nil {
837                 return p, err
838         }
839
840         var badGoError error
841         badGoFiles := make(map[string]bool)
842         badGoFile := func(name string, err error) {
843                 if badGoError == nil {
844                         badGoError = err
845                 }
846                 if !badGoFiles[name] {
847                         p.InvalidGoFiles = append(p.InvalidGoFiles, name)
848                         badGoFiles[name] = true
849                 }
850         }
851
852         var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
853         var firstFile, firstCommentFile string
854         embedPos := make(map[string][]token.Position)
855         testEmbedPos := make(map[string][]token.Position)
856         xTestEmbedPos := make(map[string][]token.Position)
857         importPos := make(map[string][]token.Position)
858         testImportPos := make(map[string][]token.Position)
859         xTestImportPos := make(map[string][]token.Position)
860         allTags := make(map[string]bool)
861         fset := token.NewFileSet()
862         for _, d := range dirs {
863                 if d.IsDir() {
864                         continue
865                 }
866                 if d.Type() == fs.ModeSymlink {
867                         if ctxt.isDir(ctxt.joinPath(p.Dir, d.Name())) {
868                                 // Symlinks to directories are not source files.
869                                 continue
870                         }
871                 }
872
873                 name := d.Name()
874                 ext := nameExt(name)
875
876                 info, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly, fset)
877                 if err != nil && strings.HasSuffix(name, ".go") {
878                         badGoFile(name, err)
879                         continue
880                 }
881                 if info == nil {
882                         if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
883                                 // not due to build constraints - don't report
884                         } else if ext == ".go" {
885                                 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
886                         } else if fileListForExt(p, ext) != nil {
887                                 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
888                         }
889                         continue
890                 }
891
892                 // Going to save the file. For non-Go files, can stop here.
893                 switch ext {
894                 case ".go":
895                         // keep going
896                 case ".S", ".sx":
897                         // special case for cgo, handled at end
898                         Sfiles = append(Sfiles, name)
899                         continue
900                 default:
901                         if list := fileListForExt(p, ext); list != nil {
902                                 *list = append(*list, name)
903                         }
904                         continue
905                 }
906
907                 data, filename := info.header, info.name
908
909                 if info.parseErr != nil {
910                         badGoFile(name, info.parseErr)
911                         // Fall through: we might still have a partial AST in info.parsed,
912                         // and we want to list files with parse errors anyway.
913                 }
914
915                 var pkg string
916                 if info.parsed != nil {
917                         pkg = info.parsed.Name.Name
918                         if pkg == "documentation" {
919                                 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
920                                 continue
921                         }
922                 }
923
924                 isTest := strings.HasSuffix(name, "_test.go")
925                 isXTest := false
926                 if isTest && strings.HasSuffix(pkg, "_test") && p.Name != pkg {
927                         isXTest = true
928                         pkg = pkg[:len(pkg)-len("_test")]
929                 }
930
931                 if p.Name == "" {
932                         p.Name = pkg
933                         firstFile = name
934                 } else if pkg != p.Name {
935                         // TODO(#45999): The choice of p.Name is arbitrary based on file iteration
936                         // order. Instead of resolving p.Name arbitrarily, we should clear out the
937                         // existing name and mark the existing files as also invalid.
938                         badGoFile(name, &MultiplePackageError{
939                                 Dir:      p.Dir,
940                                 Packages: []string{p.Name, pkg},
941                                 Files:    []string{firstFile, name},
942                         })
943                 }
944                 // Grab the first package comment as docs, provided it is not from a test file.
945                 if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest {
946                         p.Doc = doc.Synopsis(info.parsed.Doc.Text())
947                 }
948
949                 if mode&ImportComment != 0 {
950                         qcom, line := findImportComment(data)
951                         if line != 0 {
952                                 com, err := strconv.Unquote(qcom)
953                                 if err != nil {
954                                         badGoFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
955                                 } else if p.ImportComment == "" {
956                                         p.ImportComment = com
957                                         firstCommentFile = name
958                                 } else if p.ImportComment != com {
959                                         badGoFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
960                                 }
961                         }
962                 }
963
964                 // Record imports and information about cgo.
965                 isCgo := false
966                 for _, imp := range info.imports {
967                         if imp.path == "C" {
968                                 if isTest {
969                                         badGoFile(name, fmt.Errorf("use of cgo in test %s not supported", filename))
970                                         continue
971                                 }
972                                 isCgo = true
973                                 if imp.doc != nil {
974                                         if err := ctxt.saveCgo(filename, p, imp.doc); err != nil {
975                                                 badGoFile(name, err)
976                                         }
977                                 }
978                         }
979                 }
980
981                 var fileList *[]string
982                 var importMap, embedMap map[string][]token.Position
983                 var directives *[]Directive
984                 switch {
985                 case isCgo:
986                         allTags["cgo"] = true
987                         if ctxt.CgoEnabled {
988                                 fileList = &p.CgoFiles
989                                 importMap = importPos
990                                 embedMap = embedPos
991                                 directives = &p.Directives
992                         } else {
993                                 // Ignore imports and embeds from cgo files if cgo is disabled.
994                                 fileList = &p.IgnoredGoFiles
995                         }
996                 case isXTest:
997                         fileList = &p.XTestGoFiles
998                         importMap = xTestImportPos
999                         embedMap = xTestEmbedPos
1000                         directives = &p.XTestDirectives
1001                 case isTest:
1002                         fileList = &p.TestGoFiles
1003                         importMap = testImportPos
1004                         embedMap = testEmbedPos
1005                         directives = &p.TestDirectives
1006                 default:
1007                         fileList = &p.GoFiles
1008                         importMap = importPos
1009                         embedMap = embedPos
1010                         directives = &p.Directives
1011                 }
1012                 *fileList = append(*fileList, name)
1013                 if importMap != nil {
1014                         for _, imp := range info.imports {
1015                                 importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
1016                         }
1017                 }
1018                 if embedMap != nil {
1019                         for _, emb := range info.embeds {
1020                                 embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
1021                         }
1022                 }
1023                 if directives != nil {
1024                         *directives = append(*directives, info.directives...)
1025                 }
1026         }
1027
1028         for tag := range allTags {
1029                 p.AllTags = append(p.AllTags, tag)
1030         }
1031         sort.Strings(p.AllTags)
1032
1033         p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
1034         p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
1035         p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
1036
1037         p.Imports, p.ImportPos = cleanDecls(importPos)
1038         p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
1039         p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
1040
1041         // add the .S/.sx files only if we are using cgo
1042         // (which means gcc will compile them).
1043         // The standard assemblers expect .s files.
1044         if len(p.CgoFiles) > 0 {
1045                 p.SFiles = append(p.SFiles, Sfiles...)
1046                 sort.Strings(p.SFiles)
1047         } else {
1048                 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
1049                 sort.Strings(p.IgnoredOtherFiles)
1050         }
1051
1052         if badGoError != nil {
1053                 return p, badGoError
1054         }
1055         if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
1056                 return p, &NoGoError{p.Dir}
1057         }
1058         return p, pkgerr
1059 }
1060
1061 func fileListForExt(p *Package, ext string) *[]string {
1062         switch ext {
1063         case ".c":
1064                 return &p.CFiles
1065         case ".cc", ".cpp", ".cxx":
1066                 return &p.CXXFiles
1067         case ".m":
1068                 return &p.MFiles
1069         case ".h", ".hh", ".hpp", ".hxx":
1070                 return &p.HFiles
1071         case ".f", ".F", ".for", ".f90":
1072                 return &p.FFiles
1073         case ".s", ".S", ".sx":
1074                 return &p.SFiles
1075         case ".swig":
1076                 return &p.SwigFiles
1077         case ".swigcxx":
1078                 return &p.SwigCXXFiles
1079         case ".syso":
1080                 return &p.SysoFiles
1081         }
1082         return nil
1083 }
1084
1085 func uniq(list []string) []string {
1086         if list == nil {
1087                 return nil
1088         }
1089         out := make([]string, len(list))
1090         copy(out, list)
1091         sort.Strings(out)
1092         uniq := out[:0]
1093         for _, x := range out {
1094                 if len(uniq) == 0 || uniq[len(uniq)-1] != x {
1095                         uniq = append(uniq, x)
1096                 }
1097         }
1098         return uniq
1099 }
1100
1101 var errNoModules = errors.New("not using modules")
1102
1103 // importGo checks whether it can use the go command to find the directory for path.
1104 // If using the go command is not appropriate, importGo returns errNoModules.
1105 // Otherwise, importGo tries using the go command and reports whether that succeeded.
1106 // Using the go command lets build.Import and build.Context.Import find code
1107 // in Go modules. In the long term we want tools to use go/packages (currently golang.org/x/tools/go/packages),
1108 // which will also use the go command.
1109 // Invoking the go command here is not very efficient in that it computes information
1110 // about the requested package and all dependencies and then only reports about the requested package.
1111 // Then we reinvoke it for every dependency. But this is still better than not working at all.
1112 // See golang.org/issue/26504.
1113 func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode) error {
1114         // To invoke the go command,
1115         // we must not being doing special things like AllowBinary or IgnoreVendor,
1116         // and all the file system callbacks must be nil (we're meant to use the local file system).
1117         if mode&AllowBinary != 0 || mode&IgnoreVendor != 0 ||
1118                 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) {
1119                 return errNoModules
1120         }
1121
1122         // If ctxt.GOROOT is not set, we don't know which go command to invoke,
1123         // and even if we did we might return packages in GOROOT that we wouldn't otherwise find
1124         // (because we don't know to search in 'go env GOROOT' otherwise).
1125         if ctxt.GOROOT == "" {
1126                 return errNoModules
1127         }
1128
1129         // Predict whether module aware mode is enabled by checking the value of
1130         // GO111MODULE and looking for a go.mod file in the source directory or
1131         // one of its parents. Running 'go env GOMOD' in the source directory would
1132         // give a canonical answer, but we'd prefer not to execute another command.
1133         go111Module := os.Getenv("GO111MODULE")
1134         switch go111Module {
1135         case "off":
1136                 return errNoModules
1137         default: // "", "on", "auto", anything else
1138                 // Maybe use modules.
1139         }
1140
1141         if srcDir != "" {
1142                 var absSrcDir string
1143                 if filepath.IsAbs(srcDir) {
1144                         absSrcDir = srcDir
1145                 } else if ctxt.Dir != "" {
1146                         return fmt.Errorf("go/build: Dir is non-empty, so relative srcDir is not allowed: %v", srcDir)
1147                 } else {
1148                         // Find the absolute source directory. hasSubdir does not handle
1149                         // relative paths (and can't because the callbacks don't support this).
1150                         var err error
1151                         absSrcDir, err = filepath.Abs(srcDir)
1152                         if err != nil {
1153                                 return errNoModules
1154                         }
1155                 }
1156
1157                 // If the source directory is in GOROOT, then the in-process code works fine
1158                 // and we should keep using it. Moreover, the 'go list' approach below doesn't
1159                 // take standard-library vendoring into account and will fail.
1160                 if _, ok := ctxt.hasSubdir(filepath.Join(ctxt.GOROOT, "src"), absSrcDir); ok {
1161                         return errNoModules
1162                 }
1163         }
1164
1165         // For efficiency, if path is a standard library package, let the usual lookup code handle it.
1166         if dir := ctxt.joinPath(ctxt.GOROOT, "src", path); ctxt.isDir(dir) {
1167                 return errNoModules
1168         }
1169
1170         // If GO111MODULE=auto, look to see if there is a go.mod.
1171         // Since go1.13, it doesn't matter if we're inside GOPATH.
1172         if go111Module == "auto" {
1173                 var (
1174                         parent string
1175                         err    error
1176                 )
1177                 if ctxt.Dir == "" {
1178                         parent, err = os.Getwd()
1179                         if err != nil {
1180                                 // A nonexistent working directory can't be in a module.
1181                                 return errNoModules
1182                         }
1183                 } else {
1184                         parent, err = filepath.Abs(ctxt.Dir)
1185                         if err != nil {
1186                                 // If the caller passed a bogus Dir explicitly, that's materially
1187                                 // different from not having modules enabled.
1188                                 return err
1189                         }
1190                 }
1191                 for {
1192                         if f, err := ctxt.openFile(ctxt.joinPath(parent, "go.mod")); err == nil {
1193                                 buf := make([]byte, 100)
1194                                 _, err := f.Read(buf)
1195                                 f.Close()
1196                                 if err == nil || err == io.EOF {
1197                                         // go.mod exists and is readable (is a file, not a directory).
1198                                         break
1199                                 }
1200                         }
1201                         d := filepath.Dir(parent)
1202                         if len(d) >= len(parent) {
1203                                 return errNoModules // reached top of file system, no go.mod
1204                         }
1205                         parent = d
1206                 }
1207         }
1208
1209         goCmd := filepath.Join(ctxt.GOROOT, "bin", "go")
1210         cmd := exec.Command(goCmd, "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)
1211
1212         if ctxt.Dir != "" {
1213                 cmd.Dir = ctxt.Dir
1214         }
1215
1216         var stdout, stderr strings.Builder
1217         cmd.Stdout = &stdout
1218         cmd.Stderr = &stderr
1219
1220         cgo := "0"
1221         if ctxt.CgoEnabled {
1222                 cgo = "1"
1223         }
1224         cmd.Env = append(cmd.Environ(),
1225                 "GOOS="+ctxt.GOOS,
1226                 "GOARCH="+ctxt.GOARCH,
1227                 "GOROOT="+ctxt.GOROOT,
1228                 "GOPATH="+ctxt.GOPATH,
1229                 "CGO_ENABLED="+cgo,
1230         )
1231
1232         if err := cmd.Run(); err != nil {
1233                 return fmt.Errorf("go/build: go list %s: %v\n%s\n", path, err, stderr.String())
1234         }
1235
1236         f := strings.SplitN(stdout.String(), "\n", 5)
1237         if len(f) != 5 {
1238                 return fmt.Errorf("go/build: importGo %s: unexpected output:\n%s\n", path, stdout.String())
1239         }
1240         dir := f[0]
1241         errStr := strings.TrimSpace(f[4])
1242         if errStr != "" && dir == "" {
1243                 // If 'go list' could not locate the package (dir is empty),
1244                 // return the same error that 'go list' reported.
1245                 return errors.New(errStr)
1246         }
1247
1248         // If 'go list' did locate the package, ignore the error.
1249         // It was probably related to loading source files, and we'll
1250         // encounter it ourselves shortly if the FindOnly flag isn't set.
1251         p.Dir = dir
1252         p.ImportPath = f[1]
1253         p.Root = f[2]
1254         p.Goroot = f[3] == "true"
1255         return nil
1256 }
1257
1258 func equal(x, y []string) bool {
1259         if len(x) != len(y) {
1260                 return false
1261         }
1262         for i, xi := range x {
1263                 if xi != y[i] {
1264                         return false
1265                 }
1266         }
1267         return true
1268 }
1269
1270 // hasGoFiles reports whether dir contains any files with names ending in .go.
1271 // For a vendor check we must exclude directories that contain no .go files.
1272 // Otherwise it is not possible to vendor just a/b/c and still import the
1273 // non-vendored a/b. See golang.org/issue/13832.
1274 func hasGoFiles(ctxt *Context, dir string) bool {
1275         ents, _ := ctxt.readDir(dir)
1276         for _, ent := range ents {
1277                 if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") {
1278                         return true
1279                 }
1280         }
1281         return false
1282 }
1283
1284 func findImportComment(data []byte) (s string, line int) {
1285         // expect keyword package
1286         word, data := parseWord(data)
1287         if string(word) != "package" {
1288                 return "", 0
1289         }
1290
1291         // expect package name
1292         _, data = parseWord(data)
1293
1294         // now ready for import comment, a // or /* */ comment
1295         // beginning and ending on the current line.
1296         for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') {
1297                 data = data[1:]
1298         }
1299
1300         var comment []byte
1301         switch {
1302         case bytes.HasPrefix(data, slashSlash):
1303                 comment, _, _ = bytes.Cut(data[2:], newline)
1304         case bytes.HasPrefix(data, slashStar):
1305                 var ok bool
1306                 comment, _, ok = bytes.Cut(data[2:], starSlash)
1307                 if !ok {
1308                         // malformed comment
1309                         return "", 0
1310                 }
1311                 if bytes.Contains(comment, newline) {
1312                         return "", 0
1313                 }
1314         }
1315         comment = bytes.TrimSpace(comment)
1316
1317         // split comment into `import`, `"pkg"`
1318         word, arg := parseWord(comment)
1319         if string(word) != "import" {
1320                 return "", 0
1321         }
1322
1323         line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline)
1324         return strings.TrimSpace(string(arg)), line
1325 }
1326
1327 var (
1328         slashSlash = []byte("//")
1329         slashStar  = []byte("/*")
1330         starSlash  = []byte("*/")
1331         newline    = []byte("\n")
1332 )
1333
1334 // skipSpaceOrComment returns data with any leading spaces or comments removed.
1335 func skipSpaceOrComment(data []byte) []byte {
1336         for len(data) > 0 {
1337                 switch data[0] {
1338                 case ' ', '\t', '\r', '\n':
1339                         data = data[1:]
1340                         continue
1341                 case '/':
1342                         if bytes.HasPrefix(data, slashSlash) {
1343                                 i := bytes.Index(data, newline)
1344                                 if i < 0 {
1345                                         return nil
1346                                 }
1347                                 data = data[i+1:]
1348                                 continue
1349                         }
1350                         if bytes.HasPrefix(data, slashStar) {
1351                                 data = data[2:]
1352                                 i := bytes.Index(data, starSlash)
1353                                 if i < 0 {
1354                                         return nil
1355                                 }
1356                                 data = data[i+2:]
1357                                 continue
1358                         }
1359                 }
1360                 break
1361         }
1362         return data
1363 }
1364
1365 // parseWord skips any leading spaces or comments in data
1366 // and then parses the beginning of data as an identifier or keyword,
1367 // returning that word and what remains after the word.
1368 func parseWord(data []byte) (word, rest []byte) {
1369         data = skipSpaceOrComment(data)
1370
1371         // Parse past leading word characters.
1372         rest = data
1373         for {
1374                 r, size := utf8.DecodeRune(rest)
1375                 if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' {
1376                         rest = rest[size:]
1377                         continue
1378                 }
1379                 break
1380         }
1381
1382         word = data[:len(data)-len(rest)]
1383         if len(word) == 0 {
1384                 return nil, nil
1385         }
1386
1387         return word, rest
1388 }
1389
1390 // MatchFile reports whether the file with the given name in the given directory
1391 // matches the context and would be included in a Package created by ImportDir
1392 // of that directory.
1393 //
1394 // MatchFile considers the name of the file and may use ctxt.OpenFile to
1395 // read some or all of the file's content.
1396 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
1397         info, err := ctxt.matchFile(dir, name, nil, nil, nil)
1398         return info != nil, err
1399 }
1400
1401 var dummyPkg Package
1402
1403 // fileInfo records information learned about a file included in a build.
1404 type fileInfo struct {
1405         name       string // full name including dir
1406         header     []byte
1407         fset       *token.FileSet
1408         parsed     *ast.File
1409         parseErr   error
1410         imports    []fileImport
1411         embeds     []fileEmbed
1412         directives []Directive
1413 }
1414
1415 type fileImport struct {
1416         path string
1417         pos  token.Pos
1418         doc  *ast.CommentGroup
1419 }
1420
1421 type fileEmbed struct {
1422         pattern string
1423         pos     token.Position
1424 }
1425
1426 // matchFile determines whether the file with the given name in the given directory
1427 // should be included in the package being constructed.
1428 // If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
1429 // Non-nil errors are reserved for unexpected problems.
1430 //
1431 // If name denotes a Go program, matchFile reads until the end of the
1432 // imports and returns that section of the file in the fileInfo's header field,
1433 // even though it only considers text until the first non-comment
1434 // for go:build lines.
1435 //
1436 // If allTags is non-nil, matchFile records any encountered build tag
1437 // by setting allTags[tag] = true.
1438 func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
1439         if strings.HasPrefix(name, "_") ||
1440                 strings.HasPrefix(name, ".") {
1441                 return nil, nil
1442         }
1443
1444         i := strings.LastIndex(name, ".")
1445         if i < 0 {
1446                 i = len(name)
1447         }
1448         ext := name[i:]
1449
1450         if ext != ".go" && fileListForExt(&dummyPkg, ext) == nil {
1451                 // skip
1452                 return nil, nil
1453         }
1454
1455         if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
1456                 return nil, nil
1457         }
1458
1459         info := &fileInfo{name: ctxt.joinPath(dir, name), fset: fset}
1460         if ext == ".syso" {
1461                 // binary, no reading
1462                 return info, nil
1463         }
1464
1465         f, err := ctxt.openFile(info.name)
1466         if err != nil {
1467                 return nil, err
1468         }
1469
1470         if strings.HasSuffix(name, ".go") {
1471                 err = readGoInfo(f, info)
1472                 if strings.HasSuffix(name, "_test.go") {
1473                         binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
1474                 }
1475         } else {
1476                 binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
1477                 info.header, err = readComments(f)
1478         }
1479         f.Close()
1480         if err != nil {
1481                 return info, fmt.Errorf("read %s: %v", info.name, err)
1482         }
1483
1484         // Look for go:build comments to accept or reject the file.
1485         ok, sawBinaryOnly, err := ctxt.shouldBuild(info.header, allTags)
1486         if err != nil {
1487                 return nil, fmt.Errorf("%s: %v", name, err)
1488         }
1489         if !ok && !ctxt.UseAllFiles {
1490                 return nil, nil
1491         }
1492
1493         if binaryOnly != nil && sawBinaryOnly {
1494                 *binaryOnly = true
1495         }
1496
1497         return info, nil
1498 }
1499
1500 func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
1501         all := make([]string, 0, len(m))
1502         for path := range m {
1503                 all = append(all, path)
1504         }
1505         sort.Strings(all)
1506         return all, m
1507 }
1508
1509 // Import is shorthand for Default.Import.
1510 func Import(path, srcDir string, mode ImportMode) (*Package, error) {
1511         return Default.Import(path, srcDir, mode)
1512 }
1513
1514 // ImportDir is shorthand for Default.ImportDir.
1515 func ImportDir(dir string, mode ImportMode) (*Package, error) {
1516         return Default.ImportDir(dir, mode)
1517 }
1518
1519 var (
1520         plusBuild = []byte("+build")
1521
1522         goBuildComment = []byte("//go:build")
1523
1524         errMultipleGoBuild = errors.New("multiple //go:build comments")
1525 )
1526
1527 func isGoBuildComment(line []byte) bool {
1528         if !bytes.HasPrefix(line, goBuildComment) {
1529                 return false
1530         }
1531         line = bytes.TrimSpace(line)
1532         rest := line[len(goBuildComment):]
1533         return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
1534 }
1535
1536 // Special comment denoting a binary-only package.
1537 // See https://golang.org/design/2775-binary-only-packages
1538 // for more about the design of binary-only packages.
1539 var binaryOnlyComment = []byte("//go:binary-only-package")
1540
1541 // shouldBuild reports whether it is okay to use this file,
1542 // The rule is that in the file's leading run of // comments
1543 // and blank lines, which must be followed by a blank line
1544 // (to avoid including a Go package clause doc comment),
1545 // lines beginning with '//go:build' are taken as build directives.
1546 //
1547 // The file is accepted only if each such line lists something
1548 // matching the file. For example:
1549 //
1550 //      //go:build windows linux
1551 //
1552 // marks the file as applicable only on Windows and Linux.
1553 //
1554 // For each build tag it consults, shouldBuild sets allTags[tag] = true.
1555 //
1556 // shouldBuild reports whether the file should be built
1557 // and whether a //go:binary-only-package comment was found.
1558 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) (shouldBuild, binaryOnly bool, err error) {
1559         // Identify leading run of // comments and blank lines,
1560         // which must be followed by a blank line.
1561         // Also identify any //go:build comments.
1562         content, goBuild, sawBinaryOnly, err := parseFileHeader(content)
1563         if err != nil {
1564                 return false, false, err
1565         }
1566
1567         // If //go:build line is present, it controls.
1568         // Otherwise fall back to +build processing.
1569         switch {
1570         case goBuild != nil:
1571                 x, err := constraint.Parse(string(goBuild))
1572                 if err != nil {
1573                         return false, false, fmt.Errorf("parsing //go:build line: %v", err)
1574                 }
1575                 shouldBuild = ctxt.eval(x, allTags)
1576
1577         default:
1578                 shouldBuild = true
1579                 p := content
1580                 for len(p) > 0 {
1581                         line := p
1582                         if i := bytes.IndexByte(line, '\n'); i >= 0 {
1583                                 line, p = line[:i], p[i+1:]
1584                         } else {
1585                                 p = p[len(p):]
1586                         }
1587                         line = bytes.TrimSpace(line)
1588                         if !bytes.HasPrefix(line, slashSlash) || !bytes.Contains(line, plusBuild) {
1589                                 continue
1590                         }
1591                         text := string(line)
1592                         if !constraint.IsPlusBuild(text) {
1593                                 continue
1594                         }
1595                         if x, err := constraint.Parse(text); err == nil {
1596                                 if !ctxt.eval(x, allTags) {
1597                                         shouldBuild = false
1598                                 }
1599                         }
1600                 }
1601         }
1602
1603         return shouldBuild, sawBinaryOnly, nil
1604 }
1605
1606 func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
1607         end := 0
1608         p := content
1609         ended := false       // found non-blank, non-// line, so stopped accepting //go:build lines
1610         inSlashStar := false // in /* */ comment
1611
1612 Lines:
1613         for len(p) > 0 {
1614                 line := p
1615                 if i := bytes.IndexByte(line, '\n'); i >= 0 {
1616                         line, p = line[:i], p[i+1:]
1617                 } else {
1618                         p = p[len(p):]
1619                 }
1620                 line = bytes.TrimSpace(line)
1621                 if len(line) == 0 && !ended { // Blank line
1622                         // Remember position of most recent blank line.
1623                         // When we find the first non-blank, non-// line,
1624                         // this "end" position marks the latest file position
1625                         // where a //go:build line can appear.
1626                         // (It must appear _before_ a blank line before the non-blank, non-// line.
1627                         // Yes, that's confusing, which is part of why we moved to //go:build lines.)
1628                         // Note that ended==false here means that inSlashStar==false,
1629                         // since seeing a /* would have set ended==true.
1630                         end = len(content) - len(p)
1631                         continue Lines
1632                 }
1633                 if !bytes.HasPrefix(line, slashSlash) { // Not comment line
1634                         ended = true
1635                 }
1636
1637                 if !inSlashStar && isGoBuildComment(line) {
1638                         if goBuild != nil {
1639                                 return nil, nil, false, errMultipleGoBuild
1640                         }
1641                         goBuild = line
1642                 }
1643                 if !inSlashStar && bytes.Equal(line, binaryOnlyComment) {
1644                         sawBinaryOnly = true
1645                 }
1646
1647         Comments:
1648                 for len(line) > 0 {
1649                         if inSlashStar {
1650                                 if i := bytes.Index(line, starSlash); i >= 0 {
1651                                         inSlashStar = false
1652                                         line = bytes.TrimSpace(line[i+len(starSlash):])
1653                                         continue Comments
1654                                 }
1655                                 continue Lines
1656                         }
1657                         if bytes.HasPrefix(line, slashSlash) {
1658                                 continue Lines
1659                         }
1660                         if bytes.HasPrefix(line, slashStar) {
1661                                 inSlashStar = true
1662                                 line = bytes.TrimSpace(line[len(slashStar):])
1663                                 continue Comments
1664                         }
1665                         // Found non-comment text.
1666                         break Lines
1667                 }
1668         }
1669
1670         return content[:end], goBuild, sawBinaryOnly, nil
1671 }
1672
1673 // saveCgo saves the information from the #cgo lines in the import "C" comment.
1674 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
1675 // that affect the way cgo's C code is built.
1676 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
1677         text := cg.Text()
1678         for _, line := range strings.Split(text, "\n") {
1679                 orig := line
1680
1681                 // Line is
1682                 //      #cgo [GOOS/GOARCH...] LDFLAGS: stuff
1683                 //
1684                 line = strings.TrimSpace(line)
1685                 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
1686                         continue
1687                 }
1688
1689                 // Split at colon.
1690                 line, argstr, ok := strings.Cut(strings.TrimSpace(line[4:]), ":")
1691                 if !ok {
1692                         return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1693                 }
1694
1695                 // Parse GOOS/GOARCH stuff.
1696                 f := strings.Fields(line)
1697                 if len(f) < 1 {
1698                         return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1699                 }
1700
1701                 cond, verb := f[:len(f)-1], f[len(f)-1]
1702                 if len(cond) > 0 {
1703                         ok := false
1704                         for _, c := range cond {
1705                                 if ctxt.matchAuto(c, nil) {
1706                                         ok = true
1707                                         break
1708                                 }
1709                         }
1710                         if !ok {
1711                                 continue
1712                         }
1713                 }
1714
1715                 args, err := splitQuoted(argstr)
1716                 if err != nil {
1717                         return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1718                 }
1719                 for i, arg := range args {
1720                         if arg, ok = expandSrcDir(arg, di.Dir); !ok {
1721                                 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
1722                         }
1723                         args[i] = arg
1724                 }
1725
1726                 switch verb {
1727                 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS":
1728                         // Change relative paths to absolute.
1729                         ctxt.makePathsAbsolute(args, di.Dir)
1730                 }
1731
1732                 switch verb {
1733                 case "CFLAGS":
1734                         di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
1735                 case "CPPFLAGS":
1736                         di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
1737                 case "CXXFLAGS":
1738                         di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
1739                 case "FFLAGS":
1740                         di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
1741                 case "LDFLAGS":
1742                         di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
1743                 case "pkg-config":
1744                         di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
1745                 default:
1746                         return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
1747                 }
1748         }
1749         return nil
1750 }
1751
1752 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure
1753 // the result is safe for the shell.
1754 func expandSrcDir(str string, srcdir string) (string, bool) {
1755         // "\" delimited paths cause safeCgoName to fail
1756         // so convert native paths with a different delimiter
1757         // to "/" before starting (eg: on windows).
1758         srcdir = filepath.ToSlash(srcdir)
1759
1760         chunks := strings.Split(str, "${SRCDIR}")
1761         if len(chunks) < 2 {
1762                 return str, safeCgoName(str)
1763         }
1764         ok := true
1765         for _, chunk := range chunks {
1766                 ok = ok && (chunk == "" || safeCgoName(chunk))
1767         }
1768         ok = ok && (srcdir == "" || safeCgoName(srcdir))
1769         res := strings.Join(chunks, srcdir)
1770         return res, ok && res != ""
1771 }
1772
1773 // makePathsAbsolute looks for compiler options that take paths and
1774 // makes them absolute. We do this because through the 1.8 release we
1775 // ran the compiler in the package directory, so any relative -I or -L
1776 // options would be relative to that directory. In 1.9 we changed to
1777 // running the compiler in the build directory, to get consistent
1778 // build results (issue #19964). To keep builds working, we change any
1779 // relative -I or -L options to be absolute.
1780 //
1781 // Using filepath.IsAbs and filepath.Join here means the results will be
1782 // different on different systems, but that's OK: -I and -L options are
1783 // inherently system-dependent.
1784 func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) {
1785         nextPath := false
1786         for i, arg := range args {
1787                 if nextPath {
1788                         if !filepath.IsAbs(arg) {
1789                                 args[i] = filepath.Join(srcDir, arg)
1790                         }
1791                         nextPath = false
1792                 } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
1793                         if len(arg) == 2 {
1794                                 nextPath = true
1795                         } else {
1796                                 if !filepath.IsAbs(arg[2:]) {
1797                                         args[i] = arg[:2] + filepath.Join(srcDir, arg[2:])
1798                                 }
1799                         }
1800                 }
1801         }
1802 }
1803
1804 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
1805 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
1806 // See golang.org/issue/6038.
1807 // The @ is for OS X. See golang.org/issue/13720.
1808 // The % is for Jenkins. See golang.org/issue/16959.
1809 // The ! is because module paths may use them. See golang.org/issue/26716.
1810 // The ~ and ^ are for sr.ht. See golang.org/issue/32260.
1811 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%! ~^"
1812
1813 func safeCgoName(s string) bool {
1814         if s == "" {
1815                 return false
1816         }
1817         for i := 0; i < len(s); i++ {
1818                 if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 {
1819                         return false
1820                 }
1821         }
1822         return true
1823 }
1824
1825 // splitQuoted splits the string s around each instance of one or more consecutive
1826 // white space characters while taking into account quotes and escaping, and
1827 // returns an array of substrings of s or an empty list if s contains only white space.
1828 // Single quotes and double quotes are recognized to prevent splitting within the
1829 // quoted region, and are removed from the resulting substrings. If a quote in s
1830 // isn't closed err will be set and r will have the unclosed argument as the
1831 // last element. The backslash is used for escaping.
1832 //
1833 // For example, the following string:
1834 //
1835 //      a b:"c d" 'e''f'  "g\""
1836 //
1837 // Would be parsed as:
1838 //
1839 //      []string{"a", "b:c d", "ef", `g"`}
1840 func splitQuoted(s string) (r []string, err error) {
1841         var args []string
1842         arg := make([]rune, len(s))
1843         escaped := false
1844         quoted := false
1845         quote := '\x00'
1846         i := 0
1847         for _, rune := range s {
1848                 switch {
1849                 case escaped:
1850                         escaped = false
1851                 case rune == '\\':
1852                         escaped = true
1853                         continue
1854                 case quote != '\x00':
1855                         if rune == quote {
1856                                 quote = '\x00'
1857                                 continue
1858                         }
1859                 case rune == '"' || rune == '\'':
1860                         quoted = true
1861                         quote = rune
1862                         continue
1863                 case unicode.IsSpace(rune):
1864                         if quoted || i > 0 {
1865                                 quoted = false
1866                                 args = append(args, string(arg[:i]))
1867                                 i = 0
1868                         }
1869                         continue
1870                 }
1871                 arg[i] = rune
1872                 i++
1873         }
1874         if quoted || i > 0 {
1875                 args = append(args, string(arg[:i]))
1876         }
1877         if quote != 0 {
1878                 err = errors.New("unclosed quote")
1879         } else if escaped {
1880                 err = errors.New("unfinished escaping")
1881         }
1882         return args, err
1883 }
1884
1885 // matchAuto interprets text as either a +build or //go:build expression (whichever works),
1886 // reporting whether the expression matches the build context.
1887 //
1888 // matchAuto is only used for testing of tag evaluation
1889 // and in #cgo lines, which accept either syntax.
1890 func (ctxt *Context) matchAuto(text string, allTags map[string]bool) bool {
1891         if strings.ContainsAny(text, "&|()") {
1892                 text = "//go:build " + text
1893         } else {
1894                 text = "// +build " + text
1895         }
1896         x, err := constraint.Parse(text)
1897         if err != nil {
1898                 return false
1899         }
1900         return ctxt.eval(x, allTags)
1901 }
1902
1903 func (ctxt *Context) eval(x constraint.Expr, allTags map[string]bool) bool {
1904         return x.Eval(func(tag string) bool { return ctxt.matchTag(tag, allTags) })
1905 }
1906
1907 // matchTag reports whether the name is one of:
1908 //
1909 //      cgo (if cgo is enabled)
1910 //      $GOOS
1911 //      $GOARCH
1912 //      ctxt.Compiler
1913 //      linux (if GOOS = android)
1914 //      solaris (if GOOS = illumos)
1915 //      darwin (if GOOS = ios)
1916 //      unix (if this is a Unix GOOS)
1917 //      boringcrypto (if GOEXPERIMENT=boringcrypto is enabled)
1918 //      tag (if tag is listed in ctxt.BuildTags, ctxt.ToolTags, or ctxt.ReleaseTags)
1919 //
1920 // It records all consulted tags in allTags.
1921 func (ctxt *Context) matchTag(name string, allTags map[string]bool) bool {
1922         if allTags != nil {
1923                 allTags[name] = true
1924         }
1925
1926         // special tags
1927         if ctxt.CgoEnabled && name == "cgo" {
1928                 return true
1929         }
1930         if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
1931                 return true
1932         }
1933         if ctxt.GOOS == "android" && name == "linux" {
1934                 return true
1935         }
1936         if ctxt.GOOS == "illumos" && name == "solaris" {
1937                 return true
1938         }
1939         if ctxt.GOOS == "ios" && name == "darwin" {
1940                 return true
1941         }
1942         if name == "unix" && unixOS[ctxt.GOOS] {
1943                 return true
1944         }
1945         if name == "boringcrypto" {
1946                 name = "goexperiment.boringcrypto" // boringcrypto is an old name for goexperiment.boringcrypto
1947         }
1948
1949         // other tags
1950         for _, tag := range ctxt.BuildTags {
1951                 if tag == name {
1952                         return true
1953                 }
1954         }
1955         for _, tag := range ctxt.ToolTags {
1956                 if tag == name {
1957                         return true
1958                 }
1959         }
1960         for _, tag := range ctxt.ReleaseTags {
1961                 if tag == name {
1962                         return true
1963                 }
1964         }
1965
1966         return false
1967 }
1968
1969 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
1970 // suffix which does not match the current system.
1971 // The recognized name formats are:
1972 //
1973 //      name_$(GOOS).*
1974 //      name_$(GOARCH).*
1975 //      name_$(GOOS)_$(GOARCH).*
1976 //      name_$(GOOS)_test.*
1977 //      name_$(GOARCH)_test.*
1978 //      name_$(GOOS)_$(GOARCH)_test.*
1979 //
1980 // Exceptions:
1981 // if GOOS=android, then files with GOOS=linux are also matched.
1982 // if GOOS=illumos, then files with GOOS=solaris are also matched.
1983 // if GOOS=ios, then files with GOOS=darwin are also matched.
1984 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
1985         name, _, _ = strings.Cut(name, ".")
1986
1987         // Before Go 1.4, a file called "linux.go" would be equivalent to having a
1988         // build tag "linux" in that file. For Go 1.4 and beyond, we require this
1989         // auto-tagging to apply only to files with a non-empty prefix, so
1990         // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
1991         // systems, such as android, to arrive without breaking existing code with
1992         // innocuous source code in "android.go". The easiest fix: cut everything
1993         // in the name before the initial _.
1994         i := strings.Index(name, "_")
1995         if i < 0 {
1996                 return true
1997         }
1998         name = name[i:] // ignore everything before first _
1999
2000         l := strings.Split(name, "_")
2001         if n := len(l); n > 0 && l[n-1] == "test" {
2002                 l = l[:n-1]
2003         }
2004         n := len(l)
2005         if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
2006                 if allTags != nil {
2007                         // In case we short-circuit on l[n-1].
2008                         allTags[l[n-2]] = true
2009                 }
2010                 return ctxt.matchTag(l[n-1], allTags) && ctxt.matchTag(l[n-2], allTags)
2011         }
2012         if n >= 1 && (knownOS[l[n-1]] || knownArch[l[n-1]]) {
2013                 return ctxt.matchTag(l[n-1], allTags)
2014         }
2015         return true
2016 }
2017
2018 // ToolDir is the directory containing build tools.
2019 var ToolDir = getToolDir()
2020
2021 // IsLocalImport reports whether the import path is
2022 // a local import path, like ".", "..", "./foo", or "../foo".
2023 func IsLocalImport(path string) bool {
2024         return path == "." || path == ".." ||
2025                 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
2026 }
2027
2028 // ArchChar returns "?" and an error.
2029 // In earlier versions of Go, the returned string was used to derive
2030 // the compiler and linker tool names, the default object file suffix,
2031 // and the default linker output name. As of Go 1.5, those strings
2032 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
2033 func ArchChar(goarch string) (string, error) {
2034         return "?", errors.New("architecture letter no longer used")
2035 }