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