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