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