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