Source file src/pkg/cmd/go/internal/load/pkg.go
1
2
3
4
5
6 package load
7
8 import (
9 "bytes"
10 "errors"
11 "fmt"
12 "go/build"
13 "go/token"
14 "io/ioutil"
15 "os"
16 pathpkg "path"
17 "path/filepath"
18 "runtime"
19 "sort"
20 "strconv"
21 "strings"
22 "unicode"
23 "unicode/utf8"
24
25 "cmd/go/internal/base"
26 "cmd/go/internal/cfg"
27 "cmd/go/internal/modinfo"
28 "cmd/go/internal/par"
29 "cmd/go/internal/search"
30 "cmd/go/internal/str"
31 )
32
33 var (
34
35 ModInit func()
36
37
38 ModBinDir func() string
39 ModLookup func(parentPath string, parentIsStd bool, path string) (dir, realPath string, err error)
40 ModPackageModuleInfo func(path string) *modinfo.ModulePublic
41 ModImportPaths func(args []string) []*search.Match
42 ModPackageBuildInfo func(main string, deps []string) string
43 ModInfoProg func(info string) []byte
44 ModImportFromFiles func([]string)
45 ModDirImportPath func(string) string
46 )
47
48 var IgnoreImports bool
49
50
51 type Package struct {
52 PackagePublic
53 Internal PackageInternal
54 }
55
56 type PackagePublic struct {
57
58
59
60 Dir string `json:",omitempty"`
61 ImportPath string `json:",omitempty"`
62 ImportComment string `json:",omitempty"`
63 Name string `json:",omitempty"`
64 Doc string `json:",omitempty"`
65 Target string `json:",omitempty"`
66 Shlib string `json:",omitempty"`
67 Root string `json:",omitempty"`
68 ConflictDir string `json:",omitempty"`
69 ForTest string `json:",omitempty"`
70 Export string `json:",omitempty"`
71 Module *modinfo.ModulePublic `json:",omitempty"`
72 Match []string `json:",omitempty"`
73 Goroot bool `json:",omitempty"`
74 Standard bool `json:",omitempty"`
75 DepOnly bool `json:",omitempty"`
76 BinaryOnly bool `json:",omitempty"`
77 Incomplete bool `json:",omitempty"`
78
79
80
81
82 Stale bool `json:",omitempty"`
83 StaleReason string `json:",omitempty"`
84
85
86
87
88 GoFiles []string `json:",omitempty"`
89 CgoFiles []string `json:",omitempty"`
90 CompiledGoFiles []string `json:",omitempty"`
91 IgnoredGoFiles []string `json:",omitempty"`
92 CFiles []string `json:",omitempty"`
93 CXXFiles []string `json:",omitempty"`
94 MFiles []string `json:",omitempty"`
95 HFiles []string `json:",omitempty"`
96 FFiles []string `json:",omitempty"`
97 SFiles []string `json:",omitempty"`
98 SwigFiles []string `json:",omitempty"`
99 SwigCXXFiles []string `json:",omitempty"`
100 SysoFiles []string `json:",omitempty"`
101
102
103 CgoCFLAGS []string `json:",omitempty"`
104 CgoCPPFLAGS []string `json:",omitempty"`
105 CgoCXXFLAGS []string `json:",omitempty"`
106 CgoFFLAGS []string `json:",omitempty"`
107 CgoLDFLAGS []string `json:",omitempty"`
108 CgoPkgConfig []string `json:",omitempty"`
109
110
111 Imports []string `json:",omitempty"`
112 ImportMap map[string]string `json:",omitempty"`
113 Deps []string `json:",omitempty"`
114
115
116
117 Error *PackageError `json:",omitempty"`
118 DepsErrors []*PackageError `json:",omitempty"`
119
120
121
122
123 TestGoFiles []string `json:",omitempty"`
124 TestImports []string `json:",omitempty"`
125 XTestGoFiles []string `json:",omitempty"`
126 XTestImports []string `json:",omitempty"`
127 }
128
129
130
131
132
133
134 func (p *Package) AllFiles() []string {
135 return str.StringList(
136 p.GoFiles,
137 p.CgoFiles,
138
139 p.IgnoredGoFiles,
140 p.CFiles,
141 p.CXXFiles,
142 p.MFiles,
143 p.HFiles,
144 p.FFiles,
145 p.SFiles,
146 p.SwigFiles,
147 p.SwigCXXFiles,
148 p.SysoFiles,
149 p.TestGoFiles,
150 p.XTestGoFiles,
151 )
152 }
153
154
155 func (p *Package) Desc() string {
156 if p.ForTest != "" {
157 return p.ImportPath + " [" + p.ForTest + ".test]"
158 }
159 return p.ImportPath
160 }
161
162 type PackageInternal struct {
163
164 Build *build.Package
165 Imports []*Package
166 CompiledImports []string
167 RawImports []string
168 ForceLibrary bool
169 CmdlineFiles bool
170 CmdlinePkg bool
171 CmdlinePkgLiteral bool
172 Local bool
173 LocalPrefix string
174 ExeName string
175 CoverMode string
176 CoverVars map[string]*CoverVar
177 OmitDebug bool
178 GobinSubdir bool
179 BuildInfo string
180 TestmainGo *[]byte
181
182 Asmflags []string
183 Gcflags []string
184 Ldflags []string
185 Gccgoflags []string
186 }
187
188 type NoGoError struct {
189 Package *Package
190 }
191
192 func (e *NoGoError) Error() string {
193
194 dummy := 0
195 for _, name := range e.Package.IgnoredGoFiles {
196 if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
197 dummy++
198 }
199 }
200
201 if len(e.Package.IgnoredGoFiles) > dummy {
202
203 return "build constraints exclude all Go files in " + e.Package.Dir
204 }
205 if len(e.Package.TestGoFiles)+len(e.Package.XTestGoFiles) > 0 {
206
207
208
209 return "no non-test Go files in " + e.Package.Dir
210 }
211 return "no Go files in " + e.Package.Dir
212 }
213
214
215
216
217
218
219
220
221
222
223
224 func (p *Package) Resolve(imports []string) []string {
225 if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
226 panic("internal error: p.Resolve(p.Imports) called")
227 }
228 seen := make(map[string]bool)
229 var all []string
230 for _, path := range imports {
231 path = ResolveImportPath(p, path)
232 if !seen[path] {
233 seen[path] = true
234 all = append(all, path)
235 }
236 }
237 sort.Strings(all)
238 return all
239 }
240
241
242 type CoverVar struct {
243 File string
244 Var string
245 }
246
247 func (p *Package) copyBuild(pp *build.Package) {
248 p.Internal.Build = pp
249
250 if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
251 old := pp.PkgTargetRoot
252 pp.PkgRoot = cfg.BuildPkgdir
253 pp.PkgTargetRoot = cfg.BuildPkgdir
254 pp.PkgObj = filepath.Join(cfg.BuildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
255 }
256
257 p.Dir = pp.Dir
258 p.ImportPath = pp.ImportPath
259 p.ImportComment = pp.ImportComment
260 p.Name = pp.Name
261 p.Doc = pp.Doc
262 p.Root = pp.Root
263 p.ConflictDir = pp.ConflictDir
264 p.BinaryOnly = pp.BinaryOnly
265
266
267 p.Goroot = pp.Goroot
268 p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
269 p.GoFiles = pp.GoFiles
270 p.CgoFiles = pp.CgoFiles
271 p.IgnoredGoFiles = pp.IgnoredGoFiles
272 p.CFiles = pp.CFiles
273 p.CXXFiles = pp.CXXFiles
274 p.MFiles = pp.MFiles
275 p.HFiles = pp.HFiles
276 p.FFiles = pp.FFiles
277 p.SFiles = pp.SFiles
278 p.SwigFiles = pp.SwigFiles
279 p.SwigCXXFiles = pp.SwigCXXFiles
280 p.SysoFiles = pp.SysoFiles
281 p.CgoCFLAGS = pp.CgoCFLAGS
282 p.CgoCPPFLAGS = pp.CgoCPPFLAGS
283 p.CgoCXXFLAGS = pp.CgoCXXFLAGS
284 p.CgoFFLAGS = pp.CgoFFLAGS
285 p.CgoLDFLAGS = pp.CgoLDFLAGS
286 p.CgoPkgConfig = pp.CgoPkgConfig
287
288 p.Imports = make([]string, len(pp.Imports))
289 copy(p.Imports, pp.Imports)
290 p.Internal.RawImports = pp.Imports
291 p.TestGoFiles = pp.TestGoFiles
292 p.TestImports = pp.TestImports
293 p.XTestGoFiles = pp.XTestGoFiles
294 p.XTestImports = pp.XTestImports
295 if IgnoreImports {
296 p.Imports = nil
297 p.Internal.RawImports = nil
298 p.TestImports = nil
299 p.XTestImports = nil
300 }
301 }
302
303
304 type PackageError struct {
305 ImportStack []string
306 Pos string
307 Err string
308 IsImportCycle bool `json:"-"`
309 Hard bool `json:"-"`
310 }
311
312 func (p *PackageError) Error() string {
313
314 if p.IsImportCycle {
315 return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
316 }
317 if p.Pos != "" {
318
319
320 return p.Pos + ": " + p.Err
321 }
322 if len(p.ImportStack) == 0 {
323 return p.Err
324 }
325 return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err
326 }
327
328
329
330
331 type ImportStack []string
332
333 func (s *ImportStack) Push(p string) {
334 *s = append(*s, p)
335 }
336
337 func (s *ImportStack) Pop() {
338 *s = (*s)[0 : len(*s)-1]
339 }
340
341 func (s *ImportStack) Copy() []string {
342 return append([]string{}, *s...)
343 }
344
345
346
347
348 func (sp *ImportStack) shorterThan(t []string) bool {
349 s := *sp
350 if len(s) != len(t) {
351 return len(s) < len(t)
352 }
353
354 for i := range s {
355 if s[i] != t[i] {
356 return s[i] < t[i]
357 }
358 }
359 return false
360 }
361
362
363
364
365 var packageCache = map[string]*Package{}
366
367
368
369
370 func ClearPackageCache() {
371 for name := range packageCache {
372 delete(packageCache, name)
373 }
374 resolvedImportCache.Clear()
375 packageDataCache.Clear()
376 }
377
378
379
380
381
382 func ClearPackageCachePartial(args []string) {
383 shouldDelete := make(map[string]bool)
384 for _, arg := range args {
385 shouldDelete[arg] = true
386 if p := packageCache[arg]; p != nil {
387 delete(packageCache, arg)
388 }
389 }
390 resolvedImportCache.DeleteIf(func(key interface{}) bool {
391 return shouldDelete[key.(importSpec).path]
392 })
393 packageDataCache.DeleteIf(func(key interface{}) bool {
394 return shouldDelete[key.(string)]
395 })
396 }
397
398
399
400
401
402 func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
403 p := packageCache[arg]
404 if p != nil {
405 delete(packageCache, arg)
406 resolvedImportCache.DeleteIf(func(key interface{}) bool {
407 return key.(importSpec).path == p.ImportPath
408 })
409 packageDataCache.Delete(p.ImportPath)
410 }
411 return LoadImport(arg, base.Cwd, nil, stk, nil, 0)
412 }
413
414
415
416
417
418
419
420
421 func dirToImportPath(dir string) string {
422 return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
423 }
424
425 func makeImportValid(r rune) rune {
426
427 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
428 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
429 return '_'
430 }
431 return r
432 }
433
434
435 const (
436
437
438
439
440
441
442
443
444
445 ResolveImport = 1 << iota
446
447
448
449 ResolveModule
450
451
452
453 GetTestDeps
454 )
455
456
457
458
459
460
461
462
463 func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
464 return loadImport(nil, path, srcDir, parent, stk, importPos, mode)
465 }
466
467 func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
468 if path == "" {
469 panic("LoadImport called with empty package path")
470 }
471
472 stk.Push(path)
473 defer stk.Pop()
474
475 var parentPath, parentRoot string
476 parentIsStd := false
477 if parent != nil {
478 parentPath = parent.ImportPath
479 parentRoot = parent.Root
480 parentIsStd = parent.Standard
481 }
482 bp, loaded, err := loadPackageData(path, parentPath, srcDir, parentRoot, parentIsStd, mode)
483 if loaded && pre != nil && !IgnoreImports {
484 pre.preloadImports(bp.Imports, bp)
485 }
486 if bp == nil {
487 return &Package{
488 PackagePublic: PackagePublic{
489 ImportPath: path,
490 Error: &PackageError{
491 ImportStack: stk.Copy(),
492 Err: err.Error(),
493 },
494 },
495 }
496 }
497
498 importPath := bp.ImportPath
499 p := packageCache[importPath]
500 if p != nil {
501 p = reusePackage(p, stk)
502 } else {
503 p = new(Package)
504 p.Internal.Local = build.IsLocalImport(path)
505 p.ImportPath = importPath
506 packageCache[importPath] = p
507
508
509
510
511 p.load(stk, bp, err)
512 if p.Error != nil && p.Error.Pos == "" {
513 p = setErrorPos(p, importPos)
514 }
515
516 if !cfg.ModulesEnabled && path != cleanImport(path) {
517 p.Error = &PackageError{
518 ImportStack: stk.Copy(),
519 Err: fmt.Sprintf("non-canonical import path: %q should be %q", path, pathpkg.Clean(path)),
520 }
521 p.Incomplete = true
522 }
523 }
524
525
526 if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p {
527 return setErrorPos(perr, importPos)
528 }
529 if mode&ResolveImport != 0 {
530 if perr := disallowVendor(srcDir, parent, parentPath, path, p, stk); perr != p {
531 return setErrorPos(perr, importPos)
532 }
533 }
534
535 if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
536 perr := *p
537 perr.Error = &PackageError{
538 ImportStack: stk.Copy(),
539 Err: fmt.Sprintf("import %q is a program, not an importable package", path),
540 }
541 return setErrorPos(&perr, importPos)
542 }
543
544 if p.Internal.Local && parent != nil && !parent.Internal.Local {
545 perr := *p
546 errMsg := fmt.Sprintf("local import %q in non-local package", path)
547 if path == "." {
548 errMsg = "cannot import current directory"
549 }
550 perr.Error = &PackageError{
551 ImportStack: stk.Copy(),
552 Err: errMsg,
553 }
554 return setErrorPos(&perr, importPos)
555 }
556
557 return p
558 }
559
560 func setErrorPos(p *Package, importPos []token.Position) *Package {
561 if len(importPos) > 0 {
562 pos := importPos[0]
563 pos.Filename = base.ShortPath(pos.Filename)
564 p.Error.Pos = pos.String()
565 }
566 return p
567 }
568
569
570
571
572
573
574
575
576
577
578 func loadPackageData(path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) {
579 if path == "" {
580 panic("loadPackageData called with empty package path")
581 }
582
583 if strings.HasPrefix(path, "mod/") {
584
585
586
587
588
589 return nil, false, fmt.Errorf("disallowed import path %q", path)
590 }
591
592 if strings.Contains(path, "@") {
593 if cfg.ModulesEnabled {
594 return nil, false, errors.New("can only use path@version syntax with 'go get'")
595 } else {
596 return nil, false, errors.New("cannot use path@version syntax in GOPATH mode")
597 }
598 }
599
600
601
602
603
604
605 importKey := importSpec{
606 path: path,
607 parentPath: parentPath,
608 parentDir: parentDir,
609 parentRoot: parentRoot,
610 parentIsStd: parentIsStd,
611 mode: mode,
612 }
613 r := resolvedImportCache.Do(importKey, func() interface{} {
614 var r resolvedImport
615 if build.IsLocalImport(path) {
616 r.dir = filepath.Join(parentDir, path)
617 r.path = dirToImportPath(r.dir)
618 } else if cfg.ModulesEnabled {
619 r.dir, r.path, r.err = ModLookup(parentPath, parentIsStd, path)
620 } else if mode&ResolveImport != 0 {
621
622
623
624
625 r.path = resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
626 } else if mode&ResolveModule != 0 {
627 r.path = moduleImportPath(path, parentPath, parentDir, parentRoot)
628 }
629 if r.path == "" {
630 r.path = path
631 }
632 return r
633 }).(resolvedImport)
634
635
636
637
638
639
640 data := packageDataCache.Do(r.path, func() interface{} {
641 loaded = true
642 var data packageData
643 if r.dir != "" {
644 var buildMode build.ImportMode
645 if !cfg.ModulesEnabled {
646 buildMode = build.ImportComment
647 }
648 data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
649 if data.p.Root == "" && cfg.ModulesEnabled {
650 if info := ModPackageModuleInfo(path); info != nil {
651 data.p.Root = info.Dir
652 }
653 }
654 } else if r.err != nil {
655 data.p = new(build.Package)
656 data.err = r.err
657 } else if cfg.ModulesEnabled && path != "unsafe" {
658 data.p = new(build.Package)
659 data.err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", r.path)
660 } else {
661 buildMode := build.ImportComment
662 if mode&ResolveImport == 0 || r.path != path {
663
664 buildMode |= build.IgnoreVendor
665 }
666 data.p, data.err = cfg.BuildContext.Import(r.path, parentDir, buildMode)
667 }
668 data.p.ImportPath = r.path
669
670
671
672 if !data.p.Goroot {
673 if cfg.GOBIN != "" {
674 data.p.BinDir = cfg.GOBIN
675 } else if cfg.ModulesEnabled {
676 data.p.BinDir = ModBinDir()
677 }
678 }
679
680 if !cfg.ModulesEnabled && data.err == nil &&
681 data.p.ImportComment != "" && data.p.ImportComment != path &&
682 !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
683 data.err = fmt.Errorf("code in directory %s expects import %q", data.p.Dir, data.p.ImportComment)
684 }
685 return data
686 }).(packageData)
687
688 return data.p, loaded, data.err
689 }
690
691
692
693 type importSpec struct {
694 path string
695 parentPath, parentDir, parentRoot string
696 parentIsStd bool
697 mode int
698 }
699
700
701
702
703 type resolvedImport struct {
704 path, dir string
705 err error
706 }
707
708
709
710 type packageData struct {
711 p *build.Package
712 err error
713 }
714
715
716
717 var resolvedImportCache par.Cache
718
719
720
721 var packageDataCache par.Cache
722
723
724
725
726
727
728
729
730
731
732
733
734
735 var preloadWorkerCount = runtime.GOMAXPROCS(0)
736
737
738
739
740
741
742
743
744
745
746 type preload struct {
747 cancel chan struct{}
748 sema chan struct{}
749 }
750
751
752
753 func newPreload() *preload {
754 pre := &preload{
755 cancel: make(chan struct{}),
756 sema: make(chan struct{}, preloadWorkerCount),
757 }
758 return pre
759 }
760
761
762
763
764 func (pre *preload) preloadMatches(matches []*search.Match) {
765 for _, m := range matches {
766 for _, pkg := range m.Pkgs {
767 select {
768 case <-pre.cancel:
769 return
770 case pre.sema <- struct{}{}:
771 go func(pkg string) {
772 mode := 0
773 bp, loaded, err := loadPackageData(pkg, "", base.Cwd, "", false, mode)
774 <-pre.sema
775 if bp != nil && loaded && err == nil && !IgnoreImports {
776 pre.preloadImports(bp.Imports, bp)
777 }
778 }(pkg)
779 }
780 }
781 }
782 }
783
784
785
786
787 func (pre *preload) preloadImports(imports []string, parent *build.Package) {
788 parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath)
789 for _, path := range imports {
790 if path == "C" || path == "unsafe" {
791 continue
792 }
793 select {
794 case <-pre.cancel:
795 return
796 case pre.sema <- struct{}{}:
797 go func(path string) {
798 bp, loaded, err := loadPackageData(path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport)
799 <-pre.sema
800 if bp != nil && loaded && err == nil && !IgnoreImports {
801 pre.preloadImports(bp.Imports, bp)
802 }
803 }(path)
804 }
805 }
806 }
807
808
809
810
811 func (pre *preload) flush() {
812 close(pre.cancel)
813 for i := 0; i < preloadWorkerCount; i++ {
814 pre.sema <- struct{}{}
815 }
816 }
817
818 func cleanImport(path string) string {
819 orig := path
820 path = pathpkg.Clean(path)
821 if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
822 path = "./" + path
823 }
824 return path
825 }
826
827 var isDirCache par.Cache
828
829 func isDir(path string) bool {
830 return isDirCache.Do(path, func() interface{} {
831 fi, err := os.Stat(path)
832 return err == nil && fi.IsDir()
833 }).(bool)
834 }
835
836
837
838
839
840
841 func ResolveImportPath(parent *Package, path string) (found string) {
842 var parentPath, parentDir, parentRoot string
843 parentIsStd := false
844 if parent != nil {
845 parentPath = parent.ImportPath
846 parentDir = parent.Dir
847 parentRoot = parent.Root
848 parentIsStd = parent.Standard
849 }
850 return resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
851 }
852
853 func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
854 if cfg.ModulesEnabled {
855 if _, p, e := ModLookup(parentPath, parentIsStd, path); e == nil {
856 return p
857 }
858 return path
859 }
860 found = vendoredImportPath(path, parentPath, parentDir, parentRoot)
861 if found != path {
862 return found
863 }
864 return moduleImportPath(path, parentPath, parentDir, parentRoot)
865 }
866
867
868
869 func dirAndRoot(path string, dir, root string) (string, string) {
870 origDir, origRoot := dir, root
871 dir = filepath.Clean(dir)
872 root = filepath.Join(root, "src")
873 if !str.HasFilePathPrefix(dir, root) || path != "command-line-arguments" && filepath.Join(root, path) != dir {
874
875 dir = expandPath(dir)
876 root = expandPath(root)
877 }
878
879 if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || path != "command-line-arguments" && !build.IsLocalImport(path) && filepath.Join(root, path) != dir {
880 base.Fatalf("unexpected directory layout:\n"+
881 " import path: %s\n"+
882 " root: %s\n"+
883 " dir: %s\n"+
884 " expand root: %s\n"+
885 " expand dir: %s\n"+
886 " separator: %s",
887 path,
888 filepath.Join(origRoot, "src"),
889 filepath.Clean(origDir),
890 origRoot,
891 origDir,
892 string(filepath.Separator))
893 }
894
895 return dir, root
896 }
897
898
899
900
901
902 func vendoredImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
903 if parentRoot == "" {
904 return path
905 }
906
907 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
908
909 vpath := "vendor/" + path
910 for i := len(dir); i >= len(root); i-- {
911 if i < len(dir) && dir[i] != filepath.Separator {
912 continue
913 }
914
915
916
917
918 if !isDir(filepath.Join(dir[:i], "vendor")) {
919 continue
920 }
921 targ := filepath.Join(dir[:i], vpath)
922 if isDir(targ) && hasGoFiles(targ) {
923 importPath := parentPath
924 if importPath == "command-line-arguments" {
925
926
927 importPath = dir[len(root)+1:]
928 }
929
930
931
932
933
934
935
936
937 chopped := len(dir) - i
938 if chopped == len(importPath)+1 {
939
940
941
942
943 return vpath
944 }
945 return importPath[:len(importPath)-chopped] + "/" + vpath
946 }
947 }
948 return path
949 }
950
951 var (
952 modulePrefix = []byte("\nmodule ")
953 goModPathCache par.Cache
954 )
955
956
957 func goModPath(dir string) (path string) {
958 return goModPathCache.Do(dir, func() interface{} {
959 data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
960 if err != nil {
961 return ""
962 }
963 var i int
964 if bytes.HasPrefix(data, modulePrefix[1:]) {
965 i = 0
966 } else {
967 i = bytes.Index(data, modulePrefix)
968 if i < 0 {
969 return ""
970 }
971 i++
972 }
973 line := data[i:]
974
975
976 if j := bytes.IndexByte(line, '\n'); j >= 0 {
977 line = line[:j]
978 }
979 if line[len(line)-1] == '\r' {
980 line = line[:len(line)-1]
981 }
982 line = line[len("module "):]
983
984
985 path = strings.TrimSpace(string(line))
986 if path != "" && path[0] == '"' {
987 s, err := strconv.Unquote(path)
988 if err != nil {
989 return ""
990 }
991 path = s
992 }
993 return path
994 }).(string)
995 }
996
997
998
999 func findVersionElement(path string) (i, j int) {
1000 j = len(path)
1001 for i = len(path) - 1; i >= 0; i-- {
1002 if path[i] == '/' {
1003 if isVersionElement(path[i+1 : j]) {
1004 return i, j
1005 }
1006 j = i
1007 }
1008 }
1009 return -1, -1
1010 }
1011
1012
1013
1014 func isVersionElement(s string) bool {
1015 if len(s) < 2 || s[0] != 'v' || s[1] == '0' || s[1] == '1' && len(s) == 2 {
1016 return false
1017 }
1018 for i := 1; i < len(s); i++ {
1019 if s[i] < '0' || '9' < s[i] {
1020 return false
1021 }
1022 }
1023 return true
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034 func moduleImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
1035 if parentRoot == "" {
1036 return path
1037 }
1038
1039
1040
1041
1042
1043 if i, _ := findVersionElement(path); i < 0 {
1044 return path
1045 }
1046
1047 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
1048
1049
1050 for i := len(dir); i >= len(root); i-- {
1051 if i < len(dir) && dir[i] != filepath.Separator {
1052 continue
1053 }
1054 if goModPath(dir[:i]) != "" {
1055 goto HaveGoMod
1056 }
1057 }
1058
1059
1060 return path
1061
1062 HaveGoMod:
1063
1064
1065
1066
1067
1068 if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
1069 return path
1070 }
1071
1072
1073
1074
1075
1076
1077 limit := len(path)
1078 for limit > 0 {
1079 i, j := findVersionElement(path[:limit])
1080 if i < 0 {
1081 return path
1082 }
1083 if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
1084 if mpath := goModPath(bp.Dir); mpath != "" {
1085
1086
1087
1088 if mpath == path[:j] {
1089 return path[:i] + path[j:]
1090 }
1091
1092
1093
1094
1095 return path
1096 }
1097 }
1098 limit = i
1099 }
1100 return path
1101 }
1102
1103
1104
1105
1106
1107 func hasGoFiles(dir string) bool {
1108 fis, _ := ioutil.ReadDir(dir)
1109 for _, fi := range fis {
1110 if !fi.IsDir() && strings.HasSuffix(fi.Name(), ".go") {
1111 return true
1112 }
1113 }
1114 return false
1115 }
1116
1117
1118
1119
1120 func reusePackage(p *Package, stk *ImportStack) *Package {
1121
1122
1123
1124 if p.Internal.Imports == nil {
1125 if p.Error == nil {
1126 p.Error = &PackageError{
1127 ImportStack: stk.Copy(),
1128 Err: "import cycle not allowed",
1129 IsImportCycle: true,
1130 }
1131 }
1132 p.Incomplete = true
1133 }
1134
1135
1136 if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
1137 p.Error.ImportStack = stk.Copy()
1138 }
1139 return p
1140 }
1141
1142
1143
1144
1145
1146 func disallowInternal(srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *Package {
1147
1148
1149
1150
1151
1152
1153 if p.Error != nil {
1154 return p
1155 }
1156
1157
1158
1159
1160
1161 if strings.HasPrefix(p.ImportPath, "testing/internal") && len(*stk) >= 2 && (*stk)[len(*stk)-2] == "testmain" {
1162 return p
1163 }
1164
1165
1166 if cfg.BuildContext.Compiler == "gccgo" && p.Standard {
1167 return p
1168 }
1169
1170
1171
1172
1173 if p.Standard && strings.HasPrefix(importerPath, "bootstrap/") {
1174 return p
1175 }
1176
1177
1178
1179
1180
1181 if len(*stk) == 1 {
1182 return p
1183 }
1184
1185
1186 i, ok := findInternal(p.ImportPath)
1187 if !ok {
1188 return p
1189 }
1190
1191
1192
1193 if i > 0 {
1194 i--
1195 }
1196
1197 if p.Module == nil {
1198 parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
1199
1200 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1201 return p
1202 }
1203
1204
1205 srcDir = expandPath(srcDir)
1206 parent = expandPath(parent)
1207 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1208 return p
1209 }
1210 } else {
1211
1212
1213 if importer.Internal.CmdlineFiles {
1214
1215
1216
1217
1218
1219 importerPath = ModDirImportPath(importer.Dir)
1220 }
1221 parentOfInternal := p.ImportPath[:i]
1222 if str.HasPathPrefix(importerPath, parentOfInternal) {
1223 return p
1224 }
1225 }
1226
1227
1228 perr := *p
1229 perr.Error = &PackageError{
1230 ImportStack: stk.Copy(),
1231 Err: "use of internal package " + p.ImportPath + " not allowed",
1232 }
1233 perr.Incomplete = true
1234 return &perr
1235 }
1236
1237
1238
1239
1240 func findInternal(path string) (index int, ok bool) {
1241
1242
1243
1244
1245 switch {
1246 case strings.HasSuffix(path, "/internal"):
1247 return len(path) - len("internal"), true
1248 case strings.Contains(path, "/internal/"):
1249 return strings.LastIndex(path, "/internal/") + 1, true
1250 case path == "internal", strings.HasPrefix(path, "internal/"):
1251 return 0, true
1252 }
1253 return 0, false
1254 }
1255
1256
1257
1258
1259
1260 func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package {
1261
1262
1263
1264
1265 if len(*stk) == 1 {
1266 return p
1267 }
1268
1269 if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
1270 return perr
1271 }
1272
1273
1274 if i, ok := FindVendor(path); ok {
1275 perr := *p
1276 perr.Error = &PackageError{
1277 ImportStack: stk.Copy(),
1278 Err: "must be imported as " + path[i+len("vendor/"):],
1279 }
1280 perr.Incomplete = true
1281 return &perr
1282 }
1283
1284 return p
1285 }
1286
1287
1288
1289
1290
1291
1292 func disallowVendorVisibility(srcDir string, p *Package, stk *ImportStack) *Package {
1293
1294
1295
1296
1297 if len(*stk) == 1 {
1298 return p
1299 }
1300
1301
1302 i, ok := FindVendor(p.ImportPath)
1303 if !ok {
1304 return p
1305 }
1306
1307
1308
1309 if i > 0 {
1310 i--
1311 }
1312 truncateTo := i + len(p.Dir) - len(p.ImportPath)
1313 if truncateTo < 0 || len(p.Dir) < truncateTo {
1314 return p
1315 }
1316 parent := p.Dir[:truncateTo]
1317 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1318 return p
1319 }
1320
1321
1322 srcDir = expandPath(srcDir)
1323 parent = expandPath(parent)
1324 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1325 return p
1326 }
1327
1328
1329 perr := *p
1330 perr.Error = &PackageError{
1331 ImportStack: stk.Copy(),
1332 Err: "use of vendored package not allowed",
1333 }
1334 perr.Incomplete = true
1335 return &perr
1336 }
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346 func FindVendor(path string) (index int, ok bool) {
1347
1348
1349
1350 switch {
1351 case strings.Contains(path, "/vendor/"):
1352 return strings.LastIndex(path, "/vendor/") + 1, true
1353 case strings.HasPrefix(path, "vendor/"):
1354 return 0, true
1355 }
1356 return 0, false
1357 }
1358
1359 type TargetDir int
1360
1361 const (
1362 ToTool TargetDir = iota
1363 ToBin
1364 StalePath
1365 )
1366
1367
1368 func InstallTargetDir(p *Package) TargetDir {
1369 if strings.HasPrefix(p.ImportPath, "code.google.com/p/go.tools/cmd/") {
1370 return StalePath
1371 }
1372 if p.Goroot && strings.HasPrefix(p.ImportPath, "cmd/") && p.Name == "main" {
1373 switch p.ImportPath {
1374 case "cmd/go", "cmd/gofmt":
1375 return ToBin
1376 }
1377 return ToTool
1378 }
1379 return ToBin
1380 }
1381
1382 var cgoExclude = map[string]bool{
1383 "runtime/cgo": true,
1384 }
1385
1386 var cgoSyscallExclude = map[string]bool{
1387 "runtime/cgo": true,
1388 "runtime/race": true,
1389 "runtime/msan": true,
1390 }
1391
1392 var foldPath = make(map[string]string)
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402 func DefaultExecName(importPath string) string {
1403 _, elem := pathpkg.Split(importPath)
1404 if cfg.ModulesEnabled {
1405
1406
1407 if elem != importPath && isVersionElement(elem) {
1408 _, elem = pathpkg.Split(pathpkg.Dir(importPath))
1409 }
1410 }
1411 return elem
1412 }
1413
1414
1415
1416 func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
1417 p.copyBuild(bp)
1418
1419
1420
1421 if p.Internal.Local {
1422 p.Internal.LocalPrefix = dirToImportPath(p.Dir)
1423 }
1424
1425 if err != nil {
1426 if _, ok := err.(*build.NoGoError); ok {
1427 err = &NoGoError{Package: p}
1428 }
1429 p.Incomplete = true
1430 err = base.ExpandScanner(err)
1431 p.Error = &PackageError{
1432 ImportStack: stk.Copy(),
1433 Err: err.Error(),
1434 }
1435 return
1436 }
1437
1438 useBindir := p.Name == "main"
1439 if !p.Standard {
1440 switch cfg.BuildBuildmode {
1441 case "c-archive", "c-shared", "plugin":
1442 useBindir = false
1443 }
1444 }
1445
1446 if useBindir {
1447
1448 if InstallTargetDir(p) == StalePath {
1449 newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
1450 e := fmt.Sprintf("the %v command has moved; use %v instead.", p.ImportPath, newPath)
1451 p.Error = &PackageError{Err: e}
1452 return
1453 }
1454 elem := DefaultExecName(p.ImportPath)
1455 full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
1456 if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
1457
1458 elem = full
1459 }
1460 if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
1461 p.Internal.Build.BinDir = ModBinDir()
1462 }
1463 if p.Internal.Build.BinDir != "" {
1464
1465 p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
1466 if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
1467
1468 p.Target = ""
1469 p.Internal.GobinSubdir = true
1470 }
1471 }
1472 if InstallTargetDir(p) == ToTool {
1473
1474
1475 if cfg.BuildToolchainName == "gccgo" {
1476 p.Target = filepath.Join(base.ToolDir, elem)
1477 } else {
1478 p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
1479 }
1480 }
1481 if p.Target != "" && cfg.BuildContext.GOOS == "windows" {
1482 p.Target += ".exe"
1483 }
1484 } else if p.Internal.Local {
1485
1486
1487 p.Target = ""
1488 } else {
1489 p.Target = p.Internal.Build.PkgObj
1490 if cfg.BuildLinkshared {
1491 shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
1492 shlib, err := ioutil.ReadFile(shlibnamefile)
1493 if err != nil && !os.IsNotExist(err) {
1494 base.Fatalf("reading shlibname: %v", err)
1495 }
1496 if err == nil {
1497 libname := strings.TrimSpace(string(shlib))
1498 if cfg.BuildContext.Compiler == "gccgo" {
1499 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
1500 } else {
1501 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
1502 }
1503 }
1504 }
1505 }
1506
1507
1508
1509 importPaths := p.Imports
1510 addImport := func(path string, forCompiler bool) {
1511 for _, p := range importPaths {
1512 if path == p {
1513 return
1514 }
1515 }
1516 importPaths = append(importPaths, path)
1517 if forCompiler {
1518 p.Internal.CompiledImports = append(p.Internal.CompiledImports, path)
1519 }
1520 }
1521
1522
1523
1524 if p.UsesCgo() {
1525 addImport("unsafe", true)
1526 }
1527 if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
1528 addImport("runtime/cgo", true)
1529 }
1530 if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
1531 addImport("syscall", true)
1532 }
1533
1534
1535 if p.UsesSwig() {
1536 addImport("unsafe", true)
1537 if cfg.BuildContext.Compiler != "gccgo" {
1538 addImport("runtime/cgo", true)
1539 }
1540 addImport("syscall", true)
1541 addImport("sync", true)
1542
1543
1544
1545 }
1546
1547
1548 if p.Name == "main" && !p.Internal.ForceLibrary {
1549 for _, dep := range LinkerDeps(p) {
1550 addImport(dep, false)
1551 }
1552 }
1553
1554
1555
1556
1557
1558 inputs := p.AllFiles()
1559 f1, f2 := str.FoldDup(inputs)
1560 if f1 != "" {
1561 p.Error = &PackageError{
1562 ImportStack: stk.Copy(),
1563 Err: fmt.Sprintf("case-insensitive file name collision: %q and %q", f1, f2),
1564 }
1565 return
1566 }
1567
1568
1569
1570
1571
1572
1573
1574
1575 for _, file := range inputs {
1576 if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
1577 p.Error = &PackageError{
1578 ImportStack: stk.Copy(),
1579 Err: fmt.Sprintf("invalid input file name %q", file),
1580 }
1581 return
1582 }
1583 }
1584 if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
1585 p.Error = &PackageError{
1586 ImportStack: stk.Copy(),
1587 Err: fmt.Sprintf("invalid input directory name %q", name),
1588 }
1589 return
1590 }
1591 if !SafeArg(p.ImportPath) {
1592 p.Error = &PackageError{
1593 ImportStack: stk.Copy(),
1594 Err: fmt.Sprintf("invalid import path %q", p.ImportPath),
1595 }
1596 return
1597 }
1598
1599
1600 imports := make([]*Package, 0, len(p.Imports))
1601 for i, path := range importPaths {
1602 if path == "C" {
1603 continue
1604 }
1605 p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
1606
1607 path = p1.ImportPath
1608 importPaths[i] = path
1609 if i < len(p.Imports) {
1610 p.Imports[i] = path
1611 }
1612
1613 imports = append(imports, p1)
1614 if p1.Incomplete {
1615 p.Incomplete = true
1616 }
1617 }
1618 p.Internal.Imports = imports
1619 p.collectDeps()
1620
1621
1622 if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
1623 p.Target = ""
1624 }
1625
1626
1627
1628 if !cfg.BuildContext.CgoEnabled {
1629 p.CFiles = nil
1630 p.CXXFiles = nil
1631 p.MFiles = nil
1632 p.SwigFiles = nil
1633 p.SwigCXXFiles = nil
1634
1635
1636
1637
1638 }
1639
1640 setError := func(msg string) {
1641 p.Error = &PackageError{
1642 ImportStack: stk.Copy(),
1643 Err: msg,
1644 }
1645 }
1646
1647
1648 if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
1649 setError(fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
1650 return
1651 }
1652
1653
1654
1655 if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1656 setError(fmt.Sprintf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " ")))
1657 return
1658 }
1659 if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1660 setError(fmt.Sprintf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " ")))
1661 return
1662 }
1663 if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1664 setError(fmt.Sprintf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " ")))
1665 return
1666 }
1667
1668
1669 fold := str.ToFold(p.ImportPath)
1670 if other := foldPath[fold]; other == "" {
1671 foldPath[fold] = p.ImportPath
1672 } else if other != p.ImportPath {
1673 setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other))
1674 return
1675 }
1676
1677 if cfg.ModulesEnabled {
1678 mainPath := p.ImportPath
1679 if p.Internal.CmdlineFiles {
1680 mainPath = "command-line-arguments"
1681 }
1682 p.Module = ModPackageModuleInfo(mainPath)
1683 if p.Name == "main" {
1684 p.Internal.BuildInfo = ModPackageBuildInfo(mainPath, p.Deps)
1685 }
1686 }
1687 }
1688
1689
1690
1691
1692
1693
1694 func (p *Package) collectDeps() {
1695 deps := make(map[string]*Package)
1696 var q []*Package
1697 q = append(q, p.Internal.Imports...)
1698 for i := 0; i < len(q); i++ {
1699 p1 := q[i]
1700 path := p1.ImportPath
1701
1702
1703
1704 p0 := deps[path]
1705 if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
1706 deps[path] = p1
1707 for _, p2 := range p1.Internal.Imports {
1708 if deps[p2.ImportPath] != p2 {
1709 q = append(q, p2)
1710 }
1711 }
1712 }
1713 }
1714
1715 p.Deps = make([]string, 0, len(deps))
1716 for dep := range deps {
1717 p.Deps = append(p.Deps, dep)
1718 }
1719 sort.Strings(p.Deps)
1720 for _, dep := range p.Deps {
1721 p1 := deps[dep]
1722 if p1 == nil {
1723 panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
1724 }
1725 if p1.Error != nil {
1726 p.DepsErrors = append(p.DepsErrors, p1.Error)
1727 }
1728 }
1729 }
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740 func SafeArg(name string) bool {
1741 if name == "" {
1742 return false
1743 }
1744 c := name[0]
1745 return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
1746 }
1747
1748
1749 func LinkerDeps(p *Package) []string {
1750
1751 deps := []string{"runtime"}
1752
1753
1754 if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" {
1755 deps = append(deps, "runtime/cgo")
1756 }
1757
1758 if cfg.Goarch == "arm" {
1759 deps = append(deps, "math")
1760 }
1761
1762 if cfg.BuildRace {
1763 deps = append(deps, "runtime/race")
1764 }
1765
1766 if cfg.BuildMSan {
1767 deps = append(deps, "runtime/msan")
1768 }
1769
1770 return deps
1771 }
1772
1773
1774
1775 func externalLinkingForced(p *Package) bool {
1776
1777 switch cfg.BuildContext.GOOS {
1778 case "android":
1779 return true
1780 case "darwin":
1781 switch cfg.BuildContext.GOARCH {
1782 case "arm", "arm64":
1783 return true
1784 }
1785 }
1786
1787 if !cfg.BuildContext.CgoEnabled {
1788 return false
1789 }
1790
1791
1792
1793
1794
1795
1796 pieCgo := cfg.BuildBuildmode == "pie"
1797 linkmodeExternal := false
1798 if p != nil {
1799 ldflags := BuildLdflags.For(p)
1800 for i, a := range ldflags {
1801 if a == "-linkmode=external" {
1802 linkmodeExternal = true
1803 }
1804 if a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
1805 linkmodeExternal = true
1806 }
1807 }
1808 }
1809
1810 return cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal
1811 }
1812
1813
1814
1815
1816 func (p *Package) mkAbs(list []string) []string {
1817 for i, f := range list {
1818 list[i] = filepath.Join(p.Dir, f)
1819 }
1820 sort.Strings(list)
1821 return list
1822 }
1823
1824
1825
1826 func (p *Package) InternalGoFiles() []string {
1827 return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles))
1828 }
1829
1830
1831
1832 func (p *Package) InternalXGoFiles() []string {
1833 return p.mkAbs(p.XTestGoFiles)
1834 }
1835
1836
1837
1838
1839 func (p *Package) InternalAllGoFiles() []string {
1840 var extra []string
1841 for _, f := range p.IgnoredGoFiles {
1842 if f != "" && f[0] != '.' || f[0] != '_' {
1843 extra = append(extra, f)
1844 }
1845 }
1846 return p.mkAbs(str.StringList(extra, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
1847 }
1848
1849
1850 func (p *Package) UsesSwig() bool {
1851 return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
1852 }
1853
1854
1855 func (p *Package) UsesCgo() bool {
1856 return len(p.CgoFiles) > 0
1857 }
1858
1859
1860
1861 func PackageList(roots []*Package) []*Package {
1862 seen := map[*Package]bool{}
1863 all := []*Package{}
1864 var walk func(*Package)
1865 walk = func(p *Package) {
1866 if seen[p] {
1867 return
1868 }
1869 seen[p] = true
1870 for _, p1 := range p.Internal.Imports {
1871 walk(p1)
1872 }
1873 all = append(all, p)
1874 }
1875 for _, root := range roots {
1876 walk(root)
1877 }
1878 return all
1879 }
1880
1881
1882
1883
1884 func TestPackageList(roots []*Package) []*Package {
1885 seen := map[*Package]bool{}
1886 all := []*Package{}
1887 var walk func(*Package)
1888 walk = func(p *Package) {
1889 if seen[p] {
1890 return
1891 }
1892 seen[p] = true
1893 for _, p1 := range p.Internal.Imports {
1894 walk(p1)
1895 }
1896 all = append(all, p)
1897 }
1898 walkTest := func(root *Package, path string) {
1899 var stk ImportStack
1900 p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
1901 if p1.Error == nil {
1902 walk(p1)
1903 }
1904 }
1905 for _, root := range roots {
1906 walk(root)
1907 for _, path := range root.TestImports {
1908 walkTest(root, path)
1909 }
1910 for _, path := range root.XTestImports {
1911 walkTest(root, path)
1912 }
1913 }
1914 return all
1915 }
1916
1917
1918
1919
1920
1921
1922 func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
1923 p := LoadImport(path, srcDir, parent, stk, importPos, mode)
1924 setToolFlags(p)
1925 return p
1926 }
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936 func Packages(args []string) []*Package {
1937 var pkgs []*Package
1938 for _, pkg := range PackagesAndErrors(args) {
1939 if pkg.Error != nil {
1940 base.Errorf("can't load package: %s", pkg.Error)
1941 continue
1942 }
1943 pkgs = append(pkgs, pkg)
1944 }
1945 return pkgs
1946 }
1947
1948
1949
1950
1951
1952 func PackagesAndErrors(patterns []string) []*Package {
1953 for _, p := range patterns {
1954
1955
1956
1957 if strings.HasSuffix(p, ".go") {
1958
1959
1960 if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
1961 return []*Package{GoFilesPackage(patterns)}
1962 }
1963 }
1964 }
1965
1966 matches := ImportPaths(patterns)
1967 var (
1968 pkgs []*Package
1969 stk ImportStack
1970 seenPkg = make(map[*Package]bool)
1971 )
1972
1973 pre := newPreload()
1974 defer pre.flush()
1975 pre.preloadMatches(matches)
1976
1977 for _, m := range matches {
1978 for _, pkg := range m.Pkgs {
1979 if pkg == "" {
1980 panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern))
1981 }
1982 p := loadImport(pre, pkg, base.Cwd, nil, &stk, nil, 0)
1983 p.Match = append(p.Match, m.Pattern)
1984 p.Internal.CmdlinePkg = true
1985 if m.Literal {
1986
1987
1988
1989 p.Internal.CmdlinePkgLiteral = true
1990 }
1991 if seenPkg[p] {
1992 continue
1993 }
1994 seenPkg[p] = true
1995 pkgs = append(pkgs, p)
1996 }
1997 }
1998
1999
2000
2001
2002
2003 setToolFlags(pkgs...)
2004
2005 return pkgs
2006 }
2007
2008 func setToolFlags(pkgs ...*Package) {
2009 for _, p := range PackageList(pkgs) {
2010 p.Internal.Asmflags = BuildAsmflags.For(p)
2011 p.Internal.Gcflags = BuildGcflags.For(p)
2012 p.Internal.Ldflags = BuildLdflags.For(p)
2013 p.Internal.Gccgoflags = BuildGccgoflags.For(p)
2014 }
2015 }
2016
2017 func ImportPaths(args []string) []*search.Match {
2018 if ModInit(); cfg.ModulesEnabled {
2019 return ModImportPaths(args)
2020 }
2021 return search.ImportPaths(args)
2022 }
2023
2024
2025
2026
2027 func PackagesForBuild(args []string) []*Package {
2028 pkgs := PackagesAndErrors(args)
2029 printed := map[*PackageError]bool{}
2030 for _, pkg := range pkgs {
2031 if pkg.Error != nil {
2032 base.Errorf("can't load package: %s", pkg.Error)
2033 printed[pkg.Error] = true
2034 }
2035 for _, err := range pkg.DepsErrors {
2036
2037
2038
2039
2040 if !printed[err] {
2041 printed[err] = true
2042 base.Errorf("%s", err)
2043 }
2044 }
2045 }
2046 base.ExitIfErrors()
2047
2048
2049
2050
2051
2052
2053 seen := map[string]bool{}
2054 reported := map[string]bool{}
2055 for _, pkg := range PackageList(pkgs) {
2056 if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
2057 reported[pkg.ImportPath] = true
2058 base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
2059 }
2060 seen[pkg.ImportPath] = true
2061 }
2062 base.ExitIfErrors()
2063
2064 return pkgs
2065 }
2066
2067
2068
2069
2070 func GoFilesPackage(gofiles []string) *Package {
2071 ModInit()
2072
2073 for _, f := range gofiles {
2074 if !strings.HasSuffix(f, ".go") {
2075 pkg := new(Package)
2076 pkg.Internal.Local = true
2077 pkg.Internal.CmdlineFiles = true
2078 pkg.Name = f
2079 pkg.Error = &PackageError{
2080 Err: fmt.Sprintf("named files must be .go files: %s", pkg.Name),
2081 }
2082 return pkg
2083 }
2084 }
2085
2086 var stk ImportStack
2087 ctxt := cfg.BuildContext
2088 ctxt.UseAllFiles = true
2089
2090
2091
2092
2093
2094 var dirent []os.FileInfo
2095 var dir string
2096 for _, file := range gofiles {
2097 fi, err := os.Stat(file)
2098 if err != nil {
2099 base.Fatalf("%s", err)
2100 }
2101 if fi.IsDir() {
2102 base.Fatalf("%s is a directory, should be a Go file", file)
2103 }
2104 dir1, _ := filepath.Split(file)
2105 if dir1 == "" {
2106 dir1 = "./"
2107 }
2108 if dir == "" {
2109 dir = dir1
2110 } else if dir != dir1 {
2111 base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
2112 }
2113 dirent = append(dirent, fi)
2114 }
2115 ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
2116
2117 if cfg.ModulesEnabled {
2118 ModImportFromFiles(gofiles)
2119 }
2120
2121 var err error
2122 if dir == "" {
2123 dir = base.Cwd
2124 }
2125 dir, err = filepath.Abs(dir)
2126 if err != nil {
2127 base.Fatalf("%s", err)
2128 }
2129
2130 bp, err := ctxt.ImportDir(dir, 0)
2131 pkg := new(Package)
2132 pkg.Internal.Local = true
2133 pkg.Internal.CmdlineFiles = true
2134 stk.Push("main")
2135 pkg.load(&stk, bp, err)
2136 stk.Pop()
2137 pkg.Internal.LocalPrefix = dirToImportPath(dir)
2138 pkg.ImportPath = "command-line-arguments"
2139 pkg.Target = ""
2140 pkg.Match = gofiles
2141
2142 if pkg.Name == "main" {
2143 _, elem := filepath.Split(gofiles[0])
2144 exe := elem[:len(elem)-len(".go")] + cfg.ExeSuffix
2145 if cfg.BuildO == "" {
2146 cfg.BuildO = exe
2147 }
2148 if cfg.GOBIN != "" {
2149 pkg.Target = filepath.Join(cfg.GOBIN, exe)
2150 } else if cfg.ModulesEnabled {
2151 pkg.Target = filepath.Join(ModBinDir(), exe)
2152 }
2153 }
2154
2155 setToolFlags(pkg)
2156
2157 return pkg
2158 }
2159
View as plain text