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