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