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.
14 exec "internal/execabs"
31 // A Context specifies the supporting context for a build.
33 GOARCH string // target architecture
34 GOOS string // target operating system
35 GOROOT string // Go root
36 GOPATH string // Go path
38 // Dir is the caller's working directory, or the empty string to use
39 // the current directory of the running process. In module mode, this is used
40 // to locate the main module.
42 // If Dir is non-empty, directories passed to Import and ImportDir must
46 CgoEnabled bool // whether cgo files are included
47 UseAllFiles bool // use files regardless of +build lines, file names
48 Compiler string // compiler to assume when computing target paths
50 // The build and release tags specify build constraints
51 // that should be considered satisfied when processing +build lines.
52 // Clients creating a new context may customize BuildTags, which
53 // defaults to empty, but it is usually an error to customize ReleaseTags,
54 // which defaults to the list of Go releases the current release is compatible with.
55 // BuildTags is not set for the Default build Context.
56 // In addition to the BuildTags and ReleaseTags, build constraints
57 // consider the values of GOARCH and GOOS as satisfied tags.
58 // The last element in ReleaseTags is assumed to be the current release.
62 // The install suffix specifies a suffix to use in the name of the installation
63 // directory. By default it is empty, but custom builds that need to keep
64 // their outputs separate can set InstallSuffix to do so. For example, when
65 // using the race detector, the go command uses InstallSuffix = "race", so
66 // that on a Linux/386 system, packages are written to a directory named
67 // "linux_386_race" instead of the usual "linux_386".
70 // By default, Import uses the operating system's file system calls
71 // to read directories and files. To read from other sources,
72 // callers can set the following functions. They all have default
73 // behaviors that use the local file system, so clients need only set
74 // the functions whose behaviors they wish to change.
76 // JoinPath joins the sequence of path fragments into a single path.
77 // If JoinPath is nil, Import uses filepath.Join.
78 JoinPath func(elem ...string) string
80 // SplitPathList splits the path list into a slice of individual paths.
81 // If SplitPathList is nil, Import uses filepath.SplitList.
82 SplitPathList func(list string) []string
84 // IsAbsPath reports whether path is an absolute path.
85 // If IsAbsPath is nil, Import uses filepath.IsAbs.
86 IsAbsPath func(path string) bool
88 // IsDir reports whether the path names a directory.
89 // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
90 IsDir func(path string) bool
92 // HasSubdir reports whether dir is lexically a subdirectory of
93 // root, perhaps multiple levels below. It does not try to check
94 // whether dir exists.
95 // If so, HasSubdir sets rel to a slash-separated path that
96 // can be joined to root to produce a path equivalent to dir.
97 // If HasSubdir is nil, Import uses an implementation built on
98 // filepath.EvalSymlinks.
99 HasSubdir func(root, dir string) (rel string, ok bool)
101 // ReadDir returns a slice of fs.FileInfo, sorted by Name,
102 // describing the content of the named directory.
103 // If ReadDir is nil, Import uses ioutil.ReadDir.
104 ReadDir func(dir string) ([]fs.FileInfo, error)
106 // OpenFile opens a file (not a directory) for reading.
107 // If OpenFile is nil, Import uses os.Open.
108 OpenFile func(path string) (io.ReadCloser, error)
111 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
112 func (ctxt *Context) joinPath(elem ...string) string {
113 if f := ctxt.JoinPath; f != nil {
116 return filepath.Join(elem...)
119 // splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
120 func (ctxt *Context) splitPathList(s string) []string {
121 if f := ctxt.SplitPathList; f != nil {
124 return filepath.SplitList(s)
127 // isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs.
128 func (ctxt *Context) isAbsPath(path string) bool {
129 if f := ctxt.IsAbsPath; f != nil {
132 return filepath.IsAbs(path)
135 // isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
136 func (ctxt *Context) isDir(path string) bool {
137 if f := ctxt.IsDir; f != nil {
140 fi, err := os.Stat(path)
141 return err == nil && fi.IsDir()
144 // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
145 // the local file system to answer the question.
146 func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) {
147 if f := ctxt.HasSubdir; f != nil {
151 // Try using paths we received.
152 if rel, ok = hasSubdir(root, dir); ok {
156 // Try expanding symlinks and comparing
157 // expanded against unexpanded and
158 // expanded against expanded.
159 rootSym, _ := filepath.EvalSymlinks(root)
160 dirSym, _ := filepath.EvalSymlinks(dir)
162 if rel, ok = hasSubdir(rootSym, dir); ok {
165 if rel, ok = hasSubdir(root, dirSym); ok {
168 return hasSubdir(rootSym, dirSym)
171 // hasSubdir reports if dir is within root by performing lexical analysis only.
172 func hasSubdir(root, dir string) (rel string, ok bool) {
173 const sep = string(filepath.Separator)
174 root = filepath.Clean(root)
175 if !strings.HasSuffix(root, sep) {
178 dir = filepath.Clean(dir)
179 if !strings.HasPrefix(dir, root) {
182 return filepath.ToSlash(dir[len(root):]), true
185 // readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
186 func (ctxt *Context) readDir(path string) ([]fs.FileInfo, error) {
187 if f := ctxt.ReadDir; f != nil {
190 return ioutil.ReadDir(path)
193 // openFile calls ctxt.OpenFile (if not nil) or else os.Open.
194 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) {
195 if fn := ctxt.OpenFile; fn != nil {
199 f, err := os.Open(path)
201 return nil, err // nil interface
206 // isFile determines whether path is a file by trying to open it.
207 // It reuses openFile instead of adding another function to the
209 func (ctxt *Context) isFile(path string) bool {
210 f, err := ctxt.openFile(path)
218 // gopath returns the list of Go path directories.
219 func (ctxt *Context) gopath() []string {
221 for _, p := range ctxt.splitPathList(ctxt.GOPATH) {
222 if p == "" || p == ctxt.GOROOT {
223 // Empty paths are uninteresting.
224 // If the path is the GOROOT, ignore it.
225 // People sometimes set GOPATH=$GOROOT.
226 // Do not get confused by this common mistake.
229 if strings.HasPrefix(p, "~") {
230 // Path segments starting with ~ on Unix are almost always
231 // users who have incorrectly quoted ~ while setting GOPATH,
232 // preventing it from expanding to $HOME.
233 // The situation is made more confusing by the fact that
234 // bash allows quoted ~ in $PATH (most shells do not).
235 // Do not get confused by this, and do not try to use the path.
236 // It does not exist, and printing errors about it confuses
237 // those users even more, because they think "sure ~ exists!".
238 // The go command diagnoses this situation and prints a
240 // On Windows, ~ is used in short names, such as c:\progra~1
241 // for c:\program files.
249 // SrcDirs returns a list of package source root directories.
250 // It draws from the current Go root and Go path but omits directories
251 // that do not exist.
252 func (ctxt *Context) SrcDirs() []string {
254 if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
255 dir := ctxt.joinPath(ctxt.GOROOT, "src")
257 all = append(all, dir)
260 for _, p := range ctxt.gopath() {
261 dir := ctxt.joinPath(p, "src")
263 all = append(all, dir)
269 // Default is the default Context for builds.
270 // It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
271 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
272 var Default Context = defaultContext()
274 func defaultGOPATH() string {
276 if runtime.GOOS == "windows" {
278 } else if runtime.GOOS == "plan9" {
281 if home := os.Getenv(env); home != "" {
282 def := filepath.Join(home, "go")
283 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) {
284 // Don't set the default GOPATH to GOROOT,
285 // as that will trigger warnings from the go tool.
293 var defaultReleaseTags []string
295 func defaultContext() Context {
298 c.GOARCH = envOr("GOARCH", runtime.GOARCH)
299 c.GOOS = envOr("GOOS", runtime.GOOS)
300 c.GOROOT = pathpkg.Clean(runtime.GOROOT())
301 c.GOPATH = envOr("GOPATH", defaultGOPATH())
302 c.Compiler = runtime.Compiler
304 // Each major Go release in the Go 1.x series adds a new
305 // "go1.x" release tag. That is, the go1.x tag is present in
306 // all releases >= Go 1.x. Code that requires Go 1.x or later
307 // should say "+build go1.x", and code that should only be
308 // built before Go 1.x (perhaps it is the stub to use in that
309 // case) should say "+build !go1.x".
310 // The last element in ReleaseTags is the current release.
311 for i := 1; i <= goversion.Version; i++ {
312 c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i))
315 defaultReleaseTags = append([]string{}, c.ReleaseTags...) // our own private copy
317 env := os.Getenv("CGO_ENABLED")
319 env = defaultCGO_ENABLED
327 // cgo must be explicitly enabled for cross compilation builds
328 if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
329 c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
338 func envOr(name, def string) string {
346 // An ImportMode controls the behavior of the Import method.
350 // If FindOnly is set, Import stops after locating the directory
351 // that should contain the sources for a package. It does not
352 // read any files in the directory.
353 FindOnly ImportMode = 1 << iota
355 // If AllowBinary is set, Import can be satisfied by a compiled
356 // package object without corresponding sources.
359 // The supported way to create a compiled-only package is to
360 // write source code containing a //go:binary-only-package comment at
361 // the top of the file. Such a package will be recognized
362 // regardless of this flag setting (because it has source code)
363 // and will have BinaryOnly set to true in the returned Package.
366 // If ImportComment is set, parse import comments on package statements.
367 // Import returns an error if it finds a comment it cannot understand
368 // or finds conflicting comments in multiple source files.
369 // See golang.org/s/go14customimport for more information.
372 // By default, Import searches vendor directories
373 // that apply in the given source directory before searching
374 // the GOROOT and GOPATH roots.
375 // If an Import finds and returns a package using a vendor
376 // directory, the resulting ImportPath is the complete path
377 // to the package, including the path elements leading up
378 // to and including "vendor".
379 // For example, if Import("y", "x/subdir", 0) finds
380 // "x/vendor/y", the returned package's ImportPath is "x/vendor/y",
382 // See golang.org/s/go15vendor for more information.
384 // Setting IgnoreVendor ignores vendor directories.
386 // In contrast to the package's ImportPath,
387 // the returned package's Imports, TestImports, and XTestImports
388 // are always the exact import paths from the source files:
389 // Import makes no attempt to resolve or check those paths.
393 // A Package describes the Go package found in a directory.
394 type Package struct {
395 Dir string // directory containing package sources
396 Name string // package name
397 ImportComment string // path in import comment on package statement
398 Doc string // documentation synopsis
399 ImportPath string // import path of package ("" if unknown)
400 Root string // root of Go tree where this package lives
401 SrcRoot string // package source root directory ("" if unknown)
402 PkgRoot string // package install root directory ("" if unknown)
403 PkgTargetRoot string // architecture dependent install root directory ("" if unknown)
404 BinDir string // command install directory ("" if unknown)
405 Goroot bool // package found in Go root
406 PkgObj string // installed .a file
407 AllTags []string // tags that can influence file selection in this directory
408 ConflictDir string // this directory shadows Dir in $GOPATH
409 BinaryOnly bool // cannot be rebuilt from source (has //go:binary-only-package comment)
412 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
413 CgoFiles []string // .go source files that import "C"
414 IgnoredGoFiles []string // .go source files ignored for this build (including ignored _test.go files)
415 InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on)
416 IgnoredOtherFiles []string // non-.go source files ignored for this build
417 CFiles []string // .c source files
418 CXXFiles []string // .cc, .cpp and .cxx source files
419 MFiles []string // .m (Objective-C) source files
420 HFiles []string // .h, .hh, .hpp and .hxx source files
421 FFiles []string // .f, .F, .for and .f90 Fortran source files
422 SFiles []string // .s source files
423 SwigFiles []string // .swig files
424 SwigCXXFiles []string // .swigcxx files
425 SysoFiles []string // .syso system object files to add to archive
428 CgoCFLAGS []string // Cgo CFLAGS directives
429 CgoCPPFLAGS []string // Cgo CPPFLAGS directives
430 CgoCXXFLAGS []string // Cgo CXXFLAGS directives
431 CgoFFLAGS []string // Cgo FFLAGS directives
432 CgoLDFLAGS []string // Cgo LDFLAGS directives
433 CgoPkgConfig []string // Cgo pkg-config directives
436 TestGoFiles []string // _test.go files in package
437 XTestGoFiles []string // _test.go files outside package
439 // Dependency information
440 Imports []string // import paths from GoFiles, CgoFiles
441 ImportPos map[string][]token.Position // line information for Imports
442 TestImports []string // import paths from TestGoFiles
443 TestImportPos map[string][]token.Position // line information for TestImports
444 XTestImports []string // import paths from XTestGoFiles
445 XTestImportPos map[string][]token.Position // line information for XTestImports
447 // //go:embed patterns found in Go source files
448 // For example, if a source file says
450 // then the list will contain those two strings as separate entries.
451 // (See package embed for more details about //go:embed.)
452 EmbedPatterns []string // patterns from GoFiles, CgoFiles
453 EmbedPatternPos map[string][]token.Position // line information for EmbedPatterns
454 TestEmbedPatterns []string // patterns from TestGoFiles
455 TestEmbedPatternPos map[string][]token.Position // line information for TestEmbedPatterns
456 XTestEmbedPatterns []string // patterns from XTestGoFiles
457 XTestEmbedPatternPos map[string][]token.Position // line information for XTestEmbedPatternPos
460 // IsCommand reports whether the package is considered a
461 // command to be installed (not just a library).
462 // Packages named "main" are treated as commands.
463 func (p *Package) IsCommand() bool {
464 return p.Name == "main"
467 // ImportDir is like Import but processes the Go package found in
468 // the named directory.
469 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
470 return ctxt.Import(".", dir, mode)
473 // NoGoError is the error used by Import to describe a directory
474 // containing no buildable Go source files. (It may still contain
475 // test files, files hidden by build tags, and so on.)
476 type NoGoError struct {
480 func (e *NoGoError) Error() string {
481 return "no buildable Go source files in " + e.Dir
484 // MultiplePackageError describes a directory containing
485 // multiple buildable Go source files for multiple packages.
486 type MultiplePackageError struct {
487 Dir string // directory containing files
488 Packages []string // package names found
489 Files []string // corresponding files: Files[i] declares package Packages[i]
492 func (e *MultiplePackageError) Error() string {
493 // Error string limited to two entries for compatibility.
494 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)
497 func nameExt(name string) string {
498 i := strings.LastIndex(name, ".")
505 // Import returns details about the Go package named by the import path,
506 // interpreting local import paths relative to the srcDir directory.
507 // If the path is a local import path naming a package that can be imported
508 // using a standard import path, the returned package will set p.ImportPath
511 // In the directory containing the package, .go, .c, .h, and .s files are
512 // considered part of the package except for:
514 // - .go files in package documentation
515 // - files starting with _ or . (likely editor temporary files)
516 // - files with build constraints not satisfied by the context
518 // If an error occurs, Import returns a non-nil error and a non-nil
519 // *Package containing partial information.
521 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {
526 return p, fmt.Errorf("import %q: invalid import path", path)
529 var pkgtargetroot string
533 if ctxt.InstallSuffix != "" {
534 suffix = "_" + ctxt.InstallSuffix
536 switch ctxt.Compiler {
538 pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
540 pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
542 // Save error for end of function.
543 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
546 switch ctxt.Compiler {
548 dir, elem := pathpkg.Split(p.ImportPath)
549 pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
551 pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
557 if IsLocalImport(path) {
558 pkga = "" // local imports have no installed path
560 return p, fmt.Errorf("import %q: import relative to unknown directory", path)
562 if !ctxt.isAbsPath(path) {
563 p.Dir = ctxt.joinPath(srcDir, path)
565 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
566 // Determine canonical import path, if any.
567 // Exclude results where the import path would include /testdata/.
568 inTestdata := func(sub string) bool {
569 return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
571 if ctxt.GOROOT != "" {
572 root := ctxt.joinPath(ctxt.GOROOT, "src")
573 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
577 setPkga() // p.ImportPath changed
582 for i, root := range all {
583 rootsrc := ctxt.joinPath(root, "src")
584 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
585 // We found a potential import path for dir,
586 // but check that using it wouldn't find something
588 if ctxt.GOROOT != "" && ctxt.Compiler != "gccgo" {
589 if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
594 for _, earlyRoot := range all[:i] {
595 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) {
601 // sub would not name some other directory instead of this one.
605 setPkga() // p.ImportPath changed
609 // It's okay that we didn't find a root containing dir.
610 // Keep going with the information we have.
612 if strings.HasPrefix(path, "/") {
613 return p, fmt.Errorf("import %q: cannot import absolute path", path)
616 if err := ctxt.importGo(p, path, srcDir, mode); err == nil {
618 } else if err != errNoModules {
622 gopath := ctxt.gopath() // needed twice below; avoid computing many times
624 // tried records the location of unsuccessful package lookups
631 // Vendor directories get first chance to satisfy import.
632 if mode&IgnoreVendor == 0 && srcDir != "" {
633 searchVendor := func(root string, isGoroot bool) bool {
634 sub, ok := ctxt.hasSubdir(root, srcDir)
635 if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
639 vendor := ctxt.joinPath(root, sub, "vendor")
640 if ctxt.isDir(vendor) {
641 dir := ctxt.joinPath(vendor, path)
642 if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) {
644 p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
647 setPkga() // p.ImportPath changed
650 tried.vendor = append(tried.vendor, dir)
652 i := strings.LastIndex(sub, "/")
660 if ctxt.Compiler != "gccgo" && searchVendor(ctxt.GOROOT, true) {
663 for _, root := range gopath {
664 if searchVendor(root, false) {
670 // Determine directory from import path.
671 if ctxt.GOROOT != "" {
672 // If the package path starts with "vendor/", only search GOROOT before
673 // GOPATH if the importer is also within GOROOT. That way, if the user has
674 // vendored in a package that is subsequently included in the standard
675 // distribution, they'll continue to pick up their own vendored copy.
676 gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
678 _, gorootFirst = ctxt.hasSubdir(ctxt.GOROOT, srcDir)
681 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
682 if ctxt.Compiler != "gccgo" {
683 isDir := ctxt.isDir(dir)
684 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
685 if isDir || binaryOnly {
695 if ctxt.Compiler == "gccgo" && goroot.IsStandardPackage(ctxt.GOROOT, ctxt.Compiler, path) {
696 p.Dir = ctxt.joinPath(ctxt.GOROOT, "src", path)
701 for _, root := range gopath {
702 dir := ctxt.joinPath(root, "src", path)
703 isDir := ctxt.isDir(dir)
704 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga))
705 if isDir || binaryOnly {
710 tried.gopath = append(tried.gopath, dir)
713 // If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
714 // That way, the user can still get useful results from 'go list' for
715 // standard-vendored paths passed on the command line.
716 if ctxt.GOROOT != "" && tried.goroot == "" {
717 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
718 if ctxt.Compiler != "gccgo" {
719 isDir := ctxt.isDir(dir)
720 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga))
721 if isDir || binaryOnly {
731 // package was not found
733 format := "\t%s (vendor tree)"
734 for _, dir := range tried.vendor {
735 paths = append(paths, fmt.Sprintf(format, dir))
738 if tried.goroot != "" {
739 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
741 paths = append(paths, "\t($GOROOT not set)")
743 format = "\t%s (from $GOPATH)"
744 for _, dir := range tried.gopath {
745 paths = append(paths, fmt.Sprintf(format, dir))
748 if len(tried.gopath) == 0 {
749 paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
751 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
756 p.SrcRoot = ctxt.joinPath(p.Root, "src")
757 p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
758 p.BinDir = ctxt.joinPath(p.Root, "bin")
760 p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
761 p.PkgObj = ctxt.joinPath(p.Root, pkga)
765 // If it's a local import path, by the time we get here, we still haven't checked
766 // that p.Dir directory exists. This is the right time to do that check.
767 // We can't do it earlier, because we want to gather partial information for the
768 // non-nil *Package returned when an error occurs.
769 // We need to do this before we return early on FindOnly flag.
770 if IsLocalImport(path) && !ctxt.isDir(p.Dir) {
771 if ctxt.Compiler == "gccgo" && p.Goroot {
772 // gccgo has no sources for GOROOT packages.
776 // package was not found
777 return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir)
780 if mode&FindOnly != 0 {
783 if binaryOnly && (mode&AllowBinary) != 0 {
787 if ctxt.Compiler == "gccgo" && p.Goroot {
788 // gccgo has no sources for GOROOT packages.
792 dirs, err := ctxt.readDir(p.Dir)
798 var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
799 var firstFile, firstCommentFile string
800 embedPos := make(map[string][]token.Position)
801 testEmbedPos := make(map[string][]token.Position)
802 xTestEmbedPos := make(map[string][]token.Position)
803 importPos := make(map[string][]token.Position)
804 testImportPos := make(map[string][]token.Position)
805 xTestImportPos := make(map[string][]token.Position)
806 allTags := make(map[string]bool)
807 fset := token.NewFileSet()
808 for _, d := range dirs {
812 if d.Mode()&fs.ModeSymlink != 0 {
813 if ctxt.isDir(ctxt.joinPath(p.Dir, d.Name())) {
814 // Symlinks to directories are not source files.
822 badFile := func(err error) {
823 if badGoError == nil {
826 p.InvalidGoFiles = append(p.InvalidGoFiles, name)
829 info, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly, fset)
835 if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
836 // not due to build constraints - don't report
837 } else if ext == ".go" {
838 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
839 } else if fileListForExt(p, ext) != nil {
840 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
844 data, filename := info.header, info.name
846 // Going to save the file. For non-Go files, can stop here.
851 // special case for cgo, handled at end
852 Sfiles = append(Sfiles, name)
855 if list := fileListForExt(p, ext); list != nil {
856 *list = append(*list, name)
861 if info.parseErr != nil {
862 badFile(info.parseErr)
868 if pkg == "documentation" {
869 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
873 isTest := strings.HasSuffix(name, "_test.go")
875 if isTest && strings.HasSuffix(pkg, "_test") {
877 pkg = pkg[:len(pkg)-len("_test")]
883 } else if pkg != p.Name {
884 badFile(&MultiplePackageError{
886 Packages: []string{p.Name, pkg},
887 Files: []string{firstFile, name},
889 p.InvalidGoFiles = append(p.InvalidGoFiles, name)
891 // Grab the first package comment as docs, provided it is not from a test file.
892 if pf.Doc != nil && p.Doc == "" && !isTest && !isXTest {
893 p.Doc = doc.Synopsis(pf.Doc.Text())
896 if mode&ImportComment != 0 {
897 qcom, line := findImportComment(data)
899 com, err := strconv.Unquote(qcom)
901 badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
902 } else if p.ImportComment == "" {
903 p.ImportComment = com
904 firstCommentFile = name
905 } else if p.ImportComment != com {
906 badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
911 // Record imports and information about cgo.
913 for _, imp := range info.imports {
916 badFile(fmt.Errorf("use of cgo in test %s not supported", filename))
921 if err := ctxt.saveCgo(filename, p, imp.doc); err != nil {
928 var fileList *[]string
929 var importMap, embedMap map[string][]token.Position
932 allTags["cgo"] = true
934 fileList = &p.CgoFiles
935 importMap = importPos
938 // Ignore imports and embeds from cgo files if cgo is disabled.
939 fileList = &p.IgnoredGoFiles
942 fileList = &p.XTestGoFiles
943 importMap = xTestImportPos
944 embedMap = xTestEmbedPos
946 fileList = &p.TestGoFiles
947 importMap = testImportPos
948 embedMap = testEmbedPos
950 fileList = &p.GoFiles
951 importMap = importPos
954 *fileList = append(*fileList, name)
955 if importMap != nil {
956 for _, imp := range info.imports {
957 importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
961 for _, emb := range info.embeds {
962 embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
967 for tag := range allTags {
968 p.AllTags = append(p.AllTags, tag)
970 sort.Strings(p.AllTags)
972 p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
973 p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
974 p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
976 p.Imports, p.ImportPos = cleanDecls(importPos)
977 p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
978 p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
980 // add the .S/.sx files only if we are using cgo
981 // (which means gcc will compile them).
982 // The standard assemblers expect .s files.
983 if len(p.CgoFiles) > 0 {
984 p.SFiles = append(p.SFiles, Sfiles...)
985 sort.Strings(p.SFiles)
987 p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
988 sort.Strings(p.IgnoredOtherFiles)
991 if badGoError != nil {
994 if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
995 return p, &NoGoError{p.Dir}
1000 func fileListForExt(p *Package, ext string) *[]string {
1004 case ".cc", ".cpp", ".cxx":
1008 case ".h", ".hh", ".hpp", ".hxx":
1010 case ".f", ".F", ".for", ".f90":
1012 case ".s", ".S", ".sx":
1017 return &p.SwigCXXFiles
1024 func uniq(list []string) []string {
1028 out := make([]string, len(list))
1032 for _, x := range out {
1033 if len(uniq) == 0 || uniq[len(uniq)-1] != x {
1034 uniq = append(uniq, x)
1040 var errNoModules = errors.New("not using modules")
1042 // importGo checks whether it can use the go command to find the directory for path.
1043 // If using the go command is not appropriate, importGo returns errNoModules.
1044 // Otherwise, importGo tries using the go command and reports whether that succeeded.
1045 // Using the go command lets build.Import and build.Context.Import find code
1046 // in Go modules. In the long term we want tools to use go/packages (currently golang.org/x/tools/go/packages),
1047 // which will also use the go command.
1048 // Invoking the go command here is not very efficient in that it computes information
1049 // about the requested package and all dependencies and then only reports about the requested package.
1050 // Then we reinvoke it for every dependency. But this is still better than not working at all.
1051 // See golang.org/issue/26504.
1052 func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode) error {
1053 // To invoke the go command,
1054 // we must not being doing special things like AllowBinary or IgnoreVendor,
1055 // and all the file system callbacks must be nil (we're meant to use the local file system).
1056 if mode&AllowBinary != 0 || mode&IgnoreVendor != 0 ||
1057 ctxt.JoinPath != nil || ctxt.SplitPathList != nil || ctxt.IsAbsPath != nil || ctxt.IsDir != nil || ctxt.HasSubdir != nil || ctxt.ReadDir != nil || ctxt.OpenFile != nil || !equal(ctxt.ReleaseTags, defaultReleaseTags) {
1061 // Predict whether module aware mode is enabled by checking the value of
1062 // GO111MODULE and looking for a go.mod file in the source directory or
1063 // one of its parents. Running 'go env GOMOD' in the source directory would
1064 // give a canonical answer, but we'd prefer not to execute another command.
1065 go111Module := os.Getenv("GO111MODULE")
1066 switch go111Module {
1069 default: // "", "on", "auto", anything else
1070 // Maybe use modules.
1074 var absSrcDir string
1075 if filepath.IsAbs(srcDir) {
1077 } else if ctxt.Dir != "" {
1078 return fmt.Errorf("go/build: Dir is non-empty, so relative srcDir is not allowed: %v", srcDir)
1080 // Find the absolute source directory. hasSubdir does not handle
1081 // relative paths (and can't because the callbacks don't support this).
1083 absSrcDir, err = filepath.Abs(srcDir)
1089 // If the source directory is in GOROOT, then the in-process code works fine
1090 // and we should keep using it. Moreover, the 'go list' approach below doesn't
1091 // take standard-library vendoring into account and will fail.
1092 if _, ok := ctxt.hasSubdir(filepath.Join(ctxt.GOROOT, "src"), absSrcDir); ok {
1097 // For efficiency, if path is a standard library package, let the usual lookup code handle it.
1098 if ctxt.GOROOT != "" {
1099 dir := ctxt.joinPath(ctxt.GOROOT, "src", path)
1100 if ctxt.isDir(dir) {
1105 // If GO111MODULE=auto, look to see if there is a go.mod.
1106 // Since go1.13, it doesn't matter if we're inside GOPATH.
1107 if go111Module == "auto" {
1113 parent, err = os.Getwd()
1115 // A nonexistent working directory can't be in a module.
1119 parent, err = filepath.Abs(ctxt.Dir)
1121 // If the caller passed a bogus Dir explicitly, that's materially
1122 // different from not having modules enabled.
1127 if f, err := ctxt.openFile(ctxt.joinPath(parent, "go.mod")); err == nil {
1128 buf := make([]byte, 100)
1129 _, err := f.Read(buf)
1131 if err == nil || err == io.EOF {
1132 // go.mod exists and is readable (is a file, not a directory).
1136 d := filepath.Dir(parent)
1137 if len(d) >= len(parent) {
1138 return errNoModules // reached top of file system, no go.mod
1144 cmd := exec.Command("go", "list", "-e", "-compiler="+ctxt.Compiler, "-tags="+strings.Join(ctxt.BuildTags, ","), "-installsuffix="+ctxt.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n{{if .Error}}{{.Error}}{{end}}\n", "--", path)
1150 var stdout, stderr strings.Builder
1151 cmd.Stdout = &stdout
1152 cmd.Stderr = &stderr
1155 if ctxt.CgoEnabled {
1158 cmd.Env = append(os.Environ(),
1160 "GOARCH="+ctxt.GOARCH,
1161 "GOROOT="+ctxt.GOROOT,
1162 "GOPATH="+ctxt.GOPATH,
1166 if err := cmd.Run(); err != nil {
1167 return fmt.Errorf("go/build: go list %s: %v\n%s\n", path, err, stderr.String())
1170 f := strings.SplitN(stdout.String(), "\n", 5)
1172 return fmt.Errorf("go/build: importGo %s: unexpected output:\n%s\n", path, stdout.String())
1175 errStr := strings.TrimSpace(f[4])
1176 if errStr != "" && dir == "" {
1177 // If 'go list' could not locate the package (dir is empty),
1178 // return the same error that 'go list' reported.
1179 return errors.New(errStr)
1182 // If 'go list' did locate the package, ignore the error.
1183 // It was probably related to loading source files, and we'll
1184 // encounter it ourselves shortly if the FindOnly flag isn't set.
1188 p.Goroot = f[3] == "true"
1192 func equal(x, y []string) bool {
1193 if len(x) != len(y) {
1196 for i, xi := range x {
1204 // hasGoFiles reports whether dir contains any files with names ending in .go.
1205 // For a vendor check we must exclude directories that contain no .go files.
1206 // Otherwise it is not possible to vendor just a/b/c and still import the
1207 // non-vendored a/b. See golang.org/issue/13832.
1208 func hasGoFiles(ctxt *Context, dir string) bool {
1209 ents, _ := ctxt.readDir(dir)
1210 for _, ent := range ents {
1211 if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") {
1218 func findImportComment(data []byte) (s string, line int) {
1219 // expect keyword package
1220 word, data := parseWord(data)
1221 if string(word) != "package" {
1225 // expect package name
1226 _, data = parseWord(data)
1228 // now ready for import comment, a // or /* */ comment
1229 // beginning and ending on the current line.
1230 for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') {
1236 case bytes.HasPrefix(data, slashSlash):
1237 i := bytes.Index(data, newline)
1242 case bytes.HasPrefix(data, slashStar):
1244 i := bytes.Index(data, starSlash)
1246 // malformed comment
1250 if bytes.Contains(comment, newline) {
1254 comment = bytes.TrimSpace(comment)
1256 // split comment into `import`, `"pkg"`
1257 word, arg := parseWord(comment)
1258 if string(word) != "import" {
1262 line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline)
1263 return strings.TrimSpace(string(arg)), line
1267 slashSlash = []byte("//")
1268 slashStar = []byte("/*")
1269 starSlash = []byte("*/")
1270 newline = []byte("\n")
1273 // skipSpaceOrComment returns data with any leading spaces or comments removed.
1274 func skipSpaceOrComment(data []byte) []byte {
1277 case ' ', '\t', '\r', '\n':
1281 if bytes.HasPrefix(data, slashSlash) {
1282 i := bytes.Index(data, newline)
1289 if bytes.HasPrefix(data, slashStar) {
1291 i := bytes.Index(data, starSlash)
1304 // parseWord skips any leading spaces or comments in data
1305 // and then parses the beginning of data as an identifier or keyword,
1306 // returning that word and what remains after the word.
1307 func parseWord(data []byte) (word, rest []byte) {
1308 data = skipSpaceOrComment(data)
1310 // Parse past leading word characters.
1313 r, size := utf8.DecodeRune(rest)
1314 if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' {
1321 word = data[:len(data)-len(rest)]
1329 // MatchFile reports whether the file with the given name in the given directory
1330 // matches the context and would be included in a Package created by ImportDir
1331 // of that directory.
1333 // MatchFile considers the name of the file and may use ctxt.OpenFile to
1334 // read some or all of the file's content.
1335 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
1336 info, err := ctxt.matchFile(dir, name, nil, nil, nil)
1337 return info != nil, err
1340 var dummyPkg Package
1342 // fileInfo records information learned about a file included in a build.
1343 type fileInfo struct {
1344 name string // full name including dir
1349 imports []fileImport
1354 type fileImport struct {
1357 doc *ast.CommentGroup
1360 type fileEmbed struct {
1365 // matchFile determines whether the file with the given name in the given directory
1366 // should be included in the package being constructed.
1367 // If the file should be included, matchFile returns a non-nil *fileInfo (and a nil error).
1368 // Non-nil errors are reserved for unexpected problems.
1370 // If name denotes a Go program, matchFile reads until the end of the
1371 // imports and returns that section of the file in the fileInfo's header field,
1372 // even though it only considers text until the first non-comment
1373 // for +build lines.
1375 // If allTags is non-nil, matchFile records any encountered build tag
1376 // by setting allTags[tag] = true.
1377 func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
1378 if strings.HasPrefix(name, "_") ||
1379 strings.HasPrefix(name, ".") {
1383 i := strings.LastIndex(name, ".")
1389 if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
1393 if ext != ".go" && fileListForExt(&dummyPkg, ext) == nil {
1398 info := &fileInfo{name: ctxt.joinPath(dir, name), fset: fset}
1400 // binary, no reading
1404 f, err := ctxt.openFile(info.name)
1409 if strings.HasSuffix(name, ".go") {
1410 err = readGoInfo(f, info)
1411 if strings.HasSuffix(name, "_test.go") {
1412 binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
1415 binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
1416 info.header, err = readComments(f)
1420 return nil, fmt.Errorf("read %s: %v", info.name, err)
1423 // Look for +build comments to accept or reject the file.
1424 ok, sawBinaryOnly, err := ctxt.shouldBuild(info.header, allTags)
1428 if !ok && !ctxt.UseAllFiles {
1432 if binaryOnly != nil && sawBinaryOnly {
1439 func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
1440 all := make([]string, 0, len(m))
1441 for path := range m {
1442 all = append(all, path)
1448 // Import is shorthand for Default.Import.
1449 func Import(path, srcDir string, mode ImportMode) (*Package, error) {
1450 return Default.Import(path, srcDir, mode)
1453 // ImportDir is shorthand for Default.ImportDir.
1454 func ImportDir(dir string, mode ImportMode) (*Package, error) {
1455 return Default.ImportDir(dir, mode)
1459 bSlashSlash = []byte(slashSlash)
1460 bStarSlash = []byte(starSlash)
1461 bSlashStar = []byte(slashStar)
1463 goBuildComment = []byte("//go:build")
1465 errGoBuildWithoutBuild = errors.New("//go:build comment without // +build comment")
1466 errMultipleGoBuild = errors.New("multiple //go:build comments") // unused in Go 1.(N-1)
1469 func isGoBuildComment(line []byte) bool {
1470 if !bytes.HasPrefix(line, goBuildComment) {
1473 line = bytes.TrimSpace(line)
1474 rest := line[len(goBuildComment):]
1475 return len(rest) == 0 || len(bytes.TrimSpace(rest)) < len(rest)
1478 // Special comment denoting a binary-only package.
1479 // See https://golang.org/design/2775-binary-only-packages
1480 // for more about the design of binary-only packages.
1481 var binaryOnlyComment = []byte("//go:binary-only-package")
1483 // shouldBuild reports whether it is okay to use this file,
1484 // The rule is that in the file's leading run of // comments
1485 // and blank lines, which must be followed by a blank line
1486 // (to avoid including a Go package clause doc comment),
1487 // lines beginning with '// +build' are taken as build directives.
1489 // The file is accepted only if each such line lists something
1490 // matching the file. For example:
1492 // // +build windows linux
1494 // marks the file as applicable only on Windows and Linux.
1496 // For each build tag it consults, shouldBuild sets allTags[tag] = true.
1498 // shouldBuild reports whether the file should be built
1499 // and whether a //go:binary-only-package comment was found.
1500 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) (shouldBuild, binaryOnly bool, err error) {
1502 // Pass 1. Identify leading run of // comments and blank lines,
1503 // which must be followed by a blank line.
1504 // Also identify any //go:build comments.
1505 content, goBuild, sawBinaryOnly, err := parseFileHeader(content)
1507 return false, false, err
1510 // Pass 2. Process each +build line in the run.
1516 if i := bytes.IndexByte(line, '\n'); i >= 0 {
1517 line, p = line[:i], p[i+1:]
1521 line = bytes.TrimSpace(line)
1522 if !bytes.HasPrefix(line, bSlashSlash) {
1525 line = bytes.TrimSpace(line[len(bSlashSlash):])
1526 if len(line) > 0 && line[0] == '+' {
1527 // Looks like a comment +line.
1528 f := strings.Fields(string(line))
1529 if f[0] == "+build" {
1532 for _, tok := range f[1:] {
1533 if ctxt.match(tok, allTags) {
1544 if goBuild != nil && !sawBuild {
1545 return false, false, errGoBuildWithoutBuild
1548 return shouldBuild, sawBinaryOnly, nil
1551 func parseFileHeader(content []byte) (trimmed, goBuild []byte, sawBinaryOnly bool, err error) {
1554 ended := false // found non-blank, non-// line, so stopped accepting // +build lines
1555 inSlashStar := false // in /* */ comment
1560 if i := bytes.IndexByte(line, '\n'); i >= 0 {
1561 line, p = line[:i], p[i+1:]
1565 line = bytes.TrimSpace(line)
1566 if len(line) == 0 && !ended { // Blank line
1567 // Remember position of most recent blank line.
1568 // When we find the first non-blank, non-// line,
1569 // this "end" position marks the latest file position
1570 // where a // +build line can appear.
1571 // (It must appear _before_ a blank line before the non-blank, non-// line.
1572 // Yes, that's confusing, which is part of why we moved to //go:build lines.)
1573 // Note that ended==false here means that inSlashStar==false,
1574 // since seeing a /* would have set ended==true.
1575 end = len(content) - len(p)
1578 if !bytes.HasPrefix(line, slashSlash) { // Not comment line
1582 if !inSlashStar && isGoBuildComment(line) {
1583 if false && goBuild != nil { // enabled in Go 1.N
1584 return nil, nil, false, errMultipleGoBuild
1588 if !inSlashStar && bytes.Equal(line, binaryOnlyComment) {
1589 sawBinaryOnly = true
1595 if i := bytes.Index(line, starSlash); i >= 0 {
1597 line = bytes.TrimSpace(line[i+len(starSlash):])
1602 if bytes.HasPrefix(line, bSlashSlash) {
1605 if bytes.HasPrefix(line, bSlashStar) {
1607 line = bytes.TrimSpace(line[len(bSlashStar):])
1610 // Found non-comment text.
1615 return content[:end], goBuild, sawBinaryOnly, nil
1618 // saveCgo saves the information from the #cgo lines in the import "C" comment.
1619 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
1620 // that affect the way cgo's C code is built.
1621 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
1623 for _, line := range strings.Split(text, "\n") {
1627 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
1629 line = strings.TrimSpace(line)
1630 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') {
1635 line = strings.TrimSpace(line[4:])
1636 i := strings.Index(line, ":")
1638 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1640 line, argstr := line[:i], line[i+1:]
1642 // Parse GOOS/GOARCH stuff.
1643 f := strings.Fields(line)
1645 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1648 cond, verb := f[:len(f)-1], f[len(f)-1]
1651 for _, c := range cond {
1652 if ctxt.match(c, nil) {
1662 args, err := splitQuoted(argstr)
1664 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
1667 for i, arg := range args {
1668 if arg, ok = expandSrcDir(arg, di.Dir); !ok {
1669 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
1675 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS":
1676 // Change relative paths to absolute.
1677 ctxt.makePathsAbsolute(args, di.Dir)
1682 di.CgoCFLAGS = append(di.CgoCFLAGS, args...)
1684 di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
1686 di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
1688 di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
1690 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
1692 di.CgoPkgConfig = append(di.CgoPkgConfig, args...)
1694 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig)
1700 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure
1701 // the result is safe for the shell.
1702 func expandSrcDir(str string, srcdir string) (string, bool) {
1703 // "\" delimited paths cause safeCgoName to fail
1704 // so convert native paths with a different delimiter
1705 // to "/" before starting (eg: on windows).
1706 srcdir = filepath.ToSlash(srcdir)
1708 chunks := strings.Split(str, "${SRCDIR}")
1709 if len(chunks) < 2 {
1710 return str, safeCgoName(str)
1713 for _, chunk := range chunks {
1714 ok = ok && (chunk == "" || safeCgoName(chunk))
1716 ok = ok && (srcdir == "" || safeCgoName(srcdir))
1717 res := strings.Join(chunks, srcdir)
1718 return res, ok && res != ""
1721 // makePathsAbsolute looks for compiler options that take paths and
1722 // makes them absolute. We do this because through the 1.8 release we
1723 // ran the compiler in the package directory, so any relative -I or -L
1724 // options would be relative to that directory. In 1.9 we changed to
1725 // running the compiler in the build directory, to get consistent
1726 // build results (issue #19964). To keep builds working, we change any
1727 // relative -I or -L options to be absolute.
1729 // Using filepath.IsAbs and filepath.Join here means the results will be
1730 // different on different systems, but that's OK: -I and -L options are
1731 // inherently system-dependent.
1732 func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) {
1734 for i, arg := range args {
1736 if !filepath.IsAbs(arg) {
1737 args[i] = filepath.Join(srcDir, arg)
1740 } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") {
1744 if !filepath.IsAbs(arg[2:]) {
1745 args[i] = arg[:2] + filepath.Join(srcDir, arg[2:])
1752 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
1753 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
1754 // See golang.org/issue/6038.
1755 // The @ is for OS X. See golang.org/issue/13720.
1756 // The % is for Jenkins. See golang.org/issue/16959.
1757 // The ! is because module paths may use them. See golang.org/issue/26716.
1758 // The ~ and ^ are for sr.ht. See golang.org/issue/32260.
1759 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%! ~^"
1761 func safeCgoName(s string) bool {
1765 for i := 0; i < len(s); i++ {
1766 if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 {
1773 // splitQuoted splits the string s around each instance of one or more consecutive
1774 // white space characters while taking into account quotes and escaping, and
1775 // returns an array of substrings of s or an empty list if s contains only white space.
1776 // Single quotes and double quotes are recognized to prevent splitting within the
1777 // quoted region, and are removed from the resulting substrings. If a quote in s
1778 // isn't closed err will be set and r will have the unclosed argument as the
1779 // last element. The backslash is used for escaping.
1781 // For example, the following string:
1783 // a b:"c d" 'e''f' "g\""
1785 // Would be parsed as:
1787 // []string{"a", "b:c d", "ef", `g"`}
1789 func splitQuoted(s string) (r []string, err error) {
1791 arg := make([]rune, len(s))
1796 for _, rune := range s {
1803 case quote != '\x00':
1808 case rune == '"' || rune == '\'':
1812 case unicode.IsSpace(rune):
1813 if quoted || i > 0 {
1815 args = append(args, string(arg[:i]))
1823 if quoted || i > 0 {
1824 args = append(args, string(arg[:i]))
1827 err = errors.New("unclosed quote")
1829 err = errors.New("unfinished escaping")
1834 // match reports whether the name is one of:
1838 // cgo (if cgo is enabled)
1839 // !cgo (if cgo is disabled)
1843 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags)
1844 // !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags)
1845 // a comma-separated list of any of these
1847 func (ctxt *Context) match(name string, allTags map[string]bool) bool {
1850 allTags[name] = true
1854 if i := strings.Index(name, ","); i >= 0 {
1855 // comma-separated list
1856 ok1 := ctxt.match(name[:i], allTags)
1857 ok2 := ctxt.match(name[i+1:], allTags)
1860 if strings.HasPrefix(name, "!!") { // bad syntax, reject always
1863 if strings.HasPrefix(name, "!") { // negation
1864 return len(name) > 1 && !ctxt.match(name[1:], allTags)
1868 allTags[name] = true
1871 // Tags must be letters, digits, underscores or dots.
1872 // Unlike in Go identifiers, all digits are fine (e.g., "386").
1873 for _, c := range name {
1874 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
1880 if ctxt.CgoEnabled && name == "cgo" {
1883 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
1886 if ctxt.GOOS == "android" && name == "linux" {
1889 if ctxt.GOOS == "illumos" && name == "solaris" {
1892 if ctxt.GOOS == "ios" && name == "darwin" {
1895 // Let applications know that the Go+BoringCrypto toolchain is in use.
1896 if name == "boringcrypto" {
1901 for _, tag := range ctxt.BuildTags {
1906 for _, tag := range ctxt.ReleaseTags {
1915 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
1916 // suffix which does not match the current system.
1917 // The recognized name formats are:
1921 // name_$(GOOS)_$(GOARCH).*
1922 // name_$(GOOS)_test.*
1923 // name_$(GOARCH)_test.*
1924 // name_$(GOOS)_$(GOARCH)_test.*
1927 // if GOOS=android, then files with GOOS=linux are also matched.
1928 // if GOOS=illumos, then files with GOOS=solaris are also matched.
1929 // if GOOS=ios, then files with GOOS=darwin are also matched.
1930 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
1931 if dot := strings.Index(name, "."); dot != -1 {
1935 // Before Go 1.4, a file called "linux.go" would be equivalent to having a
1936 // build tag "linux" in that file. For Go 1.4 and beyond, we require this
1937 // auto-tagging to apply only to files with a non-empty prefix, so
1938 // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
1939 // systems, such as android, to arrive without breaking existing code with
1940 // innocuous source code in "android.go". The easiest fix: cut everything
1941 // in the name before the initial _.
1942 i := strings.Index(name, "_")
1946 name = name[i:] // ignore everything before first _
1948 l := strings.Split(name, "_")
1949 if n := len(l); n > 0 && l[n-1] == "test" {
1953 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
1954 return ctxt.match(l[n-1], allTags) && ctxt.match(l[n-2], allTags)
1956 if n >= 1 && (knownOS[l[n-1]] || knownArch[l[n-1]]) {
1957 return ctxt.match(l[n-1], allTags)
1962 var knownOS = make(map[string]bool)
1963 var knownArch = make(map[string]bool)
1966 for _, v := range strings.Fields(goosList) {
1969 for _, v := range strings.Fields(goarchList) {
1974 // ToolDir is the directory containing build tools.
1975 var ToolDir = getToolDir()
1977 // IsLocalImport reports whether the import path is
1978 // a local import path, like ".", "..", "./foo", or "../foo".
1979 func IsLocalImport(path string) bool {
1980 return path == "." || path == ".." ||
1981 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
1984 // ArchChar returns "?" and an error.
1985 // In earlier versions of Go, the returned string was used to derive
1986 // the compiler and linker tool names, the default object file suffix,
1987 // and the default linker output name. As of Go 1.5, those strings
1988 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
1989 func ArchChar(goarch string) (string, error) {
1990 return "?", errors.New("architecture letter no longer used")