1
2
3
4
5
6
7 package work
8
9 import (
10 "bufio"
11 "bytes"
12 "cmd/internal/cov/covcmd"
13 "cmd/internal/par"
14 "container/heap"
15 "context"
16 "debug/elf"
17 "encoding/json"
18 "fmt"
19 "internal/platform"
20 "os"
21 "path/filepath"
22 "slices"
23 "strings"
24 "sync"
25 "time"
26
27 "cmd/go/internal/base"
28 "cmd/go/internal/cache"
29 "cmd/go/internal/cfg"
30 "cmd/go/internal/load"
31 "cmd/go/internal/modload"
32 "cmd/go/internal/str"
33 "cmd/go/internal/trace"
34 "cmd/internal/buildid"
35 "cmd/internal/robustio"
36 )
37
38
39
40
41 type Builder struct {
42 WorkDir string
43 getVendorDir func() string
44 actionCache map[cacheKey]*Action
45 flagCache map[[2]string]bool
46 gccCompilerIDCache map[string]cache.ActionID
47
48 IsCmdList bool
49 NeedError bool
50 NeedExport bool
51 NeedCompiledGoFiles bool
52 AllowErrors bool
53
54 objdirSeq int
55 pkgSeq int
56
57 backgroundSh *Shell
58
59 exec sync.Mutex
60 readySema chan bool
61 ready actionQueue
62
63 id sync.Mutex
64 toolIDCache par.Cache[string, string]
65 gccToolIDCache map[string]string
66 buildIDCache map[string]string
67 }
68
69
70
71
72
73 type Actor interface {
74 Act(*Builder, context.Context, *Action) error
75 }
76
77
78 type ActorFunc func(*Builder, context.Context, *Action) error
79
80 func (f ActorFunc) Act(b *Builder, ctx context.Context, a *Action) error {
81 return f(b, ctx, a)
82 }
83
84
85 type Action struct {
86 Mode string
87 Package *load.Package
88 Deps []*Action
89 Actor Actor
90 IgnoreFail bool
91 TestOutput *bytes.Buffer
92 Args []string
93
94 Provider any
95
96 triggers []*Action
97
98 buggyInstall bool
99
100 TryCache func(*Builder, *Action, *Action) bool
101
102 CacheExecutable bool
103
104
105 Objdir string
106 Target string
107 built string
108 cachedExecutable string
109 actionID cache.ActionID
110 buildID string
111
112 VetxOnly bool
113 needVet bool
114 needBuild bool
115 needFix bool
116 vetCfg *vetConfig
117 FixArchive string
118 output []byte
119
120 sh *Shell
121
122
123 pending int
124 priority int
125 Failed *Action
126 json *actionJSON
127 nonGoOverlay map[string]string
128 traceSpan *trace.Span
129 }
130
131
132 func (a *Action) BuildActionID() string { return actionID(a.buildID) }
133
134
135 func (a *Action) BuildContentID() string { return contentID(a.buildID) }
136
137
138 func (a *Action) BuildID() string { return a.buildID }
139
140
141
142 func (a *Action) BuiltTarget() string { return a.built }
143
144
145
146 func (a *Action) CachedExecutable() string { return a.cachedExecutable }
147
148
149 type actionQueue []*Action
150
151
152 func (q *actionQueue) Len() int { return len(*q) }
153 func (q *actionQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
154 func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
155 func (q *actionQueue) Push(x any) { *q = append(*q, x.(*Action)) }
156 func (q *actionQueue) Pop() any {
157 n := len(*q) - 1
158 x := (*q)[n]
159 *q = (*q)[:n]
160 return x
161 }
162
163 func (q *actionQueue) push(a *Action) {
164 if a.json != nil {
165 a.json.TimeReady = time.Now()
166 }
167 heap.Push(q, a)
168 }
169
170 func (q *actionQueue) pop() *Action {
171 return heap.Pop(q).(*Action)
172 }
173
174 type actionJSON struct {
175 ID int
176 Mode string
177 Package string
178 Deps []int `json:",omitempty"`
179 IgnoreFail bool `json:",omitempty"`
180 Args []string `json:",omitempty"`
181 Link bool `json:",omitempty"`
182 Objdir string `json:",omitempty"`
183 Target string `json:",omitempty"`
184 Priority int `json:",omitempty"`
185 Failed bool `json:",omitempty"`
186 Built string `json:",omitempty"`
187 VetxOnly bool `json:",omitempty"`
188 NeedVet bool `json:",omitempty"`
189 NeedBuild bool `json:",omitempty"`
190 ActionID string `json:",omitempty"`
191 BuildID string `json:",omitempty"`
192 TimeReady time.Time `json:",omitempty"`
193 TimeStart time.Time `json:",omitempty"`
194 TimeDone time.Time `json:",omitempty"`
195
196 Cmd []string
197 CmdReal time.Duration `json:",omitempty"`
198 CmdUser time.Duration `json:",omitempty"`
199 CmdSys time.Duration `json:",omitempty"`
200 }
201
202
203 type cacheKey struct {
204 mode string
205 p *load.Package
206 }
207
208 func actionGraphJSON(a *Action) string {
209 var workq []*Action
210 var inWorkq = make(map[*Action]int)
211
212 add := func(a *Action) {
213 if _, ok := inWorkq[a]; ok {
214 return
215 }
216 inWorkq[a] = len(workq)
217 workq = append(workq, a)
218 }
219 add(a)
220
221 for i := 0; i < len(workq); i++ {
222 for _, dep := range workq[i].Deps {
223 add(dep)
224 }
225 }
226
227 list := make([]*actionJSON, 0, len(workq))
228 for id, a := range workq {
229 if a.json == nil {
230 a.json = &actionJSON{
231 Mode: a.Mode,
232 ID: id,
233 IgnoreFail: a.IgnoreFail,
234 Args: a.Args,
235 Objdir: a.Objdir,
236 Target: a.Target,
237 Failed: a.Failed != nil,
238 Priority: a.priority,
239 Built: a.built,
240 VetxOnly: a.VetxOnly,
241 NeedBuild: a.needBuild,
242 NeedVet: a.needVet,
243 }
244 if a.Package != nil {
245
246 a.json.Package = a.Package.ImportPath
247 }
248 for _, a1 := range a.Deps {
249 a.json.Deps = append(a.json.Deps, inWorkq[a1])
250 }
251 }
252 list = append(list, a.json)
253 }
254
255 js, err := json.MarshalIndent(list, "", "\t")
256 if err != nil {
257 fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err)
258 return ""
259 }
260 return string(js)
261 }
262
263
264
265 type BuildMode int
266
267 const (
268 ModeBuild BuildMode = iota
269 ModeInstall
270 ModeBuggyInstall
271
272 ModeVetOnly = 1 << 8
273 )
274
275
276
277
278
279
280
281 func NewBuilder(workDir string, getVendorDir func() string) *Builder {
282 b := new(Builder)
283 b.getVendorDir = getVendorDir
284
285 b.actionCache = make(map[cacheKey]*Action)
286 b.gccToolIDCache = make(map[string]string)
287 b.buildIDCache = make(map[string]string)
288
289 printWorkDir := false
290 if workDir != "" {
291 b.WorkDir = workDir
292 } else if cfg.BuildN {
293 b.WorkDir = "$WORK"
294 } else {
295 if !buildInitStarted {
296 panic("internal error: NewBuilder called before BuildInit")
297 }
298 tmp, err := os.MkdirTemp(cfg.Getenv("GOTMPDIR"), "go-build")
299 if err != nil {
300 base.Fatalf("go: creating work dir: %v", err)
301 }
302 if !filepath.IsAbs(tmp) {
303 abs, err := filepath.Abs(tmp)
304 if err != nil {
305 os.RemoveAll(tmp)
306 base.Fatalf("go: creating work dir: %v", err)
307 }
308 tmp = abs
309 }
310 b.WorkDir = tmp
311 builderWorkDirs.Store(b, b.WorkDir)
312 printWorkDir = cfg.BuildX || cfg.BuildWork
313 }
314
315 b.backgroundSh = NewShell(b.WorkDir, nil)
316
317 if printWorkDir {
318 b.BackgroundShell().Printf("WORK=%s\n", b.WorkDir)
319 }
320
321 if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil {
322 fmt.Fprintf(os.Stderr, "go: %v\n", err)
323 base.SetExitStatus(2)
324 base.Exit()
325 }
326
327 for _, tag := range cfg.BuildContext.BuildTags {
328 if strings.Contains(tag, ",") {
329 fmt.Fprintf(os.Stderr, "go: -tags space-separated list contains comma\n")
330 base.SetExitStatus(2)
331 base.Exit()
332 }
333 }
334
335 return b
336 }
337
338 var builderWorkDirs sync.Map
339
340 func (b *Builder) Close() error {
341 wd, ok := builderWorkDirs.Load(b)
342 if !ok {
343 return nil
344 }
345 defer builderWorkDirs.Delete(b)
346
347 if b.WorkDir != wd.(string) {
348 base.Errorf("go: internal error: Builder WorkDir unexpectedly changed from %s to %s", wd, b.WorkDir)
349 }
350
351 if !cfg.BuildWork {
352 if err := robustio.RemoveAll(b.WorkDir); err != nil {
353 return err
354 }
355 }
356 b.WorkDir = ""
357 return nil
358 }
359
360 func closeBuilders() {
361 leakedBuilders := 0
362 builderWorkDirs.Range(func(bi, _ any) bool {
363 leakedBuilders++
364 if err := bi.(*Builder).Close(); err != nil {
365 base.Error(err)
366 }
367 return true
368 })
369
370 if leakedBuilders > 0 && base.GetExitStatus() == 0 {
371 fmt.Fprintf(os.Stderr, "go: internal error: Builder leaked on successful exit\n")
372 base.SetExitStatus(1)
373 }
374 }
375
376 func CheckGOOSARCHPair(goos, goarch string) error {
377 if !platform.BuildModeSupported(cfg.BuildContext.Compiler, "default", goos, goarch) {
378 return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch)
379 }
380 return nil
381 }
382
383
384
385
386
387
388
389
390
391 func (b *Builder) NewObjdir() string {
392 b.objdirSeq++
393 return str.WithFilePathSeparator(filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)))
394 }
395
396
397
398
399
400 func readpkglist(s *modload.State, shlibpath string) (pkgs []*load.Package) {
401 var stk load.ImportStack
402 if cfg.BuildToolchainName == "gccgo" {
403 f, err := elf.Open(shlibpath)
404 if err != nil {
405 base.Fatal(fmt.Errorf("failed to open shared library: %v", err))
406 }
407 defer f.Close()
408 sect := f.Section(".go_export")
409 if sect == nil {
410 base.Fatal(fmt.Errorf("%s: missing .go_export section", shlibpath))
411 }
412 data, err := sect.Data()
413 if err != nil {
414 base.Fatal(fmt.Errorf("%s: failed to read .go_export section: %v", shlibpath, err))
415 }
416 pkgpath := []byte("pkgpath ")
417 for _, line := range bytes.Split(data, []byte{'\n'}) {
418 if path, found := bytes.CutPrefix(line, pkgpath); found {
419 path = bytes.TrimSuffix(path, []byte{';'})
420 pkgs = append(pkgs, load.LoadPackageWithFlags(s, string(path), base.Cwd(), &stk, nil, 0))
421 }
422 }
423 } else {
424 pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1)
425 if err != nil {
426 base.Fatalf("readELFNote failed: %v", err)
427 }
428 scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
429 for scanner.Scan() {
430 t := scanner.Text()
431 pkgs = append(pkgs, load.LoadPackageWithFlags(s, t, base.Cwd(), &stk, nil, 0))
432 }
433 }
434 return
435 }
436
437
438
439
440
441 func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action {
442 a := b.actionCache[cacheKey{mode, p}]
443 if a == nil {
444 a = f()
445 b.actionCache[cacheKey{mode, p}] = a
446 }
447 return a
448 }
449
450
451 func (b *Builder) AutoAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
452 if p.Name == "main" {
453 return b.LinkAction(s, mode, depMode, p)
454 }
455 return b.CompileAction(mode, depMode, p)
456 }
457
458
459
460
461 type buildActor struct{}
462
463 func (ba *buildActor) Act(b *Builder, ctx context.Context, a *Action) error {
464 return b.build(ctx, a)
465 }
466
467
468 func (b *Builder) pgoActionID(input string) cache.ActionID {
469 h := cache.NewHash("preprocess PGO profile " + input)
470
471 fmt.Fprintf(h, "preprocess PGO profile\n")
472 fmt.Fprintf(h, "preprofile %s\n", b.toolID("preprofile"))
473 fmt.Fprintf(h, "input %q\n", b.fileHash(input))
474
475 return h.Sum()
476 }
477
478
479 type pgoActor struct {
480
481 input string
482 }
483
484 func (p *pgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
485 if b.useCache(a, b.pgoActionID(p.input), a.Target, !b.IsCmdList) || b.IsCmdList {
486 return nil
487 }
488 defer b.flushOutput(a)
489
490 sh := b.Shell(a)
491
492 if err := sh.Mkdir(a.Objdir); err != nil {
493 return err
494 }
495
496 if err := sh.run(".", p.input, nil, cfg.BuildToolexec, base.Tool("preprofile"), "-o", a.Target, "-i", p.input); err != nil {
497 return err
498 }
499
500
501
502 a.built = a.Target
503
504 if !cfg.BuildN {
505
506
507
508
509
510
511 r, err := os.Open(a.Target)
512 if err != nil {
513 return fmt.Errorf("error opening target for caching: %w", err)
514 }
515
516 c := cache.Default()
517 outputID, _, err := c.Put(a.actionID, r)
518 r.Close()
519 if err != nil {
520 return fmt.Errorf("error adding target to cache: %w", err)
521 }
522 if cfg.BuildX {
523 sh.ShowCmd("", "%s # internal", joinUnambiguously(str.StringList("cp", a.Target, c.OutputFile(outputID))))
524 }
525 }
526
527 return nil
528 }
529
530 type checkCacheProvider struct {
531 need uint32
532 }
533
534
535
536
537
538
539
540
541
542 type checkCacheActor struct {
543 covMetaFileName string
544 buildAction *Action
545 }
546
547 func (cca *checkCacheActor) Act(b *Builder, ctx context.Context, a *Action) error {
548 buildAction := cca.buildAction
549 if buildAction.Mode == "build-install" {
550
551
552 buildAction = buildAction.Deps[0]
553 }
554 pr, err := b.checkCacheForBuild(a, buildAction, cca.covMetaFileName)
555 if err != nil {
556 return err
557 }
558 a.Provider = pr
559 return nil
560 }
561
562 type coverProvider struct {
563 goSources, cgoSources []string
564 }
565
566
567
568
569 type coverActor struct {
570
571
572
573 covMetaFileName string
574
575 buildAction *Action
576 }
577
578 func (ca *coverActor) Act(b *Builder, ctx context.Context, a *Action) error {
579 pr, err := b.runCover(a, ca.buildAction, a.Objdir, a.Package.GoFiles, a.Package.CgoFiles)
580 if err != nil {
581 return err
582 }
583 a.Provider = pr
584 return nil
585 }
586
587
588 type runCgoActor struct {
589 }
590
591 func (c runCgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
592 var cacheProvider *checkCacheProvider
593 for _, a1 := range a.Deps {
594 if pr, ok := a1.Provider.(*checkCacheProvider); ok {
595 cacheProvider = pr
596 break
597 }
598 }
599 need := cacheProvider.need
600 need &^= needCovMetaFile
601 if need == 0 {
602 return nil
603 }
604 return b.runCgo(ctx, a)
605 }
606
607 type cgoCompileActor struct {
608 file string
609
610 compileFunc func(*Action, string, string, []string, string) error
611 getFlagsFunc func(*runCgoProvider) []string
612
613 flags *[]string
614 }
615
616 func (c cgoCompileActor) Act(b *Builder, ctx context.Context, a *Action) error {
617 pr, ok := a.Deps[0].Provider.(*runCgoProvider)
618 if !ok {
619 return nil
620 }
621 a.nonGoOverlay = pr.nonGoOverlay
622 buildAction := a.triggers[0].triggers[0]
623
624 a.actionID = cache.Subkey(buildAction.actionID, "cgo compile "+c.file)
625 return c.compileFunc(a, a.Objdir, a.Target, c.getFlagsFunc(pr), c.file)
626 }
627
628
629
630
631
632
633 func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
634 vetOnly := mode&ModeVetOnly != 0
635 mode &^= ModeVetOnly
636
637 if mode != ModeBuild && p.Target == "" {
638
639 mode = ModeBuild
640 }
641 if mode != ModeBuild && p.Name == "main" {
642
643 mode = ModeBuild
644 }
645
646
647 a := b.cacheAction("build", p, func() *Action {
648 a := &Action{
649 Mode: "build",
650 Package: p,
651 Actor: &buildActor{},
652 Objdir: b.NewObjdir(),
653 }
654
655 if p.Error == nil || !p.Error.IsImportCycle {
656 for _, p1 := range p.Internal.Imports {
657 a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
658 }
659 }
660
661 if p.Internal.PGOProfile != "" {
662 pgoAction := b.cacheAction("preprocess PGO profile "+p.Internal.PGOProfile, nil, func() *Action {
663 a := &Action{
664 Mode: "preprocess PGO profile",
665 Actor: &pgoActor{input: p.Internal.PGOProfile},
666 Objdir: b.NewObjdir(),
667 }
668 a.Target = filepath.Join(a.Objdir, "pgo.preprofile")
669
670 return a
671 })
672 a.Deps = append(a.Deps, pgoAction)
673 }
674
675 if p.Standard {
676 switch p.ImportPath {
677 case "builtin", "unsafe":
678
679 a.Mode = "built-in package"
680 a.Actor = nil
681 return a
682 }
683
684
685 if cfg.BuildToolchainName == "gccgo" {
686
687 a.Mode = "gccgo stdlib"
688 a.Target = p.Target
689 a.Actor = nil
690 return a
691 }
692 }
693
694
695 var covMetaFileName string
696 if p.Internal.Cover.GenMeta {
697 covMetaFileName = covcmd.MetaFileForPackage(p.ImportPath)
698 }
699
700
701 cacheAction := &Action{
702 Mode: "build check cache",
703 Package: p,
704 Actor: &checkCacheActor{buildAction: a, covMetaFileName: covMetaFileName},
705 Objdir: a.Objdir,
706 Deps: a.Deps,
707 }
708 a.Deps = append(a.Deps, cacheAction)
709
710
711
712
713 var coverAction *Action
714 if p.Internal.Cover.Mode != "" {
715 coverAction = b.cacheAction("cover", p, func() *Action {
716 return &Action{
717 Mode: "cover",
718 Package: p,
719 Actor: &coverActor{buildAction: a, covMetaFileName: covMetaFileName},
720 Objdir: a.Objdir,
721 Deps: []*Action{cacheAction},
722 }
723 })
724 a.Deps = append(a.Deps, coverAction)
725 }
726
727
728
729
730 if p.UsesCgo() || p.UsesSwig() {
731 deps := []*Action{cacheAction}
732 if coverAction != nil {
733 deps = append(deps, coverAction)
734 }
735 a.Deps = append(a.Deps, b.cgoAction(p, a.Objdir, deps, coverAction != nil))
736 }
737
738 return a
739 })
740
741
742
743 buildAction := a
744 switch buildAction.Mode {
745 case "build", "built-in package", "gccgo stdlib":
746
747 case "build-install":
748 buildAction = a.Deps[0]
749 default:
750 panic("lost build action: " + buildAction.Mode)
751 }
752 buildAction.needBuild = buildAction.needBuild || !vetOnly
753
754
755 if mode == ModeInstall || mode == ModeBuggyInstall {
756 a = b.installAction(a, mode)
757 }
758
759 return a
760 }
761
762 func (b *Builder) cgoAction(p *load.Package, objdir string, deps []*Action, hasCover bool) *Action {
763 cgoCollectAction := b.cacheAction("cgo collect", p, func() *Action {
764
765 runCgo := b.cacheAction("cgo run", p, func() *Action {
766 return &Action{
767 Package: p,
768 Mode: "cgo run",
769 Actor: &runCgoActor{},
770 Objdir: objdir,
771 Deps: deps,
772 }
773 })
774
775
776
777
778 swigGo, swigC, swigCXX := b.swigOutputs(p, objdir)
779
780 oseq := 0
781 nextOfile := func() string {
782 oseq++
783 return objdir + fmt.Sprintf("_x%03d.o", oseq)
784 }
785 compileAction := func(file string, getFlagsFunc func(*runCgoProvider) []string, compileFunc func(*Action, string, string, []string, string) error) *Action {
786 mode := "cgo compile " + file
787 return b.cacheAction(mode, p, func() *Action {
788 return &Action{
789 Package: p,
790 Mode: mode,
791 Actor: &cgoCompileActor{file: file, getFlagsFunc: getFlagsFunc, compileFunc: compileFunc},
792 Deps: []*Action{runCgo},
793 Objdir: objdir,
794 Target: nextOfile(),
795 }
796 })
797 }
798
799 var collectDeps []*Action
800
801
802 cgoFiles := p.CgoFiles
803 if hasCover {
804 cgoFiles = slices.Clone(cgoFiles)
805 for i := range cgoFiles {
806 cgoFiles[i] = strings.TrimSuffix(cgoFiles[i], ".go") + ".cover.go"
807 }
808 }
809 cfiles := []string{"_cgo_export.c"}
810 for _, fn := range slices.Concat(cgoFiles, swigGo) {
811 cfiles = append(cfiles, strings.TrimSuffix(filepath.Base(fn), ".go")+".cgo2.c")
812 }
813 for _, f := range cfiles {
814 collectDeps = append(collectDeps, compileAction(objdir+f, (*runCgoProvider).cflags, b.gcc))
815 }
816
817
818 var sfiles []string
819
820
821
822
823 if p.Standard && p.ImportPath == "runtime/cgo" {
824 for _, f := range p.SFiles {
825 if strings.HasPrefix(f, "gcc_") {
826 sfiles = append(sfiles, f)
827 }
828 }
829 } else {
830 sfiles = p.SFiles
831 }
832 for _, f := range sfiles {
833 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cflags, b.gas))
834 }
835
836
837 for _, f := range slices.Concat(p.CFiles, p.MFiles, swigC) {
838 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cflags, b.gcc))
839 }
840
841
842 for _, f := range slices.Concat(p.CXXFiles, swigCXX) {
843 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cxxflags, b.gxx))
844 }
845
846
847 for _, f := range p.FFiles {
848 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).fflags, b.gfortran))
849 }
850
851
852
853
854 return &Action{
855 Mode: "collect cgo",
856 Actor: ActorFunc(func(b *Builder, ctx context.Context, a *Action) error {
857
858
859 a.Provider = a.Deps[0].Deps[0].Provider
860 return nil
861 }),
862 Deps: collectDeps,
863 Objdir: objdir,
864 }
865 })
866
867 return cgoCollectAction
868 }
869
870
871
872
873
874 func (b *Builder) VetAction(s *modload.State, mode, depMode BuildMode, needFix bool, p *load.Package) *Action {
875 a := b.vetAction(s, mode, depMode, p)
876 a.VetxOnly = false
877 a.needFix = needFix
878 return a
879 }
880
881 func (b *Builder) vetAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
882
883 a := b.cacheAction("vet", p, func() *Action {
884 a1 := b.CompileAction(mode|ModeVetOnly, depMode, p)
885
886 var deps []*Action
887 if a1.buggyInstall {
888
889
890
891
892 deps = []*Action{a1.Deps[0], a1}
893 } else {
894 deps = []*Action{a1}
895 }
896 for _, p1 := range p.Internal.Imports {
897 deps = append(deps, b.vetAction(s, mode, depMode, p1))
898 }
899
900 a := &Action{
901 Mode: "vet",
902 Package: p,
903 Deps: deps,
904 Objdir: a1.Objdir,
905 VetxOnly: true,
906 IgnoreFail: true,
907 }
908 if a1.Actor == nil {
909
910 return a
911 }
912 deps[0].needVet = true
913 a.Actor = ActorFunc((*Builder).vet)
914 return a
915 })
916 return a
917 }
918
919
920
921
922 func (b *Builder) LinkAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
923
924 a := b.cacheAction("link", p, func() *Action {
925 a := &Action{
926 Mode: "link",
927 Package: p,
928 }
929
930 a1 := b.CompileAction(ModeBuild, depMode, p)
931 a.Actor = ActorFunc((*Builder).link)
932 a.Deps = []*Action{a1}
933 a.Objdir = a1.Objdir
934
935
936
937
938
939
940
941
942 name := "a.out"
943 if p.Internal.ExeName != "" {
944 name = p.Internal.ExeName
945 } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" {
946
947
948
949
950
951
952
953 _, name = filepath.Split(p.Target)
954 }
955 a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
956 a.built = a.Target
957 b.addTransitiveLinkDeps(s, a, a1, "")
958
959
960
961
962
963
964
965
966 a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]})
967 return a
968 })
969
970 if mode == ModeInstall || mode == ModeBuggyInstall {
971 a = b.installAction(a, mode)
972 }
973
974 return a
975 }
976
977
978 func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action {
979
980
981
982 if strings.HasSuffix(a1.Mode, "-install") {
983 if a1.buggyInstall && mode == ModeInstall {
984
985 a1.buggyInstall = false
986 }
987 return a1
988 }
989
990
991
992
993 if a1.Actor == nil {
994 return a1
995 }
996
997 p := a1.Package
998 return b.cacheAction(a1.Mode+"-install", p, func() *Action {
999
1000
1001
1002
1003
1004
1005
1006 buildAction := new(Action)
1007 *buildAction = *a1
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017 *a1 = Action{
1018 Mode: buildAction.Mode + "-install",
1019 Actor: ActorFunc(BuildInstallFunc),
1020 Package: p,
1021 Objdir: buildAction.Objdir,
1022 Deps: []*Action{buildAction},
1023 Target: p.Target,
1024 built: p.Target,
1025
1026 buggyInstall: mode == ModeBuggyInstall,
1027 }
1028
1029 b.addInstallHeaderAction(a1)
1030 return a1
1031 })
1032 }
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043 func (b *Builder) addTransitiveLinkDeps(s *modload.State, a, a1 *Action, shlib string) {
1044
1045
1046
1047
1048
1049 workq := []*Action{a1}
1050 haveDep := map[string]bool{}
1051 if a1.Package != nil {
1052 haveDep[a1.Package.ImportPath] = true
1053 }
1054 for i := 0; i < len(workq); i++ {
1055 a1 := workq[i]
1056 for _, a2 := range a1.Deps {
1057
1058 if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] {
1059 continue
1060 }
1061 haveDep[a2.Package.ImportPath] = true
1062 a.Deps = append(a.Deps, a2)
1063 if a2.Mode == "build-install" {
1064 a2 = a2.Deps[0]
1065 }
1066 workq = append(workq, a2)
1067 }
1068 }
1069
1070
1071
1072 if cfg.BuildLinkshared {
1073 haveShlib := map[string]bool{shlib: true}
1074 for _, a1 := range a.Deps {
1075 p1 := a1.Package
1076 if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] {
1077 continue
1078 }
1079 haveShlib[filepath.Base(p1.Shlib)] = true
1080
1081
1082
1083
1084 a.Deps = append(a.Deps, b.linkSharedAction(s, ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil))
1085 }
1086 }
1087 }
1088
1089
1090
1091
1092
1093 func (b *Builder) addInstallHeaderAction(a *Action) {
1094
1095 p := a.Package
1096 if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
1097 hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h"
1098 if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" {
1099
1100
1101
1102 dir, file := filepath.Split(hdrTarget)
1103 file = strings.TrimPrefix(file, "lib")
1104 hdrTarget = filepath.Join(dir, file)
1105 }
1106 ah := &Action{
1107 Mode: "install header",
1108 Package: a.Package,
1109 Deps: []*Action{a.Deps[0]},
1110 Actor: ActorFunc((*Builder).installHeader),
1111 Objdir: a.Deps[0].Objdir,
1112 Target: hdrTarget,
1113 }
1114 a.Deps = append(a.Deps, ah)
1115 }
1116 }
1117
1118
1119
1120 func (b *Builder) buildmodeShared(s *modload.State, mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action {
1121 name, err := libname(args, pkgs)
1122 if err != nil {
1123 base.Fatalf("%v", err)
1124 }
1125 return b.linkSharedAction(s, mode, depMode, name, a1)
1126 }
1127
1128
1129
1130
1131
1132 func (b *Builder) linkSharedAction(s *modload.State, mode, depMode BuildMode, shlib string, a1 *Action) *Action {
1133 fullShlib := shlib
1134 shlib = filepath.Base(shlib)
1135 a := b.cacheAction("build-shlib "+shlib, nil, func() *Action {
1136 if a1 == nil {
1137
1138
1139 pkgs := readpkglist(s, fullShlib)
1140 a1 = &Action{
1141 Mode: "shlib packages",
1142 }
1143 for _, p := range pkgs {
1144 a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p))
1145 }
1146 }
1147
1148
1149
1150
1151 p := &load.Package{}
1152 p.Internal.CmdlinePkg = true
1153 p.Internal.Ldflags = load.BuildLdflags.For(s, p)
1154 p.Internal.Gccgoflags = load.BuildGccgoflags.For(s, p)
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166 a := &Action{
1167 Mode: "go build -buildmode=shared",
1168 Package: p,
1169 Objdir: b.NewObjdir(),
1170 Actor: ActorFunc((*Builder).linkShared),
1171 Deps: []*Action{a1},
1172 }
1173 a.Target = filepath.Join(a.Objdir, shlib)
1174 if cfg.BuildToolchainName != "gccgo" {
1175 add := func(a1 *Action, pkg string, force bool) {
1176 for _, a2 := range a1.Deps {
1177 if a2.Package != nil && a2.Package.ImportPath == pkg {
1178 return
1179 }
1180 }
1181 var stk load.ImportStack
1182 p := load.LoadPackageWithFlags(s, pkg, base.Cwd(), &stk, nil, 0)
1183 if p.Error != nil {
1184 base.Fatalf("load %s: %v", pkg, p.Error)
1185 }
1186
1187
1188
1189
1190
1191 if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg {
1192 a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p))
1193 }
1194 }
1195 add(a1, "runtime/cgo", false)
1196 if cfg.Goarch == "arm" {
1197 add(a1, "math", false)
1198 }
1199
1200
1201
1202 ldDeps, err := load.LinkerDeps(s, nil)
1203 if err != nil {
1204 base.Error(err)
1205 }
1206 for _, dep := range ldDeps {
1207 add(a, dep, true)
1208 }
1209 }
1210 b.addTransitiveLinkDeps(s, a, a1, shlib)
1211 return a
1212 })
1213
1214
1215 if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Actor != nil {
1216 buildAction := a
1217
1218 a = b.cacheAction("install-shlib "+shlib, nil, func() *Action {
1219
1220
1221
1222
1223
1224
1225 pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot
1226 for _, a2 := range a1.Deps {
1227 if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir {
1228 base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s",
1229 a1.Deps[0].Package.ImportPath,
1230 a2.Package.ImportPath,
1231 pkgDir,
1232 dir)
1233 }
1234 }
1235
1236 if cfg.BuildToolchainName == "gccgo" {
1237 pkgDir = filepath.Join(pkgDir, "shlibs")
1238 }
1239 target := filepath.Join(pkgDir, shlib)
1240
1241 a := &Action{
1242 Mode: "go install -buildmode=shared",
1243 Objdir: buildAction.Objdir,
1244 Actor: ActorFunc(BuildInstallFunc),
1245 Deps: []*Action{buildAction},
1246 Target: target,
1247 }
1248 for _, a2 := range buildAction.Deps[0].Deps {
1249 p := a2.Package
1250 pkgTargetRoot := p.Internal.Build.PkgTargetRoot
1251 if pkgTargetRoot == "" {
1252 continue
1253 }
1254 a.Deps = append(a.Deps, &Action{
1255 Mode: "shlibname",
1256 Package: p,
1257 Actor: ActorFunc((*Builder).installShlibname),
1258 Target: filepath.Join(pkgTargetRoot, p.ImportPath+".shlibname"),
1259 Deps: []*Action{a.Deps[0]},
1260 })
1261 }
1262 return a
1263 })
1264 }
1265
1266 return a
1267 }
1268
View as plain text