Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package build

import (
	
	
	
	
	
	
	exec 
	
	
	
	
	
	
	pathpkg 
	
	
	
	
	
	
	
)
A Context specifies the supporting context for a build.
type Context struct {
	GOARCH string // target architecture
	GOOS   string // target operating system
	GOROOT string // Go root
	GOPATH string // Go path
Dir is the caller's working directory, or the empty string to use the current directory of the running process. In module mode, this is used to locate the main module. If Dir is non-empty, directories passed to Import and ImportDir must be absolute.
	Dir string

	CgoEnabled  bool   // whether cgo files are included
	UseAllFiles bool   // use files regardless of +build lines, file names
	Compiler    string // compiler to assume when computing target paths
The build and release tags specify build constraints that should be considered satisfied when processing +build lines. Clients creating a new context may customize BuildTags, which defaults to empty, but it is usually an error to customize ReleaseTags, which defaults to the list of Go releases the current release is compatible with. BuildTags is not set for the Default build Context. In addition to the BuildTags and ReleaseTags, build constraints consider the values of GOARCH and GOOS as satisfied tags. The last element in ReleaseTags is assumed to be the current release.
The install suffix specifies a suffix to use in the name of the installation directory. By default it is empty, but custom builds that need to keep their outputs separate can set InstallSuffix to do so. For example, when using the race detector, the go command uses InstallSuffix = "race", so that on a Linux/386 system, packages are written to a directory named "linux_386_race" instead of the usual "linux_386".
By default, Import uses the operating system's file system calls to read directories and files. To read from other sources, callers can set the following functions. They all have default behaviors that use the local file system, so clients need only set the functions whose behaviors they wish to change.
JoinPath joins the sequence of path fragments into a single path. If JoinPath is nil, Import uses filepath.Join.
	JoinPath func(elem ...string) string
SplitPathList splits the path list into a slice of individual paths. If SplitPathList is nil, Import uses filepath.SplitList.
	SplitPathList func(list string) []string
IsAbsPath reports whether path is an absolute path. If IsAbsPath is nil, Import uses filepath.IsAbs.
	IsAbsPath func(path string) bool
IsDir reports whether the path names a directory. If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
	IsDir func(path string) bool
HasSubdir reports whether dir is lexically a subdirectory of root, perhaps multiple levels below. It does not try to check whether dir exists. If so, HasSubdir sets rel to a slash-separated path that can be joined to root to produce a path equivalent to dir. If HasSubdir is nil, Import uses an implementation built on filepath.EvalSymlinks.
	HasSubdir func(root, dir string) (rel string, ok bool)
ReadDir returns a slice of fs.FileInfo, sorted by Name, describing the content of the named directory. If ReadDir is nil, Import uses ioutil.ReadDir.
	ReadDir func(dir string) ([]fs.FileInfo, error)
OpenFile opens a file (not a directory) for reading. If OpenFile is nil, Import uses os.Open.
	OpenFile func(path string) (io.ReadCloser, error)
}
joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
func ( *Context) ( ...string) string {
	if  := .JoinPath;  != nil {
		return (...)
	}
	return filepath.Join(...)
}
splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
func ( *Context) ( string) []string {
	if  := .SplitPathList;  != nil {
		return ()
	}
	return filepath.SplitList()
}
isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs.
func ( *Context) ( string) bool {
	if  := .IsAbsPath;  != nil {
		return ()
	}
	return filepath.IsAbs()
}
isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
func ( *Context) ( string) bool {
	if  := .IsDir;  != nil {
		return ()
	}
	,  := os.Stat()
	return  == nil && .IsDir()
}
hasSubdir calls ctxt.HasSubdir (if not nil) or else uses the local file system to answer the question.
func ( *Context) (,  string) ( string,  bool) {
	if  := .HasSubdir;  != nil {
		return (, )
	}
Try using paths we received.
	if ,  = hasSubdir(, );  {
		return
	}
Try expanding symlinks and comparing expanded against unexpanded and expanded against expanded.
	,  := filepath.EvalSymlinks()
	,  := filepath.EvalSymlinks()

	if ,  = hasSubdir(, );  {
		return
	}
	if ,  = hasSubdir(, );  {
		return
	}
	return hasSubdir(, )
}
hasSubdir reports if dir is within root by performing lexical analysis only.
func (,  string) ( string,  bool) {
	const  = string(filepath.Separator)
	 = filepath.Clean()
	if !strings.HasSuffix(, ) {
		 += 
	}
	 = filepath.Clean()
	if !strings.HasPrefix(, ) {
		return "", false
	}
	return filepath.ToSlash([len():]), true
}
readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
func ( *Context) ( string) ([]fs.FileInfo, error) {
	if  := .ReadDir;  != nil {
		return ()
	}
	return ioutil.ReadDir()
}
openFile calls ctxt.OpenFile (if not nil) or else os.Open.
func ( *Context) ( string) (io.ReadCloser, error) {
	if  := .OpenFile;  != nil {
		return ()
	}

	,  := os.Open()
	if  != nil {
		return nil,  // nil interface
	}
	return , nil
}
isFile determines whether path is a file by trying to open it. It reuses openFile instead of adding another function to the list in Context.
func ( *Context) ( string) bool {
	,  := .openFile()
	if  != nil {
		return false
	}
	.Close()
	return true
}
gopath returns the list of Go path directories.
func ( *Context) () []string {
	var  []string
	for ,  := range .splitPathList(.GOPATH) {
Empty paths are uninteresting. If the path is the GOROOT, ignore it. People sometimes set GOPATH=$GOROOT. Do not get confused by this common mistake.
			continue
		}
Path segments starting with ~ on Unix are almost always users who have incorrectly quoted ~ while setting GOPATH, preventing it from expanding to $HOME. The situation is made more confusing by the fact that bash allows quoted ~ in $PATH (most shells do not). Do not get confused by this, and do not try to use the path. It does not exist, and printing errors about it confuses those users even more, because they think "sure ~ exists!". The go command diagnoses this situation and prints a useful error. On Windows, ~ is used in short names, such as c:\progra~1 for c:\program files.
			continue
		}
		 = append(, )
	}
	return 
}
SrcDirs returns a list of package source root directories. It draws from the current Go root and Go path but omits directories that do not exist.
func ( *Context) () []string {
	var  []string
	if .GOROOT != "" && .Compiler != "gccgo" {
		 := .joinPath(.GOROOT, "src")
		if .isDir() {
			 = append(, )
		}
	}
	for ,  := range .gopath() {
		 := .joinPath(, "src")
		if .isDir() {
			 = append(, )
		}
	}
	return 
}
Default is the default Context for builds. It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
var Default Context = defaultContext()

func () string {
	 := "HOME"
	if runtime.GOOS == "windows" {
		 = "USERPROFILE"
	} else if runtime.GOOS == "plan9" {
		 = "home"
	}
	if  := os.Getenv();  != "" {
		 := filepath.Join(, "go")
Don't set the default GOPATH to GOROOT, as that will trigger warnings from the go tool.
			return ""
		}
		return 
	}
	return ""
}

var defaultReleaseTags []string

func () Context {
	var  Context

	.GOARCH = envOr("GOARCH", runtime.GOARCH)
	.GOOS = envOr("GOOS", runtime.GOOS)
	.GOROOT = pathpkg.Clean(runtime.GOROOT())
	.GOPATH = envOr("GOPATH", defaultGOPATH())
	.Compiler = runtime.Compiler
Each major Go release in the Go 1.x series adds a new "go1.x" release tag. That is, the go1.x tag is present in all releases >= Go 1.x. Code that requires Go 1.x or later should say "+build go1.x", and code that should only be built before Go 1.x (perhaps it is the stub to use in that case) should say "+build !go1.x". The last element in ReleaseTags is the current release.
	for  := 1;  <= goversion.Version; ++ {
		.ReleaseTags = append(.ReleaseTags, "go1."+strconv.Itoa())
	}

	defaultReleaseTags = append([]string{}, .ReleaseTags...) // our own private copy

	 := os.Getenv("CGO_ENABLED")
	if  == "" {
		 = defaultCGO_ENABLED
	}
	switch  {
	case "1":
		.CgoEnabled = true
	case "0":
		.CgoEnabled = false
cgo must be explicitly enabled for cross compilation builds
		if runtime.GOARCH == .GOARCH && runtime.GOOS == .GOOS {
			.CgoEnabled = cgoEnabled[.GOOS+"/"+.GOARCH]
			break
		}
		.CgoEnabled = false
	}

	return 
}

func (,  string) string {
	 := os.Getenv()
	if  == "" {
		return 
	}
	return 
}
An ImportMode controls the behavior of the Import method.
If FindOnly is set, Import stops after locating the directory that should contain the sources for a package. It does not read any files in the directory.
If AllowBinary is set, Import can be satisfied by a compiled package object without corresponding sources. Deprecated: The supported way to create a compiled-only package is to write source code containing a //go:binary-only-package comment at the top of the file. Such a package will be recognized regardless of this flag setting (because it has source code) and will have BinaryOnly set to true in the returned Package.
If ImportComment is set, parse import comments on package statements. Import returns an error if it finds a comment it cannot understand or finds conflicting comments in multiple source files. See golang.org/s/go14customimport for more information.
By default, Import searches vendor directories that apply in the given source directory before searching the GOROOT and GOPATH roots. If an Import finds and returns a package using a vendor directory, the resulting ImportPath is the complete path to the package, including the path elements leading up to and including "vendor". For example, if Import("y", "x/subdir", 0) finds "x/vendor/y", the returned package's ImportPath is "x/vendor/y", not plain "y". See golang.org/s/go15vendor for more information. Setting IgnoreVendor ignores vendor directories. In contrast to the package's ImportPath, the returned package's Imports, TestImports, and XTestImports are always the exact import paths from the source files: Import makes no attempt to resolve or check those paths.
A Package describes the Go package found in a directory.
type Package struct {
	Dir           string   // directory containing package sources
	Name          string   // package name
	ImportComment string   // path in import comment on package statement
	Doc           string   // documentation synopsis
	ImportPath    string   // import path of package ("" if unknown)
	Root          string   // root of Go tree where this package lives
	SrcRoot       string   // package source root directory ("" if unknown)
	PkgRoot       string   // package install root directory ("" if unknown)
	PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
	BinDir        string   // command install directory ("" if unknown)
	Goroot        bool     // package found in Go root
	PkgObj        string   // installed .a file
	AllTags       []string // tags that can influence file selection in this directory
	ConflictDir   string   // this directory shadows Dir in $GOPATH
	BinaryOnly    bool     // cannot be rebuilt from source (has //go:binary-only-package comment)
Source files
	GoFiles           []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
	CgoFiles          []string // .go source files that import "C"
	IgnoredGoFiles    []string // .go source files ignored for this build (including ignored _test.go files)
	InvalidGoFiles    []string // .go source files with detected problems (parse error, wrong package name, and so on)
	IgnoredOtherFiles []string // non-.go source files ignored for this build
	CFiles            []string // .c source files
	CXXFiles          []string // .cc, .cpp and .cxx source files
	MFiles            []string // .m (Objective-C) source files
	HFiles            []string // .h, .hh, .hpp and .hxx source files
	FFiles            []string // .f, .F, .for and .f90 Fortran source files
	SFiles            []string // .s source files
	SwigFiles         []string // .swig files
	SwigCXXFiles      []string // .swigcxx files
	SysoFiles         []string // .syso system object files to add to archive
Cgo directives
	CgoCFLAGS    []string // Cgo CFLAGS directives
	CgoCPPFLAGS  []string // Cgo CPPFLAGS directives
	CgoCXXFLAGS  []string // Cgo CXXFLAGS directives
	CgoFFLAGS    []string // Cgo FFLAGS directives
	CgoLDFLAGS   []string // Cgo LDFLAGS directives
	CgoPkgConfig []string // Cgo pkg-config directives
Test information
	TestGoFiles  []string // _test.go files in package
	XTestGoFiles []string // _test.go files outside package
Dependency information
	Imports        []string                    // import paths from GoFiles, CgoFiles
	ImportPos      map[string][]token.Position // line information for Imports
	TestImports    []string                    // import paths from TestGoFiles
	TestImportPos  map[string][]token.Position // line information for TestImports
	XTestImports   []string                    // import paths from XTestGoFiles
	XTestImportPos map[string][]token.Position // line information for XTestImports
//go:embed patterns found in Go source files For example, if a source file says //go:embed a* b.c then the list will contain those two strings as separate entries. (See package embed for more details about //go:embed.)
	EmbedPatterns        []string                    // patterns from GoFiles, CgoFiles
	EmbedPatternPos      map[string][]token.Position // line information for EmbedPatterns
	TestEmbedPatterns    []string                    // patterns from TestGoFiles
	TestEmbedPatternPos  map[string][]token.Position // line information for TestEmbedPatterns
	XTestEmbedPatterns   []string                    // patterns from XTestGoFiles
	XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
}
IsCommand reports whether the package is considered a command to be installed (not just a library). Packages named "main" are treated as commands.
func ( *Package) () bool {
	return .Name == "main"
}
ImportDir is like Import but processes the Go package found in the named directory.
func ( *Context) ( string,  ImportMode) (*Package, error) {
	return .Import(".", , )
}
NoGoError is the error used by Import to describe a directory containing no buildable Go source files. (It may still contain test files, files hidden by build tags, and so on.)
type NoGoError struct {
	Dir string
}

func ( *NoGoError) () string {
	return "no buildable Go source files in " + .Dir
}
MultiplePackageError describes a directory containing multiple buildable Go source files for multiple packages.
type MultiplePackageError struct {
	Dir      string   // directory containing files
	Packages []string // package names found
	Files    []string // corresponding files: Files[i] declares package Packages[i]
}

Error string limited to two entries for compatibility.
	return fmt.Sprintf("found packages %s (%s) and %s (%s) in %s", .Packages[0], .Files[0], .Packages[1], .Files[1], .Dir)
}

func ( string) string {
	 := strings.LastIndex(, ".")
	if  < 0 {
		return ""
	}
	return [:]
}
Import returns details about the Go package named by the import path, interpreting local import paths relative to the srcDir directory. If the path is a local import path naming a package that can be imported using a standard import path, the returned package will set p.ImportPath to that path. In the directory containing the package, .go, .c, .h, and .s files are considered part of the package except for: - .go files in package documentation - files starting with _ or . (likely editor temporary files) - files with build constraints not satisfied by the context If an error occurs, Import returns a non-nil error and a non-nil *Package containing partial information.
func ( *Context) ( string,  string,  ImportMode) (*Package, error) {
	 := &Package{
		ImportPath: ,
	}
	if  == "" {
		return , fmt.Errorf("import %q: invalid import path", )
	}

	var  string
	var  string
	var  error
	 := ""
	if .InstallSuffix != "" {
		 = "_" + .InstallSuffix
	}
	switch .Compiler {
	case "gccgo":
		 = "pkg/gccgo_" + .GOOS + "_" + .GOARCH + 
	case "gc":
		 = "pkg/" + .GOOS + "_" + .GOARCH + 
Save error for end of function.
		 = fmt.Errorf("import %q: unknown compiler %q", , .Compiler)
	}
	 := func() {
		switch .Compiler {
		case "gccgo":
			,  := pathpkg.Split(.ImportPath)
			 =  + "/" +  + "lib" +  + ".a"
		case "gc":
			 =  + "/" + .ImportPath + ".a"
		}
	}
	()

	 := false
	if IsLocalImport() {
		 = "" // local imports have no installed path
		if  == "" {
			return , fmt.Errorf("import %q: import relative to unknown directory", )
		}
		if !.isAbsPath() {
			.Dir = .joinPath(, )
p.Dir directory may or may not exist. Gather partial information first, check if it exists later. Determine canonical import path, if any. Exclude results where the import path would include /testdata/.
		 := func( string) bool {
			return strings.Contains(, "/testdata/") || strings.HasSuffix(, "/testdata") || strings.HasPrefix(, "testdata/") ||  == "testdata"
		}
		if .GOROOT != "" {
			 := .joinPath(.GOROOT, "src")
			if ,  := .hasSubdir(, .Dir);  && !() {
				.Goroot = true
				.ImportPath = 
				.Root = .GOROOT
				() // p.ImportPath changed
				goto 
			}
		}
		 := .gopath()
		for ,  := range  {
			 := .joinPath(, "src")
We found a potential import path for dir, but check that using it wouldn't find something else first.
				if .GOROOT != "" && .Compiler != "gccgo" {
					if  := .joinPath(.GOROOT, "src", ); .isDir() {
						.ConflictDir = 
						goto 
					}
				}
				for ,  := range [:] {
					if  := .joinPath(, "src", ); .isDir() {
						.ConflictDir = 
						goto 
					}
				}
sub would not name some other directory instead of this one. Record it.
				.ImportPath = 
				.Root = 
				() // p.ImportPath changed
				goto 
			}
It's okay that we didn't find a root containing dir. Keep going with the information we have.
	} else {
		if strings.HasPrefix(, "/") {
			return , fmt.Errorf("import %q: cannot import absolute path", )
		}

		if  := .importGo(, , , );  == nil {
			goto 
		} else if  != errNoModules {
			return , 
		}

		 := .gopath() // needed twice below; avoid computing many times
tried records the location of unsuccessful package lookups
		var  struct {
			 []string
			 string
			 []string
		}
Vendor directories get first chance to satisfy import.
		if &IgnoreVendor == 0 &&  != "" {
			 := func( string,  bool) bool {
				,  := .hasSubdir(, )
				if ! || !strings.HasPrefix(, "src/") || strings.Contains(, "/testdata/") {
					return false
				}
				for {
					 := .joinPath(, , "vendor")
					if .isDir() {
						 := .joinPath(, )
						if .isDir() && hasGoFiles(, ) {
							.Dir = 
							.ImportPath = strings.TrimPrefix(pathpkg.Join(, "vendor", ), "src/")
							.Goroot = 
							.Root = 
							() // p.ImportPath changed
							return true
						}
						. = append(., )
					}
					 := strings.LastIndex(, "/")
					if  < 0 {
						break
					}
					 = [:]
				}
				return false
			}
			if .Compiler != "gccgo" && (.GOROOT, true) {
				goto 
			}
			for ,  := range  {
				if (, false) {
					goto 
				}
			}
		}
Determine directory from import path.
If the package path starts with "vendor/", only search GOROOT before GOPATH if the importer is also within GOROOT. That way, if the user has vendored in a package that is subsequently included in the standard distribution, they'll continue to pick up their own vendored copy.
			 :=  == "" || !strings.HasPrefix(, "vendor/")
			if ! {
				_,  = .hasSubdir(.GOROOT, )
			}
			if  {
				 := .joinPath(.GOROOT, "src", )
				if .Compiler != "gccgo" {
					 := .isDir()
					 = ! && &AllowBinary != 0 &&  != "" && .isFile(.joinPath(.GOROOT, ))
					if  ||  {
						.Dir = 
						.Goroot = true
						.Root = .GOROOT
						goto 
					}
				}
				. = 
			}
		}
		if .Compiler == "gccgo" && goroot.IsStandardPackage(.GOROOT, .Compiler, ) {
			.Dir = .joinPath(.GOROOT, "src", )
			.Goroot = true
			.Root = .GOROOT
			goto 
		}
		for ,  := range  {
			 := .joinPath(, "src", )
			 := .isDir()
			 = ! && &AllowBinary != 0 &&  != "" && .isFile(.joinPath(, ))
			if  ||  {
				.Dir = 
				.Root = 
				goto 
			}
			. = append(., )
		}
If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH. That way, the user can still get useful results from 'go list' for standard-vendored paths passed on the command line.
		if .GOROOT != "" && . == "" {
			 := .joinPath(.GOROOT, "src", )
			if .Compiler != "gccgo" {
				 := .isDir()
				 = ! && &AllowBinary != 0 &&  != "" && .isFile(.joinPath(.GOROOT, ))
				if  ||  {
					.Dir = 
					.Goroot = true
					.Root = .GOROOT
					goto 
				}
			}
			. = 
		}
package was not found
		var  []string
		 := "\t%s (vendor tree)"
		for ,  := range . {
			 = append(, fmt.Sprintf(, ))
			 = "\t%s"
		}
		if . != "" {
			 = append(, fmt.Sprintf("\t%s (from $GOROOT)", .))
		} else {
			 = append(, "\t($GOROOT not set)")
		}
		 = "\t%s (from $GOPATH)"
		for ,  := range . {
			 = append(, fmt.Sprintf(, ))
			 = "\t%s"
		}
		if len(.) == 0 {
			 = append(, "\t($GOPATH not set. For more details see: 'go help gopath')")
		}
		return , fmt.Errorf("cannot find package %q in any of:\n%s", , strings.Join(, "\n"))
	}

:
	if .Root != "" {
		.SrcRoot = .joinPath(.Root, "src")
		.PkgRoot = .joinPath(.Root, "pkg")
		.BinDir = .joinPath(.Root, "bin")
		if  != "" {
			.PkgTargetRoot = .joinPath(.Root, )
			.PkgObj = .joinPath(.Root, )
		}
	}
If it's a local import path, by the time we get here, we still haven't checked that p.Dir directory exists. This is the right time to do that check. We can't do it earlier, because we want to gather partial information for the non-nil *Package returned when an error occurs. We need to do this before we return early on FindOnly flag.
	if IsLocalImport() && !.isDir(.Dir) {
gccgo has no sources for GOROOT packages.
			return , nil
		}
package was not found
		return , fmt.Errorf("cannot find package %q in:\n\t%s", , .Dir)
	}

	if &FindOnly != 0 {
		return , 
	}
	if  && (&AllowBinary) != 0 {
		return , 
	}

gccgo has no sources for GOROOT packages.
		return , nil
	}

	,  := .readDir(.Dir)
	if  != nil {
		return , 
	}

	var  error
	var  []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
	var ,  string
	 := make(map[string][]token.Position)
	 := make(map[string][]token.Position)
	 := make(map[string][]token.Position)
	 := make(map[string][]token.Position)
	 := make(map[string][]token.Position)
	 := make(map[string][]token.Position)
	 := make(map[string]bool)
	 := token.NewFileSet()
	for ,  := range  {
		if .IsDir() {
			continue
		}
		if .Mode()&fs.ModeSymlink != 0 {
Symlinks to directories are not source files.
				continue
			}
		}

		 := .Name()
		 := nameExt()

		 := func( error) {
			if  == nil {
				 = 
			}
			.InvalidGoFiles = append(.InvalidGoFiles, )
		}

		,  := .matchFile(.Dir, , , &.BinaryOnly, )
		if  != nil {
			()
			continue
		}
		if  == nil {
not due to build constraints - don't report
			} else if  == ".go" {
				.IgnoredGoFiles = append(.IgnoredGoFiles, )
			} else if fileListForExt(, ) != nil {
				.IgnoredOtherFiles = append(.IgnoredOtherFiles, )
			}
			continue
		}
		,  := .header, .name
Going to save the file. For non-Go files, can stop here.
		switch  {
keep going
special case for cgo, handled at end
			 = append(, )
			continue
		default:
			if  := fileListForExt(, );  != nil {
				* = append(*, )
			}
			continue
		}

		if .parseErr != nil {
			(.parseErr)
			continue
		}
		 := .parsed

		 := .Name.Name
		if  == "documentation" {
			.IgnoredGoFiles = append(.IgnoredGoFiles, )
			continue
		}

		 := strings.HasSuffix(, "_test.go")
		 := false
		if  && strings.HasSuffix(, "_test") {
			 = true
			 = [:len()-len("_test")]
		}

		if .Name == "" {
			.Name = 
			 = 
		} else if  != .Name {
			(&MultiplePackageError{
				Dir:      .Dir,
				Packages: []string{.Name, },
				Files:    []string{, },
			})
			.InvalidGoFiles = append(.InvalidGoFiles, )
Grab the first package comment as docs, provided it is not from a test file.
		if .Doc != nil && .Doc == "" && ! && ! {
			.Doc = doc.Synopsis(.Doc.Text())
		}

		if &ImportComment != 0 {
			,  := findImportComment()
			if  != 0 {
				,  := strconv.Unquote()
				if  != nil {
					(fmt.Errorf("%s:%d: cannot parse import comment", , ))
				} else if .ImportComment == "" {
					.ImportComment = 
					 = 
				} else if .ImportComment !=  {
					(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", .ImportComment, , , , .Dir))
				}
			}
		}
Record imports and information about cgo.
		 := false
		for ,  := range .imports {
			if .path == "C" {
				if  {
					(fmt.Errorf("use of cgo in test %s not supported", ))
					continue
				}
				 = true
				if .doc != nil {
					if  := .saveCgo(, , .doc);  != nil {
						()
					}
				}
			}
		}

		var  *[]string
		var ,  map[string][]token.Position
		switch {
		case :
			["cgo"] = true
			if .CgoEnabled {
				 = &.CgoFiles
				 = 
				 = 
Ignore imports and embeds from cgo files if cgo is disabled.
				 = &.IgnoredGoFiles
			}
		case :
			 = &.XTestGoFiles
			 = 
			 = 
		case :
			 = &.TestGoFiles
			 = 
			 = 
		default:
			 = &.GoFiles
			 = 
			 = 
		}
		* = append(*, )
		if  != nil {
			for ,  := range .imports {
				[.path] = append([.path], .Position(.pos))
			}
		}
		if  != nil {
			for ,  := range .embeds {
				[.pattern] = append([.pattern], .pos)
			}
		}
	}

	for  := range  {
		.AllTags = append(.AllTags, )
	}
	sort.Strings(.AllTags)

	.EmbedPatterns, .EmbedPatternPos = cleanDecls()
	.TestEmbedPatterns, .TestEmbedPatternPos = cleanDecls()
	.XTestEmbedPatterns, .XTestEmbedPatternPos = cleanDecls()

	.Imports, .ImportPos = cleanDecls()
	.TestImports, .TestImportPos = cleanDecls()
	.XTestImports, .XTestImportPos = cleanDecls()
add the .S/.sx files only if we are using cgo (which means gcc will compile them). The standard assemblers expect .s files.
	if len(.CgoFiles) > 0 {
		.SFiles = append(.SFiles, ...)
		sort.Strings(.SFiles)
	} else {
		.IgnoredOtherFiles = append(.IgnoredOtherFiles, ...)
		sort.Strings(.IgnoredOtherFiles)
	}

	if  != nil {
		return , 
	}
	if len(.GoFiles)+len(.CgoFiles)+len(.TestGoFiles)+len(.XTestGoFiles) == 0 {
		return , &NoGoError{.Dir}
	}
	return , 
}

func ( *Package,  string) *[]string {
	switch  {
	case ".c":
		return &.CFiles
	case ".cc", ".cpp", ".cxx":
		return &.CXXFiles
	case ".m":
		return &.MFiles
	case ".h", ".hh", ".hpp", ".hxx":
		return &.HFiles
	case ".f", ".F", ".for", ".f90":
		return &.FFiles
	case ".s", ".S", ".sx":
		return &.SFiles
	case ".swig":
		return &.SwigFiles
	case ".swigcxx":
		return &.SwigCXXFiles
	case ".syso":
		return &.SysoFiles
	}
	return nil
}

func ( []string) []string {
	if  == nil {
		return nil
	}
	 := make([]string, len())
	copy(, )
	sort.Strings()
	 := [:0]
	for ,  := range  {
		if len() == 0 || [len()-1] !=  {
			 = append(, )
		}
	}
	return 
}

var errNoModules = errors.New("not using modules")
importGo checks whether it can use the go command to find the directory for path. If using the go command is not appropriate, importGo returns errNoModules. Otherwise, importGo tries using the go command and reports whether that succeeded. Using the go command lets build.Import and build.Context.Import find code in Go modules. In the long term we want tools to use go/packages (currently golang.org/x/tools/go/packages), which will also use the go command. Invoking the go command here is not very efficient in that it computes information about the requested package and all dependencies and then only reports about the requested package. Then we reinvoke it for every dependency. But this is still better than not working at all. See golang.org/issue/26504.
To invoke the go command, we must not being doing special things like AllowBinary or IgnoreVendor, and all the file system callbacks must be nil (we're meant to use the local file system).
	if &AllowBinary != 0 || &IgnoreVendor != 0 ||
		.JoinPath != nil || .SplitPathList != nil || .IsAbsPath != nil || .IsDir != nil || .HasSubdir != nil || .ReadDir != nil || .OpenFile != nil || !equal(.ReleaseTags, defaultReleaseTags) {
		return errNoModules
	}
Predict whether module aware mode is enabled by checking the value of GO111MODULE and looking for a go.mod file in the source directory or one of its parents. Running 'go env GOMOD' in the source directory would give a canonical answer, but we'd prefer not to execute another command.
	 := os.Getenv("GO111MODULE")
	switch  {
	case "off":
		return errNoModules
Maybe use modules.
	}

	if  != "" {
		var  string
		if filepath.IsAbs() {
			 = 
		} else if .Dir != "" {
			return fmt.Errorf("go/build: Dir is non-empty, so relative srcDir is not allowed: %v", )
Find the absolute source directory. hasSubdir does not handle relative paths (and can't because the callbacks don't support this).
			var  error
			,  = filepath.Abs()
			if  != nil {
				return errNoModules
			}
		}
If the source directory is in GOROOT, then the in-process code works fine and we should keep using it. Moreover, the 'go list' approach below doesn't take standard-library vendoring into account and will fail.
		if ,  := .hasSubdir(filepath.Join(.GOROOT, "src"), );  {
			return errNoModules
		}
	}
For efficiency, if path is a standard library package, let the usual lookup code handle it.
	if .GOROOT != "" {
		 := .joinPath(.GOROOT, "src", )
		if .isDir() {
			return errNoModules
		}
	}
If GO111MODULE=auto, look to see if there is a go.mod. Since go1.13, it doesn't matter if we're inside GOPATH.
	if  == "auto" {
		var (
			 string
			    error
		)
		if .Dir == "" {
			,  = os.Getwd()
A nonexistent working directory can't be in a module.
				return errNoModules
			}
		} else {
			,  = filepath.Abs(.Dir)
If the caller passed a bogus Dir explicitly, that's materially different from not having modules enabled.
				return 
			}
		}
		for {
			if ,  := .openFile(.joinPath(, "go.mod"));  == nil {
				 := make([]byte, 100)
				,  := .Read()
				.Close()
go.mod exists and is readable (is a file, not a directory).
					break
				}
			}
			 := filepath.Dir()
			if len() >= len() {
				return errNoModules // reached top of file system, no go.mod
			}
			 = 
		}
	}

	 := exec.Command("go", "list", "-e", "-compiler="+.Compiler, "-tags="+strings.Join(.BuildTags, ","), "-installsuffix="+.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n{{if .Error}}{{.Error}}{{end}}\n", "--", )

	if .Dir != "" {
		.Dir = .Dir
	}

	var ,  strings.Builder
	.Stdout = &
	.Stderr = &

	 := "0"
	if .CgoEnabled {
		 = "1"
	}
	.Env = append(os.Environ(),
		"GOOS="+.GOOS,
		"GOARCH="+.GOARCH,
		"GOROOT="+.GOROOT,
		"GOPATH="+.GOPATH,
		"CGO_ENABLED="+,
	)

	if  := .Run();  != nil {
		return fmt.Errorf("go/build: go list %s: %v\n%s\n", , , .String())
	}

	 := strings.SplitN(.String(), "\n", 5)
	if len() != 5 {
		return fmt.Errorf("go/build: importGo %s: unexpected output:\n%s\n", , .String())
	}
	 := [0]
	 := strings.TrimSpace([4])
If 'go list' could not locate the package (dir is empty), return the same error that 'go list' reported.
		return errors.New()
	}
If 'go list' did locate the package, ignore the error. It was probably related to loading source files, and we'll encounter it ourselves shortly if the FindOnly flag isn't set.
	.Dir = 
	.ImportPath = [1]
	.Root = [2]
	.Goroot = [3] == "true"
	return nil
}

func (,  []string) bool {
	if len() != len() {
		return false
	}
	for ,  := range  {
		if  != [] {
			return false
		}
	}
	return true
}
hasGoFiles reports whether dir contains any files with names ending in .go. For a vendor check we must exclude directories that contain no .go files. Otherwise it is not possible to vendor just a/b/c and still import the non-vendored a/b. See golang.org/issue/13832.
func ( *Context,  string) bool {
	,  := .readDir()
	for ,  := range  {
		if !.IsDir() && strings.HasSuffix(.Name(), ".go") {
			return true
		}
	}
	return false
}

expect keyword package
	,  := parseWord()
	if string() != "package" {
		return "", 0
	}
expect package name
	_,  = parseWord()
now ready for import comment, a // or comment beginning and ending on the current line.
	for len() > 0 && ([0] == ' ' || [0] == '\t' || [0] == '\r') {
		 = [1:]
	}

	var  []byte
	switch {
	case bytes.HasPrefix(, slashSlash):
		 := bytes.Index(, newline)
		if  < 0 {
			 = len()
		}
		 = [2:]
	case bytes.HasPrefix(, slashStar):
		 = [2:]
		 := bytes.Index(, starSlash)
malformed comment
			return "", 0
		}
		 = [:]
		if bytes.Contains(, newline) {
			return "", 0
		}
	}
	 = bytes.TrimSpace()
split comment into `import`, `"pkg"`
	,  := parseWord()
	if string() != "import" {
		return "", 0
	}

	 = 1 + bytes.Count([:cap()-cap()], newline)
	return strings.TrimSpace(string()), 
}

var (
	slashSlash = []byte("//")
	slashStar  = []byte("/*")
	starSlash  = []byte("*/")
	newline    = []byte("\n")
)
skipSpaceOrComment returns data with any leading spaces or comments removed.
func ( []byte) []byte {
	for len() > 0 {
		switch [0] {
		case ' ', '\t', '\r', '\n':
			 = [1:]
			continue
		case '/':
			if bytes.HasPrefix(, slashSlash) {
				 := bytes.Index(, newline)
				if  < 0 {
					return nil
				}
				 = [+1:]
				continue
			}
			if bytes.HasPrefix(, slashStar) {
				 = [2:]
				 := bytes.Index(, starSlash)
				if  < 0 {
					return nil
				}
				 = [+2:]
				continue
			}
		}
		break
	}
	return 
}
parseWord skips any leading spaces or comments in data and then parses the beginning of data as an identifier or keyword, returning that word and what remains after the word.
func ( []byte) (,  []byte) {
	 = skipSpaceOrComment()
Parse past leading word characters.
	 = 
	for {
		,  := utf8.DecodeRune()
		if unicode.IsLetter() || '0' <=  &&  <= '9' ||  == '_' {
			 = [:]
			continue
		}
		break
	}

	 = [:len()-len()]
	if len() == 0 {
		return nil, nil
	}

	return , 
}
MatchFile reports whether the file with the given name in the given directory matches the context and would be included in a Package created by ImportDir of that directory. MatchFile considers the name of the file and may use ctxt.OpenFile to read some or all of the file's content.
func ( *Context) (,  string) ( bool,  error) {
	,  := .matchFile(, , nil, nil, nil)
	return  != nil, 
}

var dummyPkg Package
fileInfo records information learned about a file included in a build.
matchFile determines whether the file with the given name in the given directory should be included in the package being constructed. If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error). Non-nil errors are reserved for unexpected problems. If name denotes a Go program, matchFile reads until the end of the imports and returns that section of the file in the fileInfo's header field, even though it only considers text until the first non-comment for +build lines. If allTags is non-nil, matchFile records any encountered build tag by setting allTags[tag] = true.
func ( *Context) (,  string,  map[string]bool,  *bool,  *token.FileSet) (*fileInfo, error) {
	if strings.HasPrefix(, "_") ||
		strings.HasPrefix(, ".") {
		return nil, nil
	}

	 := strings.LastIndex(, ".")
	if  < 0 {
		 = len()
	}
	 := [:]

	if !.goodOSArchFile(, ) && !.UseAllFiles {
		return nil, nil
	}

skip
		return nil, nil
	}

	 := &fileInfo{name: .joinPath(, ), fset: }
binary, no reading
		return , nil
	}

	,  := .openFile(.name)
	if  != nil {
		return nil, 
	}

	if strings.HasSuffix(, ".go") {
		 = readGoInfo(, )
		if strings.HasSuffix(, "_test.go") {
			 = nil // ignore //go:binary-only-package comments in _test.go files
		}
	} else {
		 = nil // ignore //go:binary-only-package comments in non-Go sources
		.header,  = readComments()
	}
	.Close()
	if  != nil {
		return nil, fmt.Errorf("read %s: %v", .name, )
	}
Look for +build comments to accept or reject the file.
	, ,  := .shouldBuild(.header, )
	if  != nil {
		return nil, 
	}
	if ! && !.UseAllFiles {
		return nil, nil
	}

	if  != nil &&  {
		* = true
	}

	return , nil
}

func ( map[string][]token.Position) ([]string, map[string][]token.Position) {
	 := make([]string, 0, len())
	for  := range  {
		 = append(, )
	}
	sort.Strings()
	return , 
}
Import is shorthand for Default.Import.
func (,  string,  ImportMode) (*Package, error) {
	return Default.Import(, , )
}
ImportDir is shorthand for Default.ImportDir.
func ( string,  ImportMode) (*Package, error) {
	return Default.ImportDir(, )
}

var (
	bSlashSlash = []byte(slashSlash)
	bStarSlash  = []byte(starSlash)
	bSlashStar  = []byte(slashStar)

	goBuildComment = []byte("//go:build")

	errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
	errMultipleGoBuild     = errors.New("multiple //go:build comments") // unused in Go 1.(N-1)
)

func ( []byte) bool {
	if !bytes.HasPrefix(, goBuildComment) {
		return false
	}
	 = bytes.TrimSpace()
	 := [len(goBuildComment):]
	return len() == 0 || len(bytes.TrimSpace()) < len()
}
Special comment denoting a binary-only package. See https://golang.org/design/2775-binary-only-packages for more about the design of binary-only packages.
var binaryOnlyComment = []byte("//go:binary-only-package")
shouldBuild reports whether it is okay to use this file, The rule is that in the file's leading run of // comments and blank lines, which must be followed by a blank line (to avoid including a Go package clause doc comment), lines beginning with '// +build' are taken as build directives. The file is accepted only if each such line lists something matching the file. For example: // +build windows linux marks the file as applicable only on Windows and Linux. For each build tag it consults, shouldBuild sets allTags[tag] = true. shouldBuild reports whether the file should be built and whether a //go:binary-only-package comment was found.
func ( *Context) ( []byte,  map[string]bool) (,  bool,  error) {
Pass 1. Identify leading run of // comments and blank lines, which must be followed by a blank line. Also identify any //go:build comments.
	, , ,  := parseFileHeader()
	if  != nil {
		return false, false, 
	}
Pass 2. Process each +build line in the run.
	 := 
	 = true
	 := false
	for len() > 0 {
		 := 
		if  := bytes.IndexByte(, '\n');  >= 0 {
			,  = [:], [+1:]
		} else {
			 = [len():]
		}
		 = bytes.TrimSpace()
		if !bytes.HasPrefix(, bSlashSlash) {
			continue
		}
		 = bytes.TrimSpace([len(bSlashSlash):])
Looks like a comment +line.
			 := strings.Fields(string())
			if [0] == "+build" {
				 = true
				 := false
				for ,  := range [1:] {
					if .match(, ) {
						 = true
					}
				}
				if ! {
					 = false
				}
			}
		}
	}

	if  != nil && ! {
		return false, false, errGoBuildWithoutBuild
	}

	return , , nil
}

func ( []byte) (,  []byte,  bool,  error) {
	 := 0
	 := 
	 := false       // found non-blank, non-// line, so stopped accepting // +build lines
	 := false // in /* */ comment

:
	for len() > 0 {
		 := 
		if  := bytes.IndexByte(, '\n');  >= 0 {
			,  = [:], [+1:]
		} else {
			 = [len():]
		}
		 = bytes.TrimSpace()
Remember position of most recent blank line. When we find the first non-blank, non-// line, this "end" position marks the latest file position where a // +build line can appear. (It must appear _before_ a blank line before the non-blank, non-// line. Yes, that's confusing, which is part of why we moved to //go:build lines.) Note that ended==false here means that inSlashStar==false, since seeing a would have set ended==true.
			 = len() - len()
			continue 
		}
		if !bytes.HasPrefix(, slashSlash) { // Not comment line
			 = true
		}

		if ! && isGoBuildComment() {
			if false &&  != nil { // enabled in Go 1.N
				return nil, nil, false, errMultipleGoBuild
			}
			 = 
		}
		if ! && bytes.Equal(, binaryOnlyComment) {
			 = true
		}

	:
		for len() > 0 {
			if  {
				if  := bytes.Index(, starSlash);  >= 0 {
					 = false
					 = bytes.TrimSpace([+len(starSlash):])
					continue 
				}
				continue 
			}
			if bytes.HasPrefix(, bSlashSlash) {
				continue 
			}
			if bytes.HasPrefix(, bSlashStar) {
				 = true
				 = bytes.TrimSpace([len(bSlashStar):])
				continue 
Found non-comment text.
			break 
		}
	}

	return [:], , , nil
}
saveCgo saves the information from the #cgo lines in the import "C" comment. These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives that affect the way cgo's C code is built.
func ( *Context) ( string,  *Package,  *ast.CommentGroup) error {
	 := .Text()
	for ,  := range strings.Split(, "\n") {
		 := 
Line is #cgo [GOOS/GOARCH...] LDFLAGS: stuff
		 = strings.TrimSpace()
		if len() < 5 || [:4] != "#cgo" || ([4] != ' ' && [4] != '\t') {
			continue
		}
Split at colon.
		 = strings.TrimSpace([4:])
		 := strings.Index(, ":")
		if  < 0 {
			return fmt.Errorf("%s: invalid #cgo line: %s", , )
		}
		,  := [:], [+1:]
Parse GOOS/GOARCH stuff.
		 := strings.Fields()
		if len() < 1 {
			return fmt.Errorf("%s: invalid #cgo line: %s", , )
		}

		,  := [:len()-1], [len()-1]
		if len() > 0 {
			 := false
			for ,  := range  {
				if .match(, nil) {
					 = true
					break
				}
			}
			if ! {
				continue
			}
		}

		,  := splitQuoted()
		if  != nil {
			return fmt.Errorf("%s: invalid #cgo line: %s", , )
		}
		var  bool
		for ,  := range  {
			if ,  = expandSrcDir(, .Dir); ! {
				return fmt.Errorf("%s: malformed #cgo argument: %s", , )
			}
			[] = 
		}

		switch  {
Change relative paths to absolute.
			.makePathsAbsolute(, .Dir)
		}

		switch  {
		case "CFLAGS":
			.CgoCFLAGS = append(.CgoCFLAGS, ...)
		case "CPPFLAGS":
			.CgoCPPFLAGS = append(.CgoCPPFLAGS, ...)
		case "CXXFLAGS":
			.CgoCXXFLAGS = append(.CgoCXXFLAGS, ...)
		case "FFLAGS":
			.CgoFFLAGS = append(.CgoFFLAGS, ...)
		case "LDFLAGS":
			.CgoLDFLAGS = append(.CgoLDFLAGS, ...)
		case "pkg-config":
			.CgoPkgConfig = append(.CgoPkgConfig, ...)
		default:
			return fmt.Errorf("%s: invalid #cgo verb: %s", , )
		}
	}
	return nil
}
expandSrcDir expands any occurrence of ${SRCDIR}, making sure the result is safe for the shell.
"\" delimited paths cause safeCgoName to fail so convert native paths with a different delimiter to "/" before starting (eg: on windows).
	 = filepath.ToSlash()

	 := strings.Split(, "${SRCDIR}")
	if len() < 2 {
		return , safeCgoName()
	}
	 := true
	for ,  := range  {
		 =  && ( == "" || safeCgoName())
	}
	 =  && ( == "" || safeCgoName())
	 := strings.Join(, )
	return ,  &&  != ""
}
makePathsAbsolute looks for compiler options that take paths and makes them absolute. We do this because through the 1.8 release we ran the compiler in the package directory, so any relative -I or -L options would be relative to that directory. In 1.9 we changed to running the compiler in the build directory, to get consistent build results (issue #19964). To keep builds working, we change any relative -I or -L options to be absolute. Using filepath.IsAbs and filepath.Join here means the results will be different on different systems, but that's OK: -I and -L options are inherently system-dependent.
func ( *Context) ( []string,  string) {
	 := false
	for ,  := range  {
		if  {
			if !filepath.IsAbs() {
				[] = filepath.Join(, )
			}
			 = false
		} else if strings.HasPrefix(, "-I") || strings.HasPrefix(, "-L") {
			if len() == 2 {
				 = true
			} else {
				if !filepath.IsAbs([2:]) {
					[] = [:2] + filepath.Join(, [2:])
				}
			}
		}
	}
}
NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. See golang.org/issue/6038. The @ is for OS X. See golang.org/issue/13720. The % is for Jenkins. See golang.org/issue/16959. The ! is because module paths may use them. See golang.org/issue/26716. The ~ and ^ are for sr.ht. See golang.org/issue/32260.
const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%! ~^"

func ( string) bool {
	if  == "" {
		return false
	}
	for  := 0;  < len(); ++ {
		if  := [];  < utf8.RuneSelf && strings.IndexByte(safeString, ) < 0 {
			return false
		}
	}
	return true
}
splitQuoted splits the string s around each instance of one or more consecutive white space characters while taking into account quotes and escaping, and returns an array of substrings of s or an empty list if s contains only white space. Single quotes and double quotes are recognized to prevent splitting within the quoted region, and are removed from the resulting substrings. If a quote in s isn't closed err will be set and r will have the unclosed argument as the last element. The backslash is used for escaping. For example, the following string: a b:"c d" 'e''f' "g\"" Would be parsed as: []string{"a", "b:c d", "ef", `g"`}
func ( string) ( []string,  error) {
	var  []string
	 := make([]rune, len())
	 := false
	 := false
	 := '\x00'
	 := 0
	for ,  := range  {
		switch {
		case :
			 = false
		case  == '\\':
			 = true
			continue
		case  != '\x00':
			if  ==  {
				 = '\x00'
				continue
			}
		case  == '"' ||  == '\'':
			 = true
			 = 
			continue
		case unicode.IsSpace():
			if  ||  > 0 {
				 = false
				 = append(, string([:]))
				 = 0
			}
			continue
		}
		[] = 
		++
	}
	if  ||  > 0 {
		 = append(, string([:]))
	}
	if  != 0 {
		 = errors.New("unclosed quote")
	} else if  {
		 = errors.New("unfinished escaping")
	}
	return , 
}
match reports whether the name is one of: $GOOS $GOARCH cgo (if cgo is enabled) !cgo (if cgo is disabled) ctxt.Compiler !ctxt.Compiler tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) a comma-separated list of any of these
func ( *Context) ( string,  map[string]bool) bool {
	if  == "" {
		if  != nil {
			[] = true
		}
		return false
	}
comma-separated list
		 := .([:], )
		 := .([+1:], )
		return  && 
	}
	if strings.HasPrefix(, "!!") { // bad syntax, reject always
		return false
	}
	if strings.HasPrefix(, "!") { // negation
		return len() > 1 && !.([1:], )
	}

	if  != nil {
		[] = true
	}
Tags must be letters, digits, underscores or dots. Unlike in Go identifiers, all digits are fine (e.g., "386").
	for ,  := range  {
		if !unicode.IsLetter() && !unicode.IsDigit() &&  != '_' &&  != '.' {
			return false
		}
	}
special tags
	if .CgoEnabled &&  == "cgo" {
		return true
	}
	if  == .GOOS ||  == .GOARCH ||  == .Compiler {
		return true
	}
	if .GOOS == "android" &&  == "linux" {
		return true
	}
	if .GOOS == "illumos" &&  == "solaris" {
		return true
	}
	if .GOOS == "ios" &&  == "darwin" {
		return true
	}
other tags
	for ,  := range .BuildTags {
		if  ==  {
			return true
		}
	}
	for ,  := range .ReleaseTags {
		if  ==  {
			return true
		}
	}

	return false
}
goodOSArchFile returns false if the name contains a $GOOS or $GOARCH suffix which does not match the current system. The recognized name formats are: name_$(GOOS).* name_$(GOARCH).* name_$(GOOS)_$(GOARCH).* name_$(GOOS)_test.* name_$(GOARCH)_test.* name_$(GOOS)_$(GOARCH)_test.* Exceptions: if GOOS=android, then files with GOOS=linux are also matched. if GOOS=illumos, then files with GOOS=solaris are also matched. if GOOS=ios, then files with GOOS=darwin are also matched.
func ( *Context) ( string,  map[string]bool) bool {
	if  := strings.Index(, ".");  != -1 {
		 = [:]
	}
Before Go 1.4, a file called "linux.go" would be equivalent to having a build tag "linux" in that file. For Go 1.4 and beyond, we require this auto-tagging to apply only to files with a non-empty prefix, so "foo_linux.go" is tagged but "linux.go" is not. This allows new operating systems, such as android, to arrive without breaking existing code with innocuous source code in "android.go". The easiest fix: cut everything in the name before the initial _.
	 := strings.Index(, "_")
	if  < 0 {
		return true
	}
	 = [:] // ignore everything before first _

	 := strings.Split(, "_")
	if  := len();  > 0 && [-1] == "test" {
		 = [:-1]
	}
	 := len()
	if  >= 2 && knownOS[[-2]] && knownArch[[-1]] {
		return .match([-1], ) && .match([-2], )
	}
	if  >= 1 && (knownOS[[-1]] || knownArch[[-1]]) {
		return .match([-1], )
	}
	return true
}

var knownOS = make(map[string]bool)
var knownArch = make(map[string]bool)

func () {
	for ,  := range strings.Fields(goosList) {
		knownOS[] = true
	}
	for ,  := range strings.Fields(goarchList) {
		knownArch[] = true
	}
}
ToolDir is the directory containing build tools.
IsLocalImport reports whether the import path is a local import path, like ".", "..", "./foo", or "../foo".
func ( string) bool {
	return  == "." ||  == ".." ||
		strings.HasPrefix(, "./") || strings.HasPrefix(, "../")
}
ArchChar returns "?" and an error. In earlier versions of Go, the returned string was used to derive the compiler and linker tool names, the default object file suffix, and the default linker output name. As of Go 1.5, those strings no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
func ( string) (string, error) {
	return "?", errors.New("architecture letter no longer used")