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