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