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