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