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