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