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 buildActionID(a.buildID) }
132
133
134 func (a *Action) BuildContentID() string { return buildObjectID(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 a := b.CompileAction(mode, depMode, p)
455
456 exportAction := b.BuildExportAction(mode, depMode, p)
457 b.addTransitiveCompileActions(a, exportAction)
458 return a
459 }
460
461
462 type exportProvider struct {
463 exportFile string
464 objects []string
465 cgoObjects []string
466 cfiles []string
467 sfiles []string
468 output []byte
469 compile *shellCmd
470 }
471
472
473 func (b *Builder) pgoActionID(input string) cache.ActionID {
474 h := cache.NewHash("preprocess PGO profile " + input)
475
476 fmt.Fprintf(h, "preprocess PGO profile\n")
477 fmt.Fprintf(h, "preprofile %s\n", b.toolID("preprofile"))
478 fmt.Fprintf(h, "input %q\n", b.fileHash(input))
479
480 return h.Sum()
481 }
482
483
484 type pgoActor struct {
485
486 input string
487 }
488
489 func (p *pgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
490 if b.useCache(a, b.pgoActionID(p.input), a.Target, !b.IsCmdList) || b.IsCmdList {
491 return nil
492 }
493 defer b.flushOutput(a)
494
495 sh := b.Shell(a)
496
497 if err := sh.Mkdir(a.Objdir); err != nil {
498 return err
499 }
500
501 if err := sh.run(".", p.input, nil, cfg.BuildToolexec, base.Tool("preprofile"), "-o", a.Target, "-i", p.input); err != nil {
502 return err
503 }
504
505
506
507 a.built = a.Target
508
509 if !cfg.BuildN {
510
511
512
513
514
515
516 r, err := os.Open(a.Target)
517 if err != nil {
518 return fmt.Errorf("error opening target for caching: %w", err)
519 }
520
521 c := cache.Default()
522 outputID, _, err := c.Put(a.actionID, r)
523 r.Close()
524 if err != nil {
525 return fmt.Errorf("error adding target to cache: %w", err)
526 }
527 if cfg.BuildX {
528 sh.ShowCmd("", "%s # internal", joinUnambiguously(str.StringList("cp", a.Target, c.OutputFile(outputID))))
529 }
530 }
531
532 return nil
533 }
534
535 type coverProvider struct {
536
537
538
539 covMetaFileName string
540
541
542
543 coverageConfig string
544
545 goSources, cgoSources []string
546 }
547
548
549 type runCgoActor struct {
550 }
551
552 func (c runCgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
553 return b.runCgo(ctx, a)
554 }
555
556 type cgoCompileActor struct {
557 file string
558
559 compileFunc func(*Action, string, string, []string, string) error
560 getFlagsFunc func(*runCgoProvider) []string
561 }
562
563 func (c cgoCompileActor) Act(b *Builder, ctx context.Context, a *Action) error {
564 pr, ok := a.Deps[0].Provider.(*runCgoProvider)
565 if !ok {
566 base.Fatalf("internal error: missing runCgoProvider")
567 }
568 a.nonGoOverlay = pr.nonGoOverlay
569
570 a.actionID = b.cgoCompileActionID(a, c.file, c.getFlagsFunc(pr))
571 targetBase := filepath.Base(a.Target)
572 if err := b.loadCachedObjdirFile(a, cache.Default(), targetBase); err == nil {
573 a.built = a.Target
574 return nil
575 }
576 defer b.flushOutput(a)
577
578 if err := c.compileFunc(a, a.Objdir, a.Target, c.getFlagsFunc(pr), c.file); err != nil {
579 return err
580 }
581
582 if !cfg.BuildN {
583 b.cacheObjdirFile(a, cache.Default(), targetBase)
584 }
585
586 return nil
587 }
588
589
590
591
592
593
594
595 func (b *Builder) BuildExportAction(mode, depMode BuildMode, p *load.Package) *Action {
596 vetOnly := mode&ModeVetOnly != 0
597 mode &^= ModeVetOnly
598
599 a := b.cacheAction("build-export", p, func() *Action {
600 a := &Action{
601 Mode: "build-export",
602 Package: p,
603 Actor: ActorFunc((*Builder).buildExport),
604 Objdir: b.NewObjdir(),
605 }
606
607 if p.Error == nil || !p.Error.IsImportCycle {
608 for _, p1 := range p.Internal.Imports {
609 if cfg.BuildToolchainName == "gccgo" {
610
611 a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
612 } else {
613 a.Deps = append(a.Deps, b.BuildExportAction(depMode, depMode, p1))
614 }
615 }
616 }
617
618 if p.Internal.PGOProfile != "" {
619 pgoAction := b.cacheAction("preprocess PGO profile "+p.Internal.PGOProfile, nil, func() *Action {
620 a := &Action{
621 Mode: "preprocess PGO profile",
622 Actor: &pgoActor{input: p.Internal.PGOProfile},
623 Objdir: b.NewObjdir(),
624 }
625 a.Target = filepath.Join(a.Objdir, "pgo.preprofile")
626
627 return a
628 })
629 a.Deps = append(a.Deps, pgoAction)
630 }
631
632 if p.Standard {
633 switch p.ImportPath {
634 case "builtin", "unsafe":
635
636 a.Mode = "built-in package"
637 a.Actor = nil
638 return a
639 }
640
641
642 if cfg.BuildToolchainName == "gccgo" {
643
644 a.Mode = "gccgo stdlib"
645 a.Target = p.Target
646 a.Actor = nil
647 return a
648 }
649 }
650
651
652
653
654 var coverAction *Action
655 if p.Internal.Cover.Mode != "" {
656 coverAction = b.cacheAction("cover", p, func() *Action {
657 return &Action{
658 Mode: "cover",
659 Package: p,
660 Actor: ActorFunc((*Builder).runCover),
661 Objdir: a.Objdir,
662 }
663 })
664 a.Deps = append(a.Deps, coverAction)
665 }
666
667
668
669 if p.UsesCgo() || p.UsesSwig() {
670 var cgoDeps []*Action
671 if coverAction != nil {
672 cgoDeps = append(cgoDeps, coverAction)
673 }
674 a.Deps = append(a.Deps, b.cgoAction(p, a.Objdir, cgoDeps, coverAction != nil))
675 }
676
677 return a
678 })
679 a.needBuild = a.needBuild || !vetOnly
680 return a
681 }
682
683
684
685
686
687
688 func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
689 if mode != ModeBuild && p.Target == "" {
690
691 mode = ModeBuild
692 }
693 if mode != ModeBuild && p.Name == "main" {
694
695 mode = ModeBuild
696 }
697
698 a := b.cacheAction("build", p, func() *Action {
699 exportAction := b.BuildExportAction(mode, depMode, p)
700 if exportAction.Actor == nil {
701 return exportAction
702 }
703
704 a := &Action{
705 Mode: "build",
706 Package: p,
707 Actor: ActorFunc((*Builder).buildObject),
708 Objdir: exportAction.Objdir,
709 Deps: []*Action{exportAction},
710 IgnoreFail: true,
711 }
712
713 return a
714 })
715
716
717 if mode == ModeInstall || mode == ModeBuggyInstall {
718 a = b.installAction(a, mode)
719 }
720
721 return a
722 }
723
724 func (b *Builder) cgoAction(p *load.Package, objdir string, deps []*Action, hasCover bool) *Action {
725 cgoCollectAction := b.cacheAction("cgo collect", p, func() *Action {
726
727 runCgo := b.cacheAction("cgo run", p, func() *Action {
728 return &Action{
729 Package: p,
730 Mode: "cgo run",
731 Actor: &runCgoActor{},
732 Objdir: objdir,
733 Deps: deps,
734 }
735 })
736
737
738
739
740 swigGo, swigC, swigCXX := b.swigOutputs(p, objdir)
741
742 oseq := 0
743 nextOfile := func() string {
744 oseq++
745 return objdir + fmt.Sprintf("_x%03d.o", oseq)
746 }
747 compileAction := func(file string, getFlagsFunc func(*runCgoProvider) []string, compileFunc func(*Action, string, string, []string, string) error) *Action {
748 mode := "cgo compile " + file
749 return b.cacheAction(mode, p, func() *Action {
750 return &Action{
751 Package: p,
752 Mode: mode,
753 Actor: &cgoCompileActor{file: file, getFlagsFunc: getFlagsFunc, compileFunc: compileFunc},
754 Deps: []*Action{runCgo},
755 Objdir: objdir,
756 Target: nextOfile(),
757 }
758 })
759 }
760
761 var collectDeps []*Action
762
763
764 cgoFiles := p.CgoFiles
765 if hasCover {
766 cgoFiles = slices.Clone(cgoFiles)
767 for i := range cgoFiles {
768 cgoFiles[i] = strings.TrimSuffix(cgoFiles[i], ".go") + ".cover.go"
769 }
770 }
771 cfiles := []string{"_cgo_export.c"}
772 for _, fn := range slices.Concat(cgoFiles, swigGo) {
773 cfiles = append(cfiles, strings.TrimSuffix(filepath.Base(fn), ".go")+".cgo2.c")
774 }
775 for _, f := range cfiles {
776 collectDeps = append(collectDeps, compileAction(objdir+f, (*runCgoProvider).cflags, b.gcc))
777 }
778
779
780 var sfiles []string
781
782
783
784
785 if p.Standard && p.ImportPath == "runtime/cgo" {
786 for _, f := range p.SFiles {
787 if strings.HasPrefix(f, "gcc_") {
788 sfiles = append(sfiles, f)
789 }
790 }
791 } else {
792 sfiles = p.SFiles
793 }
794 for _, f := range sfiles {
795 collectDeps = append(collectDeps, compileAction(mkAbs(p.Dir, f), (*runCgoProvider).cflags, b.gas))
796 }
797
798
799 for _, f := range slices.Concat(p.CFiles, p.MFiles) {
800 collectDeps = append(collectDeps, compileAction(filepath.Join(p.Dir, f), (*runCgoProvider).cflags, b.gcc))
801 }
802
803 for _, f := range swigC {
804 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cflags, b.gcc))
805 }
806
807
808 for _, f := range p.CXXFiles {
809 collectDeps = append(collectDeps, compileAction(filepath.Join(p.Dir, f), (*runCgoProvider).cxxflags, b.gxx))
810 }
811
812 for _, f := range swigCXX {
813 collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cxxflags, b.gxx))
814 }
815
816
817 for _, f := range p.FFiles {
818 collectDeps = append(collectDeps, compileAction(filepath.Join(p.Dir, f), (*runCgoProvider).fflags, b.gfortran))
819 }
820
821
822
823
824 return &Action{
825 Mode: "collect cgo",
826 Actor: ActorFunc(func(b *Builder, ctx context.Context, a *Action) error {
827
828
829 a.Provider = a.Deps[0].Deps[0].Provider
830 return nil
831 }),
832 Deps: collectDeps,
833 Objdir: objdir,
834 }
835 })
836
837 return cgoCollectAction
838 }
839
840
841
842
843
844 func (b *Builder) VetAction(s *modload.Loader, mode, depMode BuildMode, needFix bool, p *load.Package) *Action {
845 a := b.vetAction(s, mode, depMode, p)
846 a.VetxOnly = false
847 a.needFix = needFix
848 return a
849 }
850
851 func (b *Builder) vetAction(s *modload.Loader, mode, depMode BuildMode, p *load.Package) *Action {
852
853 a := b.cacheAction("vet", p, func() *Action {
854 a1 := b.BuildExportAction(mode|ModeVetOnly, depMode, p)
855
856 var deps []*Action
857 if a1.buggyInstall {
858
859
860
861
862 deps = []*Action{a1.Deps[0], a1}
863 } else {
864 deps = []*Action{a1}
865 }
866 for _, p1 := range p.Internal.Imports {
867 deps = append(deps, b.vetAction(s, mode, depMode, p1))
868 }
869
870 a := &Action{
871 Mode: "vet",
872 Package: p,
873 Deps: deps,
874 Objdir: a1.Objdir,
875 VetxOnly: true,
876 IgnoreFail: true,
877 }
878 if a1.Actor == nil {
879
880 return a
881 }
882 deps[0].needVet = true
883 a.Actor = ActorFunc((*Builder).vet)
884 b.addTransitiveCompileActions(a, a1)
885 return a
886 })
887 return a
888 }
889
890
891 func (b *Builder) ExportAction(p *load.Package) *Action {
892
893 if p.Standard && p.ImportPath == "unsafe" {
894 return &Action{
895 Mode: "built-in package",
896 Package: p,
897 }
898 }
899
900 return b.cacheAction("export", p, func() *Action {
901 a := &Action{
902 Mode: "export",
903 Package: p,
904 Deps: make([]*Action, len(p.Internal.Imports)),
905 Actor: ActorFunc((*Builder).export),
906 Objdir: b.NewObjdir(),
907 }
908 a.Target = a.Objdir + "export"
909 for i, imp := range p.Internal.Imports {
910 a.Deps[i] = b.ExportAction(imp)
911 }
912 if p.UsesCgo() {
913
914 a.Deps = append(a.Deps, b.cgoAction(p, a.Objdir, nil, false))
915 }
916 return a
917 })
918 }
919
920
921
922
923 func (b *Builder) LinkAction(s *modload.Loader, mode, depMode BuildMode, p *load.Package) *Action {
924
925 a := b.cacheAction("link", p, func() *Action {
926 a := &Action{
927 Mode: "link",
928 Package: p,
929 }
930
931 exportAction := b.BuildExportAction(ModeBuild, depMode, p)
932 a1 := b.CompileAction(ModeBuild, depMode, p)
933 a.Actor = ActorFunc((*Builder).link)
934 a.Deps = []*Action{a1}
935 a.Objdir = a1.Objdir
936
937
938
939
940
941
942
943
944 name := "a.out"
945 if p.Internal.ExeName != "" {
946 name = p.Internal.ExeName
947 } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" {
948
949
950
951
952
953
954
955 _, name = filepath.Split(p.Target)
956 }
957 a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
958 a.built = a.Target
959 b.addTransitiveLinkDeps(s, a, exportAction, "")
960
961
962
963
964
965
966
967
968 exportAction.Deps = append(exportAction.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]})
969 return a
970 })
971
972 if mode == ModeInstall || mode == ModeBuggyInstall {
973 a = b.installAction(a, mode)
974 }
975
976 return a
977 }
978
979
980 func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action {
981
982
983
984 if strings.HasSuffix(a1.Mode, "-install") {
985 if a1.buggyInstall && mode == ModeInstall {
986
987 a1.buggyInstall = false
988 }
989 return a1
990 }
991
992
993
994
995 if a1.Actor == nil {
996 return a1
997 }
998
999 p := a1.Package
1000 return b.cacheAction(a1.Mode+"-install", p, func() *Action {
1001
1002
1003
1004
1005
1006
1007
1008 buildAction := new(Action)
1009 *buildAction = *a1
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 *a1 = Action{
1020 Mode: buildAction.Mode + "-install",
1021 Actor: ActorFunc(BuildInstallFunc),
1022 Package: p,
1023 Objdir: buildAction.Objdir,
1024 Deps: []*Action{buildAction},
1025 Target: p.Target,
1026 built: p.Target,
1027
1028 buggyInstall: mode == ModeBuggyInstall,
1029 }
1030
1031 b.addInstallHeaderAction(a1)
1032 return a1
1033 })
1034 }
1035
1036
1037
1038 func (b *Builder) addTransitiveCompileActions(a, root *Action) {
1039 workq := []*Action{root}
1040 haveDep := map[string]bool{}
1041 if root.Package != nil {
1042 haveDep[root.Package.ImportPath] = true
1043 }
1044 for i := 0; i < len(workq); i++ {
1045 for _, a2 := range workq[i].Deps {
1046 for a2.Mode == "build-install" || a2.Mode == "build" {
1047 a2 = a2.Deps[0]
1048 }
1049
1050 if a2.Mode != "build-export" || haveDep[a2.Package.ImportPath] {
1051 continue
1052 }
1053 haveDep[a2.Package.ImportPath] = true
1054 a.Deps = append(a.Deps, b.CompileAction(ModeBuild, ModeBuild, a2.Package))
1055 workq = append(workq, a2)
1056 }
1057 }
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 func (b *Builder) addTransitiveLinkDeps(s *modload.Loader, a, a1 *Action, shlib string) {
1070
1071
1072
1073
1074
1075 b.addTransitiveCompileActions(a, a1)
1076
1077
1078
1079 if cfg.BuildLinkshared {
1080 haveShlib := map[string]bool{shlib: true}
1081 for _, a1 := range a.Deps {
1082 p1 := a1.Package
1083 if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] {
1084 continue
1085 }
1086 haveShlib[filepath.Base(p1.Shlib)] = true
1087
1088
1089
1090
1091 a.Deps = append(a.Deps, b.linkSharedAction(s, ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil))
1092 }
1093 }
1094 }
1095
1096
1097
1098
1099
1100 func (b *Builder) addInstallHeaderAction(a *Action) {
1101
1102 p := a.Package
1103 if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
1104 hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h"
1105 if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" {
1106
1107
1108
1109 dir, file := filepath.Split(hdrTarget)
1110 file = strings.TrimPrefix(file, "lib")
1111 hdrTarget = filepath.Join(dir, file)
1112 }
1113 ah := &Action{
1114 Mode: "install header",
1115 Package: a.Package,
1116 Deps: []*Action{a.Deps[0]},
1117 Actor: ActorFunc((*Builder).installHeader),
1118 Objdir: a.Deps[0].Objdir,
1119 Target: hdrTarget,
1120 }
1121 a.Deps = append(a.Deps, ah)
1122 }
1123 }
1124
1125
1126
1127 func (b *Builder) buildmodeShared(s *modload.Loader, mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action {
1128 name, err := libname(args, pkgs)
1129 if err != nil {
1130 base.Fatalf("%v", err)
1131 }
1132 return b.linkSharedAction(s, mode, depMode, name, a1)
1133 }
1134
1135
1136
1137
1138
1139 func (b *Builder) linkSharedAction(s *modload.Loader, mode, depMode BuildMode, shlib string, a1 *Action) *Action {
1140 fullShlib := shlib
1141 shlib = filepath.Base(shlib)
1142 a := b.cacheAction("build-shlib "+shlib, nil, func() *Action {
1143 if a1 == nil {
1144
1145
1146 pkgs := readpkglist(s, fullShlib)
1147 a1 = &Action{
1148 Mode: "shlib packages",
1149 }
1150 for _, p := range pkgs {
1151 a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p))
1152 }
1153 }
1154
1155
1156
1157
1158 p := &load.Package{}
1159 p.Internal.CmdlinePkg = true
1160 p.Internal.Ldflags = load.BuildLdflags.For(s, p)
1161 p.Internal.Gccgoflags = load.BuildGccgoflags.For(s, p)
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173 a := &Action{
1174 Mode: "go build -buildmode=shared",
1175 Package: p,
1176 Objdir: b.NewObjdir(),
1177 Actor: ActorFunc((*Builder).linkShared),
1178 Deps: []*Action{a1},
1179 }
1180 a.Target = filepath.Join(a.Objdir, shlib)
1181 if cfg.BuildToolchainName != "gccgo" {
1182 add := func(a1 *Action, pkg string, force bool) {
1183 for _, a2 := range a1.Deps {
1184 if a2.Package != nil && a2.Package.ImportPath == pkg {
1185 return
1186 }
1187 }
1188 var stk load.ImportStack
1189 p := load.LoadPackageWithFlags(s, pkg, base.Cwd(), &stk, nil, 0)
1190 if p.Error != nil {
1191 base.Fatalf("load %s: %v", pkg, p.Error)
1192 }
1193
1194
1195
1196
1197
1198 if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg {
1199 a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p))
1200 }
1201 }
1202 add(a1, "runtime/cgo", false)
1203 if cfg.Goarch == "arm" {
1204 add(a1, "math", false)
1205 }
1206
1207
1208
1209 ldDeps, err := load.LinkerDeps(s, nil)
1210 if err != nil {
1211 base.Error(err)
1212 }
1213 for _, dep := range ldDeps {
1214 add(a, dep, true)
1215 }
1216 }
1217 b.addTransitiveLinkDeps(s, a, a1, shlib)
1218 return a
1219 })
1220
1221
1222 if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Actor != nil {
1223 buildAction := a
1224
1225 a = b.cacheAction("install-shlib "+shlib, nil, func() *Action {
1226
1227
1228
1229
1230
1231
1232 pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot
1233 for _, a2 := range a1.Deps {
1234 if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir {
1235 base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s",
1236 a1.Deps[0].Package.ImportPath,
1237 a2.Package.ImportPath,
1238 pkgDir,
1239 dir)
1240 }
1241 }
1242
1243 if cfg.BuildToolchainName == "gccgo" {
1244 pkgDir = filepath.Join(pkgDir, "shlibs")
1245 }
1246 target := filepath.Join(pkgDir, shlib)
1247
1248 a := &Action{
1249 Mode: "go install -buildmode=shared",
1250 Objdir: buildAction.Objdir,
1251 Actor: ActorFunc(BuildInstallFunc),
1252 Deps: []*Action{buildAction},
1253 Target: target,
1254 }
1255 for _, a2 := range buildAction.Deps[0].Deps {
1256 p := a2.Package
1257 pkgTargetRoot := p.Internal.Build.PkgTargetRoot
1258 if pkgTargetRoot == "" {
1259 continue
1260 }
1261 a.Deps = append(a.Deps, &Action{
1262 Mode: "shlibname",
1263 Package: p,
1264 Actor: ActorFunc((*Builder).installShlibname),
1265 Target: filepath.Join(pkgTargetRoot, p.ImportPath+".shlibname"),
1266 Deps: []*Action{a.Deps[0]},
1267 })
1268 }
1269 return a
1270 })
1271 }
1272
1273 return a
1274 }
1275
View as plain text