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