github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/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 = 11 // go1.11 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 430 // IsCommand reports whether the package is considered a 431 // command to be installed (not just a library). 432 // Packages named "main" are treated as commands. 433 func (p *Package) IsCommand() bool { 434 return p.Name == "main" 435 } 436 437 // ImportDir is like Import but processes the Go package found in 438 // the named directory. 439 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { 440 return ctxt.Import(".", dir, mode) 441 } 442 443 // NoGoError is the error used by Import to describe a directory 444 // containing no buildable Go source files. (It may still contain 445 // test files, files hidden by build tags, and so on.) 446 type NoGoError struct { 447 Dir string 448 } 449 450 func (e *NoGoError) Error() string { 451 return "no buildable Go source files in " + e.Dir 452 } 453 454 // MultiplePackageError describes a directory containing 455 // multiple buildable Go source files for multiple packages. 456 type MultiplePackageError struct { 457 Dir string // directory containing files 458 Packages []string // package names found 459 Files []string // corresponding files: Files[i] declares package Packages[i] 460 } 461 462 func (e *MultiplePackageError) Error() string { 463 // Error string limited to two entries for compatibility. 464 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) 465 } 466 467 func nameExt(name string) string { 468 i := strings.LastIndex(name, ".") 469 if i < 0 { 470 return "" 471 } 472 return name[i:] 473 } 474 475 // Import returns details about the Go package named by the import path, 476 // interpreting local import paths relative to the srcDir directory. 477 // If the path is a local import path naming a package that can be imported 478 // using a standard import path, the returned package will set p.ImportPath 479 // to that path. 480 // 481 // In the directory containing the package, .go, .c, .h, and .s files are 482 // considered part of the package except for: 483 // 484 // - .go files in package documentation 485 // - files starting with _ or . (likely editor temporary files) 486 // - files with build constraints not satisfied by the context 487 // 488 // If an error occurs, Import returns a non-nil error and a non-nil 489 // *Package containing partial information. 490 // 491 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) { 492 p := &Package{ 493 ImportPath: path, 494 } 495 if path == "" { 496 return p, fmt.Errorf("import %q: invalid import path", path) 497 } 498 499 var pkgtargetroot string 500 var pkga string 501 var pkgerr error 502 suffix := "" 503 if ctxt.InstallSuffix != "" { 504 suffix = "_" + ctxt.InstallSuffix 505 } 506 switch ctxt.Compiler { 507 case "gccgo": 508 pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix 509 case "gc": 510 pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix 511 default: 512 // Save error for end of function. 513 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler) 514 } 515 setPkga := func() { 516 switch ctxt.Compiler { 517 case "gccgo": 518 dir, elem := pathpkg.Split(p.ImportPath) 519 pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a" 520 case "gc": 521 pkga = pkgtargetroot + "/" + p.ImportPath + ".a" 522 } 523 } 524 setPkga() 525 526 binaryOnly := false 527 if IsLocalImport(path) { 528 pkga = "" // local imports have no installed path 529 if srcDir == "" { 530 return p, fmt.Errorf("import %q: import relative to unknown directory", path) 531 } 532 if !ctxt.isAbsPath(path) { 533 p.Dir = ctxt.joinPath(srcDir, path) 534 } 535 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later. 536 // Determine canonical import path, if any. 537 // Exclude results where the import path would include /testdata/. 538 inTestdata := func(sub string) bool { 539 return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" 540 } 541 if ctxt.GOROOT != "" { 542 root := ctxt.joinPath(ctxt.GOROOT, "src") 543 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { 544 p.Goroot = true 545 p.ImportPath = sub 546 p.Root = ctxt.GOROOT 547 setPkga() // p.ImportPath changed 548 goto Found 549 } 550 } 551 all := ctxt.gopath() 552 for i, root := range all { 553 rootsrc := ctxt.joinPath(root, "src") 554 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) { 555 // We found a potential import path for dir, 556 // but check that using it wouldn't find something 557 // else first. 558 if ctxt.GOROOT != "" { 559 if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) { 560 p.ConflictDir = dir 561 goto Found 562 } 563 } 564 for _, earlyRoot := range all[:i] { 565 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) { 566 p.ConflictDir = dir 567 goto Found 568 } 569 } 570 571 // sub would not name some other directory instead of this one. 572 // Record it. 573 p.ImportPath = sub 574 p.Root = root 575 setPkga() // p.ImportPath changed 576 goto Found 577 } 578 } 579 // It's okay that we didn't find a root containing dir. 580 // Keep going with the information we have. 581 } else { 582 if strings.HasPrefix(path, "/") { 583 return p, fmt.Errorf("import %q: cannot import absolute path", path) 584 } 585 586 // tried records the location of unsuccessful package lookups 587 var tried struct { 588 vendor []string 589 goroot string 590 gopath []string 591 } 592 gopath := ctxt.gopath() 593 594 // Vendor directories get first chance to satisfy import. 595 if mode&IgnoreVendor == 0 && srcDir != "" { 596 searchVendor := func(root string, isGoroot bool) bool { 597 sub, ok := ctxt.hasSubdir(root, srcDir) 598 if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") { 599 return false 600 } 601 for { 602 vendor := ctxt.joinPath(root, sub, "vendor") 603 if ctxt.isDir(vendor) { 604 dir := ctxt.joinPath(vendor, path) 605 if ctxt.isDir(dir) && hasGoFiles(ctxt, dir) { 606 p.Dir = dir 607 p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/") 608 p.Goroot = isGoroot 609 p.Root = root 610 setPkga() // p.ImportPath changed 611 return true 612 } 613 tried.vendor = append(tried.vendor, dir) 614 } 615 i := strings.LastIndex(sub, "/") 616 if i < 0 { 617 break 618 } 619 sub = sub[:i] 620 } 621 return false 622 } 623 if searchVendor(ctxt.GOROOT, true) { 624 goto Found 625 } 626 for _, root := range gopath { 627 if searchVendor(root, false) { 628 goto Found 629 } 630 } 631 } 632 633 // Determine directory from import path. 634 if ctxt.GOROOT != "" { 635 dir := ctxt.joinPath(ctxt.GOROOT, "src", path) 636 isDir := ctxt.isDir(dir) 637 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) 638 if isDir || binaryOnly { 639 p.Dir = dir 640 p.Goroot = true 641 p.Root = ctxt.GOROOT 642 goto Found 643 } 644 tried.goroot = dir 645 } 646 for _, root := range gopath { 647 dir := ctxt.joinPath(root, "src", path) 648 isDir := ctxt.isDir(dir) 649 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga)) 650 if isDir || binaryOnly { 651 p.Dir = dir 652 p.Root = root 653 goto Found 654 } 655 tried.gopath = append(tried.gopath, dir) 656 } 657 658 // package was not found 659 var paths []string 660 format := "\t%s (vendor tree)" 661 for _, dir := range tried.vendor { 662 paths = append(paths, fmt.Sprintf(format, dir)) 663 format = "\t%s" 664 } 665 if tried.goroot != "" { 666 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot)) 667 } else { 668 paths = append(paths, "\t($GOROOT not set)") 669 } 670 format = "\t%s (from $GOPATH)" 671 for _, dir := range tried.gopath { 672 paths = append(paths, fmt.Sprintf(format, dir)) 673 format = "\t%s" 674 } 675 if len(tried.gopath) == 0 { 676 paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')") 677 } 678 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n")) 679 } 680 681 Found: 682 if p.Root != "" { 683 p.SrcRoot = ctxt.joinPath(p.Root, "src") 684 p.PkgRoot = ctxt.joinPath(p.Root, "pkg") 685 p.BinDir = ctxt.joinPath(p.Root, "bin") 686 if pkga != "" { 687 p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot) 688 p.PkgObj = ctxt.joinPath(p.Root, pkga) 689 } 690 } 691 692 // If it's a local import path, by the time we get here, we still haven't checked 693 // that p.Dir directory exists. This is the right time to do that check. 694 // We can't do it earlier, because we want to gather partial information for the 695 // non-nil *Package returned when an error occurs. 696 // We need to do this before we return early on FindOnly flag. 697 if IsLocalImport(path) && !ctxt.isDir(p.Dir) { 698 // package was not found 699 return p, fmt.Errorf("cannot find package %q in:\n\t%s", path, p.Dir) 700 } 701 702 if mode&FindOnly != 0 { 703 return p, pkgerr 704 } 705 if binaryOnly && (mode&AllowBinary) != 0 { 706 return p, pkgerr 707 } 708 709 dirs, err := ctxt.readDir(p.Dir) 710 if err != nil { 711 return p, err 712 } 713 714 var badGoError error 715 var Sfiles []string // files with ".S" (capital S) 716 var firstFile, firstCommentFile string 717 imported := make(map[string][]token.Position) 718 testImported := make(map[string][]token.Position) 719 xTestImported := make(map[string][]token.Position) 720 allTags := make(map[string]bool) 721 fset := token.NewFileSet() 722 for _, d := range dirs { 723 if d.IsDir() { 724 continue 725 } 726 727 name := d.Name() 728 ext := nameExt(name) 729 730 badFile := func(err error) { 731 if badGoError == nil { 732 badGoError = err 733 } 734 p.InvalidGoFiles = append(p.InvalidGoFiles, name) 735 } 736 737 match, data, filename, err := ctxt.matchFile(p.Dir, name, allTags, &p.BinaryOnly) 738 if err != nil { 739 badFile(err) 740 continue 741 } 742 if !match { 743 if ext == ".go" { 744 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 745 } 746 continue 747 } 748 749 // Going to save the file. For non-Go files, can stop here. 750 switch ext { 751 case ".c": 752 p.CFiles = append(p.CFiles, name) 753 continue 754 case ".cc", ".cpp", ".cxx": 755 p.CXXFiles = append(p.CXXFiles, name) 756 continue 757 case ".m": 758 p.MFiles = append(p.MFiles, name) 759 continue 760 case ".h", ".hh", ".hpp", ".hxx": 761 p.HFiles = append(p.HFiles, name) 762 continue 763 case ".f", ".F", ".for", ".f90": 764 p.FFiles = append(p.FFiles, name) 765 continue 766 case ".s": 767 p.SFiles = append(p.SFiles, name) 768 continue 769 case ".S": 770 Sfiles = append(Sfiles, name) 771 continue 772 case ".swig": 773 p.SwigFiles = append(p.SwigFiles, name) 774 continue 775 case ".swigcxx": 776 p.SwigCXXFiles = append(p.SwigCXXFiles, name) 777 continue 778 case ".syso": 779 // binary objects to add to package archive 780 // Likely of the form foo_windows.syso, but 781 // the name was vetted above with goodOSArchFile. 782 p.SysoFiles = append(p.SysoFiles, name) 783 continue 784 } 785 786 pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments) 787 if err != nil { 788 badFile(err) 789 continue 790 } 791 792 pkg := pf.Name.Name 793 if pkg == "documentation" { 794 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 795 continue 796 } 797 798 isTest := strings.HasSuffix(name, "_test.go") 799 isXTest := false 800 if isTest && strings.HasSuffix(pkg, "_test") { 801 isXTest = true 802 pkg = pkg[:len(pkg)-len("_test")] 803 } 804 805 if p.Name == "" { 806 p.Name = pkg 807 firstFile = name 808 } else if pkg != p.Name { 809 badFile(&MultiplePackageError{ 810 Dir: p.Dir, 811 Packages: []string{p.Name, pkg}, 812 Files: []string{firstFile, name}, 813 }) 814 p.InvalidGoFiles = append(p.InvalidGoFiles, name) 815 } 816 if pf.Doc != nil && p.Doc == "" { 817 p.Doc = doc.Synopsis(pf.Doc.Text()) 818 } 819 820 if mode&ImportComment != 0 { 821 qcom, line := findImportComment(data) 822 if line != 0 { 823 com, err := strconv.Unquote(qcom) 824 if err != nil { 825 badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line)) 826 } else if p.ImportComment == "" { 827 p.ImportComment = com 828 firstCommentFile = name 829 } else if p.ImportComment != com { 830 badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)) 831 } 832 } 833 } 834 835 // Record imports and information about cgo. 836 isCgo := false 837 for _, decl := range pf.Decls { 838 d, ok := decl.(*ast.GenDecl) 839 if !ok { 840 continue 841 } 842 for _, dspec := range d.Specs { 843 spec, ok := dspec.(*ast.ImportSpec) 844 if !ok { 845 continue 846 } 847 quoted := spec.Path.Value 848 path, err := strconv.Unquote(quoted) 849 if err != nil { 850 log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) 851 } 852 if isXTest { 853 xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos())) 854 } else if isTest { 855 testImported[path] = append(testImported[path], fset.Position(spec.Pos())) 856 } else { 857 imported[path] = append(imported[path], fset.Position(spec.Pos())) 858 } 859 if path == "C" { 860 if isTest { 861 badFile(fmt.Errorf("use of cgo in test %s not supported", filename)) 862 } else { 863 cg := spec.Doc 864 if cg == nil && len(d.Specs) == 1 { 865 cg = d.Doc 866 } 867 if cg != nil { 868 if err := ctxt.saveCgo(filename, p, cg); err != nil { 869 badFile(err) 870 } 871 } 872 isCgo = true 873 } 874 } 875 } 876 } 877 if isCgo { 878 allTags["cgo"] = true 879 if ctxt.CgoEnabled { 880 p.CgoFiles = append(p.CgoFiles, name) 881 } else { 882 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 883 } 884 } else if isXTest { 885 p.XTestGoFiles = append(p.XTestGoFiles, name) 886 } else if isTest { 887 p.TestGoFiles = append(p.TestGoFiles, name) 888 } else { 889 p.GoFiles = append(p.GoFiles, name) 890 } 891 } 892 if badGoError != nil { 893 return p, badGoError 894 } 895 if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { 896 return p, &NoGoError{p.Dir} 897 } 898 899 for tag := range allTags { 900 p.AllTags = append(p.AllTags, tag) 901 } 902 sort.Strings(p.AllTags) 903 904 p.Imports, p.ImportPos = cleanImports(imported) 905 p.TestImports, p.TestImportPos = cleanImports(testImported) 906 p.XTestImports, p.XTestImportPos = cleanImports(xTestImported) 907 908 // add the .S files only if we are using cgo 909 // (which means gcc will compile them). 910 // The standard assemblers expect .s files. 911 if len(p.CgoFiles) > 0 { 912 p.SFiles = append(p.SFiles, Sfiles...) 913 sort.Strings(p.SFiles) 914 } 915 916 return p, pkgerr 917 } 918 919 // hasGoFiles reports whether dir contains any files with names ending in .go. 920 // For a vendor check we must exclude directories that contain no .go files. 921 // Otherwise it is not possible to vendor just a/b/c and still import the 922 // non-vendored a/b. See golang.org/issue/13832. 923 func hasGoFiles(ctxt *Context, dir string) bool { 924 ents, _ := ctxt.readDir(dir) 925 for _, ent := range ents { 926 if !ent.IsDir() && strings.HasSuffix(ent.Name(), ".go") { 927 return true 928 } 929 } 930 return false 931 } 932 933 func findImportComment(data []byte) (s string, line int) { 934 // expect keyword package 935 word, data := parseWord(data) 936 if string(word) != "package" { 937 return "", 0 938 } 939 940 // expect package name 941 _, data = parseWord(data) 942 943 // now ready for import comment, a // or /* */ comment 944 // beginning and ending on the current line. 945 for len(data) > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\r') { 946 data = data[1:] 947 } 948 949 var comment []byte 950 switch { 951 case bytes.HasPrefix(data, slashSlash): 952 i := bytes.Index(data, newline) 953 if i < 0 { 954 i = len(data) 955 } 956 comment = data[2:i] 957 case bytes.HasPrefix(data, slashStar): 958 data = data[2:] 959 i := bytes.Index(data, starSlash) 960 if i < 0 { 961 // malformed comment 962 return "", 0 963 } 964 comment = data[:i] 965 if bytes.Contains(comment, newline) { 966 return "", 0 967 } 968 } 969 comment = bytes.TrimSpace(comment) 970 971 // split comment into `import`, `"pkg"` 972 word, arg := parseWord(comment) 973 if string(word) != "import" { 974 return "", 0 975 } 976 977 line = 1 + bytes.Count(data[:cap(data)-cap(arg)], newline) 978 return strings.TrimSpace(string(arg)), line 979 } 980 981 var ( 982 slashSlash = []byte("//") 983 slashStar = []byte("/*") 984 starSlash = []byte("*/") 985 newline = []byte("\n") 986 ) 987 988 // skipSpaceOrComment returns data with any leading spaces or comments removed. 989 func skipSpaceOrComment(data []byte) []byte { 990 for len(data) > 0 { 991 switch data[0] { 992 case ' ', '\t', '\r', '\n': 993 data = data[1:] 994 continue 995 case '/': 996 if bytes.HasPrefix(data, slashSlash) { 997 i := bytes.Index(data, newline) 998 if i < 0 { 999 return nil 1000 } 1001 data = data[i+1:] 1002 continue 1003 } 1004 if bytes.HasPrefix(data, slashStar) { 1005 data = data[2:] 1006 i := bytes.Index(data, starSlash) 1007 if i < 0 { 1008 return nil 1009 } 1010 data = data[i+2:] 1011 continue 1012 } 1013 } 1014 break 1015 } 1016 return data 1017 } 1018 1019 // parseWord skips any leading spaces or comments in data 1020 // and then parses the beginning of data as an identifier or keyword, 1021 // returning that word and what remains after the word. 1022 func parseWord(data []byte) (word, rest []byte) { 1023 data = skipSpaceOrComment(data) 1024 1025 // Parse past leading word characters. 1026 rest = data 1027 for { 1028 r, size := utf8.DecodeRune(rest) 1029 if unicode.IsLetter(r) || '0' <= r && r <= '9' || r == '_' { 1030 rest = rest[size:] 1031 continue 1032 } 1033 break 1034 } 1035 1036 word = data[:len(data)-len(rest)] 1037 if len(word) == 0 { 1038 return nil, nil 1039 } 1040 1041 return word, rest 1042 } 1043 1044 // MatchFile reports whether the file with the given name in the given directory 1045 // matches the context and would be included in a Package created by ImportDir 1046 // of that directory. 1047 // 1048 // MatchFile considers the name of the file and may use ctxt.OpenFile to 1049 // read some or all of the file's content. 1050 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) { 1051 match, _, _, err = ctxt.matchFile(dir, name, nil, nil) 1052 return 1053 } 1054 1055 // matchFile determines whether the file with the given name in the given directory 1056 // should be included in the package being constructed. 1057 // It returns the data read from the file. 1058 // If name denotes a Go program, matchFile reads until the end of the 1059 // imports (and returns that data) even though it only considers text 1060 // until the first non-comment. 1061 // If allTags is non-nil, matchFile records any encountered build tag 1062 // by setting allTags[tag] = true. 1063 func (ctxt *Context) matchFile(dir, name string, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) { 1064 if strings.HasPrefix(name, "_") || 1065 strings.HasPrefix(name, ".") { 1066 return 1067 } 1068 1069 i := strings.LastIndex(name, ".") 1070 if i < 0 { 1071 i = len(name) 1072 } 1073 ext := name[i:] 1074 1075 if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles { 1076 return 1077 } 1078 1079 switch ext { 1080 case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx": 1081 // tentatively okay - read to make sure 1082 case ".syso": 1083 // binary, no reading 1084 match = true 1085 return 1086 default: 1087 // skip 1088 return 1089 } 1090 1091 filename = ctxt.joinPath(dir, name) 1092 f, err := ctxt.openFile(filename) 1093 if err != nil { 1094 return 1095 } 1096 1097 if strings.HasSuffix(filename, ".go") { 1098 data, err = readImports(f, false, nil) 1099 if strings.HasSuffix(filename, "_test.go") { 1100 binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files 1101 } 1102 } else { 1103 binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources 1104 data, err = readComments(f) 1105 } 1106 f.Close() 1107 if err != nil { 1108 err = fmt.Errorf("read %s: %v", filename, err) 1109 return 1110 } 1111 1112 // Look for +build comments to accept or reject the file. 1113 var sawBinaryOnly bool 1114 if !ctxt.shouldBuild(data, allTags, &sawBinaryOnly) && !ctxt.UseAllFiles { 1115 return 1116 } 1117 1118 if binaryOnly != nil && sawBinaryOnly { 1119 *binaryOnly = true 1120 } 1121 match = true 1122 return 1123 } 1124 1125 func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) { 1126 all := make([]string, 0, len(m)) 1127 for path := range m { 1128 all = append(all, path) 1129 } 1130 sort.Strings(all) 1131 return all, m 1132 } 1133 1134 // Import is shorthand for Default.Import. 1135 func Import(path, srcDir string, mode ImportMode) (*Package, error) { 1136 return Default.Import(path, srcDir, mode) 1137 } 1138 1139 // ImportDir is shorthand for Default.ImportDir. 1140 func ImportDir(dir string, mode ImportMode) (*Package, error) { 1141 return Default.ImportDir(dir, mode) 1142 } 1143 1144 var slashslash = []byte("//") 1145 1146 // Special comment denoting a binary-only package. 1147 // See https://golang.org/design/2775-binary-only-packages 1148 // for more about the design of binary-only packages. 1149 var binaryOnlyComment = []byte("//go:binary-only-package") 1150 1151 // shouldBuild reports whether it is okay to use this file, 1152 // The rule is that in the file's leading run of // comments 1153 // and blank lines, which must be followed by a blank line 1154 // (to avoid including a Go package clause doc comment), 1155 // lines beginning with '// +build' are taken as build directives. 1156 // 1157 // The file is accepted only if each such line lists something 1158 // matching the file. For example: 1159 // 1160 // // +build windows linux 1161 // 1162 // marks the file as applicable only on Windows and Linux. 1163 // 1164 // If shouldBuild finds a //go:binary-only-package comment in the file, 1165 // it sets *binaryOnly to true. Otherwise it does not change *binaryOnly. 1166 // 1167 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool { 1168 sawBinaryOnly := false 1169 1170 // Pass 1. Identify leading run of // comments and blank lines, 1171 // which must be followed by a blank line. 1172 end := 0 1173 p := content 1174 for len(p) > 0 { 1175 line := p 1176 if i := bytes.IndexByte(line, '\n'); i >= 0 { 1177 line, p = line[:i], p[i+1:] 1178 } else { 1179 p = p[len(p):] 1180 } 1181 line = bytes.TrimSpace(line) 1182 if len(line) == 0 { // Blank line 1183 end = len(content) - len(p) 1184 continue 1185 } 1186 if !bytes.HasPrefix(line, slashslash) { // Not comment line 1187 break 1188 } 1189 } 1190 content = content[:end] 1191 1192 // Pass 2. Process each line in the run. 1193 p = content 1194 allok := true 1195 for len(p) > 0 { 1196 line := p 1197 if i := bytes.IndexByte(line, '\n'); i >= 0 { 1198 line, p = line[:i], p[i+1:] 1199 } else { 1200 p = p[len(p):] 1201 } 1202 line = bytes.TrimSpace(line) 1203 if !bytes.HasPrefix(line, slashslash) { 1204 continue 1205 } 1206 if bytes.Equal(line, binaryOnlyComment) { 1207 sawBinaryOnly = true 1208 } 1209 line = bytes.TrimSpace(line[len(slashslash):]) 1210 if len(line) > 0 && line[0] == '+' { 1211 // Looks like a comment +line. 1212 f := strings.Fields(string(line)) 1213 if f[0] == "+build" { 1214 ok := false 1215 for _, tok := range f[1:] { 1216 if ctxt.match(tok, allTags) { 1217 ok = true 1218 } 1219 } 1220 if !ok { 1221 allok = false 1222 } 1223 } 1224 } 1225 } 1226 1227 if binaryOnly != nil && sawBinaryOnly { 1228 *binaryOnly = true 1229 } 1230 1231 return allok 1232 } 1233 1234 // saveCgo saves the information from the #cgo lines in the import "C" comment. 1235 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives 1236 // that affect the way cgo's C code is built. 1237 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { 1238 text := cg.Text() 1239 for _, line := range strings.Split(text, "\n") { 1240 orig := line 1241 1242 // Line is 1243 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff 1244 // 1245 line = strings.TrimSpace(line) 1246 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') { 1247 continue 1248 } 1249 1250 // Split at colon. 1251 line = strings.TrimSpace(line[4:]) 1252 i := strings.Index(line, ":") 1253 if i < 0 { 1254 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1255 } 1256 line, argstr := line[:i], line[i+1:] 1257 1258 // Parse GOOS/GOARCH stuff. 1259 f := strings.Fields(line) 1260 if len(f) < 1 { 1261 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1262 } 1263 1264 cond, verb := f[:len(f)-1], f[len(f)-1] 1265 if len(cond) > 0 { 1266 ok := false 1267 for _, c := range cond { 1268 if ctxt.match(c, nil) { 1269 ok = true 1270 break 1271 } 1272 } 1273 if !ok { 1274 continue 1275 } 1276 } 1277 1278 args, err := splitQuoted(argstr) 1279 if err != nil { 1280 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 1281 } 1282 var ok bool 1283 for i, arg := range args { 1284 if arg, ok = expandSrcDir(arg, di.Dir); !ok { 1285 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg) 1286 } 1287 args[i] = arg 1288 } 1289 1290 switch verb { 1291 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS": 1292 // Change relative paths to absolute. 1293 ctxt.makePathsAbsolute(args, di.Dir) 1294 } 1295 1296 switch verb { 1297 case "CFLAGS": 1298 di.CgoCFLAGS = append(di.CgoCFLAGS, args...) 1299 case "CPPFLAGS": 1300 di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...) 1301 case "CXXFLAGS": 1302 di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...) 1303 case "FFLAGS": 1304 di.CgoFFLAGS = append(di.CgoFFLAGS, args...) 1305 case "LDFLAGS": 1306 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...) 1307 case "pkg-config": 1308 di.CgoPkgConfig = append(di.CgoPkgConfig, args...) 1309 default: 1310 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig) 1311 } 1312 } 1313 return nil 1314 } 1315 1316 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure 1317 // the result is safe for the shell. 1318 func expandSrcDir(str string, srcdir string) (string, bool) { 1319 // "\" delimited paths cause safeCgoName to fail 1320 // so convert native paths with a different delimiter 1321 // to "/" before starting (eg: on windows). 1322 srcdir = filepath.ToSlash(srcdir) 1323 1324 chunks := strings.Split(str, "${SRCDIR}") 1325 if len(chunks) < 2 { 1326 return str, safeCgoName(str) 1327 } 1328 ok := true 1329 for _, chunk := range chunks { 1330 ok = ok && (chunk == "" || safeCgoName(chunk)) 1331 } 1332 ok = ok && (srcdir == "" || safeCgoName(srcdir)) 1333 res := strings.Join(chunks, srcdir) 1334 return res, ok && res != "" 1335 } 1336 1337 // makePathsAbsolute looks for compiler options that take paths and 1338 // makes them absolute. We do this because through the 1.8 release we 1339 // ran the compiler in the package directory, so any relative -I or -L 1340 // options would be relative to that directory. In 1.9 we changed to 1341 // running the compiler in the build directory, to get consistent 1342 // build results (issue #19964). To keep builds working, we change any 1343 // relative -I or -L options to be absolute. 1344 // 1345 // Using filepath.IsAbs and filepath.Join here means the results will be 1346 // different on different systems, but that's OK: -I and -L options are 1347 // inherently system-dependent. 1348 func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) { 1349 nextPath := false 1350 for i, arg := range args { 1351 if nextPath { 1352 if !filepath.IsAbs(arg) { 1353 args[i] = filepath.Join(srcDir, arg) 1354 } 1355 nextPath = false 1356 } else if strings.HasPrefix(arg, "-I") || strings.HasPrefix(arg, "-L") { 1357 if len(arg) == 2 { 1358 nextPath = true 1359 } else { 1360 if !filepath.IsAbs(arg[2:]) { 1361 args[i] = arg[:2] + filepath.Join(srcDir, arg[2:]) 1362 } 1363 } 1364 } 1365 } 1366 } 1367 1368 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. 1369 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. 1370 // See golang.org/issue/6038. 1371 // The @ is for OS X. See golang.org/issue/13720. 1372 // The % is for Jenkins. See golang.org/issue/16959. 1373 const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% " 1374 1375 func safeCgoName(s string) bool { 1376 if s == "" { 1377 return false 1378 } 1379 for i := 0; i < len(s); i++ { 1380 if c := s[i]; c < utf8.RuneSelf && strings.IndexByte(safeString, c) < 0 { 1381 return false 1382 } 1383 } 1384 return true 1385 } 1386 1387 // splitQuoted splits the string s around each instance of one or more consecutive 1388 // white space characters while taking into account quotes and escaping, and 1389 // returns an array of substrings of s or an empty list if s contains only white space. 1390 // Single quotes and double quotes are recognized to prevent splitting within the 1391 // quoted region, and are removed from the resulting substrings. If a quote in s 1392 // isn't closed err will be set and r will have the unclosed argument as the 1393 // last element. The backslash is used for escaping. 1394 // 1395 // For example, the following string: 1396 // 1397 // a b:"c d" 'e''f' "g\"" 1398 // 1399 // Would be parsed as: 1400 // 1401 // []string{"a", "b:c d", "ef", `g"`} 1402 // 1403 func splitQuoted(s string) (r []string, err error) { 1404 var args []string 1405 arg := make([]rune, len(s)) 1406 escaped := false 1407 quoted := false 1408 quote := '\x00' 1409 i := 0 1410 for _, rune := range s { 1411 switch { 1412 case escaped: 1413 escaped = false 1414 case rune == '\\': 1415 escaped = true 1416 continue 1417 case quote != '\x00': 1418 if rune == quote { 1419 quote = '\x00' 1420 continue 1421 } 1422 case rune == '"' || rune == '\'': 1423 quoted = true 1424 quote = rune 1425 continue 1426 case unicode.IsSpace(rune): 1427 if quoted || i > 0 { 1428 quoted = false 1429 args = append(args, string(arg[:i])) 1430 i = 0 1431 } 1432 continue 1433 } 1434 arg[i] = rune 1435 i++ 1436 } 1437 if quoted || i > 0 { 1438 args = append(args, string(arg[:i])) 1439 } 1440 if quote != 0 { 1441 err = errors.New("unclosed quote") 1442 } else if escaped { 1443 err = errors.New("unfinished escaping") 1444 } 1445 return args, err 1446 } 1447 1448 // match reports whether the name is one of: 1449 // 1450 // $GOOS 1451 // $GOARCH 1452 // cgo (if cgo is enabled) 1453 // !cgo (if cgo is disabled) 1454 // ctxt.Compiler 1455 // !ctxt.Compiler 1456 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) 1457 // !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) 1458 // a comma-separated list of any of these 1459 // 1460 func (ctxt *Context) match(name string, allTags map[string]bool) bool { 1461 if name == "" { 1462 if allTags != nil { 1463 allTags[name] = true 1464 } 1465 return false 1466 } 1467 if i := strings.Index(name, ","); i >= 0 { 1468 // comma-separated list 1469 ok1 := ctxt.match(name[:i], allTags) 1470 ok2 := ctxt.match(name[i+1:], allTags) 1471 return ok1 && ok2 1472 } 1473 if strings.HasPrefix(name, "!!") { // bad syntax, reject always 1474 return false 1475 } 1476 if strings.HasPrefix(name, "!") { // negation 1477 return len(name) > 1 && !ctxt.match(name[1:], allTags) 1478 } 1479 1480 if allTags != nil { 1481 allTags[name] = true 1482 } 1483 1484 // Tags must be letters, digits, underscores or dots. 1485 // Unlike in Go identifiers, all digits are fine (e.g., "386"). 1486 for _, c := range name { 1487 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { 1488 return false 1489 } 1490 } 1491 1492 // special tags 1493 if ctxt.CgoEnabled && name == "cgo" { 1494 return true 1495 } 1496 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { 1497 return true 1498 } 1499 if ctxt.GOOS == "android" && name == "linux" { 1500 return true 1501 } 1502 1503 // other tags 1504 for _, tag := range ctxt.BuildTags { 1505 if tag == name { 1506 return true 1507 } 1508 } 1509 for _, tag := range ctxt.ReleaseTags { 1510 if tag == name { 1511 return true 1512 } 1513 } 1514 1515 return false 1516 } 1517 1518 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH 1519 // suffix which does not match the current system. 1520 // The recognized name formats are: 1521 // 1522 // name_$(GOOS).* 1523 // name_$(GOARCH).* 1524 // name_$(GOOS)_$(GOARCH).* 1525 // name_$(GOOS)_test.* 1526 // name_$(GOARCH)_test.* 1527 // name_$(GOOS)_$(GOARCH)_test.* 1528 // 1529 // An exception: if GOOS=android, then files with GOOS=linux are also matched. 1530 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { 1531 if dot := strings.Index(name, "."); dot != -1 { 1532 name = name[:dot] 1533 } 1534 1535 // Before Go 1.4, a file called "linux.go" would be equivalent to having a 1536 // build tag "linux" in that file. For Go 1.4 and beyond, we require this 1537 // auto-tagging to apply only to files with a non-empty prefix, so 1538 // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating 1539 // systems, such as android, to arrive without breaking existing code with 1540 // innocuous source code in "android.go". The easiest fix: cut everything 1541 // in the name before the initial _. 1542 i := strings.Index(name, "_") 1543 if i < 0 { 1544 return true 1545 } 1546 name = name[i:] // ignore everything before first _ 1547 1548 l := strings.Split(name, "_") 1549 if n := len(l); n > 0 && l[n-1] == "test" { 1550 l = l[:n-1] 1551 } 1552 n := len(l) 1553 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { 1554 if allTags != nil { 1555 allTags[l[n-2]] = true 1556 allTags[l[n-1]] = true 1557 } 1558 if l[n-1] != ctxt.GOARCH { 1559 return false 1560 } 1561 if ctxt.GOOS == "android" && l[n-2] == "linux" { 1562 return true 1563 } 1564 return l[n-2] == ctxt.GOOS 1565 } 1566 if n >= 1 && knownOS[l[n-1]] { 1567 if allTags != nil { 1568 allTags[l[n-1]] = true 1569 } 1570 if ctxt.GOOS == "android" && l[n-1] == "linux" { 1571 return true 1572 } 1573 return l[n-1] == ctxt.GOOS 1574 } 1575 if n >= 1 && knownArch[l[n-1]] { 1576 if allTags != nil { 1577 allTags[l[n-1]] = true 1578 } 1579 return l[n-1] == ctxt.GOARCH 1580 } 1581 return true 1582 } 1583 1584 var knownOS = make(map[string]bool) 1585 var knownArch = make(map[string]bool) 1586 1587 func init() { 1588 for _, v := range strings.Fields(goosList) { 1589 knownOS[v] = true 1590 } 1591 for _, v := range strings.Fields(goarchList) { 1592 knownArch[v] = true 1593 } 1594 } 1595 1596 // ToolDir is the directory containing build tools. 1597 var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) 1598 1599 // IsLocalImport reports whether the import path is 1600 // a local import path, like ".", "..", "./foo", or "../foo". 1601 func IsLocalImport(path string) bool { 1602 return path == "." || path == ".." || 1603 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") 1604 } 1605 1606 // ArchChar returns "?" and an error. 1607 // In earlier versions of Go, the returned string was used to derive 1608 // the compiler and linker tool names, the default object file suffix, 1609 // and the default linker output name. As of Go 1.5, those strings 1610 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively. 1611 func ArchChar(goarch string) (string, error) { 1612 return "?", errors.New("architecture letter no longer used") 1613 }