PageRenderTime 52ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/gofrontend/libgo/go/go/build/build.go

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