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