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