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