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