github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/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 "go/ast" 12 "go/doc" 13 "go/parser" 14 "go/token" 15 "io" 16 "io/ioutil" 17 "log" 18 "os" 19 pathpkg "path" 20 "path/filepath" 21 "runtime" 22 "sort" 23 "strconv" 24 "strings" 25 "unicode" 26 "unicode/utf8" 27 ) 28 29 // A Context specifies the supporting context for a build. 30 type Context struct { 31 GOARCH string // target architecture 32 GOOS string // target operating system 33 GOROOT string // Go root 34 GOPATH string // Go path 35 CgoEnabled bool // whether cgo can be used 36 UseAllFiles bool // use files regardless of +build lines, file names 37 Compiler string // compiler to assume when computing target paths 38 39 // The build and release tags specify build constraints 40 // that should be considered satisfied when processing +build lines. 41 // Clients creating a new context may customize BuildTags, which 42 // defaults to empty, but it is usually an error to customize ReleaseTags, 43 // which defaults to the list of Go releases the current release is compatible with. 44 // In addition to the BuildTags and ReleaseTags, build constraints 45 // consider the values of GOARCH and GOOS as satisfied tags. 46 BuildTags []string 47 ReleaseTags []string 48 49 // The install suffix specifies a suffix to use in the name of the installation 50 // directory. By default it is empty, but custom builds that need to keep 51 // their outputs separate can set InstallSuffix to do so. For example, when 52 // using the race detector, the go command uses InstallSuffix = "race", so 53 // that on a Linux/386 system, packages are written to a directory named 54 // "linux_386_race" instead of the usual "linux_386". 55 InstallSuffix string 56 57 // By default, Import uses the operating system's file system calls 58 // to read directories and files. To read from other sources, 59 // callers can set the following functions. They all have default 60 // behaviors that use the local file system, so clients need only set 61 // the functions whose behaviors they wish to change. 62 63 // JoinPath joins the sequence of path fragments into a single path. 64 // If JoinPath is nil, Import uses filepath.Join. 65 JoinPath func(elem ...string) string 66 67 // SplitPathList splits the path list into a slice of individual paths. 68 // If SplitPathList is nil, Import uses filepath.SplitList. 69 SplitPathList func(list string) []string 70 71 // IsAbsPath reports whether path is an absolute path. 72 // If IsAbsPath is nil, Import uses filepath.IsAbs. 73 IsAbsPath func(path string) bool 74 75 // IsDir reports whether the path names a directory. 76 // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method. 77 IsDir func(path string) bool 78 79 // HasSubdir reports whether dir is lexically a subdirectory of 80 // root, perhaps multiple levels below. It does not try to check 81 // whether dir exists. 82 // If so, HasSubdir sets rel to a slash-separated path that 83 // can be joined to root to produce a path equivalent to dir. 84 // If HasSubdir is nil, Import uses an implementation built on 85 // filepath.EvalSymlinks. 86 HasSubdir func(root, dir string) (rel string, ok bool) 87 88 // ReadDir returns a slice of os.FileInfo, sorted by Name, 89 // describing the content of the named directory. 90 // If ReadDir is nil, Import uses ioutil.ReadDir. 91 ReadDir func(dir string) ([]os.FileInfo, error) 92 93 // OpenFile opens a file (not a directory) for reading. 94 // If OpenFile is nil, Import uses os.Open. 95 OpenFile func(path string) (io.ReadCloser, error) 96 } 97 98 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join. 99 func (ctxt *Context) joinPath(elem ...string) string { 100 if f := ctxt.JoinPath; f != nil { 101 return f(elem...) 102 } 103 return filepath.Join(elem...) 104 } 105 106 // splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList. 107 func (ctxt *Context) splitPathList(s string) []string { 108 if f := ctxt.SplitPathList; f != nil { 109 return f(s) 110 } 111 return filepath.SplitList(s) 112 } 113 114 // isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs. 115 func (ctxt *Context) isAbsPath(path string) bool { 116 if f := ctxt.IsAbsPath; f != nil { 117 return f(path) 118 } 119 return filepath.IsAbs(path) 120 } 121 122 // isDir calls ctxt.IsDir (if not nil) or else uses os.Stat. 123 func (ctxt *Context) isDir(path string) bool { 124 if f := ctxt.IsDir; f != nil { 125 return f(path) 126 } 127 fi, err := os.Stat(path) 128 return err == nil && fi.IsDir() 129 } 130 131 // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses 132 // the local file system to answer the question. 133 func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) { 134 if f := ctxt.HasSubdir; f != nil { 135 return f(root, dir) 136 } 137 138 // Try using paths we received. 139 if rel, ok = hasSubdir(root, dir); ok { 140 return 141 } 142 143 // Try expanding symlinks and comparing 144 // expanded against unexpanded and 145 // expanded against expanded. 146 rootSym, _ := filepath.EvalSymlinks(root) 147 dirSym, _ := filepath.EvalSymlinks(dir) 148 149 if rel, ok = hasSubdir(rootSym, dir); ok { 150 return 151 } 152 if rel, ok = hasSubdir(root, dirSym); ok { 153 return 154 } 155 return hasSubdir(rootSym, dirSym) 156 } 157 158 // hasSubdir reports if dir is within root by performing lexical analysis only. 159 func hasSubdir(root, dir string) (rel string, ok bool) { 160 const sep = string(filepath.Separator) 161 root = filepath.Clean(root) 162 if !strings.HasSuffix(root, sep) { 163 root += sep 164 } 165 dir = filepath.Clean(dir) 166 if !strings.HasPrefix(dir, root) { 167 return "", false 168 } 169 return filepath.ToSlash(dir[len(root):]), true 170 } 171 172 // readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir. 173 func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) { 174 if f := ctxt.ReadDir; f != nil { 175 return f(path) 176 } 177 return ioutil.ReadDir(path) 178 } 179 180 // openFile calls ctxt.OpenFile (if not nil) or else os.Open. 181 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) { 182 if fn := ctxt.OpenFile; fn != nil { 183 return fn(path) 184 } 185 186 f, err := os.Open(path) 187 if err != nil { 188 return nil, err // nil interface 189 } 190 return f, nil 191 } 192 193 // isFile determines whether path is a file by trying to open it. 194 // It reuses openFile instead of adding another function to the 195 // list in Context. 196 func (ctxt *Context) isFile(path string) bool { 197 f, err := ctxt.openFile(path) 198 if err != nil { 199 return false 200 } 201 f.Close() 202 return true 203 } 204 205 // gopath returns the list of Go path directories. 206 func (ctxt *Context) gopath() []string { 207 var all []string 208 for _, p := range ctxt.splitPathList(ctxt.GOPATH) { 209 if p == "" || p == ctxt.GOROOT { 210 // Empty paths are uninteresting. 211 // If the path is the GOROOT, ignore it. 212 // People sometimes set GOPATH=$GOROOT. 213 // Do not get confused by this common mistake. 214 continue 215 } 216 if strings.HasPrefix(p, "~") { 217 // Path segments starting with ~ on Unix are almost always 218 // users who have incorrectly quoted ~ while setting GOPATH, 219 // preventing it from expanding to $HOME. 220 // The situation is made more confusing by the fact that 221 // bash allows quoted ~ in $PATH (most shells do not). 222 // Do not get confused by this, and do not try to use the path. 223 // It does not exist, and printing errors about it confuses 224 // those users even more, because they think "sure ~ exists!". 225 // The go command diagnoses this situation and prints a 226 // useful error. 227 // On Windows, ~ is used in short names, such as c:\progra~1 228 // for c:\program files. 229 continue 230 } 231 all = append(all, p) 232 } 233 return all 234 } 235 236 // SrcDirs returns a list of package source root directories. 237 // It draws from the current Go root and Go path but omits directories 238 // that do not exist. 239 func (ctxt *Context) SrcDirs() []string { 240 var all []string 241 if ctxt.GOROOT != "" { 242 dir := ctxt.joinPath(ctxt.GOROOT, "src") 243 if ctxt.isDir(dir) { 244 all = append(all, dir) 245 } 246 } 247 for _, p := range ctxt.gopath() { 248 dir := ctxt.joinPath(p, "src") 249 if ctxt.isDir(dir) { 250 all = append(all, dir) 251 } 252 } 253 return all 254 } 255 256 // Default is the default Context for builds. 257 // It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables 258 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT. 259 var Default Context = defaultContext() 260 261 func defaultGOPATH() string { 262 env := "HOME" 263 if runtime.GOOS == "windows" { 264 env = "USERPROFILE" 265 } else if runtime.GOOS == "plan9" { 266 env = "home" 267 } 268 if home := os.Getenv(env); home != "" { 269 def := filepath.Join(home, "go") 270 if filepath.Clean(def) == filepath.Clean(runtime.GOROOT()) { 271 // Don't set the default GOPATH to GOROOT, 272 // as that will trigger warnings from the go tool. 273 return "" 274 } 275 return def 276 } 277 return "" 278 } 279 280 func defaultContext() Context { 281 var c Context 282 283 c.GOARCH = envOr("GOARCH", runtime.GOARCH) 284 c.GOOS = envOr("GOOS", runtime.GOOS) 285 c.GOROOT = pathpkg.Clean(runtime.GOROOT()) 286 c.GOPATH = envOr("GOPATH", defaultGOPATH()) 287 c.Compiler = runtime.Compiler 288 289 // Each major Go release in the Go 1.x series should add a tag here. 290 // Old tags should not be removed. That is, the go1.x tag is present 291 // in all releases >= Go 1.x. Code that requires Go 1.x or later should 292 // say "+build go1.x", and code that should only be built before Go 1.x 293 // (perhaps it is the stub to use in that case) should say "+build !go1.x". 294 // NOTE: If you add to this list, also update the doc comment in doc.go. 295 const version = 10 // go1.10 296 for i := 1; i <= version; i++ { 297 c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i)) 298 } 299 300 env := os.Getenv("CGO_ENABLED") 301 if env == "" { 302 env = defaultCGO_ENABLED 303 } 304 switch env { 305 case "1": 306 c.CgoEnabled = true 307 case "0": 308 c.CgoEnabled = false 309 default: 310 // cgo must be explicitly enabled for cross compilation builds 311 if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS { 312 c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH] 313 break 314 } 315 c.CgoEnabled = false 316 } 317 318 return c 319 } 320 321 func envOr(name, def string) string { 322 s := os.Getenv(name) 323 if s == "" { 324 return def 325 } 326 return s 327 } 328 329 // An ImportMode controls the behavior of the Import method. 330 type ImportMode uint 331 332 const ( 333 // If FindOnly is set, Import stops after locating the directory 334 // that should contain the sources for a package. It does not 335 // read any files in the directory. 336 FindOnly ImportMode = 1 << iota 337 338 // If AllowBinary is set, Import can be satisfied by a compiled 339 // package object without corresponding sources. 340 // 341 // Deprecated: 342 // The supported way to create a compiled-only package is to 343 // write source code containing a //go:binary-only-package comment at 344 // the top of the file. Such a package will be recognized 345 // regardless of this flag setting (because it has source code) 346 // and will have BinaryOnly set to true in the returned Package. 347 AllowBinary 348 349 // If ImportComment is set, parse import comments on package statements. 350 // Import returns an error if it finds a comment it cannot understand 351 // or finds conflicting comments in multiple source files. 352 // See golang.org/s/go14customimport for more information. 353 ImportComment 354 355 // By default, Import searches vendor directories 356 // that apply in the given source directory before searching 357 // the GOROOT and GOPATH roots. 358 // If an Import finds and returns a package using a vendor 359 // directory, the resulting ImportPath is the complete path 360 // to the package, including the path elements leading up 361 // to and including "vendor". 362 // For example, if Import("y", "x/subdir", 0) finds 363 // "x/vendor/y", the returned package's ImportPath is "x/vendor/y", 364 // not plain "y". 365 // See golang.org/s/go15vendor for more information. 366 // 367 // Setting IgnoreVendor ignores vendor directories. 368 // 369 // In contrast to the package's ImportPath, 370 // the returned package's Imports, TestImports, and XTestImports 371 // are always the exact import paths from the source files: 372 // Import makes no attempt to resolve or check those paths. 373 IgnoreVendor 374 ) 375 376 // A Package describes the Go package found in a directory. 377 type Package struct { 378 Dir string // directory containing package sources 379 Name string // package name 380 ImportComment string // path in import comment on package statement 381 Doc string // documentation synopsis 382 ImportPath string // import path of package ("" if unknown) 383 Root string // root of Go tree where this package lives 384 SrcRoot string // package source root directory ("" if unknown) 385 PkgRoot string // package install root directory ("" if unknown) 386 PkgTargetRoot string // architecture dependent install root directory ("" if unknown) 387 BinDir string // command install directory ("" if unknown) 388 Goroot bool // package found in Go root 389 PkgObj string // installed .a file 390 AllTags []string // tags that can influence file selection in this directory 391 ConflictDir string // this directory shadows Dir in $GOPATH 392 BinaryOnly bool // cannot be rebuilt from source (has //go:binary-only-package comment) 393 394 // Source files 395 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) 396 CgoFiles []string // .go source files that import "C" 397 IgnoredGoFiles []string // .go source files ignored for this build 398 InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on) 399 CFiles []string // .c source files 400 CXXFiles []string // .cc, .cpp and .cxx source files 401 MFiles []string // .m (Objective-C) source files 402 HFiles []string // .h, .hh, .hpp and .hxx source files 403 FFiles []string // .f, .F, .for and .f90 Fortran source files 404 SFiles []string // .s source files 405 SwigFiles []string // .swig files 406 SwigCXXFiles []string // .swigcxx files 407 SysoFiles []string // .syso system object files to add to archive 408 409 // Cgo directives 410 CgoCFLAGS []string // Cgo CFLAGS directives 411 CgoCPPFLAGS []string // Cgo CPPFLAGS directives 412 CgoCXXFLAGS []string // Cgo CXXFLAGS directives 413 CgoFFLAGS []string // Cgo FFLAGS directives 414 CgoLDFLAGS []string // Cgo LDFLAGS directives 415 CgoPkgConfig []string // Cgo pkg-config directives 416 417 // Dependency information 418 Imports []string // import paths from GoFiles, CgoFiles 419 ImportPos map[string][]token.Position // line information for Imports 420 421 // Test information 422 TestGoFiles []string // _test.go files in package 423 TestImports []string // import paths from TestGoFiles 424 TestImportPos map[string][]token.Position // line information for TestImports 425 XTestGoFiles []string // _test.go files outside package 426 XTestImports []string // import paths from XTestGoFiles 427 XTestImportPos map[string][]token.Position // line information for XTestImports 428 429 // Gosecure information 430 Gosectargets map[string][]string // The gosecure nodes sorted by package 431 } 432 433 // IsCommand reports whether the package is considered a 434 // command to be installed (not just a library). 435 // Packages named "main" are treated as commands. 436 func (p *Package) IsCommand() bool { 437 return p.Name == "main" 438 } 439 440 // ImportDir is like Import but processes the Go package found in 441 // the named directory. 442 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { 443 return ctxt.Import(".", dir, mode) 444 } 445 446 // NoGoError is the error used by Import to describe a directory 447 // containing no buildable Go source files. (It may still contain 448 // test files, files hidden by build tags, and so on.) 449 type NoGoError struct { 450 Dir string 451 } 452 453 func (e *NoGoError) Error() string { 454 return "no buildable Go source files in " + e.Dir 455 } 456 457 // MultiplePackageError describes a directory containing 458 // multiple buildable Go source files for multiple packages. 459 type MultiplePackageError struct { 460 Dir string // directory containing files 461 Packages []string // package names found 462 Files []string // corresponding files: Files[i] declares package Packages[i] 463 } 464 465 func (e *MultiplePackageError) Error() string { 466 // Error string limited to two entries for compatibility. 467 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) 468 } 469 470 func nameExt(name string) string { 471 i := strings.LastIndex(name, ".") 472 if i < 0 { 473 return "" 474 } 475 return name[i:] 476 } 477 478 // Import returns details about the Go package named by the import path, 479 // interpreting local import paths relative to the srcDir directory. 480 // If the path is a local import path naming a package that can be imported 481 // using a standard import path, the returned package will set p.ImportPath 482 // to that path. 483 // 484 // In the directory containing the package, .go, .c, .h, and .s files are 485 // considered part of the package except for: 486 // 487 // - .go files in package documentation 488 // - files starting with _ or . (likely editor temporary files) 489 // - files with build constraints not satisfied by the context 490 // 491 // If an error occurs, Import returns a non-nil error and a non-nil 492 // *Package containing partial information. 493 // 494 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) { 495 p := &Package{ 496 ImportPath: path, 497 } 498 if path == "" { 499 return p, fmt.Errorf("import %q: invalid import path", path) 500 } 501 502 var pkgtargetroot string 503 var pkga string 504 var pkgerr error 505 suffix := "" 506 if ctxt.InstallSuffix != "" { 507 suffix = "_" + ctxt.InstallSuffix 508 } 509 switch ctxt.Compiler { 510 case "gccgo": 511 pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix 512 case "gc": 513 pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix 514 default: 515 // Save error for end of function. 516 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler) 517 } 518 setPkga := func() { 519 switch ctxt.Compiler { 520 case "gccgo": 521 dir, elem := pathpkg.Split(p.ImportPath) 522 pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a" 523 case "gc": 524 pkga = pkgtargetroot + "/" + p.ImportPath + ".a" 525 } 526 } 527 setPkga() 528 529 binaryOnly := false 530 if IsLocalImport(path) { 531 pkga = "" // local imports have no installed path 532 if srcDir == "" { 533 return p, fmt.Errorf("import %q: import relative to unknown directory", path) 534 } 535 if !ctxt.isAbsPath(path) { 536 p.Dir = ctxt.joinPath(srcDir, path) 537 } 538 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later. 539 // Determine canonical import path, if any. 540 // Exclude results where the import path would include /testdata/. 541 inTestdata := func(sub string) bool { 542 return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" 543 } 544 if ctxt.GOROOT != "" { 545 root := ctxt.joinPath(ctxt.GOROOT, "src") 546 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { 547 p.Goroot = true 548 p.ImportPath = sub 549 p.Root = ctxt.GOROOT 550 setPkga() // p.ImportPath changed 551 goto Found 552 } 553 } 554 all := ctxt.gopath() 555 for i, root := range all { 556 rootsrc := ctxt.joinPath(root, "src") 557 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) { 558 // We found a potential import path for dir, 559 // but check that using it wouldn't find something 560 // else first. 561 if ctxt.GOROOT != "" { 562 if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) { 563 p.ConflictDir = dir 564 goto Found 565 } 566 } 567 for _, earlyRoot := range all[:i] { 568 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) { 569 p.ConflictDir = dir 570 goto Found 571 } 572 } 573 574 // sub would not name some other directory instead of this one. 575 // Record it. 576 p.ImportPath = sub 577 p.Root = root 578 setPkga() // p.ImportPath changed 579 goto Found 580 } 581 } 582 // It's okay that we didn't find a root containing dir. 583 // Keep going with the information we have. 584 } else { 585 if strings.HasPrefix(path, "/") { 586 return p, fmt.Errorf("import %q: cannot import absolute path", path) 587 } 588 589 // tried records the location of unsuccessful package lookups 590 var tried struct { 591 vendor []string 592 goroot string 593 gopath []string 594 } 595 gopath := ctxt.gopath() 596 597 // Vendor directories get first chance to satisfy import. 598 if mode&IgnoreVendor == 0 && srcDir != "" { 599 searchVendor := func(root string, isGoroot bool) bool { 600 sub, ok := ctxt.hasSubdir(root, srcDir) 601 if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") { 602 return false 603 } 604 for { 605 vendor := ctxt.joinPath(root, sub, "vendor") 606 if ctxt.isDir(vendor) { 607 dir := ctxt.joinPath(vendor, path) 608 if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) { 609 p.Dir = dir 610 p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/") 611 p.Goroot = isGoroot 612 p.Root = root 613 setPkga() // p.ImportPath changed 614 return true 615 } 616 tried.vendor = append(tried.vendor, dir) 617 } 618 i := strings.LastIndex(sub, "/") 619 if i < 0 { 620 break 621 } 622 sub = sub[:i] 623 } 624 return false 625 } 626 if searchVendor(ctxt.GOROOT, true) { 627 goto Found 628 } 629 for _, root := range gopath { 630 if searchVendor(root, false) { 631 goto Found 632 } 633 } 634 } 635 636 // Determine directory from import path. 637 if ctxt.GOROOT != "" { 638 dir := ctxt.joinPath(ctxt.GOROOT, "src", path) 639 isDir := ctxt.isDir(dir) 640 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) 641 if isDir || binaryOnly { 642 p.Dir = dir 643 p.Goroot = true 644 p.Root = ctxt.GOROOT 645 goto Found 646 } 647 tried.goroot = dir 648 } 649 for _, root := range gopath { 650 dir := ctxt.joinPath(root, "src", path) 651 isDir := ctxt.isDir(dir) 652 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga)) 653 if isDir || binaryOnly { 654 p.Dir = dir 655 p.Root = root 656 goto Found 657 } 658 tried.gopath = append(tried.gopath, dir) 659 } 660 661 // package was not found 662 var paths []string 663 format := "\t%s (vendor tree)" 664 for _, dir := range tried.vendor { 665 paths = append(paths, fmt.Sprintf(format, dir)) 666 format = "\t%s" 667 } 668 if tried.goroot != "" { 669 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot)) 670 } else { 671 paths = append(paths, "\t($GOROOT not set)") 672 } 673 format = "\t%s (from $GOPATH)" 674 for _, dir := range tried.gopath { 675 paths = append(paths, fmt.Sprintf(format, dir)) 676 format = "\t%s" 677 } 678 if len(tried.gopath) == 0 { 679 paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')") 680 } 681 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n")) 682 } 683 684 Found: 685 if p.Root != "" { 686 p.SrcRoot = ctxt.joinPath(p.Root, "src") 687 p.PkgRoot = ctxt.joinPath(p.Root, "pkg") 688 p.BinDir = ctxt.joinPath(p.Root, "bin") 689 if pkga != "" { 690 p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot) 691 p.PkgObj = ctxt.joinPath(p.Root, pkga) 692 } 693 } 694 695 // If it's a local import path, by the time we get here, we still haven't checked 696 // that p.Dir directory exists. This is the right time to do that check. 697 // We can't do it earlier, because we want to gather partial information for the 698 // non-nil *Package returned when an error occurs. 699 // We need to do this before we return early on FindOnly flag. 700 if IsLocalImport(path) && !ctxt.isDir(p.Dir) { 701 // package was not found 702 return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir) 703 } 704 705 if mode&FindOnly != 0 { 706 return p, pkgerr 707 } 708 if binaryOnly && (mode&AllowBinary) != 0 { 709 return p, pkgerr 710 } 711 712 dirs, err := ctxt.readDir(p.Dir) 713 if err != nil { 714 return p, err 715 } 716 717 var badGoError error 718 var Sfiles []string // files with ".S" (capital S) 719 var firstFile, firstCommentFile string 720 imported := make(map[string][]token.Position) 721 testImported := make(map[string][]token.Position) 722 xTestImported := make(map[string][]token.Position) 723 allTags := make(map[string]bool) 724 fset := token.NewFileSet() 725 for _, d := range dirs { 726 if d.IsDir() { 727 continue 728 } 729 730 name := d.Name() 731 ext := nameExt(name) 732 733 badFile := func(err error) { 734 if badGoError == nil { 735 badGoError = err 736 } 737 p.InvalidGoFiles = append(p.InvalidGoFiles, name) 738 } 739 740 match, data, filename, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly) 741 if err != nil { 742 badFile(err) 743 continue 744 } 745 if !match { 746 if ext == ".go" { 747 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 748 } 749 continue 750 } 751 752 // Going to save the file. For non-Go files, can stop here. 753 switch ext { 754 case ".c": 755 p.CFiles = append(p.CFiles, name) 756 continue 757 case ".cc", ".cpp", ".cxx": 758 p.CXXFiles = append(p.CXXFiles, name) 759 continue 760 case ".m": 761 p.MFiles = append(p.MFiles, name) 762 continue 763 case ".h", ".hh", ".hpp", ".hxx": 764 p.HFiles = append(p.HFiles, name) 765 continue 766 case ".f", ".F", ".for", ".f90": 767 p.FFiles = append(p.FFiles, name) 768 continue 769 case ".s": 770 p.SFiles = append(p.SFiles, name) 771 continue 772 case ".S": 773 Sfiles = append(Sfiles, name) 774 continue 775 case ".swig": 776 p.SwigFiles = append(p.SwigFiles, name) 777 continue 778 case ".swigcxx": 779 p.SwigCXXFiles = append(p.SwigCXXFiles, name) 780 continue 781 case ".syso": 782 // binary objects to add to package archive 783 // Likely of the form foo_windows.syso, but 784 // the name was vetted above with goodOSArchFile. 785 p.SysoFiles = append(p.SysoFiles, name) 786 continue 787 } 788 789 pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments) 790 if err != nil { 791 badFile(err) 792 continue 793 } 794 795 pkg := pf.Name.Name 796 if pkg == "documentation" { 797 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 798 continue 799 } 800 801 isTest := strings.HasSuffix(name, "_test.go") 802 isXTest := false 803 if isTest && strings.HasSuffix(pkg, "_test") { 804 isXTest = true 805 pkg = pkg[:len(pkg)-len("_test")] 806 } 807 808 if p.Name == "" { 809 p.Name = pkg 810 firstFile = name 811 } else if pkg != p.Name { 812 badFile(&MultiplePackageError{ 813 Dir: p.Dir, 814 Packages: []string{p.Name, pkg}, 815 Files: []string{firstFile, name}, 816 }) 817 p.InvalidGoFiles = append(p.InvalidGoFiles, name) 818 } 819 if pf.Doc != nil && p.Doc == "" { 820 p.Doc = doc.Synopsis(pf.Doc.Text()) 821 } 822 823 if mode&ImportComment != 0 { 824 qcom, line := findImportComment(data) 825 if line != 0 { 826 com, err := strconv.Unquote(qcom) 827 if err != nil { 828 badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line)) 829 } else if p.ImportComment == "" { 830 p.ImportComment = com 831 firstCommentFile = name 832 } else if p.ImportComment != com { 833 badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)) 834 } 835 } 836 } 837 838 // Record imports and information about cgo. 839 isCgo := false 840 for _, decl := range pf.Decls { 841 d, ok := decl.(*ast.GenDecl) 842 if !ok { 843 continue 844 } 845 for _, dspec := range d.Specs { 846 spec, ok := dspec.(*ast.ImportSpec) 847 if !ok { 848 continue 849 } 850 quoted := spec.Path.Value 851 path, err := strconv.Unquote(quoted) 852 if err != nil { 853 log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) 854 } 855 if isXTest { 856 xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos())) 857 } else if isTest { 858 testImported[path] = append(testImported[path], fset.Position(spec.Pos())) 859 } else { 860 imported[path] = append(imported[path], fset.Position(spec.Pos())) 861 } 862 if path == "C" { 863 if isTest { 864 badFile(fmt.Errorf("use of cgo in test %s not supported", filename)) 865 } else { 866 cg := spec.Doc 867 if cg == nil && len(d.Specs) == 1 { 868 cg = d.Doc 869 } 870 if cg != nil { 871 if err := ctxt.saveCgo(filename, p, cg); err != nil { 872 badFile(err) 873 } 874 } 875 isCgo = true 876 } 877 } 878 } 879 } 880 if isCgo { 881 allTags["cgo"] = true 882 if ctxt.CgoEnabled { 883 p.CgoFiles = append(p.CgoFiles, name) 884 } else { 885 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 886 } 887 } else if isXTest { 888 p.XTestGoFiles = append(p.XTestGoFiles, name) 889 } else if isTest { 890 p.TestGoFiles = append(p.TestGoFiles, name) 891 } else { 892 p.GoFiles = append(p.GoFiles, name) 893 } 894 895 // @aghosn add the gosecure callees. 896 p.Gosectargets = pf.GosecCalls 897 } 898 if badGoError != nil { 899 return p, badGoError 900 } 901 if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { 902 return p, &NoGoError{p.Dir} 903 } 904 905 for tag := range allTags { 906 p.AllTags = append(p.AllTags, tag) 907 } 908 sort.Strings(p.AllTags) 909 910 p.Imports, p.ImportPos = cleanImports(imported) 911 if p.Gosectargets != nil && len(p.Gosectargets) > 0 { 912 p.Imports = append(p.Imports, "gosec") 913 } 914 p.TestImports, p.TestImportPos = cleanImports(testImported) 915 p.XTestImports, p.XTestImportPos = cleanImports(xTestImported) 916 917 // add the .S files only if we are using cgo 918 // (which means gcc will compile them). 919 // The standard assemblers expect .s files. 920 if len(p.CgoFiles) > 0 { 921 p.SFiles = append(p.SFiles, Sfiles...) 922 sort.Strings(p.SFiles) 923 } 924 925 return p, pkgerr 926 } 927 928 // hasGoFiles reports whether dir contains any files with names ending in .go. 929 // For a vendor check we must exclude directories that contain no .go files. 930 // Otherwise it is not possible to vendor just a/b/c and still import the 931 // non-vendored a/b. See golang.org/issue/13832. 932 func hasGoFiles(ctxt *Context, dir string) bool { 933 ents, _ := ctxt.readDir(dir) 934 for _, ent := range ents { 935 if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") { 936 return true 937 } 938 } 939 return false 940 } 941 942 func findImportComment(data []byte) (s string, line int) { 943 // expect keyword package 944 word, data := parseWord(data) 945 if string(word) != "package" { 946 return "", 0 947 } 948 949 // expect package name 950 _, data = parseWord(data) 951 952 // now ready for import comment, a // or /* */ comment 953 // beginning and ending on the current line. 954 for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') { 955 data = data[1:] 956 } 957 958 var comment []byte 959 switch { 960 case bytes.HasPrefix(data, slashSlash): 961 i := bytes.Index(data, newline) 962 if i < 0 { 963 i = len(data) 964 } 965 comment = data[2:i] 966 case bytes.HasPrefix(data, slashStar): 967 data = data[2:] 968 i := bytes.Index(data, starSlash) 969 if i < 0 { 970 // malformed comment 971 return "", 0 972 } 973 comment = data[:i] 974 if bytes.Contains(comment, newline) { 975 return "", 0 976 } 977 } 978 comment = bytes.TrimSpace(comment) 979 980 // split comment into `import`, `"pkg"` 981 word, arg := parseWord(comment) 982 if string(word) != "import" { 983 return "", 0 984 } 985 986 line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline) 987 return strings.TrimSpace(string(arg)), line 988 } 989 990 var ( 991 slashSlash = []byte("//") 992 slashStar = []byte("/*") 993 starSlash = []byte("*/") 994 newline = []byte("\n") 995 ) 996 997 // skipSpaceOrComment returns data with any leading spaces or comments removed. 998 func skipSpaceOrComment(data []byte) []byte { 999 for len(data) > 0 { 1000 switch data[0] { 1001 case ' ', '\t', '\r', '\n': 1002 data = data[1:] 1003 continue 1004 case '/': 1005 if bytes.HasPrefix(data, slashSlash) { 1006 i := bytes.Index(data, newline) 1007 if i < 0 { 1008 return nil 1009 } 1010 data = data[i+1:] 1011 continue 1012 } 1013 if bytes.HasPrefix(data, slashStar) { 1014 data = data[2:] 1015 i := bytes.Index(data, starSlash) 1016 if i < 0 { 1017 return nil 1018 } 1019 data = data[i+2:] 1020 continue 1021 } 1022 } 1023 break 1024 } 1025 return data 1026 } 1027 1028 // parseWord skips any leading spaces or comments in data 1029 // and then parses the beginning of data as an identifier or keyword, 1030 // returning that word and what remains after the word. 1031 func parseWord(data []byte) (word, rest []byte) { 1032 data = skipSpaceOrComment(data) 1033 1034 // Parse past leading word characters. 1035 rest = data 1036 for { 1037 r, size := utf8.DecodeRune(rest) 1038 if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' { 1039 rest = rest[size:] 1040 continue 1041 } 1042 break 1043 } 1044 1045 word = data[:len(data)-len(rest)] 1046 if len(word) == 0 { 1047 return nil, nil 1048 } 1049 1050 return word, rest 1051 } 1052 1053 // MatchFile reports whether the file with the given name in the given directory 1054 // matches the context and would be included in a Package created by ImportDir 1055 // of that directory. 1056 // 1057 // MatchFile considers the name of the file and may use ctxt.OpenFile to 1058 // read some or all of the file's content. 1059 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) { 1060 match, _, _, err = ctxt.matchFile(dir, name, nil, nil) 1061 return 1062 } 1063 1064 // matchFile determines whether the file with the given name in the given directory 1065 // should be included in the package being constructed. 1066 // It returns the data read from the file. 1067 // If name denotes a Go program, matchFile reads until the end of the 1068 // imports (and returns that data) even though it only considers text 1069 // until the first non-comment. 1070 // If allTags is non-nil, matchFile records any encountered build tag 1071 // by setting allTags[tag] = true. 1072 func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) { 1073 if strings.HasPrefix(name, "_") || 1074 strings.HasPrefix(name, ".") { 1075 return 1076 } 1077 1078 i := strings.LastIndex(name, ".") 1079 if i < 0 { 1080 i = len(name) 1081 } 1082 ext := name[i:] 1083 1084 if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles { 1085 return 1086 } 1087 1088 switch ext { 1089 case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx": 1090 // tentatively okay - read to make sure 1091 case ".syso": 1092 // binary, no reading 1093 match = true 1094 return 1095 default: 1096 // skip 1097 return 1098 } 1099 1100 filename = ctxt.joinPath(dir, name) 1101 f, err := ctxt.openFile(filename) 1102 if err != nil { 1103 return 1104 } 1105 1106 if strings.HasSuffix(filename, ".go") { 1107 data, err = readImports(f, false, nil) 1108 if strings.HasSuffix(filename, "_test.go") { 1109 binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files 1110 } 1111 } else { 1112 binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources 1113 data, err = readComments(f) 1114 } 1115 f.Close() 1116 if err != nil { 1117 err = fmt.Errorf("read %s: %v", filename, err) 1118 return 1119 } 1120 1121 // Look for +build comments to accept or reject the file. 1122 var sawBinaryOnly bool 1123 if !ctxt.shouldBuild(data, allTags, &sawBinaryOnly) && !ctxt.UseAllFiles { 1124 return 1125 } 1126 1127 if binaryOnly != nil && sawBinaryOnly { 1128 *binaryOnly = true 1129 } 1130 match = true 1131 return 1132 } 1133 1134 func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) { 1135 all := make([]string, 0, len(m)) 1136 for path := range m { 1137 all = append(all, path) 1138 } 1139 sort.Strings(all) 1140 return all, m 1141 } 1142 1143 // Import is shorthand for Default.Import. 1144 func Import(path, srcDir string, mode ImportMode) (*Package, error) { 1145 return Default.Import(path, srcDir, mode) 1146 } 1147 1148 // ImportDir is shorthand for Default.ImportDir. 1149 func ImportDir(dir string, mode ImportMode) (*Package, error) { 1150 return Default.ImportDir(dir, mode) 1151 } 1152 1153 var slashslash = []byte("//") 1154 1155 // Special comment denoting a binary-only package. 1156 // See https://golang.org/design/2775-binary-only-packages 1157 // for more about the design of binary-only packages. 1158 var binaryOnlyComment = []byte("//go:binary-only-package") 1159 1160 // shouldBuild reports whether it is okay to use this file, 1161 // The rule is that in the file's leading run of // comments 1162 // and blank lines, which must be followed by a blank line 1163 // (to avoid including a Go package clause doc comment), 1164 // lines beginning with '// +build' are taken as build directives. 1165 // 1166 // The file is accepted only if each such line lists something 1167 // matching the file. For example: 1168 // 1169 // // +build windows linux 1170 // 1171 // marks the file as applicable only on Windows and Linux. 1172 // 1173 // If shouldBuild finds a //go:binary-only-package comment in the file, 1174 // it sets *binaryOnly to true. Otherwise it does not change *binaryOnly. 1175 // 1176 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool { 1177 sawBinaryOnly := false 1178 1179 // Pass 1. Identify leading run of // comments and blank lines, 1180 // which must be followed by a blank line. 1181 end := 0 1182 p := content 1183 for len(p) > 0 { 1184 line := p 1185 if i := bytes.IndexByte(line, '\n'); i >= 0 { 1186 line, p = line[:i], p[i+1:] 1187 } else { 1188 p = p[len(p):] 1189 } 1190 line = bytes.TrimSpace(line) 1191 if len(line) == 0 { // Blank line 1192 end = len(content) - len(p) 1193 continue 1194 } 1195 if !bytes.HasPrefix(line, slashslash) { // Not comment line 1196 break 1197 } 1198 } 1199 content = content[:end] 1200 1201 // Pass 2. Process each line in the run. 1202 p = content 1203 allok := true 1204 for len(p) > 0 { 1205 line := p 1206 if i := bytes.IndexByte(line, '\n'); i >= 0 { 1207 line, p = line[:i], p[i+1:] 1208 } else { 1209 p = p[len(p):] 1210 } 1211 line = bytes.TrimSpace(line) 1212 if !bytes.HasPrefix(line, slashslash) { 1213 continue 1214 } 1215 if bytes.Equal(line, binaryOnlyComment) { 1216 sawBinaryOnly = true 1217 } 1218 line = bytes.TrimSpace(line[len(slashslash):]) 1219 if len(line) > 0 && line[0] == '+' { 1220 // Looks like a comment +line. 1221 f := strings.Fields(string(line)) 1222 if f[0] == "+build" { 1223 ok := false 1224 for _, tok := range f[1:] { 1225 if ctxt.match(tok, allTags) { 1226 ok = true 1227 } 1228 } 1229 if !ok { 1230 allok = false 1231 } 1232 } 1233 } 1234 } 1235 1236 if binaryOnly != nil && sawBinaryOnly { 1237 *binaryOnly = true 1238 } 1239 1240 return allok 1241 } 1242 1243 // saveCgo saves the information from the #cgo lines in the import "C" comment. 1244 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives 1245 // that affect the way cgo's C code is built. 1246 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { 1247 text := cg.Text() 1248 for _, line := range strings.Split(text, "\n") { 1249 orig := line 1250 1251 // Line is 1252 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff 1253 // 1254 line = strings.TrimSpace(line) 1255 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') { 1256 continue 1257 } 1258 1259 // Split at colon. 1260 line = strings.TrimSpace(line[4:]) 1261 i := strings.Index(line, ":") 1262 if i < 0 { 1263 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1264 } 1265 line, argstr := line[:i], line[i+1:] 1266 1267 // Parse GOOS/GOARCH stuff. 1268 f := strings.Fields(line) 1269 if len(f) < 1 { 1270 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1271 } 1272 1273 cond, verb := f[:len(f)-1], f[len(f)-1] 1274 if len(cond) > 0 { 1275 ok := false 1276 for _, c := range cond { 1277 if ctxt.match(c, nil) { 1278 ok = true 1279 break 1280 } 1281 } 1282 if !ok { 1283 continue 1284 } 1285 } 1286 1287 args, err := splitQuoted(argstr) 1288 if err != nil { 1289 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1290 } 1291 var ok bool 1292 for i, arg := range args { 1293 if arg, ok = expandSrcDir(arg, di.Dir); !ok { 1294 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg) 1295 } 1296 args[i] = arg 1297 } 1298 1299 switch verb { 1300 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS": 1301 // Change relative paths to absolute. 1302 ctxt.makePathsAbsolute(args, di.Dir) 1303 } 1304 1305 switch verb { 1306 case "CFLAGS": 1307 di.CgoCFLAGS = append(di.CgoCFLAGS, args...) 1308 case "CPPFLAGS": 1309 di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...) 1310 case "CXXFLAGS": 1311 di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...) 1312 case "FFLAGS": 1313 di.CgoFFLAGS = append(di.CgoFFLAGS, args...) 1314 case "LDFLAGS": 1315 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...) 1316 case "pkg-config": 1317 di.CgoPkgConfig = append(di.CgoPkgConfig, args...) 1318 default: 1319 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig) 1320 } 1321 } 1322 return nil 1323 } 1324 1325 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure 1326 // the result is safe for the shell. 1327 func expandSrcDir(str string, srcdir string) (string, bool) { 1328 // "\" delimited paths cause safeCgoName to fail 1329 // so convert native paths with a different delimiter 1330 // to "/" before starting (eg: on windows). 1331 srcdir = filepath.ToSlash(srcdir) 1332 1333 chunks := strings.Split(str, "${SRCDIR}") 1334 if len(chunks) < 2 { 1335 return str, safeCgoName(str) 1336 } 1337 ok := true 1338 for _, chunk := range chunks { 1339 ok = ok && (chunk == "" || safeCgoName(chunk)) 1340 } 1341 ok = ok && (srcdir == "" || safeCgoName(srcdir)) 1342 res := strings.Join(chunks, srcdir) 1343 return res, ok && res != "" 1344 } 1345 1346 // makePathsAbsolute looks for compiler options that take paths and 1347 // makes them absolute. We do this because through the 1.8 release we 1348 // ran the compiler in the package directory, so any relative -I or -L 1349 // options would be relative to that directory. In 1.9 we changed to 1350 // running the compiler in the build directory, to get consistent 1351 // build results (issue #19964). To keep builds working, we change any 1352 // relative -I or -L options to be absolute. 1353 // 1354 // Using filepath.IsAbs and filepath.Join here means the results will be 1355 // different on different systems, but that's OK: -I and -L options are 1356 // inherently system-dependent. 1357 func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) { 1358 nextPath := false 1359 for i, arg := range args { 1360 if nextPath { 1361 if !filepath.IsAbs(arg) { 1362 args[i] = filepath.Join(srcDir, arg) 1363 } 1364 nextPath = false 1365 } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") { 1366 if len(arg) == 2 { 1367 nextPath = true 1368 } else { 1369 if !filepath.IsAbs(arg[2:]) { 1370 args[i] = arg[:2] + filepath.Join(srcDir, arg[2:]) 1371 } 1372 } 1373 } 1374 } 1375 } 1376 1377 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. 1378 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. 1379 // See golang.org/issue/6038. 1380 // The @ is for OS X. See golang.org/issue/13720. 1381 // The % is for Jenkins. See golang.org/issue/16959. 1382 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% " 1383 1384 func safeCgoName(s string) bool { 1385 if s == "" { 1386 return false 1387 } 1388 for i := 0; i < len(s); i++ { 1389 if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 { 1390 return false 1391 } 1392 } 1393 return true 1394 } 1395 1396 // splitQuoted splits the string s around each instance of one or more consecutive 1397 // white space characters while taking into account quotes and escaping, and 1398 // returns an array of substrings of s or an empty list if s contains only white space. 1399 // Single quotes and double quotes are recognized to prevent splitting within the 1400 // quoted region, and are removed from the resulting substrings. If a quote in s 1401 // isn't closed err will be set and r will have the unclosed argument as the 1402 // last element. The backslash is used for escaping. 1403 // 1404 // For example, the following string: 1405 // 1406 // a b:"c d" 'e''f' "g\"" 1407 // 1408 // Would be parsed as: 1409 // 1410 // []string{"a", "b:c d", "ef", `g"`} 1411 // 1412 func splitQuoted(s string) (r []string, err error) { 1413 var args []string 1414 arg := make([]rune, len(s)) 1415 escaped := false 1416 quoted := false 1417 quote := '\x00' 1418 i := 0 1419 for _, rune := range s { 1420 switch { 1421 case escaped: 1422 escaped = false 1423 case rune == '\\': 1424 escaped = true 1425 continue 1426 case quote != '\x00': 1427 if rune == quote { 1428 quote = '\x00' 1429 continue 1430 } 1431 case rune == '"' || rune == '\'': 1432 quoted = true 1433 quote = rune 1434 continue 1435 case unicode.IsSpace(rune): 1436 if quoted || i > 0 { 1437 quoted = false 1438 args = append(args, string(arg[:i])) 1439 i = 0 1440 } 1441 continue 1442 } 1443 arg[i] = rune 1444 i++ 1445 } 1446 if quoted || i > 0 { 1447 args = append(args, string(arg[:i])) 1448 } 1449 if quote != 0 { 1450 err = errors.New("unclosed quote") 1451 } else if escaped { 1452 err = errors.New("unfinished escaping") 1453 } 1454 return args, err 1455 } 1456 1457 // match reports whether the name is one of: 1458 // 1459 // $GOOS 1460 // $GOARCH 1461 // cgo (if cgo is enabled) 1462 // !cgo (if cgo is disabled) 1463 // ctxt.Compiler 1464 // !ctxt.Compiler 1465 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) 1466 // !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) 1467 // a comma-separated list of any of these 1468 // 1469 func (ctxt *Context) match(name string, allTags map[string]bool) bool { 1470 if name == "" { 1471 if allTags != nil { 1472 allTags[name] = true 1473 } 1474 return false 1475 } 1476 if i := strings.Index(name, ","); i >= 0 { 1477 // comma-separated list 1478 ok1 := ctxt.match(name[:i], allTags) 1479 ok2 := ctxt.match(name[i+1:], allTags) 1480 return ok1 && ok2 1481 } 1482 if strings.HasPrefix(name, "!!") { // bad syntax, reject always 1483 return false 1484 } 1485 if strings.HasPrefix(name, "!") { // negation 1486 return len(name) > 1 && !ctxt.match(name[1:], allTags) 1487 } 1488 1489 if allTags != nil { 1490 allTags[name] = true 1491 } 1492 1493 // Tags must be letters, digits, underscores or dots. 1494 // Unlike in Go identifiers, all digits are fine (e.g., "386"). 1495 for _, c := range name { 1496 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { 1497 return false 1498 } 1499 } 1500 1501 // special tags 1502 if ctxt.CgoEnabled && name == "cgo" { 1503 return true 1504 } 1505 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { 1506 return true 1507 } 1508 if ctxt.GOOS == "android" && name == "linux" { 1509 return true 1510 } 1511 1512 // other tags 1513 for _, tag := range ctxt.BuildTags { 1514 if tag == name { 1515 return true 1516 } 1517 } 1518 for _, tag := range ctxt.ReleaseTags { 1519 if tag == name { 1520 return true 1521 } 1522 } 1523 1524 return false 1525 } 1526 1527 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH 1528 // suffix which does not match the current system. 1529 // The recognized name formats are: 1530 // 1531 // name_$(GOOS).* 1532 // name_$(GOARCH).* 1533 // name_$(GOOS)_$(GOARCH).* 1534 // name_$(GOOS)_test.* 1535 // name_$(GOARCH)_test.* 1536 // name_$(GOOS)_$(GOARCH)_test.* 1537 // 1538 // An exception: if GOOS=android, then files with GOOS=linux are also matched. 1539 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { 1540 if dot := strings.Index(name, "."); dot != -1 { 1541 name = name[:dot] 1542 } 1543 1544 // Before Go 1.4, a file called "linux.go" would be equivalent to having a 1545 // build tag "linux" in that file. For Go 1.4 and beyond, we require this 1546 // auto-tagging to apply only to files with a non-empty prefix, so 1547 // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating 1548 // systems, such as android, to arrive without breaking existing code with 1549 // innocuous source code in "android.go". The easiest fix: cut everything 1550 // in the name before the initial _. 1551 i := strings.Index(name, "_") 1552 if i < 0 { 1553 return true 1554 } 1555 name = name[i:] // ignore everything before first _ 1556 1557 l := strings.Split(name, "_") 1558 if n := len(l); n > 0 && l[n-1] == "test" { 1559 l = l[:n-1] 1560 } 1561 n := len(l) 1562 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { 1563 if allTags != nil { 1564 allTags[l[n-2]] = true 1565 allTags[l[n-1]] = true 1566 } 1567 if l[n-1] != ctxt.GOARCH { 1568 return false 1569 } 1570 if ctxt.GOOS == "android" && l[n-2] == "linux" { 1571 return true 1572 } 1573 return l[n-2] == ctxt.GOOS 1574 } 1575 if n >= 1 && knownOS[l[n-1]] { 1576 if allTags != nil { 1577 allTags[l[n-1]] = true 1578 } 1579 if ctxt.GOOS == "android" && l[n-1] == "linux" { 1580 return true 1581 } 1582 return l[n-1] == ctxt.GOOS 1583 } 1584 if n >= 1 && knownArch[l[n-1]] { 1585 if allTags != nil { 1586 allTags[l[n-1]] = true 1587 } 1588 return l[n-1] == ctxt.GOARCH 1589 } 1590 return true 1591 } 1592 1593 var knownOS = make(map[string]bool) 1594 var knownArch = make(map[string]bool) 1595 1596 func init() { 1597 for _, v := range strings.Fields(goosList) { 1598 knownOS[v] = true 1599 } 1600 for _, v := range strings.Fields(goarchList) { 1601 knownArch[v] = true 1602 } 1603 } 1604 1605 // ToolDir is the directory containing build tools. 1606 var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) 1607 1608 // IsLocalImport reports whether the import path is 1609 // a local import path, like ".", "..", "./foo", or "../foo". 1610 func IsLocalImport(path string) bool { 1611 return path == "." || path == ".." || 1612 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") 1613 } 1614 1615 // ArchChar returns "?" and an error. 1616 // In earlier versions of Go, the returned string was used to derive 1617 // the compiler and linker tool names, the default object file suffix, 1618 // and the default linker output name. As of Go 1.5, those strings 1619 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively. 1620 func ArchChar(goarch string) (string, error) { 1621 return "?", errors.New("architecture letter no longer used") 1622 }