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