1
2
3
4
5
6 package load
7
8 import (
9 "bytes"
10 "context"
11 "crypto/sha256"
12 "encoding/json"
13 "errors"
14 "fmt"
15 "go/build"
16 "go/scanner"
17 "go/token"
18 "internal/platform"
19 "io/fs"
20 "os"
21 pathpkg "path"
22 "path/filepath"
23 "runtime"
24 "runtime/debug"
25 "slices"
26 "sort"
27 "strconv"
28 "strings"
29 "time"
30 "unicode"
31 "unicode/utf8"
32
33 "cmd/go/internal/base"
34 "cmd/go/internal/cfg"
35 "cmd/go/internal/fips140"
36 "cmd/go/internal/fsys"
37 "cmd/go/internal/gover"
38 "cmd/go/internal/imports"
39 "cmd/go/internal/modfetch"
40 "cmd/go/internal/modindex"
41 "cmd/go/internal/modinfo"
42 "cmd/go/internal/modload"
43 "cmd/go/internal/search"
44 "cmd/go/internal/str"
45 "cmd/go/internal/trace"
46 "cmd/go/internal/vcs"
47 "cmd/internal/par"
48 "cmd/internal/pathcache"
49 "cmd/internal/pkgpattern"
50
51 "golang.org/x/mod/modfile"
52 "golang.org/x/mod/module"
53 )
54
55
56 type Package struct {
57 PackagePublic
58 Internal PackageInternal
59 }
60
61 type PackagePublic struct {
62
63
64
65 Dir string `json:",omitempty"`
66 ImportPath string `json:",omitempty"`
67 ImportComment string `json:",omitempty"`
68 Name string `json:",omitempty"`
69 Doc string `json:",omitempty"`
70 Target string `json:",omitempty"`
71 Shlib string `json:",omitempty"`
72 Root string `json:",omitempty"`
73 ConflictDir string `json:",omitempty"`
74 ForTest string `json:",omitempty"`
75 Export string `json:",omitempty"`
76 BuildID string `json:",omitempty"`
77 Module *modinfo.ModulePublic `json:",omitempty"`
78 Match []string `json:",omitempty"`
79 Goroot bool `json:",omitempty"`
80 Standard bool `json:",omitempty"`
81 DepOnly bool `json:",omitempty"`
82 BinaryOnly bool `json:",omitempty"`
83 Incomplete bool `json:",omitempty"`
84
85 DefaultGODEBUG string `json:",omitempty"`
86
87
88
89
90 Stale bool `json:",omitempty"`
91 StaleReason string `json:",omitempty"`
92
93
94
95
96 GoFiles []string `json:",omitempty"`
97 CgoFiles []string `json:",omitempty"`
98 CompiledGoFiles []string `json:",omitempty"`
99 IgnoredGoFiles []string `json:",omitempty"`
100 InvalidGoFiles []string `json:",omitempty"`
101 IgnoredOtherFiles []string `json:",omitempty"`
102 CFiles []string `json:",omitempty"`
103 CXXFiles []string `json:",omitempty"`
104 MFiles []string `json:",omitempty"`
105 HFiles []string `json:",omitempty"`
106 FFiles []string `json:",omitempty"`
107 SFiles []string `json:",omitempty"`
108 SwigFiles []string `json:",omitempty"`
109 SwigCXXFiles []string `json:",omitempty"`
110 SysoFiles []string `json:",omitempty"`
111
112
113 EmbedPatterns []string `json:",omitempty"`
114 EmbedFiles []string `json:",omitempty"`
115
116
117 CgoCFLAGS []string `json:",omitempty"`
118 CgoCPPFLAGS []string `json:",omitempty"`
119 CgoCXXFLAGS []string `json:",omitempty"`
120 CgoFFLAGS []string `json:",omitempty"`
121 CgoLDFLAGS []string `json:",omitempty"`
122 CgoPkgConfig []string `json:",omitempty"`
123
124
125 Imports []string `json:",omitempty"`
126 ImportMap map[string]string `json:",omitempty"`
127 Deps []string `json:",omitempty"`
128
129
130
131 Error *PackageError `json:",omitempty"`
132 DepsErrors []*PackageError `json:",omitempty"`
133
134
135
136
137 TestGoFiles []string `json:",omitempty"`
138 TestImports []string `json:",omitempty"`
139 TestEmbedPatterns []string `json:",omitempty"`
140 TestEmbedFiles []string `json:",omitempty"`
141 XTestGoFiles []string `json:",omitempty"`
142 XTestImports []string `json:",omitempty"`
143 XTestEmbedPatterns []string `json:",omitempty"`
144 XTestEmbedFiles []string `json:",omitempty"`
145 }
146
147
148
149
150
151
152 func (p *Package) AllFiles() []string {
153 files := str.StringList(
154 p.GoFiles,
155 p.CgoFiles,
156
157 p.IgnoredGoFiles,
158
159 p.IgnoredOtherFiles,
160 p.CFiles,
161 p.CXXFiles,
162 p.MFiles,
163 p.HFiles,
164 p.FFiles,
165 p.SFiles,
166 p.SwigFiles,
167 p.SwigCXXFiles,
168 p.SysoFiles,
169 p.TestGoFiles,
170 p.XTestGoFiles,
171 )
172
173
174
175
176
177 var have map[string]bool
178 for _, file := range p.EmbedFiles {
179 if !strings.Contains(file, "/") {
180 if have == nil {
181 have = make(map[string]bool)
182 for _, file := range files {
183 have[file] = true
184 }
185 }
186 if have[file] {
187 continue
188 }
189 }
190 files = append(files, file)
191 }
192 return files
193 }
194
195
196 func (p *Package) Desc() string {
197 if p.ForTest != "" {
198 return p.ImportPath + " [" + p.ForTest + ".test]"
199 }
200 if p.Internal.ForMain != "" {
201 return p.ImportPath + " [" + p.Internal.ForMain + "]"
202 }
203 return p.ImportPath
204 }
205
206
207
208
209
210
211
212 func (p *Package) IsTestOnly() bool {
213 return p.ForTest != "" ||
214 p.Internal.TestmainGo != nil ||
215 len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 && len(p.GoFiles)+len(p.CgoFiles) == 0
216 }
217
218 type PackageInternal struct {
219
220 Build *build.Package
221 Imports []*Package
222 CompiledImports []string
223 RawImports []string
224 ForceLibrary bool
225 CmdlineFiles bool
226 CmdlinePkg bool
227 CmdlinePkgLiteral bool
228 Local bool
229 LocalPrefix string
230 ExeName string
231 FuzzInstrument bool
232 Cover CoverSetup
233 CoverVars map[string]*CoverVar
234 OmitDebug bool
235 GobinSubdir bool
236 BuildInfo *debug.BuildInfo
237 TestmainGo *[]byte
238 Embed map[string][]string
239 OrigImportPath string
240 PGOProfile string
241 ForMain string
242
243 Asmflags []string
244 Gcflags []string
245 Ldflags []string
246 Gccgoflags []string
247 }
248
249
250
251
252
253
254 type NoGoError struct {
255 Package *Package
256 }
257
258 func (e *NoGoError) Error() string {
259 if len(e.Package.IgnoredGoFiles) > 0 {
260
261 return "build constraints exclude all Go files in " + e.Package.Dir
262 }
263 if len(e.Package.TestGoFiles)+len(e.Package.XTestGoFiles) > 0 {
264
265
266
267 return "no non-test Go files in " + e.Package.Dir
268 }
269 return "no Go files in " + e.Package.Dir
270 }
271
272
273
274
275
276
277
278
279 func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack, importPos []token.Position) {
280 matchErr, isMatchErr := err.(*search.MatchError)
281 if isMatchErr && matchErr.Match.Pattern() == path {
282 if matchErr.Match.IsLiteral() {
283
284
285
286
287 err = matchErr.Err
288 }
289 }
290
291
292
293 var nogoErr *build.NoGoError
294 if errors.As(err, &nogoErr) {
295 if p.Dir == "" && nogoErr.Dir != "" {
296 p.Dir = nogoErr.Dir
297 }
298 err = &NoGoError{Package: p}
299 }
300
301
302
303
304 var pos string
305 var isScanErr bool
306 if scanErr, ok := err.(scanner.ErrorList); ok && len(scanErr) > 0 {
307 isScanErr = true
308
309 scanPos := scanErr[0].Pos
310 scanPos.Filename = base.ShortPath(scanPos.Filename)
311 pos = scanPos.String()
312 err = errors.New(scanErr[0].Msg)
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330 if !isMatchErr && (nogoErr != nil || isScanErr) {
331 stk.Push(ImportInfo{Pkg: path, Pos: extractFirstImport(importPos)})
332 defer stk.Pop()
333 }
334
335 p.Error = &PackageError{
336 ImportStack: stk.Copy(),
337 Pos: pos,
338 Err: err,
339 }
340 p.Incomplete = true
341
342 top, ok := stk.Top()
343 if ok && path != top.Pkg {
344 p.Error.setPos(importPos)
345 }
346 }
347
348
349
350
351
352
353
354
355
356
357
358 func (p *Package) Resolve(imports []string) []string {
359 if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
360 panic("internal error: p.Resolve(p.Imports) called")
361 }
362 seen := make(map[string]bool)
363 var all []string
364 for _, path := range imports {
365 path = ResolveImportPath(p, path)
366 if !seen[path] {
367 seen[path] = true
368 all = append(all, path)
369 }
370 }
371 sort.Strings(all)
372 return all
373 }
374
375
376 type CoverVar struct {
377 File string
378 Var string
379 }
380
381
382 type CoverSetup struct {
383 Mode string
384 Cfg string
385 GenMeta bool
386 }
387
388 func (p *Package) copyBuild(opts PackageOpts, pp *build.Package) {
389 p.Internal.Build = pp
390
391 if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
392 old := pp.PkgTargetRoot
393 pp.PkgRoot = cfg.BuildPkgdir
394 pp.PkgTargetRoot = cfg.BuildPkgdir
395 if pp.PkgObj != "" {
396 pp.PkgObj = filepath.Join(cfg.BuildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
397 }
398 }
399
400 p.Dir = pp.Dir
401 p.ImportPath = pp.ImportPath
402 p.ImportComment = pp.ImportComment
403 p.Name = pp.Name
404 p.Doc = pp.Doc
405 p.Root = pp.Root
406 p.ConflictDir = pp.ConflictDir
407 p.BinaryOnly = pp.BinaryOnly
408
409
410 p.Goroot = pp.Goroot || fips140.Snapshot() && str.HasFilePathPrefix(p.Dir, fips140.Dir())
411 p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
412 p.GoFiles = pp.GoFiles
413 p.CgoFiles = pp.CgoFiles
414 p.IgnoredGoFiles = pp.IgnoredGoFiles
415 p.InvalidGoFiles = pp.InvalidGoFiles
416 p.IgnoredOtherFiles = pp.IgnoredOtherFiles
417 p.CFiles = pp.CFiles
418 p.CXXFiles = pp.CXXFiles
419 p.MFiles = pp.MFiles
420 p.HFiles = pp.HFiles
421 p.FFiles = pp.FFiles
422 p.SFiles = pp.SFiles
423 p.SwigFiles = pp.SwigFiles
424 p.SwigCXXFiles = pp.SwigCXXFiles
425 p.SysoFiles = pp.SysoFiles
426 if cfg.BuildMSan {
427
428
429
430 p.SysoFiles = nil
431 }
432 p.CgoCFLAGS = pp.CgoCFLAGS
433 p.CgoCPPFLAGS = pp.CgoCPPFLAGS
434 p.CgoCXXFLAGS = pp.CgoCXXFLAGS
435 p.CgoFFLAGS = pp.CgoFFLAGS
436 p.CgoLDFLAGS = pp.CgoLDFLAGS
437 p.CgoPkgConfig = pp.CgoPkgConfig
438
439 p.Imports = make([]string, len(pp.Imports))
440 copy(p.Imports, pp.Imports)
441 p.Internal.RawImports = pp.Imports
442 p.TestGoFiles = pp.TestGoFiles
443 p.TestImports = pp.TestImports
444 p.XTestGoFiles = pp.XTestGoFiles
445 p.XTestImports = pp.XTestImports
446 if opts.IgnoreImports {
447 p.Imports = nil
448 p.Internal.RawImports = nil
449 p.TestImports = nil
450 p.XTestImports = nil
451 }
452 p.EmbedPatterns = pp.EmbedPatterns
453 p.TestEmbedPatterns = pp.TestEmbedPatterns
454 p.XTestEmbedPatterns = pp.XTestEmbedPatterns
455 p.Internal.OrigImportPath = pp.ImportPath
456 }
457
458
459 type PackageError struct {
460 ImportStack ImportStack
461 Pos string
462 Err error
463 IsImportCycle bool
464 alwaysPrintStack bool
465 }
466
467 func (p *PackageError) Error() string {
468
469
470
471 if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
472
473
474 return p.Pos + ": " + p.Err.Error()
475 }
476
477
478
479
480
481
482
483 if len(p.ImportStack) == 0 {
484 return p.Err.Error()
485 }
486 var optpos string
487 if p.Pos != "" {
488 optpos = "\n\t" + p.Pos
489 }
490 imports := p.ImportStack.Pkgs()
491 if p.IsImportCycle {
492 imports = p.ImportStack.PkgsWithPos()
493 }
494 return "package " + strings.Join(imports, "\n\timports ") + optpos + ": " + p.Err.Error()
495 }
496
497 func (p *PackageError) Unwrap() error { return p.Err }
498
499
500
501 func (p *PackageError) MarshalJSON() ([]byte, error) {
502 perr := struct {
503 ImportStack []string
504 Pos string
505 Err string
506 }{p.ImportStack.Pkgs(), p.Pos, p.Err.Error()}
507 return json.Marshal(perr)
508 }
509
510 func (p *PackageError) setPos(posList []token.Position) {
511 if len(posList) == 0 {
512 return
513 }
514 pos := posList[0]
515 pos.Filename = base.ShortPath(pos.Filename)
516 p.Pos = pos.String()
517 }
518
519
520
521
522
523
524
525
526
527 type ImportPathError interface {
528 error
529 ImportPath() string
530 }
531
532 var (
533 _ ImportPathError = (*importError)(nil)
534 _ ImportPathError = (*mainPackageError)(nil)
535 _ ImportPathError = (*modload.ImportMissingError)(nil)
536 _ ImportPathError = (*modload.ImportMissingSumError)(nil)
537 _ ImportPathError = (*modload.DirectImportFromImplicitDependencyError)(nil)
538 )
539
540 type importError struct {
541 importPath string
542 err error
543 }
544
545 func ImportErrorf(path, format string, args ...any) ImportPathError {
546 err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
547 if errStr := err.Error(); !strings.Contains(errStr, path) && !strings.Contains(errStr, strconv.Quote(path)) {
548 panic(fmt.Sprintf("path %q not in error %q", path, errStr))
549 }
550 return err
551 }
552
553 func (e *importError) Error() string {
554 return e.err.Error()
555 }
556
557 func (e *importError) Unwrap() error {
558
559
560 return errors.Unwrap(e.err)
561 }
562
563 func (e *importError) ImportPath() string {
564 return e.importPath
565 }
566
567 type ImportInfo struct {
568 Pkg string
569 Pos *token.Position
570 }
571
572
573
574
575 type ImportStack []ImportInfo
576
577 func NewImportInfo(pkg string, pos *token.Position) ImportInfo {
578 return ImportInfo{Pkg: pkg, Pos: pos}
579 }
580
581 func (s *ImportStack) Push(p ImportInfo) {
582 *s = append(*s, p)
583 }
584
585 func (s *ImportStack) Pop() {
586 *s = (*s)[0 : len(*s)-1]
587 }
588
589 func (s *ImportStack) Copy() ImportStack {
590 return slices.Clone(*s)
591 }
592
593 func (s *ImportStack) Pkgs() []string {
594 ss := make([]string, 0, len(*s))
595 for _, v := range *s {
596 ss = append(ss, v.Pkg)
597 }
598 return ss
599 }
600
601 func (s *ImportStack) PkgsWithPos() []string {
602 ss := make([]string, 0, len(*s))
603 for _, v := range *s {
604 if v.Pos != nil {
605 ss = append(ss, v.Pkg+" from "+filepath.Base(v.Pos.Filename))
606 } else {
607 ss = append(ss, v.Pkg)
608 }
609 }
610 return ss
611 }
612
613 func (s *ImportStack) Top() (ImportInfo, bool) {
614 if len(*s) == 0 {
615 return ImportInfo{}, false
616 }
617 return (*s)[len(*s)-1], true
618 }
619
620
621
622
623 func (sp *ImportStack) shorterThan(t []string) bool {
624 s := *sp
625 if len(s) != len(t) {
626 return len(s) < len(t)
627 }
628
629 for i := range s {
630 siPkg := s[i].Pkg
631 if siPkg != t[i] {
632 return siPkg < t[i]
633 }
634 }
635 return false
636 }
637
638
639
640
641 var packageCache = map[string]*Package{}
642
643
644
645
646
647
648
649
650 func dirToImportPath(dir string) string {
651 return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
652 }
653
654 func makeImportValid(r rune) rune {
655
656 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
657 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
658 return '_'
659 }
660 return r
661 }
662
663
664 const (
665
666
667
668
669
670
671
672
673
674 ResolveImport = 1 << iota
675
676
677
678 ResolveModule
679
680
681
682 GetTestDeps
683
684
685
686
687 cmdlinePkg
688
689
690
691 cmdlinePkgLiteral
692 )
693
694
695 func LoadPackage(ctx context.Context, opts PackageOpts, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package {
696 p, err := loadImport(ctx, opts, nil, path, srcDir, nil, stk, importPos, mode)
697 if err != nil {
698 base.Fatalf("internal error: loadImport of %q with nil parent returned an error", path)
699 }
700 return p
701 }
702
703
704
705
706
707
708
709
710
711
712 func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) {
713 ctx, span := trace.StartSpan(ctx, "modload.loadImport "+path)
714 defer span.Done()
715
716 if path == "" {
717 panic("LoadImport called with empty package path")
718 }
719
720 var parentPath, parentRoot string
721 parentIsStd := false
722 if parent != nil {
723 parentPath = parent.ImportPath
724 parentRoot = parent.Root
725 parentIsStd = parent.Standard
726 }
727 bp, loaded, err := loadPackageData(ctx, path, parentPath, srcDir, parentRoot, parentIsStd, mode)
728 if loaded && pre != nil && !opts.IgnoreImports {
729 pre.preloadImports(ctx, opts, bp.Imports, bp)
730 }
731 if bp == nil {
732 p := &Package{
733 PackagePublic: PackagePublic{
734 ImportPath: path,
735 Incomplete: true,
736 },
737 }
738 if importErr, ok := err.(ImportPathError); !ok || importErr.ImportPath() != path {
739
740
741
742
743
744
745
746 stk.Push(ImportInfo{Pkg: path, Pos: extractFirstImport(importPos)})
747 defer stk.Pop()
748 }
749 p.setLoadPackageDataError(err, path, stk, nil)
750 return p, nil
751 }
752
753 setCmdline := func(p *Package) {
754 if mode&cmdlinePkg != 0 {
755 p.Internal.CmdlinePkg = true
756 }
757 if mode&cmdlinePkgLiteral != 0 {
758 p.Internal.CmdlinePkgLiteral = true
759 }
760 }
761
762 importPath := bp.ImportPath
763 p := packageCache[importPath]
764 if p != nil {
765 stk.Push(ImportInfo{Pkg: path, Pos: extractFirstImport(importPos)})
766 p = reusePackage(p, stk)
767 stk.Pop()
768 setCmdline(p)
769 } else {
770 p = new(Package)
771 p.Internal.Local = build.IsLocalImport(path)
772 p.ImportPath = importPath
773 packageCache[importPath] = p
774
775 setCmdline(p)
776
777
778
779
780 p.load(ctx, opts, path, stk, importPos, bp, err)
781
782 if !cfg.ModulesEnabled && path != cleanImport(path) {
783 p.Error = &PackageError{
784 ImportStack: stk.Copy(),
785 Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
786 }
787 p.Incomplete = true
788 p.Error.setPos(importPos)
789 }
790 }
791
792
793 if perr := disallowInternal(ctx, srcDir, parent, parentPath, p, stk); perr != nil {
794 perr.setPos(importPos)
795 return p, perr
796 }
797 if mode&ResolveImport != 0 {
798 if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != nil {
799 perr.setPos(importPos)
800 return p, perr
801 }
802 }
803
804 if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
805 perr := &PackageError{
806 ImportStack: stk.Copy(),
807 Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
808 }
809 perr.setPos(importPos)
810 return p, perr
811 }
812
813 if p.Internal.Local && parent != nil && !parent.Internal.Local {
814 var err error
815 if path == "." {
816 err = ImportErrorf(path, "%s: cannot import current directory", path)
817 } else {
818 err = ImportErrorf(path, "local import %q in non-local package", path)
819 }
820 perr := &PackageError{
821 ImportStack: stk.Copy(),
822 Err: err,
823 }
824 perr.setPos(importPos)
825 return p, perr
826 }
827
828 return p, nil
829 }
830
831 func extractFirstImport(importPos []token.Position) *token.Position {
832 if len(importPos) == 0 {
833 return nil
834 }
835 return &importPos[0]
836 }
837
838
839
840
841
842
843
844
845
846
847 func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) {
848 ctx, span := trace.StartSpan(ctx, "load.loadPackageData "+path)
849 defer span.Done()
850
851 if path == "" {
852 panic("loadPackageData called with empty package path")
853 }
854
855 if strings.HasPrefix(path, "mod/") {
856
857
858
859
860
861 return nil, false, fmt.Errorf("disallowed import path %q", path)
862 }
863
864 if strings.Contains(path, "@") {
865 return nil, false, errors.New("can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
866 }
867
868
869
870
871
872
873
874
875
876
877
878 importKey := importSpec{
879 path: path,
880 parentPath: parentPath,
881 parentDir: parentDir,
882 parentRoot: parentRoot,
883 parentIsStd: parentIsStd,
884 mode: mode,
885 }
886 r := resolvedImportCache.Do(importKey, func() resolvedImport {
887 var r resolvedImport
888 if newPath, dir, ok := fips140.ResolveImport(path); ok {
889 r.path = newPath
890 r.dir = dir
891 } else if cfg.ModulesEnabled {
892 r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path)
893 } else if build.IsLocalImport(path) {
894 r.dir = filepath.Join(parentDir, path)
895 r.path = dirToImportPath(r.dir)
896 } else if mode&ResolveImport != 0 {
897
898
899
900
901 r.path = resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
902 } else if mode&ResolveModule != 0 {
903 r.path = moduleImportPath(path, parentPath, parentDir, parentRoot)
904 }
905 if r.path == "" {
906 r.path = path
907 }
908 return r
909 })
910
911
912
913
914
915
916 p, err := packageDataCache.Do(r.path, func() (*build.Package, error) {
917 loaded = true
918 var data struct {
919 p *build.Package
920 err error
921 }
922 if r.dir != "" {
923 var buildMode build.ImportMode
924 buildContext := cfg.BuildContext
925 if !cfg.ModulesEnabled {
926 buildMode = build.ImportComment
927 } else {
928 buildContext.GOPATH = ""
929 }
930 modroot := modload.PackageModRoot(ctx, r.path)
931 if modroot == "" && str.HasPathPrefix(r.dir, cfg.GOROOTsrc) {
932 modroot = cfg.GOROOTsrc
933 gorootSrcCmd := filepath.Join(cfg.GOROOTsrc, "cmd")
934 if str.HasPathPrefix(r.dir, gorootSrcCmd) {
935 modroot = gorootSrcCmd
936 }
937 }
938 if modroot != "" {
939 if rp, err := modindex.GetPackage(modroot, r.dir); err == nil {
940 data.p, data.err = rp.Import(cfg.BuildContext, buildMode)
941 goto Happy
942 } else if !errors.Is(err, modindex.ErrNotIndexed) {
943 base.Fatal(err)
944 }
945 }
946 data.p, data.err = buildContext.ImportDir(r.dir, buildMode)
947 Happy:
948 if cfg.ModulesEnabled {
949
950
951 if info := modload.PackageModuleInfo(ctx, path); info != nil {
952 data.p.Root = info.Dir
953 }
954 }
955 if r.err != nil {
956 if data.err != nil {
957
958
959
960
961 } else if errors.Is(r.err, imports.ErrNoGo) {
962
963
964
965
966
967
968
969
970
971
972 } else {
973 data.err = r.err
974 }
975 }
976 } else if r.err != nil {
977 data.p = new(build.Package)
978 data.err = r.err
979 } else if cfg.ModulesEnabled && path != "unsafe" {
980 data.p = new(build.Package)
981 data.err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", r.path)
982 } else {
983 buildMode := build.ImportComment
984 if mode&ResolveImport == 0 || r.path != path {
985
986 buildMode |= build.IgnoreVendor
987 }
988 data.p, data.err = cfg.BuildContext.Import(r.path, parentDir, buildMode)
989 }
990 data.p.ImportPath = r.path
991
992
993
994 if !data.p.Goroot {
995 if cfg.GOBIN != "" {
996 data.p.BinDir = cfg.GOBIN
997 } else if cfg.ModulesEnabled {
998 data.p.BinDir = modload.BinDir()
999 }
1000 }
1001
1002 if !cfg.ModulesEnabled && data.err == nil &&
1003 data.p.ImportComment != "" && data.p.ImportComment != path &&
1004 !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
1005 data.err = fmt.Errorf("code in directory %s expects import %q", data.p.Dir, data.p.ImportComment)
1006 }
1007 return data.p, data.err
1008 })
1009
1010 return p, loaded, err
1011 }
1012
1013
1014
1015 type importSpec struct {
1016 path string
1017 parentPath, parentDir, parentRoot string
1018 parentIsStd bool
1019 mode int
1020 }
1021
1022
1023
1024
1025 type resolvedImport struct {
1026 path, dir string
1027 err error
1028 }
1029
1030
1031 var resolvedImportCache par.Cache[importSpec, resolvedImport]
1032
1033
1034 var packageDataCache par.ErrCache[string, *build.Package]
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 var preloadWorkerCount = runtime.GOMAXPROCS(0)
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 type preload struct {
1060 cancel chan struct{}
1061 sema chan struct{}
1062 }
1063
1064
1065
1066 func newPreload() *preload {
1067 pre := &preload{
1068 cancel: make(chan struct{}),
1069 sema: make(chan struct{}, preloadWorkerCount),
1070 }
1071 return pre
1072 }
1073
1074
1075
1076
1077 func (pre *preload) preloadMatches(ctx context.Context, opts PackageOpts, matches []*search.Match) {
1078 for _, m := range matches {
1079 for _, pkg := range m.Pkgs {
1080 select {
1081 case <-pre.cancel:
1082 return
1083 case pre.sema <- struct{}{}:
1084 go func(pkg string) {
1085 mode := 0
1086 bp, loaded, err := loadPackageData(ctx, pkg, "", base.Cwd(), "", false, mode)
1087 <-pre.sema
1088 if bp != nil && loaded && err == nil && !opts.IgnoreImports {
1089 pre.preloadImports(ctx, opts, bp.Imports, bp)
1090 }
1091 }(pkg)
1092 }
1093 }
1094 }
1095 }
1096
1097
1098
1099
1100 func (pre *preload) preloadImports(ctx context.Context, opts PackageOpts, imports []string, parent *build.Package) {
1101 parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath)
1102 for _, path := range imports {
1103 if path == "C" || path == "unsafe" {
1104 continue
1105 }
1106 select {
1107 case <-pre.cancel:
1108 return
1109 case pre.sema <- struct{}{}:
1110 go func(path string) {
1111 bp, loaded, err := loadPackageData(ctx, path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport)
1112 <-pre.sema
1113 if bp != nil && loaded && err == nil && !opts.IgnoreImports {
1114 pre.preloadImports(ctx, opts, bp.Imports, bp)
1115 }
1116 }(path)
1117 }
1118 }
1119 }
1120
1121
1122
1123
1124 func (pre *preload) flush() {
1125
1126
1127 if v := recover(); v != nil {
1128 panic(v)
1129 }
1130
1131 close(pre.cancel)
1132 for i := 0; i < preloadWorkerCount; i++ {
1133 pre.sema <- struct{}{}
1134 }
1135 }
1136
1137 func cleanImport(path string) string {
1138 orig := path
1139 path = pathpkg.Clean(path)
1140 if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
1141 path = "./" + path
1142 }
1143 return path
1144 }
1145
1146 var isDirCache par.Cache[string, bool]
1147
1148 func isDir(path string) bool {
1149 return isDirCache.Do(path, func() bool {
1150 fi, err := fsys.Stat(path)
1151 return err == nil && fi.IsDir()
1152 })
1153 }
1154
1155
1156
1157
1158
1159
1160 func ResolveImportPath(parent *Package, path string) (found string) {
1161 var parentPath, parentDir, parentRoot string
1162 parentIsStd := false
1163 if parent != nil {
1164 parentPath = parent.ImportPath
1165 parentDir = parent.Dir
1166 parentRoot = parent.Root
1167 parentIsStd = parent.Standard
1168 }
1169 return resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
1170 }
1171
1172 func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
1173 if cfg.ModulesEnabled {
1174 if _, p, e := modload.Lookup(parentPath, parentIsStd, path); e == nil {
1175 return p
1176 }
1177 return path
1178 }
1179 found = vendoredImportPath(path, parentPath, parentDir, parentRoot)
1180 if found != path {
1181 return found
1182 }
1183 return moduleImportPath(path, parentPath, parentDir, parentRoot)
1184 }
1185
1186
1187
1188 func dirAndRoot(path string, dir, root string) (string, string) {
1189 origDir, origRoot := dir, root
1190 dir = filepath.Clean(dir)
1191 root = filepath.Join(root, "src")
1192 if !str.HasFilePathPrefix(dir, root) || path != "command-line-arguments" && filepath.Join(root, path) != dir {
1193
1194 dir = expandPath(dir)
1195 root = expandPath(root)
1196 }
1197
1198 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 {
1199 debug.PrintStack()
1200 base.Fatalf("unexpected directory layout:\n"+
1201 " import path: %s\n"+
1202 " root: %s\n"+
1203 " dir: %s\n"+
1204 " expand root: %s\n"+
1205 " expand dir: %s\n"+
1206 " separator: %s",
1207 path,
1208 filepath.Join(origRoot, "src"),
1209 filepath.Clean(origDir),
1210 origRoot,
1211 origDir,
1212 string(filepath.Separator))
1213 }
1214
1215 return dir, root
1216 }
1217
1218
1219
1220
1221
1222 func vendoredImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
1223 if parentRoot == "" {
1224 return path
1225 }
1226
1227 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
1228
1229 vpath := "vendor/" + path
1230 for i := len(dir); i >= len(root); i-- {
1231 if i < len(dir) && dir[i] != filepath.Separator {
1232 continue
1233 }
1234
1235
1236
1237
1238 if !isDir(filepath.Join(dir[:i], "vendor")) {
1239 continue
1240 }
1241 targ := filepath.Join(dir[:i], vpath)
1242 if isDir(targ) && hasGoFiles(targ) {
1243 importPath := parentPath
1244 if importPath == "command-line-arguments" {
1245
1246
1247 importPath = dir[len(root)+1:]
1248 }
1249
1250
1251
1252
1253
1254
1255
1256
1257 chopped := len(dir) - i
1258 if chopped == len(importPath)+1 {
1259
1260
1261
1262
1263 return vpath
1264 }
1265 return importPath[:len(importPath)-chopped] + "/" + vpath
1266 }
1267 }
1268 return path
1269 }
1270
1271 var (
1272 modulePrefix = []byte("\nmodule ")
1273 goModPathCache par.Cache[string, string]
1274 )
1275
1276
1277 func goModPath(dir string) (path string) {
1278 return goModPathCache.Do(dir, func() string {
1279 data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
1280 if err != nil {
1281 return ""
1282 }
1283 var i int
1284 if bytes.HasPrefix(data, modulePrefix[1:]) {
1285 i = 0
1286 } else {
1287 i = bytes.Index(data, modulePrefix)
1288 if i < 0 {
1289 return ""
1290 }
1291 i++
1292 }
1293 line := data[i:]
1294
1295
1296 if j := bytes.IndexByte(line, '\n'); j >= 0 {
1297 line = line[:j]
1298 }
1299 if line[len(line)-1] == '\r' {
1300 line = line[:len(line)-1]
1301 }
1302 line = line[len("module "):]
1303
1304
1305 path = strings.TrimSpace(string(line))
1306 if path != "" && path[0] == '"' {
1307 s, err := strconv.Unquote(path)
1308 if err != nil {
1309 return ""
1310 }
1311 path = s
1312 }
1313 return path
1314 })
1315 }
1316
1317
1318
1319 func findVersionElement(path string) (i, j int) {
1320 j = len(path)
1321 for i = len(path) - 1; i >= 0; i-- {
1322 if path[i] == '/' {
1323 if isVersionElement(path[i+1 : j]) {
1324 return i, j
1325 }
1326 j = i
1327 }
1328 }
1329 return -1, -1
1330 }
1331
1332
1333
1334 func isVersionElement(s string) bool {
1335 if len(s) < 2 || s[0] != 'v' || s[1] == '0' || s[1] == '1' && len(s) == 2 {
1336 return false
1337 }
1338 for i := 1; i < len(s); i++ {
1339 if s[i] < '0' || '9' < s[i] {
1340 return false
1341 }
1342 }
1343 return true
1344 }
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354 func moduleImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
1355 if parentRoot == "" {
1356 return path
1357 }
1358
1359
1360
1361
1362
1363 if i, _ := findVersionElement(path); i < 0 {
1364 return path
1365 }
1366
1367 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
1368
1369
1370 for i := len(dir); i >= len(root); i-- {
1371 if i < len(dir) && dir[i] != filepath.Separator {
1372 continue
1373 }
1374 if goModPath(dir[:i]) != "" {
1375 goto HaveGoMod
1376 }
1377 }
1378
1379
1380 return path
1381
1382 HaveGoMod:
1383
1384
1385
1386
1387
1388 if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
1389 return path
1390 }
1391
1392
1393
1394
1395
1396
1397 limit := len(path)
1398 for limit > 0 {
1399 i, j := findVersionElement(path[:limit])
1400 if i < 0 {
1401 return path
1402 }
1403 if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
1404 if mpath := goModPath(bp.Dir); mpath != "" {
1405
1406
1407
1408 if mpath == path[:j] {
1409 return path[:i] + path[j:]
1410 }
1411
1412
1413
1414
1415 return path
1416 }
1417 }
1418 limit = i
1419 }
1420 return path
1421 }
1422
1423
1424
1425
1426
1427 func hasGoFiles(dir string) bool {
1428 files, _ := os.ReadDir(dir)
1429 for _, f := range files {
1430 if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
1431 return true
1432 }
1433 }
1434 return false
1435 }
1436
1437
1438
1439
1440 func reusePackage(p *Package, stk *ImportStack) *Package {
1441
1442
1443
1444 if p.Internal.Imports == nil {
1445 if p.Error == nil {
1446 p.Error = &PackageError{
1447 ImportStack: stk.Copy(),
1448 Err: errors.New("import cycle not allowed"),
1449 IsImportCycle: true,
1450 }
1451 } else if !p.Error.IsImportCycle {
1452
1453
1454
1455 p.Error.IsImportCycle = true
1456 }
1457 p.Incomplete = true
1458 }
1459
1460
1461 if p.Error != nil && p.Error.ImportStack != nil &&
1462 !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack.Pkgs()) {
1463 p.Error.ImportStack = stk.Copy()
1464 }
1465 return p
1466 }
1467
1468
1469
1470
1471
1472 func disallowInternal(ctx context.Context, srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *PackageError {
1473
1474
1475
1476
1477
1478
1479 if p.Error != nil {
1480 return nil
1481 }
1482
1483
1484
1485
1486
1487 if str.HasPathPrefix(p.ImportPath, "testing/internal") && importerPath == "testmain" {
1488 return nil
1489 }
1490
1491
1492 if cfg.BuildContext.Compiler == "gccgo" && p.Standard {
1493 return nil
1494 }
1495
1496
1497
1498
1499 if p.Standard && strings.HasPrefix(importerPath, "bootstrap/") {
1500 return nil
1501 }
1502
1503
1504
1505
1506 if importerPath == "" {
1507 return nil
1508 }
1509
1510
1511 i, ok := findInternal(p.ImportPath)
1512 if !ok {
1513 return nil
1514 }
1515
1516
1517
1518 if i > 0 {
1519 i--
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529 if str.HasPathPrefix(importerPath, "crypto") && str.HasPathPrefix(p.ImportPath, "crypto/internal/fips140") {
1530 return nil
1531 }
1532 if str.HasPathPrefix(importerPath, "crypto/internal/fips140") {
1533 if str.HasPathPrefix(p.ImportPath, "crypto/internal") {
1534 return nil
1535 }
1536 goto Error
1537 }
1538
1539 if p.Module == nil {
1540 parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
1541
1542 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1543 return nil
1544 }
1545
1546
1547 srcDir = expandPath(srcDir)
1548 parent = expandPath(parent)
1549 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1550 return nil
1551 }
1552 } else {
1553
1554
1555 if importer.Internal.CmdlineFiles {
1556
1557
1558
1559
1560
1561 importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
1562 }
1563 parentOfInternal := p.ImportPath[:i]
1564 if str.HasPathPrefix(importerPath, parentOfInternal) {
1565 return nil
1566 }
1567 }
1568
1569 Error:
1570
1571 perr := &PackageError{
1572 alwaysPrintStack: true,
1573 ImportStack: stk.Copy(),
1574 Err: ImportErrorf(p.ImportPath, "use of internal package %s not allowed", p.ImportPath),
1575 }
1576 return perr
1577 }
1578
1579
1580
1581
1582 func findInternal(path string) (index int, ok bool) {
1583
1584
1585
1586
1587 switch {
1588 case strings.HasSuffix(path, "/internal"):
1589 return len(path) - len("internal"), true
1590 case strings.Contains(path, "/internal/"):
1591 return strings.LastIndex(path, "/internal/") + 1, true
1592 case path == "internal", strings.HasPrefix(path, "internal/"):
1593 return 0, true
1594 }
1595 return 0, false
1596 }
1597
1598
1599
1600
1601 func disallowVendor(srcDir string, path string, importerPath string, p *Package, stk *ImportStack) *PackageError {
1602
1603
1604
1605 if importerPath == "" {
1606 return nil
1607 }
1608
1609 if perr := disallowVendorVisibility(srcDir, p, importerPath, stk); perr != nil {
1610 return perr
1611 }
1612
1613
1614 if i, ok := FindVendor(path); ok {
1615 perr := &PackageError{
1616 ImportStack: stk.Copy(),
1617 Err: ImportErrorf(path, "%s must be imported as %s", path, path[i+len("vendor/"):]),
1618 }
1619 return perr
1620 }
1621
1622 return nil
1623 }
1624
1625
1626
1627
1628
1629
1630 func disallowVendorVisibility(srcDir string, p *Package, importerPath string, stk *ImportStack) *PackageError {
1631
1632
1633
1634
1635 if importerPath == "" {
1636 return nil
1637 }
1638
1639
1640 i, ok := FindVendor(p.ImportPath)
1641 if !ok {
1642 return nil
1643 }
1644
1645
1646
1647 if i > 0 {
1648 i--
1649 }
1650 truncateTo := i + len(p.Dir) - len(p.ImportPath)
1651 if truncateTo < 0 || len(p.Dir) < truncateTo {
1652 return nil
1653 }
1654 parent := p.Dir[:truncateTo]
1655 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1656 return nil
1657 }
1658
1659
1660 srcDir = expandPath(srcDir)
1661 parent = expandPath(parent)
1662 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1663 return nil
1664 }
1665
1666
1667
1668 perr := &PackageError{
1669 ImportStack: stk.Copy(),
1670 Err: errors.New("use of vendored package not allowed"),
1671 }
1672 return perr
1673 }
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683 func FindVendor(path string) (index int, ok bool) {
1684
1685
1686
1687 switch {
1688 case strings.Contains(path, "/vendor/"):
1689 return strings.LastIndex(path, "/vendor/") + 1, true
1690 case strings.HasPrefix(path, "vendor/"):
1691 return 0, true
1692 }
1693 return 0, false
1694 }
1695
1696 type TargetDir int
1697
1698 const (
1699 ToTool TargetDir = iota
1700 ToBin
1701 StalePath
1702 )
1703
1704
1705 func InstallTargetDir(p *Package) TargetDir {
1706 if strings.HasPrefix(p.ImportPath, "code.google.com/p/go.tools/cmd/") {
1707 return StalePath
1708 }
1709 if p.Goroot && strings.HasPrefix(p.ImportPath, "cmd/") && p.Name == "main" {
1710 switch p.ImportPath {
1711 case "cmd/go", "cmd/gofmt":
1712 return ToBin
1713 }
1714 return ToTool
1715 }
1716 return ToBin
1717 }
1718
1719 var cgoExclude = map[string]bool{
1720 "runtime/cgo": true,
1721 }
1722
1723 var cgoSyscallExclude = map[string]bool{
1724 "runtime/cgo": true,
1725 "runtime/race": true,
1726 "runtime/msan": true,
1727 "runtime/asan": true,
1728 }
1729
1730 var foldPath = make(map[string]string)
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740 func (p *Package) exeFromImportPath() string {
1741 _, elem := pathpkg.Split(p.ImportPath)
1742 if cfg.ModulesEnabled {
1743
1744
1745 if elem != p.ImportPath && isVersionElement(elem) {
1746 _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
1747 }
1748 }
1749 return elem
1750 }
1751
1752
1753
1754
1755
1756 func (p *Package) exeFromFiles() string {
1757 var src string
1758 if len(p.GoFiles) > 0 {
1759 src = p.GoFiles[0]
1760 } else if len(p.CgoFiles) > 0 {
1761 src = p.CgoFiles[0]
1762 } else {
1763 return ""
1764 }
1765 _, elem := filepath.Split(src)
1766 return elem[:len(elem)-len(".go")]
1767 }
1768
1769
1770 func (p *Package) DefaultExecName() string {
1771 if p.Internal.CmdlineFiles {
1772 return p.exeFromFiles()
1773 }
1774 return p.exeFromImportPath()
1775 }
1776
1777
1778
1779
1780 func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
1781 p.copyBuild(opts, bp)
1782
1783
1784
1785
1786 if p.Internal.Local && !cfg.ModulesEnabled {
1787 p.Internal.LocalPrefix = dirToImportPath(p.Dir)
1788 }
1789
1790
1791
1792
1793 setError := func(err error) {
1794 if p.Error == nil {
1795 p.Error = &PackageError{
1796 ImportStack: stk.Copy(),
1797 Err: err,
1798 }
1799 p.Incomplete = true
1800
1801
1802
1803
1804
1805
1806
1807 top, ok := stk.Top()
1808 if ok && path != top.Pkg && len(importPos) > 0 {
1809 p.Error.setPos(importPos)
1810 }
1811 }
1812 }
1813
1814 if err != nil {
1815 p.Incomplete = true
1816 p.setLoadPackageDataError(err, path, stk, importPos)
1817 }
1818
1819 useBindir := p.Name == "main"
1820 if !p.Standard {
1821 switch cfg.BuildBuildmode {
1822 case "c-archive", "c-shared", "plugin":
1823 useBindir = false
1824 }
1825 }
1826
1827 if useBindir {
1828
1829 if InstallTargetDir(p) == StalePath {
1830
1831
1832 newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
1833 e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
1834 setError(e)
1835 return
1836 }
1837 elem := p.DefaultExecName() + cfg.ExeSuffix
1838 full := filepath.Join(cfg.BuildContext.GOOS+"_"+cfg.BuildContext.GOARCH, elem)
1839 if cfg.BuildContext.GOOS != runtime.GOOS || cfg.BuildContext.GOARCH != runtime.GOARCH {
1840
1841 elem = full
1842 }
1843 if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
1844 p.Internal.Build.BinDir = modload.BinDir()
1845 }
1846 if p.Internal.Build.BinDir != "" {
1847
1848 p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
1849 if !p.Goroot && strings.Contains(elem, string(filepath.Separator)) && cfg.GOBIN != "" {
1850
1851 p.Target = ""
1852 p.Internal.GobinSubdir = true
1853 }
1854 }
1855 if InstallTargetDir(p) == ToTool {
1856
1857
1858 if cfg.BuildToolchainName == "gccgo" {
1859 p.Target = filepath.Join(build.ToolDir, elem)
1860 } else {
1861 p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
1862 }
1863 }
1864 } else if p.Internal.Local {
1865
1866
1867 p.Target = ""
1868 } else if p.Standard && cfg.BuildContext.Compiler == "gccgo" {
1869
1870 p.Target = ""
1871 } else {
1872 p.Target = p.Internal.Build.PkgObj
1873 if cfg.BuildBuildmode == "shared" && p.Internal.Build.PkgTargetRoot != "" {
1874
1875
1876
1877 p.Target = filepath.Join(p.Internal.Build.PkgTargetRoot, p.ImportPath+".a")
1878 }
1879 if cfg.BuildLinkshared && p.Internal.Build.PkgTargetRoot != "" {
1880
1881
1882
1883 targetPrefix := filepath.Join(p.Internal.Build.PkgTargetRoot, p.ImportPath)
1884 p.Target = targetPrefix + ".a"
1885 shlibnamefile := targetPrefix + ".shlibname"
1886 shlib, err := os.ReadFile(shlibnamefile)
1887 if err != nil && !os.IsNotExist(err) {
1888 base.Fatalf("reading shlibname: %v", err)
1889 }
1890 if err == nil {
1891 libname := strings.TrimSpace(string(shlib))
1892 if cfg.BuildContext.Compiler == "gccgo" {
1893 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
1894 } else {
1895 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
1896 }
1897 }
1898 }
1899 }
1900
1901
1902
1903 importPaths := p.Imports
1904 addImport := func(path string, forCompiler bool) {
1905 for _, p := range importPaths {
1906 if path == p {
1907 return
1908 }
1909 }
1910 importPaths = append(importPaths, path)
1911 if forCompiler {
1912 p.Internal.CompiledImports = append(p.Internal.CompiledImports, path)
1913 }
1914 }
1915
1916 if !opts.IgnoreImports {
1917
1918
1919 if p.UsesCgo() {
1920 addImport("unsafe", true)
1921 }
1922 if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
1923 addImport("runtime/cgo", true)
1924 }
1925 if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
1926 addImport("syscall", true)
1927 }
1928
1929
1930 if p.UsesSwig() {
1931 addImport("unsafe", true)
1932 if cfg.BuildContext.Compiler != "gccgo" {
1933 addImport("runtime/cgo", true)
1934 }
1935 addImport("syscall", true)
1936 addImport("sync", true)
1937
1938
1939
1940 }
1941
1942
1943 if p.Name == "main" && !p.Internal.ForceLibrary {
1944 ldDeps, err := LinkerDeps(p)
1945 if err != nil {
1946 setError(err)
1947 return
1948 }
1949 for _, dep := range ldDeps {
1950 addImport(dep, false)
1951 }
1952 }
1953 }
1954
1955
1956
1957
1958 fold := str.ToFold(p.ImportPath)
1959 if other := foldPath[fold]; other == "" {
1960 foldPath[fold] = p.ImportPath
1961 } else if other != p.ImportPath {
1962 setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other))
1963 return
1964 }
1965
1966 if !SafeArg(p.ImportPath) {
1967 setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath))
1968 return
1969 }
1970
1971
1972
1973
1974 stk.Push(ImportInfo{Pkg: path, Pos: extractFirstImport(importPos)})
1975 defer stk.Pop()
1976
1977 pkgPath := p.ImportPath
1978 if p.Internal.CmdlineFiles {
1979 pkgPath = "command-line-arguments"
1980 }
1981 if cfg.ModulesEnabled {
1982 p.Module = modload.PackageModuleInfo(ctx, pkgPath)
1983 }
1984 p.DefaultGODEBUG = defaultGODEBUG(p, nil, nil, nil)
1985
1986 if !opts.SuppressEmbedFiles {
1987 p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)
1988 if err != nil {
1989 p.Incomplete = true
1990 setError(err)
1991 embedErr := err.(*EmbedError)
1992 p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
1993 }
1994 }
1995
1996
1997
1998
1999
2000 inputs := p.AllFiles()
2001 f1, f2 := str.FoldDup(inputs)
2002 if f1 != "" {
2003 setError(fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2))
2004 return
2005 }
2006
2007
2008
2009
2010
2011
2012
2013
2014 for _, file := range inputs {
2015 if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
2016 setError(fmt.Errorf("invalid input file name %q", file))
2017 return
2018 }
2019 }
2020 if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
2021 setError(fmt.Errorf("invalid input directory name %q", name))
2022 return
2023 }
2024 if strings.ContainsAny(p.Dir, "\r\n") {
2025 setError(fmt.Errorf("invalid package directory %q", p.Dir))
2026 return
2027 }
2028
2029
2030 imports := make([]*Package, 0, len(p.Imports))
2031 for i, path := range importPaths {
2032 if path == "C" {
2033 continue
2034 }
2035 p1, err := loadImport(ctx, opts, nil, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
2036 if err != nil && p.Error == nil {
2037 p.Error = err
2038 p.Incomplete = true
2039 }
2040
2041 path = p1.ImportPath
2042 importPaths[i] = path
2043 if i < len(p.Imports) {
2044 p.Imports[i] = path
2045 }
2046
2047 imports = append(imports, p1)
2048 if p1.Incomplete {
2049 p.Incomplete = true
2050 }
2051 }
2052 p.Internal.Imports = imports
2053 if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && !p.Incomplete && !opts.SuppressBuildInfo {
2054
2055
2056
2057
2058 p.setBuildInfo(ctx, opts.AutoVCS)
2059 }
2060
2061
2062
2063 if !cfg.BuildContext.CgoEnabled {
2064 p.CFiles = nil
2065 p.CXXFiles = nil
2066 p.MFiles = nil
2067 p.SwigFiles = nil
2068 p.SwigCXXFiles = nil
2069
2070
2071
2072
2073 }
2074
2075
2076 if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
2077 setError(fmt.Errorf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
2078 return
2079 }
2080
2081
2082
2083 if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
2084 setError(fmt.Errorf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " ")))
2085 return
2086 }
2087 if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
2088 setError(fmt.Errorf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " ")))
2089 return
2090 }
2091 if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
2092 setError(fmt.Errorf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " ")))
2093 return
2094 }
2095 }
2096
2097
2098 type EmbedError struct {
2099 Pattern string
2100 Err error
2101 }
2102
2103 func (e *EmbedError) Error() string {
2104 return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err)
2105 }
2106
2107 func (e *EmbedError) Unwrap() error {
2108 return e.Err
2109 }
2110
2111
2112
2113
2114
2115
2116 func ResolveEmbed(dir string, patterns []string) ([]string, error) {
2117 files, _, err := resolveEmbed(dir, patterns)
2118 return files, err
2119 }
2120
2121
2122
2123
2124
2125 func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[string][]string, err error) {
2126 var pattern string
2127 defer func() {
2128 if err != nil {
2129 err = &EmbedError{
2130 Pattern: pattern,
2131 Err: err,
2132 }
2133 }
2134 }()
2135
2136
2137 pmap = make(map[string][]string)
2138 have := make(map[string]int)
2139 dirOK := make(map[string]bool)
2140 pid := 0
2141 for _, pattern = range patterns {
2142 pid++
2143
2144 glob, all := strings.CutPrefix(pattern, "all:")
2145
2146 if _, err := pathpkg.Match(glob, ""); err != nil || !validEmbedPattern(glob) {
2147 return nil, nil, fmt.Errorf("invalid pattern syntax")
2148 }
2149
2150
2151 match, err := fsys.Glob(str.QuoteGlob(str.WithFilePathSeparator(pkgdir)) + filepath.FromSlash(glob))
2152 if err != nil {
2153 return nil, nil, err
2154 }
2155
2156
2157
2158
2159
2160 var list []string
2161 for _, file := range match {
2162
2163 rel := filepath.ToSlash(str.TrimFilePathPrefix(file, pkgdir))
2164
2165 what := "file"
2166 info, err := fsys.Lstat(file)
2167 if err != nil {
2168 return nil, nil, err
2169 }
2170 if info.IsDir() {
2171 what = "directory"
2172 }
2173
2174
2175
2176 for dir := file; len(dir) > len(pkgdir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
2177 if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
2178 return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
2179 }
2180 if dir != file {
2181 if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
2182 return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(pkgdir)+1:])
2183 }
2184 }
2185 dirOK[dir] = true
2186 if elem := filepath.Base(dir); isBadEmbedName(elem) {
2187 if dir == file {
2188 return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
2189 } else {
2190 return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
2191 }
2192 }
2193 }
2194
2195 switch {
2196 default:
2197 return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
2198
2199 case info.Mode().IsRegular():
2200 if have[rel] != pid {
2201 have[rel] = pid
2202 list = append(list, rel)
2203 }
2204
2205 case info.IsDir():
2206
2207
2208 count := 0
2209 err := fsys.WalkDir(file, func(path string, d fs.DirEntry, err error) error {
2210 if err != nil {
2211 return err
2212 }
2213 rel := filepath.ToSlash(str.TrimFilePathPrefix(path, pkgdir))
2214 name := d.Name()
2215 if path != file && (isBadEmbedName(name) || ((name[0] == '.' || name[0] == '_') && !all)) {
2216
2217
2218
2219 if d.IsDir() {
2220 return fs.SkipDir
2221 }
2222 return nil
2223 }
2224 if d.IsDir() {
2225 if _, err := fsys.Stat(filepath.Join(path, "go.mod")); err == nil {
2226 return filepath.SkipDir
2227 }
2228 return nil
2229 }
2230 if !d.Type().IsRegular() {
2231 return nil
2232 }
2233 count++
2234 if have[rel] != pid {
2235 have[rel] = pid
2236 list = append(list, rel)
2237 }
2238 return nil
2239 })
2240 if err != nil {
2241 return nil, nil, err
2242 }
2243 if count == 0 {
2244 return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel)
2245 }
2246 }
2247 }
2248
2249 if len(list) == 0 {
2250 return nil, nil, fmt.Errorf("no matching files found")
2251 }
2252 sort.Strings(list)
2253 pmap[pattern] = list
2254 }
2255
2256 for file := range have {
2257 files = append(files, file)
2258 }
2259 sort.Strings(files)
2260 return files, pmap, nil
2261 }
2262
2263 func validEmbedPattern(pattern string) bool {
2264 return pattern != "." && fs.ValidPath(pattern)
2265 }
2266
2267
2268
2269
2270 func isBadEmbedName(name string) bool {
2271 if err := module.CheckFilePath(name); err != nil {
2272 return true
2273 }
2274 switch name {
2275
2276 case "":
2277 return true
2278
2279 case ".bzr", ".hg", ".git", ".svn":
2280 return true
2281 }
2282 return false
2283 }
2284
2285
2286
2287 var vcsStatusCache par.ErrCache[string, vcs.Status]
2288
2289 func appendBuildSetting(info *debug.BuildInfo, key, value string) {
2290 value = strings.ReplaceAll(value, "\n", " ")
2291 info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
2292 }
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303 func (p *Package) setBuildInfo(ctx context.Context, autoVCS bool) {
2304 setPkgErrorf := func(format string, args ...any) {
2305 if p.Error == nil {
2306 p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
2307 p.Incomplete = true
2308 }
2309 }
2310
2311 var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
2312 debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
2313 version := mi.Version
2314 if version == "" {
2315 version = "(devel)"
2316 }
2317 dm := &debug.Module{
2318 Path: mi.Path,
2319 Version: version,
2320 }
2321 if mi.Replace != nil {
2322 dm.Replace = debugModFromModinfo(mi.Replace)
2323 } else if mi.Version != "" && cfg.BuildMod != "vendor" {
2324 dm.Sum = modfetch.Sum(ctx, module.Version{Path: mi.Path, Version: mi.Version})
2325 }
2326 return dm
2327 }
2328
2329 var main debug.Module
2330 if p.Module != nil {
2331 main = *debugModFromModinfo(p.Module)
2332 }
2333
2334 visited := make(map[*Package]bool)
2335 mdeps := make(map[module.Version]*debug.Module)
2336 var q []*Package
2337 q = append(q, p.Internal.Imports...)
2338 for len(q) > 0 {
2339 p1 := q[0]
2340 q = q[1:]
2341 if visited[p1] {
2342 continue
2343 }
2344 visited[p1] = true
2345 if p1.Module != nil {
2346 m := module.Version{Path: p1.Module.Path, Version: p1.Module.Version}
2347 if p1.Module.Path != main.Path && mdeps[m] == nil {
2348 mdeps[m] = debugModFromModinfo(p1.Module)
2349 }
2350 }
2351 q = append(q, p1.Internal.Imports...)
2352 }
2353 sortedMods := make([]module.Version, 0, len(mdeps))
2354 for mod := range mdeps {
2355 sortedMods = append(sortedMods, mod)
2356 }
2357 gover.ModSort(sortedMods)
2358 deps := make([]*debug.Module, len(sortedMods))
2359 for i, mod := range sortedMods {
2360 deps[i] = mdeps[mod]
2361 }
2362
2363 pkgPath := p.ImportPath
2364 if p.Internal.CmdlineFiles {
2365 pkgPath = "command-line-arguments"
2366 }
2367 info := &debug.BuildInfo{
2368 Path: pkgPath,
2369 Main: main,
2370 Deps: deps,
2371 }
2372 appendSetting := func(key, value string) {
2373 appendBuildSetting(info, key, value)
2374 }
2375
2376
2377
2378
2379 if cfg.BuildASan {
2380 appendSetting("-asan", "true")
2381 }
2382 if BuildAsmflags.present {
2383 appendSetting("-asmflags", BuildAsmflags.String())
2384 }
2385 buildmode := cfg.BuildBuildmode
2386 if buildmode == "default" {
2387 if p.Name == "main" {
2388 buildmode = "exe"
2389 } else {
2390 buildmode = "archive"
2391 }
2392 }
2393 appendSetting("-buildmode", buildmode)
2394 appendSetting("-compiler", cfg.BuildContext.Compiler)
2395 if gccgoflags := BuildGccgoflags.String(); gccgoflags != "" && cfg.BuildContext.Compiler == "gccgo" {
2396 appendSetting("-gccgoflags", gccgoflags)
2397 }
2398 if gcflags := BuildGcflags.String(); gcflags != "" && cfg.BuildContext.Compiler == "gc" {
2399 appendSetting("-gcflags", gcflags)
2400 }
2401 if ldflags := BuildLdflags.String(); ldflags != "" {
2402
2403
2404
2405
2406
2407
2408
2409
2410 if !cfg.BuildTrimpath {
2411 appendSetting("-ldflags", ldflags)
2412 }
2413 }
2414 if cfg.BuildCover {
2415 appendSetting("-cover", "true")
2416 }
2417 if cfg.BuildMSan {
2418 appendSetting("-msan", "true")
2419 }
2420
2421 if cfg.BuildRace {
2422 appendSetting("-race", "true")
2423 }
2424 if tags := cfg.BuildContext.BuildTags; len(tags) > 0 {
2425 appendSetting("-tags", strings.Join(tags, ","))
2426 }
2427 if cfg.BuildTrimpath {
2428 appendSetting("-trimpath", "true")
2429 }
2430 if p.DefaultGODEBUG != "" {
2431 appendSetting("DefaultGODEBUG", p.DefaultGODEBUG)
2432 }
2433 cgo := "0"
2434 if cfg.BuildContext.CgoEnabled {
2435 cgo = "1"
2436 }
2437 appendSetting("CGO_ENABLED", cgo)
2438
2439
2440
2441
2442
2443
2444
2445 if cfg.BuildContext.CgoEnabled && !cfg.BuildTrimpath {
2446 for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
2447 appendSetting(name, cfg.Getenv(name))
2448 }
2449 }
2450 appendSetting("GOARCH", cfg.BuildContext.GOARCH)
2451 if cfg.RawGOEXPERIMENT != "" {
2452 appendSetting("GOEXPERIMENT", cfg.RawGOEXPERIMENT)
2453 }
2454 if fips140.Enabled() {
2455 appendSetting("GOFIPS140", fips140.Version())
2456 }
2457 appendSetting("GOOS", cfg.BuildContext.GOOS)
2458 if key, val, _ := cfg.GetArchEnv(); key != "" && val != "" {
2459 appendSetting(key, val)
2460 }
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470 setVCSError := func(err error) {
2471 setPkgErrorf("error obtaining VCS status: %v\n\tUse -buildvcs=false to disable VCS stamping.", err)
2472 }
2473
2474 var repoDir string
2475 var vcsCmd *vcs.Cmd
2476 var err error
2477 const allowNesting = true
2478
2479 wantVCS := false
2480 switch cfg.BuildBuildvcs {
2481 case "true":
2482 wantVCS = true
2483 case "auto":
2484 wantVCS = autoVCS && !p.IsTestOnly()
2485 case "false":
2486 default:
2487 panic(fmt.Sprintf("unexpected value for cfg.BuildBuildvcs: %q", cfg.BuildBuildvcs))
2488 }
2489
2490 if wantVCS && p.Module != nil && p.Module.Version == "" && !p.Standard {
2491 if p.Module.Path == "bootstrap" && cfg.GOROOT == os.Getenv("GOROOT_BOOTSTRAP") {
2492
2493
2494
2495 goto omitVCS
2496 }
2497 repoDir, vcsCmd, err = vcs.FromDir(base.Cwd(), "", allowNesting)
2498 if err != nil && !errors.Is(err, os.ErrNotExist) {
2499 setVCSError(err)
2500 return
2501 }
2502 if !str.HasFilePathPrefix(p.Module.Dir, repoDir) &&
2503 !str.HasFilePathPrefix(repoDir, p.Module.Dir) {
2504
2505
2506
2507
2508 goto omitVCS
2509 }
2510 if cfg.BuildBuildvcs == "auto" && vcsCmd != nil && vcsCmd.Cmd != "" {
2511 if _, err := pathcache.LookPath(vcsCmd.Cmd); err != nil {
2512
2513
2514 goto omitVCS
2515 }
2516 }
2517 }
2518 if repoDir != "" && vcsCmd.Status != nil {
2519
2520
2521
2522
2523 pkgRepoDir, _, err := vcs.FromDir(p.Dir, "", allowNesting)
2524 if err != nil {
2525 setVCSError(err)
2526 return
2527 }
2528 if pkgRepoDir != repoDir {
2529 if cfg.BuildBuildvcs != "auto" {
2530 setVCSError(fmt.Errorf("main package is in repository %q but current directory is in repository %q", pkgRepoDir, repoDir))
2531 return
2532 }
2533 goto omitVCS
2534 }
2535 modRepoDir, _, err := vcs.FromDir(p.Module.Dir, "", allowNesting)
2536 if err != nil {
2537 setVCSError(err)
2538 return
2539 }
2540 if modRepoDir != repoDir {
2541 if cfg.BuildBuildvcs != "auto" {
2542 setVCSError(fmt.Errorf("main module is in repository %q but current directory is in repository %q", modRepoDir, repoDir))
2543 return
2544 }
2545 goto omitVCS
2546 }
2547
2548 st, err := vcsStatusCache.Do(repoDir, func() (vcs.Status, error) {
2549 return vcsCmd.Status(vcsCmd, repoDir)
2550 })
2551 if err != nil {
2552 setVCSError(err)
2553 return
2554 }
2555
2556 appendSetting("vcs", vcsCmd.Cmd)
2557 if st.Revision != "" {
2558 appendSetting("vcs.revision", st.Revision)
2559 }
2560 if !st.CommitTime.IsZero() {
2561 stamp := st.CommitTime.UTC().Format(time.RFC3339Nano)
2562 appendSetting("vcs.time", stamp)
2563 }
2564 appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted))
2565
2566 repo := modfetch.LookupLocal(ctx, repoDir)
2567 revInfo, err := repo.Stat(ctx, st.Revision)
2568 if err != nil {
2569 goto omitVCS
2570 }
2571 vers := revInfo.Version
2572 if vers != "" {
2573 if st.Uncommitted {
2574
2575 if strings.HasSuffix(vers, "+incompatible") {
2576 vers += ".dirty"
2577 } else {
2578 vers += "+dirty"
2579 }
2580 }
2581 info.Main.Version = vers
2582 }
2583 }
2584 omitVCS:
2585
2586 p.Internal.BuildInfo = info
2587 }
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598 func SafeArg(name string) bool {
2599 if name == "" {
2600 return false
2601 }
2602 c := name[0]
2603 return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
2604 }
2605
2606
2607 func LinkerDeps(p *Package) ([]string, error) {
2608
2609 deps := []string{"runtime"}
2610
2611
2612 if what := externalLinkingReason(p); what != "" && cfg.BuildContext.Compiler != "gccgo" {
2613 if !cfg.BuildContext.CgoEnabled {
2614 return nil, fmt.Errorf("%s requires external (cgo) linking, but cgo is not enabled", what)
2615 }
2616 deps = append(deps, "runtime/cgo")
2617 }
2618
2619 if cfg.Goarch == "arm" {
2620 deps = append(deps, "math")
2621 }
2622
2623 if cfg.BuildRace {
2624 deps = append(deps, "runtime/race")
2625 }
2626
2627 if cfg.BuildMSan {
2628 deps = append(deps, "runtime/msan")
2629 }
2630
2631 if cfg.BuildASan {
2632 deps = append(deps, "runtime/asan")
2633 }
2634
2635 if cfg.BuildCover && cfg.Experiment.CoverageRedesign {
2636 deps = append(deps, "runtime/coverage")
2637 }
2638
2639 return deps, nil
2640 }
2641
2642
2643
2644
2645 func externalLinkingReason(p *Package) (what string) {
2646
2647 if platform.MustLinkExternal(cfg.Goos, cfg.Goarch, false) {
2648 return cfg.Goos + "/" + cfg.Goarch
2649 }
2650
2651
2652 switch cfg.BuildBuildmode {
2653 case "c-shared":
2654 if cfg.BuildContext.GOARCH == "wasm" {
2655 break
2656 }
2657 fallthrough
2658 case "plugin":
2659 return "-buildmode=" + cfg.BuildBuildmode
2660 }
2661
2662
2663 if cfg.BuildLinkshared {
2664 return "-linkshared"
2665 }
2666
2667
2668
2669 isPIE := false
2670 if cfg.BuildBuildmode == "pie" {
2671 isPIE = true
2672 } else if cfg.BuildBuildmode == "default" && platform.DefaultPIE(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH, cfg.BuildRace) {
2673 isPIE = true
2674 }
2675
2676
2677
2678 if isPIE && !platform.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH) {
2679 if cfg.BuildBuildmode == "pie" {
2680 return "-buildmode=pie"
2681 }
2682 return "default PIE binary"
2683 }
2684
2685
2686
2687 if p != nil {
2688 ldflags := BuildLdflags.For(p)
2689 for i := len(ldflags) - 1; i >= 0; i-- {
2690 a := ldflags[i]
2691 if a == "-linkmode=external" ||
2692 a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
2693 return a
2694 } else if a == "-linkmode=internal" ||
2695 a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" {
2696 return ""
2697 }
2698 }
2699 }
2700
2701 return ""
2702 }
2703
2704
2705
2706
2707 func (p *Package) mkAbs(list []string) []string {
2708 for i, f := range list {
2709 list[i] = filepath.Join(p.Dir, f)
2710 }
2711 sort.Strings(list)
2712 return list
2713 }
2714
2715
2716
2717 func (p *Package) InternalGoFiles() []string {
2718 return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles))
2719 }
2720
2721
2722
2723 func (p *Package) InternalXGoFiles() []string {
2724 return p.mkAbs(p.XTestGoFiles)
2725 }
2726
2727
2728
2729
2730 func (p *Package) InternalAllGoFiles() []string {
2731 return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
2732 }
2733
2734
2735 func (p *Package) UsesSwig() bool {
2736 return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
2737 }
2738
2739
2740 func (p *Package) UsesCgo() bool {
2741 return len(p.CgoFiles) > 0
2742 }
2743
2744
2745
2746 func PackageList(roots []*Package) []*Package {
2747 seen := map[*Package]bool{}
2748 all := []*Package{}
2749 var walk func(*Package)
2750 walk = func(p *Package) {
2751 if seen[p] {
2752 return
2753 }
2754 seen[p] = true
2755 for _, p1 := range p.Internal.Imports {
2756 walk(p1)
2757 }
2758 all = append(all, p)
2759 }
2760 for _, root := range roots {
2761 walk(root)
2762 }
2763 return all
2764 }
2765
2766
2767
2768
2769 func TestPackageList(ctx context.Context, opts PackageOpts, roots []*Package) []*Package {
2770 seen := map[*Package]bool{}
2771 all := []*Package{}
2772 var walk func(*Package)
2773 walk = func(p *Package) {
2774 if seen[p] {
2775 return
2776 }
2777 seen[p] = true
2778 for _, p1 := range p.Internal.Imports {
2779 walk(p1)
2780 }
2781 all = append(all, p)
2782 }
2783 walkTest := func(root *Package, path string) {
2784 var stk ImportStack
2785 p1, err := loadImport(ctx, opts, nil, path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
2786 if err != nil && root.Error == nil {
2787
2788 root.Error = err
2789 root.Incomplete = true
2790 }
2791 if p1.Error == nil {
2792 walk(p1)
2793 }
2794 }
2795 for _, root := range roots {
2796 walk(root)
2797 for _, path := range root.TestImports {
2798 walkTest(root, path)
2799 }
2800 for _, path := range root.XTestImports {
2801 walkTest(root, path)
2802 }
2803 }
2804 return all
2805 }
2806
2807
2808
2809
2810
2811
2812 func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) {
2813 p, err := loadImport(context.TODO(), PackageOpts{}, nil, path, srcDir, parent, stk, importPos, mode)
2814 setToolFlags(p)
2815 return p, err
2816 }
2817
2818
2819
2820 func LoadPackageWithFlags(path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package {
2821 p := LoadPackage(context.TODO(), PackageOpts{}, path, srcDir, stk, importPos, mode)
2822 setToolFlags(p)
2823 return p
2824 }
2825
2826
2827
2828 type PackageOpts struct {
2829
2830
2831
2832 IgnoreImports bool
2833
2834
2835
2836
2837
2838
2839
2840
2841 ModResolveTests bool
2842
2843
2844
2845
2846
2847
2848 MainOnly bool
2849
2850
2851
2852 AutoVCS bool
2853
2854
2855
2856 SuppressBuildInfo bool
2857
2858
2859
2860 SuppressEmbedFiles bool
2861 }
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871 func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string) []*Package {
2872 ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors")
2873 defer span.Done()
2874
2875 for _, p := range patterns {
2876
2877
2878
2879 if strings.HasSuffix(p, ".go") {
2880
2881
2882 if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
2883 pkgs := []*Package{GoFilesPackage(ctx, opts, patterns)}
2884 setPGOProfilePath(pkgs)
2885 return pkgs
2886 }
2887 }
2888 }
2889
2890 var matches []*search.Match
2891 if modload.Init(); cfg.ModulesEnabled {
2892 modOpts := modload.PackageOpts{
2893 ResolveMissingImports: true,
2894 LoadTests: opts.ModResolveTests,
2895 SilencePackageErrors: true,
2896 }
2897 matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
2898 } else {
2899 noModRoots := []string{}
2900 matches = search.ImportPaths(patterns, noModRoots)
2901 }
2902
2903 var (
2904 pkgs []*Package
2905 stk ImportStack
2906 seenPkg = make(map[*Package]bool)
2907 )
2908
2909 pre := newPreload()
2910 defer pre.flush()
2911 pre.preloadMatches(ctx, opts, matches)
2912
2913 for _, m := range matches {
2914 for _, pkg := range m.Pkgs {
2915 if pkg == "" {
2916 panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern()))
2917 }
2918 mode := cmdlinePkg
2919 if m.IsLiteral() {
2920
2921
2922
2923 mode |= cmdlinePkgLiteral
2924 }
2925 p, perr := loadImport(ctx, opts, pre, pkg, base.Cwd(), nil, &stk, nil, mode)
2926 if perr != nil {
2927 base.Fatalf("internal error: loadImport of %q with nil parent returned an error", pkg)
2928 }
2929 p.Match = append(p.Match, m.Pattern())
2930 if seenPkg[p] {
2931 continue
2932 }
2933 seenPkg[p] = true
2934 pkgs = append(pkgs, p)
2935 }
2936
2937 if len(m.Errs) > 0 {
2938
2939
2940
2941 p := new(Package)
2942 p.ImportPath = m.Pattern()
2943
2944 var stk ImportStack
2945 var importPos []token.Position
2946 p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk, importPos)
2947 p.Incomplete = true
2948 p.Match = append(p.Match, m.Pattern())
2949 p.Internal.CmdlinePkg = true
2950 if m.IsLiteral() {
2951 p.Internal.CmdlinePkgLiteral = true
2952 }
2953 pkgs = append(pkgs, p)
2954 }
2955 }
2956
2957 if opts.MainOnly {
2958 pkgs = mainPackagesOnly(pkgs, matches)
2959 }
2960
2961
2962
2963
2964
2965 setToolFlags(pkgs...)
2966
2967 setPGOProfilePath(pkgs)
2968
2969 return pkgs
2970 }
2971
2972
2973
2974 func setPGOProfilePath(pkgs []*Package) {
2975 updateBuildInfo := func(p *Package, file string) {
2976
2977 if p.Internal.BuildInfo == nil {
2978 return
2979 }
2980
2981 if cfg.BuildTrimpath {
2982 appendBuildSetting(p.Internal.BuildInfo, "-pgo", filepath.Base(file))
2983 } else {
2984 appendBuildSetting(p.Internal.BuildInfo, "-pgo", file)
2985 }
2986
2987 slices.SortFunc(p.Internal.BuildInfo.Settings, func(x, y debug.BuildSetting) int {
2988 return strings.Compare(x.Key, y.Key)
2989 })
2990 }
2991
2992 switch cfg.BuildPGO {
2993 case "off":
2994 return
2995
2996 case "auto":
2997
2998
2999
3000
3001
3002
3003
3004 for _, p := range pkgs {
3005 if p.Name != "main" {
3006 continue
3007 }
3008 pmain := p
3009 file := filepath.Join(pmain.Dir, "default.pgo")
3010 if _, err := os.Stat(file); err != nil {
3011 continue
3012 }
3013
3014
3015
3016
3017 visited := make(map[*Package]*Package)
3018 var split func(p *Package) *Package
3019 split = func(p *Package) *Package {
3020 if p1 := visited[p]; p1 != nil {
3021 return p1
3022 }
3023
3024 if len(pkgs) > 1 && p != pmain {
3025
3026
3027
3028
3029 if p.Internal.PGOProfile != "" {
3030 panic("setPGOProfilePath: already have profile")
3031 }
3032 p1 := new(Package)
3033 *p1 = *p
3034
3035
3036
3037 p1.Imports = slices.Clone(p.Imports)
3038 p1.Internal.Imports = slices.Clone(p.Internal.Imports)
3039 p1.Internal.ForMain = pmain.ImportPath
3040 visited[p] = p1
3041 p = p1
3042 } else {
3043 visited[p] = p
3044 }
3045 p.Internal.PGOProfile = file
3046 updateBuildInfo(p, file)
3047
3048 for i, pp := range p.Internal.Imports {
3049 p.Internal.Imports[i] = split(pp)
3050 }
3051 return p
3052 }
3053
3054
3055 split(pmain)
3056 }
3057
3058 default:
3059
3060
3061 file, err := filepath.Abs(cfg.BuildPGO)
3062 if err != nil {
3063 base.Fatalf("fail to get absolute path of PGO file %s: %v", cfg.BuildPGO, err)
3064 }
3065
3066 for _, p := range PackageList(pkgs) {
3067 p.Internal.PGOProfile = file
3068 updateBuildInfo(p, file)
3069 }
3070 }
3071 }
3072
3073
3074
3075 func CheckPackageErrors(pkgs []*Package) {
3076 PackageErrors(pkgs, func(p *Package) {
3077 DefaultPrinter().Errorf(p, "%v", p.Error)
3078 })
3079 base.ExitIfErrors()
3080 }
3081
3082
3083 func PackageErrors(pkgs []*Package, report func(*Package)) {
3084 var anyIncomplete, anyErrors bool
3085 for _, pkg := range pkgs {
3086 if pkg.Incomplete {
3087 anyIncomplete = true
3088 }
3089 }
3090 if anyIncomplete {
3091 all := PackageList(pkgs)
3092 for _, p := range all {
3093 if p.Error != nil {
3094 report(p)
3095 anyErrors = true
3096 }
3097 }
3098 }
3099 if anyErrors {
3100 return
3101 }
3102
3103
3104
3105
3106
3107
3108 seen := map[string]bool{}
3109 reported := map[string]bool{}
3110 for _, pkg := range PackageList(pkgs) {
3111
3112
3113
3114 key := pkg.ImportPath
3115 if pkg.Internal.PGOProfile != "" {
3116 key += " pgo:" + pkg.Internal.PGOProfile
3117 }
3118 if seen[key] && !reported[key] {
3119 reported[key] = true
3120 base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
3121 }
3122 seen[key] = true
3123 }
3124 if len(reported) > 0 {
3125 base.ExitIfErrors()
3126 }
3127 }
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140 func mainPackagesOnly(pkgs []*Package, matches []*search.Match) []*Package {
3141 treatAsMain := map[string]bool{}
3142 for _, m := range matches {
3143 if m.IsLiteral() {
3144 for _, path := range m.Pkgs {
3145 treatAsMain[path] = true
3146 }
3147 }
3148 }
3149
3150 var mains []*Package
3151 for _, pkg := range pkgs {
3152 if pkg.Name == "main" || (pkg.Name == "" && pkg.Error != nil) {
3153 treatAsMain[pkg.ImportPath] = true
3154 mains = append(mains, pkg)
3155 continue
3156 }
3157
3158 if len(pkg.InvalidGoFiles) > 0 {
3159
3160
3161
3162 treatAsMain[pkg.ImportPath] = true
3163 }
3164 if treatAsMain[pkg.ImportPath] {
3165 if pkg.Error == nil {
3166 pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
3167 pkg.Incomplete = true
3168 }
3169 mains = append(mains, pkg)
3170 }
3171 }
3172
3173 for _, m := range matches {
3174 if m.IsLiteral() || len(m.Pkgs) == 0 {
3175 continue
3176 }
3177 foundMain := false
3178 for _, path := range m.Pkgs {
3179 if treatAsMain[path] {
3180 foundMain = true
3181 break
3182 }
3183 }
3184 if !foundMain {
3185 fmt.Fprintf(os.Stderr, "go: warning: %q matched only non-main packages\n", m.Pattern())
3186 }
3187 }
3188
3189 return mains
3190 }
3191
3192 type mainPackageError struct {
3193 importPath string
3194 }
3195
3196 func (e *mainPackageError) Error() string {
3197 return fmt.Sprintf("package %s is not a main package", e.importPath)
3198 }
3199
3200 func (e *mainPackageError) ImportPath() string {
3201 return e.importPath
3202 }
3203
3204 func setToolFlags(pkgs ...*Package) {
3205 for _, p := range PackageList(pkgs) {
3206 p.Internal.Asmflags = BuildAsmflags.For(p)
3207 p.Internal.Gcflags = BuildGcflags.For(p)
3208 p.Internal.Ldflags = BuildLdflags.For(p)
3209 p.Internal.Gccgoflags = BuildGccgoflags.For(p)
3210 }
3211 }
3212
3213
3214
3215
3216 func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Package {
3217 modload.Init()
3218
3219 for _, f := range gofiles {
3220 if !strings.HasSuffix(f, ".go") {
3221 pkg := new(Package)
3222 pkg.Internal.Local = true
3223 pkg.Internal.CmdlineFiles = true
3224 pkg.Name = f
3225 pkg.Error = &PackageError{
3226 Err: fmt.Errorf("named files must be .go files: %s", pkg.Name),
3227 }
3228 pkg.Incomplete = true
3229 return pkg
3230 }
3231 }
3232
3233 var stk ImportStack
3234 ctxt := cfg.BuildContext
3235 ctxt.UseAllFiles = true
3236
3237
3238
3239
3240
3241 var dirent []fs.FileInfo
3242 var dir string
3243 for _, file := range gofiles {
3244 fi, err := fsys.Stat(file)
3245 if err != nil {
3246 base.Fatalf("%s", err)
3247 }
3248 if fi.IsDir() {
3249 base.Fatalf("%s is a directory, should be a Go file", file)
3250 }
3251 dir1 := filepath.Dir(file)
3252 if dir == "" {
3253 dir = dir1
3254 } else if dir != dir1 {
3255 base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
3256 }
3257 dirent = append(dirent, fi)
3258 }
3259 ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil }
3260
3261 if cfg.ModulesEnabled {
3262 modload.ImportFromFiles(ctx, gofiles)
3263 }
3264
3265 var err error
3266 if dir == "" {
3267 dir = base.Cwd()
3268 }
3269 dir, err = filepath.Abs(dir)
3270 if err != nil {
3271 base.Fatalf("%s", err)
3272 }
3273
3274 bp, err := ctxt.ImportDir(dir, 0)
3275 pkg := new(Package)
3276 pkg.Internal.Local = true
3277 pkg.Internal.CmdlineFiles = true
3278 pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
3279 if !cfg.ModulesEnabled {
3280 pkg.Internal.LocalPrefix = dirToImportPath(dir)
3281 }
3282 pkg.ImportPath = "command-line-arguments"
3283 pkg.Target = ""
3284 pkg.Match = gofiles
3285
3286 if pkg.Name == "main" {
3287 exe := pkg.DefaultExecName() + cfg.ExeSuffix
3288
3289 if cfg.GOBIN != "" {
3290 pkg.Target = filepath.Join(cfg.GOBIN, exe)
3291 } else if cfg.ModulesEnabled {
3292 pkg.Target = filepath.Join(modload.BinDir(), exe)
3293 }
3294 }
3295
3296 if opts.MainOnly && pkg.Name != "main" && pkg.Error == nil {
3297 pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
3298 pkg.Incomplete = true
3299 }
3300 setToolFlags(pkg)
3301
3302 return pkg
3303 }
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320 func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args []string) ([]*Package, error) {
3321 if !modload.ForceUseModules {
3322 panic("modload.ForceUseModules must be true")
3323 }
3324 if modload.RootMode != modload.NoRoot {
3325 panic("modload.RootMode must be NoRoot")
3326 }
3327
3328
3329 var version string
3330 var firstPath string
3331 for _, arg := range args {
3332 if i := strings.Index(arg, "@"); i >= 0 {
3333 firstPath, version = arg[:i], arg[i+1:]
3334 if version == "" {
3335 return nil, fmt.Errorf("%s: version must not be empty", arg)
3336 }
3337 break
3338 }
3339 }
3340 patterns := make([]string, len(args))
3341 for i, arg := range args {
3342 p, found := strings.CutSuffix(arg, "@"+version)
3343 if !found {
3344 return nil, fmt.Errorf("%s: all arguments must refer to packages in the same module at the same version (@%s)", arg, version)
3345 }
3346 switch {
3347 case build.IsLocalImport(p):
3348 return nil, fmt.Errorf("%s: argument must be a package path, not a relative path", arg)
3349 case filepath.IsAbs(p):
3350 return nil, fmt.Errorf("%s: argument must be a package path, not an absolute path", arg)
3351 case search.IsMetaPackage(p):
3352 return nil, fmt.Errorf("%s: argument must be a package path, not a meta-package", arg)
3353 case pathpkg.Clean(p) != p:
3354 return nil, fmt.Errorf("%s: argument must be a clean package path", arg)
3355 case !strings.Contains(p, "...") && search.IsStandardImportPath(p) && modindex.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, p):
3356 return nil, fmt.Errorf("%s: argument must not be a package in the standard library", arg)
3357 default:
3358 patterns[i] = p
3359 }
3360 }
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370 allowed := modload.CheckAllowed
3371 if modload.IsRevisionQuery(firstPath, version) {
3372
3373 allowed = nil
3374 }
3375 noneSelected := func(path string) (version string) { return "none" }
3376 qrs, err := modload.QueryPackages(ctx, patterns[0], version, noneSelected, allowed)
3377 if err != nil {
3378 return nil, fmt.Errorf("%s: %w", args[0], err)
3379 }
3380 rootMod := qrs[0].Mod
3381 deprecation, err := modload.CheckDeprecation(ctx, rootMod)
3382 if err != nil {
3383 return nil, fmt.Errorf("%s: %w", args[0], err)
3384 }
3385 if deprecation != "" {
3386 fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", rootMod.Path, modload.ShortMessage(deprecation, ""))
3387 }
3388 data, err := modfetch.GoMod(ctx, rootMod.Path, rootMod.Version)
3389 if err != nil {
3390 return nil, fmt.Errorf("%s: %w", args[0], err)
3391 }
3392 f, err := modfile.Parse("go.mod", data, nil)
3393 if err != nil {
3394 return nil, fmt.Errorf("%s (in %s): %w", args[0], rootMod, err)
3395 }
3396 directiveFmt := "%s (in %s):\n" +
3397 "\tThe go.mod file for the module providing named packages contains one or\n" +
3398 "\tmore %s directives. It must not contain directives that would cause\n" +
3399 "\tit to be interpreted differently than if it were the main module."
3400 if len(f.Replace) > 0 {
3401 return nil, fmt.Errorf(directiveFmt, args[0], rootMod, "replace")
3402 }
3403 if len(f.Exclude) > 0 {
3404 return nil, fmt.Errorf(directiveFmt, args[0], rootMod, "exclude")
3405 }
3406
3407
3408
3409
3410 if _, err := modload.EditBuildList(ctx, nil, []module.Version{rootMod}); err != nil {
3411 return nil, fmt.Errorf("%s: %w", args[0], err)
3412 }
3413
3414
3415 pkgs := PackagesAndErrors(ctx, opts, patterns)
3416
3417
3418 for _, pkg := range pkgs {
3419 var pkgErr error
3420 if pkg.Module == nil {
3421
3422
3423 pkgErr = fmt.Errorf("package %s not provided by module %s", pkg.ImportPath, rootMod)
3424 } else if pkg.Module.Path != rootMod.Path || pkg.Module.Version != rootMod.Version {
3425 pkgErr = fmt.Errorf("package %s provided by module %s@%s\n\tAll packages must be provided by the same module (%s).", pkg.ImportPath, pkg.Module.Path, pkg.Module.Version, rootMod)
3426 }
3427 if pkgErr != nil && pkg.Error == nil {
3428 pkg.Error = &PackageError{Err: pkgErr}
3429 pkg.Incomplete = true
3430 }
3431 }
3432
3433 matchers := make([]func(string) bool, len(patterns))
3434 for i, p := range patterns {
3435 if strings.Contains(p, "...") {
3436 matchers[i] = pkgpattern.MatchPattern(p)
3437 }
3438 }
3439 return pkgs, nil
3440 }
3441
3442
3443 func EnsureImport(p *Package, pkg string) {
3444 for _, d := range p.Internal.Imports {
3445 if d.Name == pkg {
3446 return
3447 }
3448 }
3449
3450 p1, err := LoadImportWithFlags(pkg, p.Dir, p, &ImportStack{}, nil, 0)
3451 if err != nil {
3452 base.Fatalf("load %s: %v", pkg, err)
3453 }
3454 if p1.Error != nil {
3455 base.Fatalf("load %s: %v", pkg, p1.Error)
3456 }
3457
3458 p.Internal.Imports = append(p.Internal.Imports, p1)
3459 }
3460
3461
3462
3463
3464
3465
3466 func PrepareForCoverageBuild(pkgs []*Package) {
3467 var match []func(*Package) bool
3468
3469 matchMainModAndCommandLine := func(p *Package) bool {
3470
3471 return p.Internal.CmdlineFiles || p.Internal.CmdlinePkg || (p.Module != nil && p.Module.Main)
3472 }
3473
3474 if len(cfg.BuildCoverPkg) != 0 {
3475
3476
3477 match = make([]func(*Package) bool, len(cfg.BuildCoverPkg))
3478 for i := range cfg.BuildCoverPkg {
3479 match[i] = MatchPackage(cfg.BuildCoverPkg[i], base.Cwd())
3480 }
3481 } else {
3482
3483
3484
3485 match = []func(*Package) bool{matchMainModAndCommandLine}
3486 }
3487
3488
3489
3490
3491 SelectCoverPackages(PackageList(pkgs), match, "build")
3492 }
3493
3494 func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op string) []*Package {
3495 var warntag string
3496 var includeMain bool
3497 switch op {
3498 case "build":
3499 warntag = "built"
3500 includeMain = true
3501 case "test":
3502 warntag = "tested"
3503 default:
3504 panic("internal error, bad mode passed to SelectCoverPackages")
3505 }
3506
3507 covered := []*Package{}
3508 matched := make([]bool, len(match))
3509 for _, p := range roots {
3510 haveMatch := false
3511 for i := range match {
3512 if match[i](p) {
3513 matched[i] = true
3514 haveMatch = true
3515 }
3516 }
3517 if !haveMatch {
3518 continue
3519 }
3520
3521
3522
3523 if p.ImportPath == "unsafe" {
3524 continue
3525 }
3526
3527
3528
3529
3530
3531
3532
3533
3534 if len(p.GoFiles)+len(p.CgoFiles) == 0 {
3535 continue
3536 }
3537
3538
3539
3540
3541
3542 if cfg.BuildCoverMode == "atomic" && p.Standard &&
3543 (p.ImportPath == "sync/atomic" || p.ImportPath == "internal/runtime/atomic") {
3544 continue
3545 }
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555 cmode := cfg.BuildCoverMode
3556 if cfg.BuildRace && p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal")) {
3557 cmode = "regonly"
3558 }
3559
3560
3561
3562
3563 if includeMain && p.Name == "main" && !haveMatch {
3564 haveMatch = true
3565 cmode = "regonly"
3566 }
3567
3568
3569 p.Internal.Cover.Mode = cmode
3570 covered = append(covered, p)
3571
3572
3573 if cfg.BuildCoverMode == "atomic" {
3574 EnsureImport(p, "sync/atomic")
3575 }
3576
3577
3578 if !cfg.Experiment.CoverageRedesign {
3579 var coverFiles []string
3580 coverFiles = append(coverFiles, p.GoFiles...)
3581 coverFiles = append(coverFiles, p.CgoFiles...)
3582 p.Internal.CoverVars = DeclareCoverVars(p, coverFiles...)
3583 }
3584 }
3585
3586
3587 for i := range cfg.BuildCoverPkg {
3588 if !matched[i] {
3589 fmt.Fprintf(os.Stderr, "warning: no packages being %s depend on matches for pattern %s\n", warntag, cfg.BuildCoverPkg[i])
3590 }
3591 }
3592
3593 return covered
3594 }
3595
3596
3597
3598
3599
3600 func DeclareCoverVars(p *Package, files ...string) map[string]*CoverVar {
3601 coverVars := make(map[string]*CoverVar)
3602 coverIndex := 0
3603
3604
3605
3606
3607
3608
3609 sum := sha256.Sum256([]byte(p.ImportPath))
3610 h := fmt.Sprintf("%x", sum[:6])
3611 for _, file := range files {
3612 if base.IsTestFile(file) {
3613 continue
3614 }
3615
3616
3617
3618
3619
3620 var longFile string
3621 if p.Internal.Local {
3622 longFile = filepath.Join(p.Dir, file)
3623 } else {
3624 longFile = pathpkg.Join(p.ImportPath, file)
3625 }
3626 coverVars[file] = &CoverVar{
3627 File: longFile,
3628 Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h),
3629 }
3630 coverIndex++
3631 }
3632 return coverVars
3633 }
3634
View as plain text