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