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