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