github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/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 ) 27 28 // A Context specifies the supporting context for a build. 29 type Context struct { 30 GOARCH string // target architecture 31 GOOS string // target operating system 32 GOROOT string // Go root 33 GOPATH string // Go path 34 CgoEnabled bool // whether cgo can be used 35 UseAllFiles bool // use files regardless of +build lines, file names 36 Compiler string // compiler to assume when computing target paths 37 38 // The build and release tags specify build constraints 39 // that should be considered satisfied when processing +build lines. 40 // Clients creating a new context may customize BuildTags, which 41 // defaults to empty, but it is usually an error to customize ReleaseTags, 42 // which defaults to the list of Go releases the current release is compatible with. 43 // In addition to the BuildTags and ReleaseTags, build constraints 44 // consider the values of GOARCH and GOOS as satisfied tags. 45 BuildTags []string 46 ReleaseTags []string 47 48 // The install suffix specifies a suffix to use in the name of the installation 49 // directory. By default it is empty, but custom builds that need to keep 50 // their outputs separate can set InstallSuffix to do so. For example, when 51 // using the race detector, the go command uses InstallSuffix = "race", so 52 // that on a Linux/386 system, packages are written to a directory named 53 // "linux_386_race" instead of the usual "linux_386". 54 InstallSuffix string 55 56 // By default, Import uses the operating system's file system calls 57 // to read directories and files. To read from other sources, 58 // callers can set the following functions. They all have default 59 // behaviors that use the local file system, so clients need only set 60 // the functions whose behaviors they wish to change. 61 62 // JoinPath joins the sequence of path fragments into a single path. 63 // If JoinPath is nil, Import uses filepath.Join. 64 JoinPath func(elem ...string) string 65 66 // SplitPathList splits the path list into a slice of individual paths. 67 // If SplitPathList is nil, Import uses filepath.SplitList. 68 SplitPathList func(list string) []string 69 70 // IsAbsPath reports whether path is an absolute path. 71 // If IsAbsPath is nil, Import uses filepath.IsAbs. 72 IsAbsPath func(path string) bool 73 74 // IsDir reports whether the path names a directory. 75 // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method. 76 IsDir func(path string) bool 77 78 // HasSubdir reports whether dir is a subdirectory of 79 // (perhaps multiple levels below) root. 80 // If so, HasSubdir sets rel to a slash-separated path that 81 // can be joined to root to produce a path equivalent to dir. 82 // If HasSubdir is nil, Import uses an implementation built on 83 // filepath.EvalSymlinks. 84 HasSubdir func(root, dir string) (rel string, ok bool) 85 86 // ReadDir returns a slice of os.FileInfo, sorted by Name, 87 // describing the content of the named directory. 88 // If ReadDir is nil, Import uses ioutil.ReadDir. 89 ReadDir func(dir string) (fi []os.FileInfo, err error) 90 91 // OpenFile opens a file (not a directory) for reading. 92 // If OpenFile is nil, Import uses os.Open. 93 OpenFile func(path string) (r io.ReadCloser, err error) 94 } 95 96 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join. 97 func (ctxt *Context) joinPath(elem ...string) string { 98 if f := ctxt.JoinPath; f != nil { 99 return f(elem...) 100 } 101 return filepath.Join(elem...) 102 } 103 104 // splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList. 105 func (ctxt *Context) splitPathList(s string) []string { 106 if f := ctxt.SplitPathList; f != nil { 107 return f(s) 108 } 109 return filepath.SplitList(s) 110 } 111 112 // isAbsPath calls ctxt.IsAbsSPath (if not nil) or else filepath.IsAbs. 113 func (ctxt *Context) isAbsPath(path string) bool { 114 if f := ctxt.IsAbsPath; f != nil { 115 return f(path) 116 } 117 return filepath.IsAbs(path) 118 } 119 120 // isDir calls ctxt.IsDir (if not nil) or else uses os.Stat. 121 func (ctxt *Context) isDir(path string) bool { 122 if f := ctxt.IsDir; f != nil { 123 return f(path) 124 } 125 fi, err := os.Stat(path) 126 return err == nil && fi.IsDir() 127 } 128 129 // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses 130 // the local file system to answer the question. 131 func (ctxt *Context) hasSubdir(root, dir string) (rel string, ok bool) { 132 if f := ctxt.HasSubdir; f != nil { 133 return f(root, dir) 134 } 135 136 // Try using paths we received. 137 if rel, ok = hasSubdir(root, dir); ok { 138 return 139 } 140 141 // Try expanding symlinks and comparing 142 // expanded against unexpanded and 143 // expanded against expanded. 144 rootSym, _ := filepath.EvalSymlinks(root) 145 dirSym, _ := filepath.EvalSymlinks(dir) 146 147 if rel, ok = hasSubdir(rootSym, dir); ok { 148 return 149 } 150 if rel, ok = hasSubdir(root, dirSym); ok { 151 return 152 } 153 return hasSubdir(rootSym, dirSym) 154 } 155 156 func hasSubdir(root, dir string) (rel string, ok bool) { 157 const sep = string(filepath.Separator) 158 root = filepath.Clean(root) 159 if !strings.HasSuffix(root, sep) { 160 root += sep 161 } 162 dir = filepath.Clean(dir) 163 if !strings.HasPrefix(dir, root) { 164 return "", false 165 } 166 return filepath.ToSlash(dir[len(root):]), true 167 } 168 169 // readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir. 170 func (ctxt *Context) readDir(path string) ([]os.FileInfo, error) { 171 if f := ctxt.ReadDir; f != nil { 172 return f(path) 173 } 174 return ioutil.ReadDir(path) 175 } 176 177 // openFile calls ctxt.OpenFile (if not nil) or else os.Open. 178 func (ctxt *Context) openFile(path string) (io.ReadCloser, error) { 179 if fn := ctxt.OpenFile; fn != nil { 180 return fn(path) 181 } 182 183 f, err := os.Open(path) 184 if err != nil { 185 return nil, err // nil interface 186 } 187 return f, nil 188 } 189 190 // isFile determines whether path is a file by trying to open it. 191 // It reuses openFile instead of adding another function to the 192 // list in Context. 193 func (ctxt *Context) isFile(path string) bool { 194 f, err := ctxt.openFile(path) 195 if err != nil { 196 return false 197 } 198 f.Close() 199 return true 200 } 201 202 // gopath returns the list of Go path directories. 203 func (ctxt *Context) gopath() []string { 204 var all []string 205 for _, p := range ctxt.splitPathList(ctxt.GOPATH) { 206 if p == "" || p == ctxt.GOROOT { 207 // Empty paths are uninteresting. 208 // If the path is the GOROOT, ignore it. 209 // People sometimes set GOPATH=$GOROOT, which is useless 210 // but would cause us to find packages with import paths 211 // like "pkg/math". 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", "pkg") 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 var cgoEnabled = map[string]bool{ 261 "darwin/386": true, 262 "darwin/amd64": true, 263 "dragonfly/386": true, 264 "dragonfly/amd64": true, 265 "freebsd/386": true, 266 "freebsd/amd64": true, 267 "freebsd/arm": true, 268 "linux/386": true, 269 "linux/amd64": true, 270 "linux/arm": true, 271 "netbsd/386": true, 272 "netbsd/amd64": true, 273 "netbsd/arm": true, 274 "openbsd/386": true, 275 "openbsd/amd64": true, 276 "windows/386": true, 277 "windows/amd64": true, 278 } 279 280 func defaultContext() Context { 281 var c Context 282 283 c.GOARCH = envOr("GOARCH", runtime.GOARCH) 284 c.GOOS = envOr("GOOS", runtime.GOOS) 285 c.GOROOT = runtime.GOROOT() 286 c.GOPATH = envOr("GOPATH", "") 287 c.Compiler = runtime.Compiler 288 289 // Each major Go release in the Go 1.x series should add a tag here. 290 // Old tags should not be removed. That is, the go1.x tag is present 291 // in all releases >= Go 1.x. Code that requires Go 1.x or later should 292 // say "+build go1.x", and code that should only be built before Go 1.x 293 // (perhaps it is the stub to use in that case) should say "+build !go1.x". 294 // 295 // When we reach Go 1.4 the line will read 296 // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} 297 // and so on. 298 c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"} 299 300 switch os.Getenv("CGO_ENABLED") { 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 AllowBinary 337 ) 338 339 // A Package describes the Go package found in a directory. 340 type Package struct { 341 Dir string // directory containing package sources 342 Name string // package name 343 Doc string // documentation synopsis 344 ImportPath string // import path of package ("" if unknown) 345 Root string // root of Go tree where this package lives 346 SrcRoot string // package source root directory ("" if unknown) 347 PkgRoot string // package install root directory ("" if unknown) 348 BinDir string // command install directory ("" if unknown) 349 Goroot bool // package found in Go root 350 PkgObj string // installed .a file 351 AllTags []string // tags that can influence file selection in this directory 352 ConflictDir string // this directory shadows Dir in $GOPATH 353 354 // Source files 355 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) 356 CgoFiles []string // .go source files that import "C" 357 IgnoredGoFiles []string // .go source files ignored for this build 358 CFiles []string // .c source files 359 CXXFiles []string // .cc, .cpp and .cxx source files 360 MFiles []string // .m (Objective-C) source files 361 HFiles []string // .h, .hh, .hpp and .hxx source files 362 SFiles []string // .s source files 363 SwigFiles []string // .swig files 364 SwigCXXFiles []string // .swigcxx files 365 SysoFiles []string // .syso system object files to add to archive 366 367 // Cgo directives 368 CgoCFLAGS []string // Cgo CFLAGS directives 369 CgoCPPFLAGS []string // Cgo CPPFLAGS directives 370 CgoCXXFLAGS []string // Cgo CXXFLAGS directives 371 CgoLDFLAGS []string // Cgo LDFLAGS directives 372 CgoPkgConfig []string // Cgo pkg-config directives 373 374 // Dependency information 375 Imports []string // imports from GoFiles, CgoFiles 376 ImportPos map[string][]token.Position // line information for Imports 377 378 // Test information 379 TestGoFiles []string // _test.go files in package 380 TestImports []string // imports from TestGoFiles 381 TestImportPos map[string][]token.Position // line information for TestImports 382 XTestGoFiles []string // _test.go files outside package 383 XTestImports []string // imports from XTestGoFiles 384 XTestImportPos map[string][]token.Position // line information for XTestImports 385 } 386 387 // IsCommand reports whether the package is considered a 388 // command to be installed (not just a library). 389 // Packages named "main" are treated as commands. 390 func (p *Package) IsCommand() bool { 391 return p.Name == "main" 392 } 393 394 // ImportDir is like Import but processes the Go package found in 395 // the named directory. 396 func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) { 397 return ctxt.Import(".", dir, mode) 398 } 399 400 // NoGoError is the error used by Import to describe a directory 401 // containing no buildable Go source files. (It may still contain 402 // test files, files hidden by build tags, and so on.) 403 type NoGoError struct { 404 Dir string 405 } 406 407 func (e *NoGoError) Error() string { 408 return "no buildable Go source files in " + e.Dir 409 } 410 411 func nameExt(name string) string { 412 i := strings.LastIndex(name, ".") 413 if i < 0 { 414 return "" 415 } 416 return name[i:] 417 } 418 419 // Import returns details about the Go package named by the import path, 420 // interpreting local import paths relative to the srcDir directory. 421 // If the path is a local import path naming a package that can be imported 422 // using a standard import path, the returned package will set p.ImportPath 423 // to that path. 424 // 425 // In the directory containing the package, .go, .c, .h, and .s files are 426 // considered part of the package except for: 427 // 428 // - .go files in package documentation 429 // - files starting with _ or . (likely editor temporary files) 430 // - files with build constraints not satisfied by the context 431 // 432 // If an error occurs, Import returns a non-nil error and a non-nil 433 // *Package containing partial information. 434 // 435 func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) { 436 p := &Package{ 437 ImportPath: path, 438 } 439 if path == "" { 440 return p, fmt.Errorf("import %q: invalid import path", path) 441 } 442 443 var pkga string 444 var pkgerr error 445 switch ctxt.Compiler { 446 case "gccgo": 447 dir, elem := pathpkg.Split(p.ImportPath) 448 pkga = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + dir + "lib" + elem + ".a" 449 case "gc": 450 suffix := "" 451 if ctxt.InstallSuffix != "" { 452 suffix = "_" + ctxt.InstallSuffix 453 } 454 pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a" 455 default: 456 // Save error for end of function. 457 pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler) 458 } 459 460 binaryOnly := false 461 if IsLocalImport(path) { 462 pkga = "" // local imports have no installed path 463 if srcDir == "" { 464 return p, fmt.Errorf("import %q: import relative to unknown directory", path) 465 } 466 if !ctxt.isAbsPath(path) { 467 p.Dir = ctxt.joinPath(srcDir, path) 468 } 469 // Determine canonical import path, if any. 470 if ctxt.GOROOT != "" { 471 root := ctxt.joinPath(ctxt.GOROOT, "src", "pkg") 472 if sub, ok := ctxt.hasSubdir(root, p.Dir); ok { 473 p.Goroot = true 474 p.ImportPath = sub 475 p.Root = ctxt.GOROOT 476 goto Found 477 } 478 } 479 all := ctxt.gopath() 480 for i, root := range all { 481 rootsrc := ctxt.joinPath(root, "src") 482 if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok { 483 // We found a potential import path for dir, 484 // but check that using it wouldn't find something 485 // else first. 486 if ctxt.GOROOT != "" { 487 if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) { 488 p.ConflictDir = dir 489 goto Found 490 } 491 } 492 for _, earlyRoot := range all[:i] { 493 if dir := ctxt.joinPath(earlyRoot, "src", sub); ctxt.isDir(dir) { 494 p.ConflictDir = dir 495 goto Found 496 } 497 } 498 499 // sub would not name some other directory instead of this one. 500 // Record it. 501 p.ImportPath = sub 502 p.Root = root 503 goto Found 504 } 505 } 506 // It's okay that we didn't find a root containing dir. 507 // Keep going with the information we have. 508 } else { 509 if strings.HasPrefix(path, "/") { 510 return p, fmt.Errorf("import %q: cannot import absolute path", path) 511 } 512 513 // tried records the location of unsuccessful package lookups 514 var tried struct { 515 goroot string 516 gopath []string 517 } 518 519 // Determine directory from import path. 520 if ctxt.GOROOT != "" { 521 dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", path) 522 isDir := ctxt.isDir(dir) 523 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(ctxt.GOROOT, pkga)) 524 if isDir || binaryOnly { 525 p.Dir = dir 526 p.Goroot = true 527 p.Root = ctxt.GOROOT 528 goto Found 529 } 530 tried.goroot = dir 531 } 532 for _, root := range ctxt.gopath() { 533 dir := ctxt.joinPath(root, "src", path) 534 isDir := ctxt.isDir(dir) 535 binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && ctxt.isFile(ctxt.joinPath(root, pkga)) 536 if isDir || binaryOnly { 537 p.Dir = dir 538 p.Root = root 539 goto Found 540 } 541 tried.gopath = append(tried.gopath, dir) 542 } 543 544 // package was not found 545 var paths []string 546 if tried.goroot != "" { 547 paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot)) 548 } else { 549 paths = append(paths, "\t($GOROOT not set)") 550 } 551 var i int 552 var format = "\t%s (from $GOPATH)" 553 for ; i < len(tried.gopath); i++ { 554 if i > 0 { 555 format = "\t%s" 556 } 557 paths = append(paths, fmt.Sprintf(format, tried.gopath[i])) 558 } 559 if i == 0 { 560 paths = append(paths, "\t($GOPATH not set)") 561 } 562 return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n")) 563 } 564 565 Found: 566 if p.Root != "" { 567 if p.Goroot { 568 p.SrcRoot = ctxt.joinPath(p.Root, "src", "pkg") 569 } else { 570 p.SrcRoot = ctxt.joinPath(p.Root, "src") 571 } 572 p.PkgRoot = ctxt.joinPath(p.Root, "pkg") 573 p.BinDir = ctxt.joinPath(p.Root, "bin") 574 if pkga != "" { 575 p.PkgObj = ctxt.joinPath(p.Root, pkga) 576 } 577 } 578 579 if mode&FindOnly != 0 { 580 return p, pkgerr 581 } 582 if binaryOnly && (mode&AllowBinary) != 0 { 583 return p, pkgerr 584 } 585 586 dirs, err := ctxt.readDir(p.Dir) 587 if err != nil { 588 return p, err 589 } 590 591 var Sfiles []string // files with ".S" (capital S) 592 var firstFile string 593 imported := make(map[string][]token.Position) 594 testImported := make(map[string][]token.Position) 595 xTestImported := make(map[string][]token.Position) 596 allTags := make(map[string]bool) 597 fset := token.NewFileSet() 598 for _, d := range dirs { 599 if d.IsDir() { 600 continue 601 } 602 603 name := d.Name() 604 ext := nameExt(name) 605 606 match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags) 607 if err != nil { 608 return p, err 609 } 610 if !match { 611 if ext == ".go" { 612 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 613 } 614 continue 615 } 616 617 // Going to save the file. For non-Go files, can stop here. 618 switch ext { 619 case ".c": 620 p.CFiles = append(p.CFiles, name) 621 continue 622 case ".cc", ".cpp", ".cxx": 623 p.CXXFiles = append(p.CXXFiles, name) 624 continue 625 case ".m": 626 p.MFiles = append(p.MFiles, name) 627 continue 628 case ".h", ".hh", ".hpp", ".hxx": 629 p.HFiles = append(p.HFiles, name) 630 continue 631 case ".s": 632 p.SFiles = append(p.SFiles, name) 633 continue 634 case ".S": 635 Sfiles = append(Sfiles, name) 636 continue 637 case ".swig": 638 p.SwigFiles = append(p.SwigFiles, name) 639 continue 640 case ".swigcxx": 641 p.SwigCXXFiles = append(p.SwigCXXFiles, name) 642 continue 643 case ".syso": 644 // binary objects to add to package archive 645 // Likely of the form foo_windows.syso, but 646 // the name was vetted above with goodOSArchFile. 647 p.SysoFiles = append(p.SysoFiles, name) 648 continue 649 } 650 651 pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments) 652 if err != nil { 653 return p, err 654 } 655 656 pkg := pf.Name.Name 657 if pkg == "documentation" { 658 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 659 continue 660 } 661 662 isTest := strings.HasSuffix(name, "_test.go") 663 isXTest := false 664 if isTest && strings.HasSuffix(pkg, "_test") { 665 isXTest = true 666 pkg = pkg[:len(pkg)-len("_test")] 667 } 668 669 if p.Name == "" { 670 p.Name = pkg 671 firstFile = name 672 } else if pkg != p.Name { 673 return p, fmt.Errorf("found packages %s (%s) and %s (%s) in %s", p.Name, firstFile, pkg, name, p.Dir) 674 } 675 if pf.Doc != nil && p.Doc == "" { 676 p.Doc = doc.Synopsis(pf.Doc.Text()) 677 } 678 679 // Record imports and information about cgo. 680 isCgo := false 681 for _, decl := range pf.Decls { 682 d, ok := decl.(*ast.GenDecl) 683 if !ok { 684 continue 685 } 686 for _, dspec := range d.Specs { 687 spec, ok := dspec.(*ast.ImportSpec) 688 if !ok { 689 continue 690 } 691 quoted := spec.Path.Value 692 path, err := strconv.Unquote(quoted) 693 if err != nil { 694 log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) 695 } 696 if isXTest { 697 xTestImported[path] = append(xTestImported[path], fset.Position(spec.Pos())) 698 } else if isTest { 699 testImported[path] = append(testImported[path], fset.Position(spec.Pos())) 700 } else { 701 imported[path] = append(imported[path], fset.Position(spec.Pos())) 702 } 703 if path == "C" { 704 if isTest { 705 return p, fmt.Errorf("use of cgo in test %s not supported", filename) 706 } 707 cg := spec.Doc 708 if cg == nil && len(d.Specs) == 1 { 709 cg = d.Doc 710 } 711 if cg != nil { 712 if err := ctxt.saveCgo(filename, p, cg); err != nil { 713 return p, err 714 } 715 } 716 isCgo = true 717 } 718 } 719 } 720 if isCgo { 721 allTags["cgo"] = true 722 if ctxt.CgoEnabled { 723 p.CgoFiles = append(p.CgoFiles, name) 724 } else { 725 p.IgnoredGoFiles = append(p.IgnoredGoFiles, name) 726 } 727 } else if isXTest { 728 p.XTestGoFiles = append(p.XTestGoFiles, name) 729 } else if isTest { 730 p.TestGoFiles = append(p.TestGoFiles, name) 731 } else { 732 p.GoFiles = append(p.GoFiles, name) 733 } 734 } 735 if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { 736 return p, &NoGoError{p.Dir} 737 } 738 739 for tag := range allTags { 740 p.AllTags = append(p.AllTags, tag) 741 } 742 sort.Strings(p.AllTags) 743 744 p.Imports, p.ImportPos = cleanImports(imported) 745 p.TestImports, p.TestImportPos = cleanImports(testImported) 746 p.XTestImports, p.XTestImportPos = cleanImports(xTestImported) 747 748 // add the .S files only if we are using cgo 749 // (which means gcc will compile them). 750 // The standard assemblers expect .s files. 751 if len(p.CgoFiles) > 0 { 752 p.SFiles = append(p.SFiles, Sfiles...) 753 sort.Strings(p.SFiles) 754 } 755 756 return p, pkgerr 757 } 758 759 // MatchFile reports whether the file with the given name in the given directory 760 // matches the context and would be included in a Package created by ImportDir 761 // of that directory. 762 // 763 // MatchFile considers the name of the file and may use ctxt.OpenFile to 764 // read some or all of the file's content. 765 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) { 766 match, _, _, err = ctxt.matchFile(dir, name, false, nil) 767 return 768 } 769 770 // matchFile determines whether the file with the given name in the given directory 771 // should be included in the package being constructed. 772 // It returns the data read from the file. 773 // If returnImports is true and name denotes a Go program, matchFile reads 774 // until the end of the imports (and returns that data) even though it only 775 // considers text until the first non-comment. 776 // If allTags is non-nil, matchFile records any encountered build tag 777 // by setting allTags[tag] = true. 778 func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) { 779 if strings.HasPrefix(name, "_") || 780 strings.HasPrefix(name, ".") { 781 return 782 } 783 784 i := strings.LastIndex(name, ".") 785 if i < 0 { 786 i = len(name) 787 } 788 ext := name[i:] 789 790 if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles { 791 return 792 } 793 794 switch ext { 795 case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx": 796 // tentatively okay - read to make sure 797 case ".syso": 798 // binary, no reading 799 match = true 800 return 801 default: 802 // skip 803 return 804 } 805 806 filename = ctxt.joinPath(dir, name) 807 f, err := ctxt.openFile(filename) 808 if err != nil { 809 return 810 } 811 812 if strings.HasSuffix(filename, ".go") { 813 data, err = readImports(f, false) 814 } else { 815 data, err = readComments(f) 816 } 817 f.Close() 818 if err != nil { 819 err = fmt.Errorf("read %s: %v", filename, err) 820 return 821 } 822 823 // Look for +build comments to accept or reject the file. 824 if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles { 825 return 826 } 827 828 match = true 829 return 830 } 831 832 func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) { 833 all := make([]string, 0, len(m)) 834 for path := range m { 835 all = append(all, path) 836 } 837 sort.Strings(all) 838 return all, m 839 } 840 841 // Import is shorthand for Default.Import. 842 func Import(path, srcDir string, mode ImportMode) (*Package, error) { 843 return Default.Import(path, srcDir, mode) 844 } 845 846 // ImportDir is shorthand for Default.ImportDir. 847 func ImportDir(dir string, mode ImportMode) (*Package, error) { 848 return Default.ImportDir(dir, mode) 849 } 850 851 var slashslash = []byte("//") 852 853 // shouldBuild reports whether it is okay to use this file, 854 // The rule is that in the file's leading run of // comments 855 // and blank lines, which must be followed by a blank line 856 // (to avoid including a Go package clause doc comment), 857 // lines beginning with '// +build' are taken as build directives. 858 // 859 // The file is accepted only if each such line lists something 860 // matching the file. For example: 861 // 862 // // +build windows linux 863 // 864 // marks the file as applicable only on Windows and Linux. 865 // 866 func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool { 867 // Pass 1. Identify leading run of // comments and blank lines, 868 // which must be followed by a blank line. 869 end := 0 870 p := content 871 for len(p) > 0 { 872 line := p 873 if i := bytes.IndexByte(line, '\n'); i >= 0 { 874 line, p = line[:i], p[i+1:] 875 } else { 876 p = p[len(p):] 877 } 878 line = bytes.TrimSpace(line) 879 if len(line) == 0 { // Blank line 880 end = len(content) - len(p) 881 continue 882 } 883 if !bytes.HasPrefix(line, slashslash) { // Not comment line 884 break 885 } 886 } 887 content = content[:end] 888 889 // Pass 2. Process each line in the run. 890 p = content 891 allok := true 892 for len(p) > 0 { 893 line := p 894 if i := bytes.IndexByte(line, '\n'); i >= 0 { 895 line, p = line[:i], p[i+1:] 896 } else { 897 p = p[len(p):] 898 } 899 line = bytes.TrimSpace(line) 900 if bytes.HasPrefix(line, slashslash) { 901 line = bytes.TrimSpace(line[len(slashslash):]) 902 if len(line) > 0 && line[0] == '+' { 903 // Looks like a comment +line. 904 f := strings.Fields(string(line)) 905 if f[0] == "+build" { 906 ok := false 907 for _, tok := range f[1:] { 908 if ctxt.match(tok, allTags) { 909 ok = true 910 } 911 } 912 if !ok { 913 allok = false 914 } 915 } 916 } 917 } 918 } 919 920 return allok 921 } 922 923 // saveCgo saves the information from the #cgo lines in the import "C" comment. 924 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives 925 // that affect the way cgo's C code is built. 926 // 927 // TODO(rsc): This duplicates code in cgo. 928 // Once the dust settles, remove this code from cgo. 929 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { 930 text := cg.Text() 931 for _, line := range strings.Split(text, "\n") { 932 orig := line 933 934 // Line is 935 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff 936 // 937 line = strings.TrimSpace(line) 938 if len(line) < 5 || line[:4] != "#cgo" || (line[4] != ' ' && line[4] != '\t') { 939 continue 940 } 941 942 // Split at colon. 943 line = strings.TrimSpace(line[4:]) 944 i := strings.Index(line, ":") 945 if i < 0 { 946 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 947 } 948 line, argstr := line[:i], line[i+1:] 949 950 // Parse GOOS/GOARCH stuff. 951 f := strings.Fields(line) 952 if len(f) < 1 { 953 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 954 } 955 956 cond, verb := f[:len(f)-1], f[len(f)-1] 957 if len(cond) > 0 { 958 ok := false 959 for _, c := range cond { 960 if ctxt.match(c, nil) { 961 ok = true 962 break 963 } 964 } 965 if !ok { 966 continue 967 } 968 } 969 970 args, err := splitQuoted(argstr) 971 if err != nil { 972 return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) 973 } 974 for _, arg := range args { 975 if !safeCgoName(arg) { 976 return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg) 977 } 978 } 979 980 switch verb { 981 case "CFLAGS": 982 di.CgoCFLAGS = append(di.CgoCFLAGS, args...) 983 case "CPPFLAGS": 984 di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...) 985 case "CXXFLAGS": 986 di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...) 987 case "LDFLAGS": 988 di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...) 989 case "pkg-config": 990 di.CgoPkgConfig = append(di.CgoPkgConfig, args...) 991 default: 992 return fmt.Errorf("%s: invalid #cgo verb: %s", filename, orig) 993 } 994 } 995 return nil 996 } 997 998 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. 999 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. 1000 // See golang.org/issue/6038. 1001 var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$") 1002 1003 func safeCgoName(s string) bool { 1004 if s == "" { 1005 return false 1006 } 1007 for i := 0; i < len(s); i++ { 1008 if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { 1009 return false 1010 } 1011 } 1012 return true 1013 } 1014 1015 // splitQuoted splits the string s around each instance of one or more consecutive 1016 // white space characters while taking into account quotes and escaping, and 1017 // returns an array of substrings of s or an empty list if s contains only white space. 1018 // Single quotes and double quotes are recognized to prevent splitting within the 1019 // quoted region, and are removed from the resulting substrings. If a quote in s 1020 // isn't closed err will be set and r will have the unclosed argument as the 1021 // last element. The backslash is used for escaping. 1022 // 1023 // For example, the following string: 1024 // 1025 // a b:"c d" 'e''f' "g\"" 1026 // 1027 // Would be parsed as: 1028 // 1029 // []string{"a", "b:c d", "ef", `g"`} 1030 // 1031 func splitQuoted(s string) (r []string, err error) { 1032 var args []string 1033 arg := make([]rune, len(s)) 1034 escaped := false 1035 quoted := false 1036 quote := '\x00' 1037 i := 0 1038 for _, rune := range s { 1039 switch { 1040 case escaped: 1041 escaped = false 1042 case rune == '\\': 1043 escaped = true 1044 continue 1045 case quote != '\x00': 1046 if rune == quote { 1047 quote = '\x00' 1048 continue 1049 } 1050 case rune == '"' || rune == '\'': 1051 quoted = true 1052 quote = rune 1053 continue 1054 case unicode.IsSpace(rune): 1055 if quoted || i > 0 { 1056 quoted = false 1057 args = append(args, string(arg[:i])) 1058 i = 0 1059 } 1060 continue 1061 } 1062 arg[i] = rune 1063 i++ 1064 } 1065 if quoted || i > 0 { 1066 args = append(args, string(arg[:i])) 1067 } 1068 if quote != 0 { 1069 err = errors.New("unclosed quote") 1070 } else if escaped { 1071 err = errors.New("unfinished escaping") 1072 } 1073 return args, err 1074 } 1075 1076 // match returns true if the name is one of: 1077 // 1078 // $GOOS 1079 // $GOARCH 1080 // cgo (if cgo is enabled) 1081 // !cgo (if cgo is disabled) 1082 // ctxt.Compiler 1083 // !ctxt.Compiler 1084 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags) 1085 // !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags) 1086 // a comma-separated list of any of these 1087 // 1088 func (ctxt *Context) match(name string, allTags map[string]bool) bool { 1089 if name == "" { 1090 if allTags != nil { 1091 allTags[name] = true 1092 } 1093 return false 1094 } 1095 if i := strings.Index(name, ","); i >= 0 { 1096 // comma-separated list 1097 ok1 := ctxt.match(name[:i], allTags) 1098 ok2 := ctxt.match(name[i+1:], allTags) 1099 return ok1 && ok2 1100 } 1101 if strings.HasPrefix(name, "!!") { // bad syntax, reject always 1102 return false 1103 } 1104 if strings.HasPrefix(name, "!") { // negation 1105 return len(name) > 1 && !ctxt.match(name[1:], allTags) 1106 } 1107 1108 if allTags != nil { 1109 allTags[name] = true 1110 } 1111 1112 // Tags must be letters, digits, underscores or dots. 1113 // Unlike in Go identifiers, all digits are fine (e.g., "386"). 1114 for _, c := range name { 1115 if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' { 1116 return false 1117 } 1118 } 1119 1120 // special tags 1121 if ctxt.CgoEnabled && name == "cgo" { 1122 return true 1123 } 1124 if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { 1125 return true 1126 } 1127 1128 // other tags 1129 for _, tag := range ctxt.BuildTags { 1130 if tag == name { 1131 return true 1132 } 1133 } 1134 for _, tag := range ctxt.ReleaseTags { 1135 if tag == name { 1136 return true 1137 } 1138 } 1139 1140 return false 1141 } 1142 1143 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH 1144 // suffix which does not match the current system. 1145 // The recognized name formats are: 1146 // 1147 // name_$(GOOS).* 1148 // name_$(GOARCH).* 1149 // name_$(GOOS)_$(GOARCH).* 1150 // name_$(GOOS)_test.* 1151 // name_$(GOARCH)_test.* 1152 // name_$(GOOS)_$(GOARCH)_test.* 1153 // 1154 func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { 1155 if dot := strings.Index(name, "."); dot != -1 { 1156 name = name[:dot] 1157 } 1158 l := strings.Split(name, "_") 1159 if n := len(l); n > 0 && l[n-1] == "test" { 1160 l = l[:n-1] 1161 } 1162 n := len(l) 1163 if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { 1164 if allTags != nil { 1165 allTags[l[n-2]] = true 1166 allTags[l[n-1]] = true 1167 } 1168 return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH 1169 } 1170 if n >= 1 && knownOS[l[n-1]] { 1171 if allTags != nil { 1172 allTags[l[n-1]] = true 1173 } 1174 return l[n-1] == ctxt.GOOS 1175 } 1176 if n >= 1 && knownArch[l[n-1]] { 1177 if allTags != nil { 1178 allTags[l[n-1]] = true 1179 } 1180 return l[n-1] == ctxt.GOARCH 1181 } 1182 return true 1183 } 1184 1185 var knownOS = make(map[string]bool) 1186 var knownArch = make(map[string]bool) 1187 1188 func init() { 1189 for _, v := range strings.Fields(goosList) { 1190 knownOS[v] = true 1191 } 1192 for _, v := range strings.Fields(goarchList) { 1193 knownArch[v] = true 1194 } 1195 } 1196 1197 // ToolDir is the directory containing build tools. 1198 var ToolDir = filepath.Join(runtime.GOROOT(), "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) 1199 1200 // IsLocalImport reports whether the import path is 1201 // a local import path, like ".", "..", "./foo", or "../foo". 1202 func IsLocalImport(path string) bool { 1203 return path == "." || path == ".." || 1204 strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") 1205 } 1206 1207 // ArchChar returns the architecture character for the given goarch. 1208 // For example, ArchChar("amd64") returns "6". 1209 func ArchChar(goarch string) (string, error) { 1210 switch goarch { 1211 case "386": 1212 return "8", nil 1213 case "amd64", "amd64p32": 1214 return "6", nil 1215 case "arm": 1216 return "5", nil 1217 } 1218 return "", errors.New("unsupported GOARCH " + goarch) 1219 }