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