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