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