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