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.
29 // A Context specifies the supporting context for a build.
31 GOARCH
string // target architecture
32 GOOS
string // target operating system
33 GOROOT
string // Go root
34 GOPATH
string // Go path
35 CgoEnabled
bool // whether cgo can be used
36 UseAllFiles
bool // use files regardless of +build lines, file names
37 Compiler
string // compiler to assume when computing target paths
39 // The build and release tags specify build constraints
40 // that should be considered satisfied when processing +build lines.
41 // Clients creating a new context may customize BuildTags, which
42 // defaults to empty, but it is usually an error to customize ReleaseTags,
43 // which defaults to the list of Go releases the current release is compatible with.
44 // In addition to the BuildTags and ReleaseTags, build constraints
45 // consider the values of GOARCH and GOOS as satisfied tags.
49 // The install suffix specifies a suffix to use in the name of the installation
50 // directory. By default it is empty, but custom builds that need to keep
51 // their outputs separate can set InstallSuffix to do so. For example, when
52 // using the race detector, the go command uses InstallSuffix = "race", so
53 // that on a Linux/386 system, packages are written to a directory named
54 // "linux_386_race" instead of the usual "linux_386".
57 // By default, Import uses the operating system's file system calls
58 // to read directories and files. To read from other sources,
59 // callers can set the following functions. They all have default
60 // behaviors that use the local file system, so clients need only set
61 // the functions whose behaviors they wish to change.
63 // JoinPath joins the sequence of path fragments into a single path.
64 // If JoinPath is nil, Import uses filepath.Join.
65 JoinPath
func(elem
...string) string
67 // SplitPathList splits the path list into a slice of individual paths.
68 // If SplitPathList is nil, Import uses filepath.SplitList.
69 SplitPathList
func(list
string) []string
71 // IsAbsPath reports whether path is an absolute path.
72 // If IsAbsPath is nil, Import uses filepath.IsAbs.
73 IsAbsPath
func(path
string) bool
75 // IsDir reports whether the path names a directory.
76 // If IsDir is nil, Import calls os.Stat and uses the result's IsDir method.
77 IsDir
func(path
string) bool
79 // HasSubdir reports whether dir is lexically a subdirectory of
80 // root, perhaps multiple levels below. It does not try to check
81 // whether dir exists.
82 // If so, HasSubdir sets rel to a slash-separated path that
83 // can be joined to root to produce a path equivalent to dir.
84 // If HasSubdir is nil, Import uses an implementation built on
85 // filepath.EvalSymlinks.
86 HasSubdir
func(root
, dir
string) (rel
string, ok
bool)
88 // ReadDir returns a slice of os.FileInfo, sorted by Name,
89 // describing the content of the named directory.
90 // If ReadDir is nil, Import uses ioutil.ReadDir.
91 ReadDir
func(dir
string) ([]os
.FileInfo
, error
)
93 // OpenFile opens a file (not a directory) for reading.
94 // If OpenFile is nil, Import uses os.Open.
95 OpenFile
func(path
string) (io
.ReadCloser
, error
)
98 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
99 func (ctxt
*Context
) joinPath(elem
...string) string {
100 if f
:= ctxt
.JoinPath
; f
!= nil {
103 return filepath
.Join(elem
...)
106 // splitPathList calls ctxt.SplitPathList (if not nil) or else filepath.SplitList.
107 func (ctxt
*Context
) splitPathList(s
string) []string {
108 if f
:= ctxt
.SplitPathList
; f
!= nil {
111 return filepath
.SplitList(s
)
114 // isAbsPath calls ctxt.IsAbsPath (if not nil) or else filepath.IsAbs.
115 func (ctxt
*Context
) isAbsPath(path
string) bool {
116 if f
:= ctxt
.IsAbsPath
; f
!= nil {
119 return filepath
.IsAbs(path
)
122 // isDir calls ctxt.IsDir (if not nil) or else uses os.Stat.
123 func (ctxt
*Context
) isDir(path
string) bool {
124 if f
:= ctxt
.IsDir
; f
!= nil {
127 fi
, err
:= os
.Stat(path
)
128 return err
== nil && fi
.IsDir()
131 // hasSubdir calls ctxt.HasSubdir (if not nil) or else uses
132 // the local file system to answer the question.
133 func (ctxt
*Context
) hasSubdir(root
, dir
string) (rel
string, ok
bool) {
134 if f
:= ctxt
.HasSubdir
; f
!= nil {
138 // Try using paths we received.
139 if rel
, ok
= hasSubdir(root
, dir
); ok
{
143 // Try expanding symlinks and comparing
144 // expanded against unexpanded and
145 // expanded against expanded.
146 rootSym
, _
:= filepath
.EvalSymlinks(root
)
147 dirSym
, _
:= filepath
.EvalSymlinks(dir
)
149 if rel
, ok
= hasSubdir(rootSym
, dir
); ok
{
152 if rel
, ok
= hasSubdir(root
, dirSym
); ok
{
155 return hasSubdir(rootSym
, dirSym
)
158 // hasSubdir reports if dir is within root by performing lexical analysis only.
159 func hasSubdir(root
, dir
string) (rel
string, ok
bool) {
160 const sep
= string(filepath
.Separator
)
161 root
= filepath
.Clean(root
)
162 if !strings
.HasSuffix(root
, sep
) {
165 dir
= filepath
.Clean(dir
)
166 if !strings
.HasPrefix(dir
, root
) {
169 return filepath
.ToSlash(dir
[len(root
):]), true
172 // readDir calls ctxt.ReadDir (if not nil) or else ioutil.ReadDir.
173 func (ctxt
*Context
) readDir(path
string) ([]os
.FileInfo
, error
) {
174 if f
:= ctxt
.ReadDir
; f
!= nil {
177 return ioutil
.ReadDir(path
)
180 // openFile calls ctxt.OpenFile (if not nil) or else os.Open.
181 func (ctxt
*Context
) openFile(path
string) (io
.ReadCloser
, error
) {
182 if fn
:= ctxt
.OpenFile
; fn
!= nil {
186 f
, err
:= os
.Open(path
)
188 return nil, err
// nil interface
193 // isFile determines whether path is a file by trying to open it.
194 // It reuses openFile instead of adding another function to the
196 func (ctxt
*Context
) isFile(path
string) bool {
197 f
, err
:= ctxt
.openFile(path
)
205 // gopath returns the list of Go path directories.
206 func (ctxt
*Context
) gopath() []string {
208 for _
, p
:= range ctxt
.splitPathList(ctxt
.GOPATH
) {
209 if p
== "" || p
== ctxt
.GOROOT
{
210 // Empty paths are uninteresting.
211 // If the path is the GOROOT, ignore it.
212 // People sometimes set GOPATH=$GOROOT.
213 // Do not get confused by this common mistake.
216 if strings
.HasPrefix(p
, "~") {
217 // Path segments starting with ~ on Unix are almost always
218 // users who have incorrectly quoted ~ while setting GOPATH,
219 // preventing it from expanding to $HOME.
220 // The situation is made more confusing by the fact that
221 // bash allows quoted ~ in $PATH (most shells do not).
222 // Do not get confused by this, and do not try to use the path.
223 // It does not exist, and printing errors about it confuses
224 // those users even more, because they think "sure ~ exists!".
225 // The go command diagnoses this situation and prints a
227 // On Windows, ~ is used in short names, such as c:\progra~1
228 // for c:\program files.
236 // SrcDirs returns a list of package source root directories.
237 // It draws from the current Go root and Go path but omits directories
238 // that do not exist.
239 func (ctxt
*Context
) SrcDirs() []string {
241 if ctxt
.GOROOT
!= "" && ctxt
.Compiler
!= "gccgo" {
242 dir
:= ctxt
.joinPath(ctxt
.GOROOT
, "src")
244 all
= append(all
, dir
)
247 for _
, p
:= range ctxt
.gopath() {
248 dir
:= ctxt
.joinPath(p
, "src")
250 all
= append(all
, dir
)
256 // Default is the default Context for builds.
257 // It uses the GOARCH, GOOS, GOROOT, and GOPATH environment variables
258 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
259 var Default Context
= defaultContext()
261 func defaultGOPATH() string {
263 if runtime
.GOOS
== "windows" {
265 } else if runtime
.GOOS
== "plan9" {
268 if home
:= os
.Getenv(env
); home
!= "" {
269 def
:= filepath
.Join(home
, "go")
270 if filepath
.Clean(def
) == filepath
.Clean(runtime
.GOROOT()) {
271 // Don't set the default GOPATH to GOROOT,
272 // as that will trigger warnings from the go tool.
280 func defaultContext() Context
{
283 c
.GOARCH
= envOr("GOARCH", runtime
.GOARCH
)
284 c
.GOOS
= envOr("GOOS", runtime
.GOOS
)
285 c
.GOROOT
= pathpkg
.Clean(runtime
.GOROOT())
286 c
.GOPATH
= envOr("GOPATH", defaultGOPATH())
287 c
.Compiler
= runtime
.Compiler
289 // Each major Go release in the Go 1.x series should add a tag here.
290 // Old tags should not be removed. That is, the go1.x tag is present
291 // in all releases >= Go 1.x. Code that requires Go 1.x or later should
292 // say "+build go1.x", and code that should only be built before Go 1.x
293 // (perhaps it is the stub to use in that case) should say "+build !go1.x".
294 // NOTE: If you add to this list, also update the doc comment in doc.go.
295 const version
= 10 // go1.10
296 for i
:= 1; i
<= version
; i
++ {
297 c
.ReleaseTags
= append(c
.ReleaseTags
, "go1."+strconv
.Itoa(i
))
300 env
:= os
.Getenv("CGO_ENABLED")
301 // No defaultCGO_ENABLED in gccgo.
303 // env = defaultCGO_ENABLED
311 // cgo must be explicitly enabled for cross compilation builds
312 if runtime
.GOARCH
== c
.GOARCH
&& runtime
.GOOS
== c
.GOOS
{
313 // Always enabled for gccgo.
323 func envOr(name
, def
string) string {
331 // An ImportMode controls the behavior of the Import method.
335 // If FindOnly is set, Import stops after locating the directory
336 // that should contain the sources for a package. It does not
337 // read any files in the directory.
338 FindOnly ImportMode
= 1 << iota
340 // If AllowBinary is set, Import can be satisfied by a compiled
341 // package object without corresponding sources.
344 // The supported way to create a compiled-only package is to
345 // write source code containing a //go:binary-only-package comment at
346 // the top of the file. Such a package will be recognized
347 // regardless of this flag setting (because it has source code)
348 // and will have BinaryOnly set to true in the returned Package.
351 // If ImportComment is set, parse import comments on package statements.
352 // Import returns an error if it finds a comment it cannot understand
353 // or finds conflicting comments in multiple source files.
354 // See golang.org/s/go14customimport for more information.
357 // By default, Import searches vendor directories
358 // that apply in the given source directory before searching
359 // the GOROOT and GOPATH roots.
360 // If an Import finds and returns a package using a vendor
361 // directory, the resulting ImportPath is the complete path
362 // to the package, including the path elements leading up
363 // to and including "vendor".
364 // For example, if Import("y", "x/subdir", 0) finds
365 // "x/vendor/y", the returned package's ImportPath is "x/vendor/y",
367 // See golang.org/s/go15vendor for more information.
369 // Setting IgnoreVendor ignores vendor directories.
371 // In contrast to the package's ImportPath,
372 // the returned package's Imports, TestImports, and XTestImports
373 // are always the exact import paths from the source files:
374 // Import makes no attempt to resolve or check those paths.
378 // A Package describes the Go package found in a directory.
379 type Package
struct {
380 Dir
string // directory containing package sources
381 Name
string // package name
382 ImportComment
string // path in import comment on package statement
383 Doc
string // documentation synopsis
384 ImportPath
string // import path of package ("" if unknown)
385 Root
string // root of Go tree where this package lives
386 SrcRoot
string // package source root directory ("" if unknown)
387 PkgRoot
string // package install root directory ("" if unknown)
388 PkgTargetRoot
string // architecture dependent install root directory ("" if unknown)
389 BinDir
string // command install directory ("" if unknown)
390 Goroot
bool // package found in Go root
391 PkgObj
string // installed .a file
392 AllTags
[]string // tags that can influence file selection in this directory
393 ConflictDir
string // this directory shadows Dir in $GOPATH
394 BinaryOnly
bool // cannot be rebuilt from source (has //go:binary-only-package comment)
397 GoFiles
[]string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
398 CgoFiles
[]string // .go source files that import "C"
399 IgnoredGoFiles
[]string // .go source files ignored for this build
400 InvalidGoFiles
[]string // .go source files with detected problems (parse error, wrong package name, and so on)
401 CFiles
[]string // .c source files
402 CXXFiles
[]string // .cc, .cpp and .cxx source files
403 MFiles
[]string // .m (Objective-C) source files
404 HFiles
[]string // .h, .hh, .hpp and .hxx source files
405 FFiles
[]string // .f, .F, .for and .f90 Fortran source files
406 SFiles
[]string // .s source files
407 SwigFiles
[]string // .swig files
408 SwigCXXFiles
[]string // .swigcxx files
409 SysoFiles
[]string // .syso system object files to add to archive
412 CgoCFLAGS
[]string // Cgo CFLAGS directives
413 CgoCPPFLAGS
[]string // Cgo CPPFLAGS directives
414 CgoCXXFLAGS
[]string // Cgo CXXFLAGS directives
415 CgoFFLAGS
[]string // Cgo FFLAGS directives
416 CgoLDFLAGS
[]string // Cgo LDFLAGS directives
417 CgoPkgConfig
[]string // Cgo pkg-config directives
419 // Dependency information
420 Imports
[]string // import paths from GoFiles, CgoFiles
421 ImportPos
map[string][]token
.Position
// line information for Imports
424 TestGoFiles
[]string // _test.go files in package
425 TestImports
[]string // import paths from TestGoFiles
426 TestImportPos
map[string][]token
.Position
// line information for TestImports
427 XTestGoFiles
[]string // _test.go files outside package
428 XTestImports
[]string // import paths from XTestGoFiles
429 XTestImportPos
map[string][]token
.Position
// line information for XTestImports
432 // IsCommand reports whether the package is considered a
433 // command to be installed (not just a library).
434 // Packages named "main" are treated as commands.
435 func (p
*Package
) IsCommand() bool {
436 return p
.Name
== "main"
439 // ImportDir is like Import but processes the Go package found in
440 // the named directory.
441 func (ctxt
*Context
) ImportDir(dir
string, mode ImportMode
) (*Package
, error
) {
442 return ctxt
.Import(".", dir
, mode
)
445 // NoGoError is the error used by Import to describe a directory
446 // containing no buildable Go source files. (It may still contain
447 // test files, files hidden by build tags, and so on.)
448 type NoGoError
struct {
452 func (e
*NoGoError
) Error() string {
453 return "no buildable Go source files in " + e
.Dir
456 // MultiplePackageError describes a directory containing
457 // multiple buildable Go source files for multiple packages.
458 type MultiplePackageError
struct {
459 Dir
string // directory containing files
460 Packages
[]string // package names found
461 Files
[]string // corresponding files: Files[i] declares package Packages[i]
464 func (e
*MultiplePackageError
) Error() string {
465 // Error string limited to two entries for compatibility.
466 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
)
469 func nameExt(name
string) string {
470 i
:= strings
.LastIndex(name
, ".")
477 // Import returns details about the Go package named by the import path,
478 // interpreting local import paths relative to the srcDir directory.
479 // If the path is a local import path naming a package that can be imported
480 // using a standard import path, the returned package will set p.ImportPath
483 // In the directory containing the package, .go, .c, .h, and .s files are
484 // considered part of the package except for:
486 // - .go files in package documentation
487 // - files starting with _ or . (likely editor temporary files)
488 // - files with build constraints not satisfied by the context
490 // If an error occurs, Import returns a non-nil error and a non-nil
491 // *Package containing partial information.
493 func (ctxt
*Context
) Import(path
string, srcDir
string, mode ImportMode
) (*Package
, error
) {
498 return p
, fmt
.Errorf("import %q: invalid import path", path
)
501 var pkgtargetroot
string
505 if ctxt
.InstallSuffix
!= "" {
506 suffix
= "_" + ctxt
.InstallSuffix
508 switch ctxt
.Compiler
{
510 pkgtargetroot
= "pkg/gccgo_" + ctxt
.GOOS
+ "_" + ctxt
.GOARCH
+ suffix
512 pkgtargetroot
= "pkg/" + ctxt
.GOOS
+ "_" + ctxt
.GOARCH
+ suffix
514 // Save error for end of function.
515 pkgerr
= fmt
.Errorf("import %q: unknown compiler %q", path
, ctxt
.Compiler
)
518 switch ctxt
.Compiler
{
520 dir
, elem
:= pathpkg
.Split(p
.ImportPath
)
521 pkga
= pkgtargetroot
+ "/" + dir
+ "lib" + elem
+ ".a"
523 pkga
= pkgtargetroot
+ "/" + p
.ImportPath
+ ".a"
529 if IsLocalImport(path
) {
530 pkga
= "" // local imports have no installed path
532 return p
, fmt
.Errorf("import %q: import relative to unknown directory", path
)
534 if !ctxt
.isAbsPath(path
) {
535 p
.Dir
= ctxt
.joinPath(srcDir
, path
)
537 // p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
538 // Determine canonical import path, if any.
539 // Exclude results where the import path would include /testdata/.
540 inTestdata
:= func(sub
string) bool {
541 return strings
.Contains(sub
, "/testdata/") || strings
.HasSuffix(sub
, "/testdata") || strings
.HasPrefix(sub
, "testdata/") || sub
== "testdata"
543 if ctxt
.GOROOT
!= "" && ctxt
.Compiler
!= "gccgo" {
544 root
:= ctxt
.joinPath(ctxt
.GOROOT
, "src")
545 if sub
, ok
:= ctxt
.hasSubdir(root
, p
.Dir
); ok
&& !inTestdata(sub
) {
549 setPkga() // p.ImportPath changed
554 for i
, root
:= range all
{
555 rootsrc
:= ctxt
.joinPath(root
, "src")
556 if sub
, ok
:= ctxt
.hasSubdir(rootsrc
, p
.Dir
); ok
&& !inTestdata(sub
) {
557 // We found a potential import path for dir,
558 // but check that using it wouldn't find something
560 if ctxt
.GOROOT
!= "" && ctxt
.Compiler
!= "gccgo" {
561 if dir
:= ctxt
.joinPath(ctxt
.GOROOT
, "src", sub
); ctxt
.isDir(dir
) {
566 for _
, earlyRoot
:= range all
[:i
] {
567 if dir
:= ctxt
.joinPath(earlyRoot
, "src", sub
); ctxt
.isDir(dir
) {
573 // sub would not name some other directory instead of this one.
577 setPkga() // p.ImportPath changed
581 // It's okay that we didn't find a root containing dir.
582 // Keep going with the information we have.
584 if strings
.HasPrefix(path
, "/") {
585 return p
, fmt
.Errorf("import %q: cannot import absolute path", path
)
588 // tried records the location of unsuccessful package lookups
594 gopath
:= ctxt
.gopath()
596 // Vendor directories get first chance to satisfy import.
597 if mode
&IgnoreVendor
== 0 && srcDir
!= "" {
598 searchVendor
:= func(root
string, isGoroot
bool) bool {
599 sub
, ok
:= ctxt
.hasSubdir(root
, srcDir
)
600 if !ok ||
!strings
.HasPrefix(sub
, "src/") || strings
.Contains(sub
, "/testdata/") {
604 vendor
:= ctxt
.joinPath(root
, sub
, "vendor")
605 if ctxt
.isDir(vendor
) {
606 dir
:= ctxt
.joinPath(vendor
, path
)
607 if ctxt
.isDir(dir
) && hasGoFiles(ctxt
, dir
) {
609 p
.ImportPath
= strings
.TrimPrefix(pathpkg
.Join(sub
, "vendor", path
), "src/")
612 setPkga() // p.ImportPath changed
615 tried
.vendor
= append(tried
.vendor
, dir
)
617 i
:= strings
.LastIndex(sub
, "/")
625 if ctxt
.Compiler
!= "gccgo" && searchVendor(ctxt
.GOROOT
, true) {
628 for _
, root
:= range gopath
{
629 if searchVendor(root
, false) {
635 // Determine directory from import path.
636 if ctxt
.GOROOT
!= "" {
637 dir
:= ctxt
.joinPath(ctxt
.GOROOT
, "src", path
)
638 if ctxt
.Compiler
!= "gccgo" {
639 isDir
:= ctxt
.isDir(dir
)
640 binaryOnly
= !isDir
&& mode
&AllowBinary
!= 0 && pkga
!= "" && ctxt
.isFile(ctxt
.joinPath(ctxt
.GOROOT
, pkga
))
641 if isDir || binaryOnly
{
650 if ctxt
.Compiler
== "gccgo" && isStandardPackage(path
) {
651 p
.Dir
= ctxt
.joinPath(ctxt
.GOROOT
, "src", path
)
656 for _
, root
:= range gopath
{
657 dir
:= ctxt
.joinPath(root
, "src", path
)
658 isDir
:= ctxt
.isDir(dir
)
659 binaryOnly
= !isDir
&& mode
&AllowBinary
!= 0 && pkga
!= "" && ctxt
.isFile(ctxt
.joinPath(root
, pkga
))
660 if isDir || binaryOnly
{
665 tried
.gopath
= append(tried
.gopath
, dir
)
668 // package was not found
670 format
:= "\t%s (vendor tree)"
671 for _
, dir
:= range tried
.vendor
{
672 paths
= append(paths
, fmt
.Sprintf(format
, dir
))
675 if tried
.goroot
!= "" {
676 paths
= append(paths
, fmt
.Sprintf("\t%s (from $GOROOT)", tried
.goroot
))
678 paths
= append(paths
, "\t($GOROOT not set)")
680 format
= "\t%s (from $GOPATH)"
681 for _
, dir
:= range tried
.gopath
{
682 paths
= append(paths
, fmt
.Sprintf(format
, dir
))
685 if len(tried
.gopath
) == 0 {
686 paths
= append(paths
, "\t($GOPATH not set. For more details see: 'go help gopath')")
688 return p
, fmt
.Errorf("cannot find package %q in any of:\n%s", path
, strings
.Join(paths
, "\n"))
693 p
.SrcRoot
= ctxt
.joinPath(p
.Root
, "src")
694 p
.PkgRoot
= ctxt
.joinPath(p
.Root
, "pkg")
695 p
.BinDir
= ctxt
.joinPath(p
.Root
, "bin")
697 p
.PkgTargetRoot
= ctxt
.joinPath(p
.Root
, pkgtargetroot
)
698 p
.PkgObj
= ctxt
.joinPath(p
.Root
, pkga
)
702 // If it's a local import path, by the time we get here, we still haven't checked
703 // that p.Dir directory exists. This is the right time to do that check.
704 // We can't do it earlier, because we want to gather partial information for the
705 // non-nil *Package returned when an error occurs.
706 // We need to do this before we return early on FindOnly flag.
707 if IsLocalImport(path
) && !ctxt
.isDir(p
.Dir
) {
708 // package was not found
709 return p
, fmt
.Errorf("cannot find package %q in:\n\t%s", path
, p
.Dir
)
712 if mode
&FindOnly
!= 0 {
715 if binaryOnly
&& (mode
&AllowBinary
) != 0 {
719 if ctxt
.Compiler
== "gccgo" && p
.Goroot
{
720 // gccgo has no sources for GOROOT packages.
724 dirs
, err
:= ctxt
.readDir(p
.Dir
)
730 var Sfiles
[]string // files with ".S" (capital S)
731 var firstFile
, firstCommentFile
string
732 imported
:= make(map[string][]token
.Position
)
733 testImported
:= make(map[string][]token
.Position
)
734 xTestImported
:= make(map[string][]token
.Position
)
735 allTags
:= make(map[string]bool)
736 fset
:= token
.NewFileSet()
737 for _
, d
:= range dirs
{
745 badFile
:= func(err error
) {
746 if badGoError
== nil {
749 p
.InvalidGoFiles
= append(p
.InvalidGoFiles
, name
)
752 match
, data
, filename
, err
:= ctxt
.matchFile(p
.Dir
, name
, allTags
, &p
.BinaryOnly
)
759 p
.IgnoredGoFiles
= append(p
.IgnoredGoFiles
, name
)
764 // Going to save the file. For non-Go files, can stop here.
767 p
.CFiles
= append(p
.CFiles
, name
)
769 case ".cc", ".cpp", ".cxx":
770 p
.CXXFiles
= append(p
.CXXFiles
, name
)
773 p
.MFiles
= append(p
.MFiles
, name
)
775 case ".h", ".hh", ".hpp", ".hxx":
776 p
.HFiles
= append(p
.HFiles
, name
)
778 case ".f", ".F", ".for", ".f90":
779 p
.FFiles
= append(p
.FFiles
, name
)
782 p
.SFiles
= append(p
.SFiles
, name
)
785 Sfiles
= append(Sfiles
, name
)
788 p
.SwigFiles
= append(p
.SwigFiles
, name
)
791 p
.SwigCXXFiles
= append(p
.SwigCXXFiles
, name
)
794 // binary objects to add to package archive
795 // Likely of the form foo_windows.syso, but
796 // the name was vetted above with goodOSArchFile.
797 p
.SysoFiles
= append(p
.SysoFiles
, name
)
801 pf
, err
:= parser
.ParseFile(fset
, filename
, data
, parser
.ImportsOnly|parser
.ParseComments
)
808 if pkg
== "documentation" {
809 p
.IgnoredGoFiles
= append(p
.IgnoredGoFiles
, name
)
813 isTest
:= strings
.HasSuffix(name
, "_test.go")
815 if isTest
&& strings
.HasSuffix(pkg
, "_test") {
817 pkg
= pkg
[:len(pkg
)-len("_test")]
823 } else if pkg
!= p
.Name
{
824 badFile(&MultiplePackageError
{
826 Packages
: []string{p
.Name
, pkg
},
827 Files
: []string{firstFile
, name
},
829 p
.InvalidGoFiles
= append(p
.InvalidGoFiles
, name
)
831 if pf
.Doc
!= nil && p
.Doc
== "" {
832 p
.Doc
= doc
.Synopsis(pf
.Doc
.Text())
835 if mode
&ImportComment
!= 0 {
836 qcom
, line
:= findImportComment(data
)
838 com
, err
:= strconv
.Unquote(qcom
)
840 badFile(fmt
.Errorf("%s:%d: cannot parse import comment", filename
, line
))
841 } else if p
.ImportComment
== "" {
842 p
.ImportComment
= com
843 firstCommentFile
= name
844 } else if p
.ImportComment
!= com
{
845 badFile(fmt
.Errorf("found import comments %q (%s) and %q (%s) in %s", p
.ImportComment
, firstCommentFile
, com
, name
, p
.Dir
))
850 // Record imports and information about cgo.
852 for _
, decl
:= range pf
.Decls
{
853 d
, ok
:= decl
.(*ast
.GenDecl
)
857 for _
, dspec
:= range d
.Specs
{
858 spec
, ok
:= dspec
.(*ast
.ImportSpec
)
862 quoted
:= spec
.Path
.Value
863 path
, err
:= strconv
.Unquote(quoted
)
865 log
.Panicf("%s: parser returned invalid quoted string: <%s>", filename
, quoted
)
868 xTestImported
[path
] = append(xTestImported
[path
], fset
.Position(spec
.Pos()))
870 testImported
[path
] = append(testImported
[path
], fset
.Position(spec
.Pos()))
872 imported
[path
] = append(imported
[path
], fset
.Position(spec
.Pos()))
876 badFile(fmt
.Errorf("use of cgo in test %s not supported", filename
))
879 if cg
== nil && len(d
.Specs
) == 1 {
883 if err
:= ctxt
.saveCgo(filename
, p
, cg
); err
!= nil {
893 allTags
["cgo"] = true
895 p
.CgoFiles
= append(p
.CgoFiles
, name
)
897 p
.IgnoredGoFiles
= append(p
.IgnoredGoFiles
, name
)
900 p
.XTestGoFiles
= append(p
.XTestGoFiles
, name
)
902 p
.TestGoFiles
= append(p
.TestGoFiles
, name
)
904 p
.GoFiles
= append(p
.GoFiles
, name
)
907 if badGoError
!= nil {
910 if len(p
.GoFiles
)+len(p
.CgoFiles
)+len(p
.TestGoFiles
)+len(p
.XTestGoFiles
) == 0 {
911 return p
, &NoGoError
{p
.Dir
}
914 for tag
:= range allTags
{
915 p
.AllTags
= append(p
.AllTags
, tag
)
917 sort
.Strings(p
.AllTags
)
919 p
.Imports
, p
.ImportPos
= cleanImports(imported
)
920 p
.TestImports
, p
.TestImportPos
= cleanImports(testImported
)
921 p
.XTestImports
, p
.XTestImportPos
= cleanImports(xTestImported
)
923 // add the .S files only if we are using cgo
924 // (which means gcc will compile them).
925 // The standard assemblers expect .s files.
926 if len(p
.CgoFiles
) > 0 {
927 p
.SFiles
= append(p
.SFiles
, Sfiles
...)
928 sort
.Strings(p
.SFiles
)
934 // hasGoFiles reports whether dir contains any files with names ending in .go.
935 // For a vendor check we must exclude directories that contain no .go files.
936 // Otherwise it is not possible to vendor just a/b/c and still import the
937 // non-vendored a/b. See golang.org/issue/13832.
938 func hasGoFiles(ctxt
*Context
, dir
string) bool {
939 ents
, _
:= ctxt
.readDir(dir
)
940 for _
, ent
:= range ents
{
941 if !ent
.IsDir() && strings
.HasSuffix(ent
.Name(), ".go") {
948 func findImportComment(data
[]byte) (s
string, line
int) {
949 // expect keyword package
950 word
, data
:= parseWord(data
)
951 if string(word
) != "package" {
955 // expect package name
956 _
, data
= parseWord(data
)
958 // now ready for import comment, a // or /* */ comment
959 // beginning and ending on the current line.
960 for len(data
) > 0 && (data
[0] == ' ' || data
[0] == '\t' || data
[0] == '\r') {
966 case bytes
.HasPrefix(data
, slashSlash
):
967 i
:= bytes
.Index(data
, newline
)
972 case bytes
.HasPrefix(data
, slashStar
):
974 i
:= bytes
.Index(data
, starSlash
)
980 if bytes
.Contains(comment
, newline
) {
984 comment
= bytes
.TrimSpace(comment
)
986 // split comment into `import`, `"pkg"`
987 word
, arg
:= parseWord(comment
)
988 if string(word
) != "import" {
992 line
= 1 + bytes
.Count(data
[:cap(data
)-cap(arg
)], newline
)
993 return strings
.TrimSpace(string(arg
)), line
997 slashSlash
= []byte("//")
998 slashStar
= []byte("/*")
999 starSlash
= []byte("*/")
1000 newline
= []byte("\n")
1003 // skipSpaceOrComment returns data with any leading spaces or comments removed.
1004 func skipSpaceOrComment(data
[]byte) []byte {
1007 case ' ', '\t', '\r', '\n':
1011 if bytes
.HasPrefix(data
, slashSlash
) {
1012 i
:= bytes
.Index(data
, newline
)
1019 if bytes
.HasPrefix(data
, slashStar
) {
1021 i
:= bytes
.Index(data
, starSlash
)
1034 // parseWord skips any leading spaces or comments in data
1035 // and then parses the beginning of data as an identifier or keyword,
1036 // returning that word and what remains after the word.
1037 func parseWord(data
[]byte) (word
, rest
[]byte) {
1038 data
= skipSpaceOrComment(data
)
1040 // Parse past leading word characters.
1043 r
, size
:= utf8
.DecodeRune(rest
)
1044 if unicode
.IsLetter(r
) ||
'0' <= r
&& r
<= '9' || r
== '_' {
1051 word
= data
[:len(data
)-len(rest
)]
1059 // MatchFile reports whether the file with the given name in the given directory
1060 // matches the context and would be included in a Package created by ImportDir
1061 // of that directory.
1063 // MatchFile considers the name of the file and may use ctxt.OpenFile to
1064 // read some or all of the file's content.
1065 func (ctxt
*Context
) MatchFile(dir
, name
string) (match
bool, err error
) {
1066 match
, _
, _
, err
= ctxt
.matchFile(dir
, name
, nil, nil)
1070 // matchFile determines whether the file with the given name in the given directory
1071 // should be included in the package being constructed.
1072 // It returns the data read from the file.
1073 // If name denotes a Go program, matchFile reads until the end of the
1074 // imports (and returns that data) even though it only considers text
1075 // until the first non-comment.
1076 // If allTags is non-nil, matchFile records any encountered build tag
1077 // by setting allTags[tag] = true.
1078 func (ctxt
*Context
) matchFile(dir
, name
string, allTags
map[string]bool, binaryOnly
*bool) (match
bool, data
[]byte, filename
string, err error
) {
1079 if strings
.HasPrefix(name
, "_") ||
1080 strings
.HasPrefix(name
, ".") {
1084 i
:= strings
.LastIndex(name
, ".")
1090 if !ctxt
.goodOSArchFile(name
, allTags
) && !ctxt
.UseAllFiles
{
1095 case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx":
1096 // tentatively okay - read to make sure
1098 // binary, no reading
1106 filename
= ctxt
.joinPath(dir
, name
)
1107 f
, err
:= ctxt
.openFile(filename
)
1112 if strings
.HasSuffix(filename
, ".go") {
1113 data
, err
= readImports(f
, false, nil)
1114 if strings
.HasSuffix(filename
, "_test.go") {
1115 binaryOnly
= nil // ignore //go:binary-only-package comments in _test.go files
1118 binaryOnly
= nil // ignore //go:binary-only-package comments in non-Go sources
1119 data
, err
= readComments(f
)
1123 err
= fmt
.Errorf("read %s: %v", filename
, err
)
1127 // Look for +build comments to accept or reject the file.
1128 var sawBinaryOnly
bool
1129 if !ctxt
.shouldBuild(data
, allTags
, &sawBinaryOnly
) && !ctxt
.UseAllFiles
{
1133 if binaryOnly
!= nil && sawBinaryOnly
{
1140 func cleanImports(m
map[string][]token
.Position
) ([]string, map[string][]token
.Position
) {
1141 all
:= make([]string, 0, len(m
))
1142 for path
:= range m
{
1143 all
= append(all
, path
)
1149 // Import is shorthand for Default.Import.
1150 func Import(path
, srcDir
string, mode ImportMode
) (*Package
, error
) {
1151 return Default
.Import(path
, srcDir
, mode
)
1154 // ImportDir is shorthand for Default.ImportDir.
1155 func ImportDir(dir
string, mode ImportMode
) (*Package
, error
) {
1156 return Default
.ImportDir(dir
, mode
)
1159 var slashslash
= []byte("//")
1161 // Special comment denoting a binary-only package.
1162 // See https://golang.org/design/2775-binary-only-packages
1163 // for more about the design of binary-only packages.
1164 var binaryOnlyComment
= []byte("//go:binary-only-package")
1166 // shouldBuild reports whether it is okay to use this file,
1167 // The rule is that in the file's leading run of // comments
1168 // and blank lines, which must be followed by a blank line
1169 // (to avoid including a Go package clause doc comment),
1170 // lines beginning with '// +build' are taken as build directives.
1172 // The file is accepted only if each such line lists something
1173 // matching the file. For example:
1175 // // +build windows linux
1177 // marks the file as applicable only on Windows and Linux.
1179 // If shouldBuild finds a //go:binary-only-package comment in the file,
1180 // it sets *binaryOnly to true. Otherwise it does not change *binaryOnly.
1182 func (ctxt
*Context
) shouldBuild(content
[]byte, allTags
map[string]bool, binaryOnly
*bool) bool {
1183 sawBinaryOnly
:= false
1185 // Pass 1. Identify leading run of // comments and blank lines,
1186 // which must be followed by a blank line.
1191 if i
:= bytes
.IndexByte(line
, '\n'); i
>= 0 {
1192 line
, p
= line
[:i
], p
[i
+1:]
1196 line
= bytes
.TrimSpace(line
)
1197 if len(line
) == 0 { // Blank line
1198 end
= len(content
) - len(p
)
1201 if !bytes
.HasPrefix(line
, slashslash
) { // Not comment line
1205 content
= content
[:end
]
1207 // Pass 2. Process each line in the run.
1212 if i
:= bytes
.IndexByte(line
, '\n'); i
>= 0 {
1213 line
, p
= line
[:i
], p
[i
+1:]
1217 line
= bytes
.TrimSpace(line
)
1218 if !bytes
.HasPrefix(line
, slashslash
) {
1221 if bytes
.Equal(line
, binaryOnlyComment
) {
1222 sawBinaryOnly
= true
1224 line
= bytes
.TrimSpace(line
[len(slashslash
):])
1225 if len(line
) > 0 && line
[0] == '+' {
1226 // Looks like a comment +line.
1227 f
:= strings
.Fields(string(line
))
1228 if f
[0] == "+build" {
1230 for _
, tok
:= range f
[1:] {
1231 if ctxt
.match(tok
, allTags
) {
1242 if binaryOnly
!= nil && sawBinaryOnly
{
1249 // saveCgo saves the information from the #cgo lines in the import "C" comment.
1250 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
1251 // that affect the way cgo's C code is built.
1252 func (ctxt
*Context
) saveCgo(filename
string, di
*Package
, cg
*ast
.CommentGroup
) error
{
1254 for _
, line
:= range strings
.Split(text
, "\n") {
1258 // #cgo [GOOS/GOARCH...] LDFLAGS: stuff
1260 line
= strings
.TrimSpace(line
)
1261 if len(line
) < 5 || line
[:4] != "#cgo" ||
(line
[4] != ' ' && line
[4] != '\t') {
1266 line
= strings
.TrimSpace(line
[4:])
1267 i
:= strings
.Index(line
, ":")
1269 return fmt
.Errorf("%s: invalid #cgo line: %s", filename
, orig
)
1271 line
, argstr
:= line
[:i
], line
[i
+1:]
1273 // Parse GOOS/GOARCH stuff.
1274 f
:= strings
.Fields(line
)
1276 return fmt
.Errorf("%s: invalid #cgo line: %s", filename
, orig
)
1279 cond
, verb
:= f
[:len(f
)-1], f
[len(f
)-1]
1282 for _
, c
:= range cond
{
1283 if ctxt
.match(c
, nil) {
1293 args
, err
:= splitQuoted(argstr
)
1295 return fmt
.Errorf("%s: invalid #cgo line: %s", filename
, orig
)
1298 for i
, arg
:= range args
{
1299 if arg
, ok
= expandSrcDir(arg
, di
.Dir
); !ok
{
1300 return fmt
.Errorf("%s: malformed #cgo argument: %s", filename
, arg
)
1306 case "CFLAGS", "CPPFLAGS", "CXXFLAGS", "FFLAGS", "LDFLAGS":
1307 // Change relative paths to absolute.
1308 ctxt
.makePathsAbsolute(args
, di
.Dir
)
1313 di
.CgoCFLAGS
= append(di
.CgoCFLAGS
, args
...)
1315 di
.CgoCPPFLAGS
= append(di
.CgoCPPFLAGS
, args
...)
1317 di
.CgoCXXFLAGS
= append(di
.CgoCXXFLAGS
, args
...)
1319 di
.CgoFFLAGS
= append(di
.CgoFFLAGS
, args
...)
1321 di
.CgoLDFLAGS
= append(di
.CgoLDFLAGS
, args
...)
1323 di
.CgoPkgConfig
= append(di
.CgoPkgConfig
, args
...)
1325 return fmt
.Errorf("%s: invalid #cgo verb: %s", filename
, orig
)
1331 // expandSrcDir expands any occurrence of ${SRCDIR}, making sure
1332 // the result is safe for the shell.
1333 func expandSrcDir(str
string, srcdir
string) (string, bool) {
1334 // "\" delimited paths cause safeCgoName to fail
1335 // so convert native paths with a different delimiter
1336 // to "/" before starting (eg: on windows).
1337 srcdir
= filepath
.ToSlash(srcdir
)
1339 chunks
:= strings
.Split(str
, "${SRCDIR}")
1340 if len(chunks
) < 2 {
1341 return str
, safeCgoName(str
)
1344 for _
, chunk
:= range chunks
{
1345 ok
= ok
&& (chunk
== "" ||
safeCgoName(chunk
))
1347 ok
= ok
&& (srcdir
== "" ||
safeCgoName(srcdir
))
1348 res
:= strings
.Join(chunks
, srcdir
)
1349 return res
, ok
&& res
!= ""
1352 // makePathsAbsolute looks for compiler options that take paths and
1353 // makes them absolute. We do this because through the 1.8 release we
1354 // ran the compiler in the package directory, so any relative -I or -L
1355 // options would be relative to that directory. In 1.9 we changed to
1356 // running the compiler in the build directory, to get consistent
1357 // build results (issue #19964). To keep builds working, we change any
1358 // relative -I or -L options to be absolute.
1360 // Using filepath.IsAbs and filepath.Join here means the results will be
1361 // different on different systems, but that's OK: -I and -L options are
1362 // inherently system-dependent.
1363 func (ctxt
*Context
) makePathsAbsolute(args
[]string, srcDir
string) {
1365 for i
, arg
:= range args
{
1367 if !filepath
.IsAbs(arg
) {
1368 args
[i
] = filepath
.Join(srcDir
, arg
)
1371 } else if strings
.HasPrefix(arg
, "-I") || strings
.HasPrefix(arg
, "-L") {
1375 if !filepath
.IsAbs(arg
[2:]) {
1376 args
[i
] = arg
[:2] + filepath
.Join(srcDir
, arg
[2:])
1383 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
1384 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
1385 // See golang.org/issue/6038.
1386 // The @ is for OS X. See golang.org/issue/13720.
1387 // The % is for Jenkins. See golang.org/issue/16959.
1388 const safeString
= "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% "
1390 func safeCgoName(s
string) bool {
1394 for i
:= 0; i
< len(s
); i
++ {
1395 if c
:= s
[i
]; c
< utf8
.RuneSelf
&& strings
.IndexByte(safeString
, c
) < 0 {
1402 // splitQuoted splits the string s around each instance of one or more consecutive
1403 // white space characters while taking into account quotes and escaping, and
1404 // returns an array of substrings of s or an empty list if s contains only white space.
1405 // Single quotes and double quotes are recognized to prevent splitting within the
1406 // quoted region, and are removed from the resulting substrings. If a quote in s
1407 // isn't closed err will be set and r will have the unclosed argument as the
1408 // last element. The backslash is used for escaping.
1410 // For example, the following string:
1412 // a b:"c d" 'e''f' "g\""
1414 // Would be parsed as:
1416 // []string{"a", "b:c d", "ef", `g"`}
1418 func splitQuoted(s
string) (r
[]string, err error
) {
1420 arg
:= make([]rune
, len(s
))
1425 for _
, rune
:= range s
{
1432 case quote
!= '\x00':
1437 case rune
== '"' || rune
== '\'':
1441 case unicode
.IsSpace(rune
):
1442 if quoted || i
> 0 {
1444 args
= append(args
, string(arg
[:i
]))
1452 if quoted || i
> 0 {
1453 args
= append(args
, string(arg
[:i
]))
1456 err
= errors
.New("unclosed quote")
1458 err
= errors
.New("unfinished escaping")
1463 // match reports whether the name is one of:
1467 // cgo (if cgo is enabled)
1468 // !cgo (if cgo is disabled)
1471 // tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags)
1472 // !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags)
1473 // a comma-separated list of any of these
1475 func (ctxt
*Context
) match(name
string, allTags
map[string]bool) bool {
1478 allTags
[name
] = true
1482 if i
:= strings
.Index(name
, ","); i
>= 0 {
1483 // comma-separated list
1484 ok1
:= ctxt
.match(name
[:i
], allTags
)
1485 ok2
:= ctxt
.match(name
[i
+1:], allTags
)
1488 if strings
.HasPrefix(name
, "!!") { // bad syntax, reject always
1491 if strings
.HasPrefix(name
, "!") { // negation
1492 return len(name
) > 1 && !ctxt
.match(name
[1:], allTags
)
1496 allTags
[name
] = true
1499 // Tags must be letters, digits, underscores or dots.
1500 // Unlike in Go identifiers, all digits are fine (e.g., "386").
1501 for _
, c
:= range name
{
1502 if !unicode
.IsLetter(c
) && !unicode
.IsDigit(c
) && c
!= '_' && c
!= '.' {
1508 if ctxt
.CgoEnabled
&& name
== "cgo" {
1511 if name
== ctxt
.GOOS || name
== ctxt
.GOARCH || name
== ctxt
.Compiler
{
1514 if ctxt
.GOOS
== "android" && name
== "linux" {
1519 for _
, tag
:= range ctxt
.BuildTags
{
1524 for _
, tag
:= range ctxt
.ReleaseTags
{
1533 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
1534 // suffix which does not match the current system.
1535 // The recognized name formats are:
1539 // name_$(GOOS)_$(GOARCH).*
1540 // name_$(GOOS)_test.*
1541 // name_$(GOARCH)_test.*
1542 // name_$(GOOS)_$(GOARCH)_test.*
1544 // An exception: if GOOS=android, then files with GOOS=linux are also matched.
1545 func (ctxt
*Context
) goodOSArchFile(name
string, allTags
map[string]bool) bool {
1546 if dot
:= strings
.Index(name
, "."); dot
!= -1 {
1550 // Before Go 1.4, a file called "linux.go" would be equivalent to having a
1551 // build tag "linux" in that file. For Go 1.4 and beyond, we require this
1552 // auto-tagging to apply only to files with a non-empty prefix, so
1553 // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
1554 // systems, such as android, to arrive without breaking existing code with
1555 // innocuous source code in "android.go". The easiest fix: cut everything
1556 // in the name before the initial _.
1557 i
:= strings
.Index(name
, "_")
1561 name
= name
[i
:] // ignore everything before first _
1563 l
:= strings
.Split(name
, "_")
1564 if n
:= len(l
); n
> 0 && l
[n
-1] == "test" {
1568 if n
>= 2 && knownOS
[l
[n
-2]] && knownArch
[l
[n
-1]] {
1570 allTags
[l
[n
-2]] = true
1571 allTags
[l
[n
-1]] = true
1573 if l
[n
-1] != ctxt
.GOARCH
{
1576 if ctxt
.GOOS
== "android" && l
[n
-2] == "linux" {
1579 return l
[n
-2] == ctxt
.GOOS
1581 if n
>= 1 && knownOS
[l
[n
-1]] {
1583 allTags
[l
[n
-1]] = true
1585 if ctxt
.GOOS
== "android" && l
[n
-1] == "linux" {
1588 return l
[n
-1] == ctxt
.GOOS
1590 if n
>= 1 && knownArch
[l
[n
-1]] {
1592 allTags
[l
[n
-1]] = true
1594 return l
[n
-1] == ctxt
.GOARCH
1599 var knownOS
= make(map[string]bool)
1600 var knownArch
= make(map[string]bool)
1603 for _
, v
:= range strings
.Fields(goosList
) {
1606 for _
, v
:= range strings
.Fields(goarchList
) {
1611 // ToolDir is the directory containing build tools.
1612 var ToolDir
= getToolDir()
1614 // IsLocalImport reports whether the import path is
1615 // a local import path, like ".", "..", "./foo", or "../foo".
1616 func IsLocalImport(path
string) bool {
1617 return path
== "." || path
== ".." ||
1618 strings
.HasPrefix(path
, "./") || strings
.HasPrefix(path
, "../")
1621 // ArchChar returns "?" and an error.
1622 // In earlier versions of Go, the returned string was used to derive
1623 // the compiler and linker tool names, the default object file suffix,
1624 // and the default linker output name. As of Go 1.5, those strings
1625 // no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
1626 func ArchChar(goarch
string) (string, error
) {
1627 return "?", errors
.New("architecture letter no longer used")