]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/work/action.go
60ab68c65c940f5bf4caf7785659a66af81f9285
[gostls13.git] / src / cmd / go / internal / work / action.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Action graph creation (planning).
6
7 package work
8
9 import (
10         "bufio"
11         "bytes"
12         "container/heap"
13         "context"
14         "debug/elf"
15         "encoding/json"
16         "fmt"
17         "os"
18         "path/filepath"
19         "strings"
20         "sync"
21         "time"
22
23         "cmd/go/internal/base"
24         "cmd/go/internal/cache"
25         "cmd/go/internal/cfg"
26         "cmd/go/internal/load"
27         "cmd/go/internal/robustio"
28         "cmd/go/internal/trace"
29         "cmd/internal/buildid"
30 )
31
32 // A Builder holds global state about a build.
33 // It does not hold per-package state, because we
34 // build packages in parallel, and the builder is shared.
35 type Builder struct {
36         WorkDir     string               // the temporary work directory (ends in filepath.Separator)
37         actionCache map[cacheKey]*Action // a cache of already-constructed actions
38         mkdirCache  map[string]bool      // a cache of created directories
39         flagCache   map[[2]string]bool   // a cache of supported compiler flags
40         Print       func(args ...any) (int, error)
41
42         IsCmdList           bool // running as part of go list; set p.Stale and additional fields below
43         NeedError           bool // list needs p.Error
44         NeedExport          bool // list needs p.Export
45         NeedCompiledGoFiles bool // list needs p.CompiledGoFiles
46         AllowErrors         bool // errors don't immediately exit the program
47
48         objdirSeq int // counter for NewObjdir
49         pkgSeq    int
50
51         output    sync.Mutex
52         scriptDir string // current directory in printed script
53
54         exec      sync.Mutex
55         readySema chan bool
56         ready     actionQueue
57
58         id           sync.Mutex
59         toolIDCache  map[string]string // tool name -> tool ID
60         buildIDCache map[string]string // file name -> build ID
61 }
62
63 // NOTE: Much of Action would not need to be exported if not for test.
64 // Maybe test functionality should move into this package too?
65
66 // An Action represents a single action in the action graph.
67 type Action struct {
68         Mode       string                                         // description of action operation
69         Package    *load.Package                                  // the package this action works on
70         Deps       []*Action                                      // actions that must happen before this one
71         Func       func(*Builder, context.Context, *Action) error // the action itself (nil = no-op)
72         IgnoreFail bool                                           // whether to run f even if dependencies fail
73         TestOutput *bytes.Buffer                                  // test output buffer
74         Args       []string                                       // additional args for runProgram
75
76         triggers []*Action // inverse of deps
77
78         buggyInstall bool // is this a buggy install (see -linkshared)?
79
80         TryCache func(*Builder, *Action) bool // callback for cache bypass
81
82         // Generated files, directories.
83         Objdir   string         // directory for intermediate objects
84         Target   string         // goal of the action: the created package or executable
85         built    string         // the actual created package or executable
86         actionID cache.ActionID // cache ID of action input
87         buildID  string         // build ID of action output
88
89         VetxOnly  bool       // Mode=="vet": only being called to supply info about dependencies
90         needVet   bool       // Mode=="build": need to fill in vet config
91         needBuild bool       // Mode=="build": need to do actual build (can be false if needVet is true)
92         vetCfg    *vetConfig // vet config
93         output    []byte     // output redirect buffer (nil means use b.Print)
94
95         // Execution state.
96         pending      int               // number of deps yet to complete
97         priority     int               // relative execution priority
98         Failed       bool              // whether the action failed
99         json         *actionJSON       // action graph information
100         nonGoOverlay map[string]string // map from non-.go source files to copied files in objdir. Nil if no overlay is used.
101         traceSpan    *trace.Span
102 }
103
104 // BuildActionID returns the action ID section of a's build ID.
105 func (a *Action) BuildActionID() string { return actionID(a.buildID) }
106
107 // BuildContentID returns the content ID section of a's build ID.
108 func (a *Action) BuildContentID() string { return contentID(a.buildID) }
109
110 // BuildID returns a's build ID.
111 func (a *Action) BuildID() string { return a.buildID }
112
113 // BuiltTarget returns the actual file that was built. This differs
114 // from Target when the result was cached.
115 func (a *Action) BuiltTarget() string { return a.built }
116
117 // An actionQueue is a priority queue of actions.
118 type actionQueue []*Action
119
120 // Implement heap.Interface
121 func (q *actionQueue) Len() int           { return len(*q) }
122 func (q *actionQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
123 func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
124 func (q *actionQueue) Push(x any)         { *q = append(*q, x.(*Action)) }
125 func (q *actionQueue) Pop() any {
126         n := len(*q) - 1
127         x := (*q)[n]
128         *q = (*q)[:n]
129         return x
130 }
131
132 func (q *actionQueue) push(a *Action) {
133         if a.json != nil {
134                 a.json.TimeReady = time.Now()
135         }
136         heap.Push(q, a)
137 }
138
139 func (q *actionQueue) pop() *Action {
140         return heap.Pop(q).(*Action)
141 }
142
143 type actionJSON struct {
144         ID         int
145         Mode       string
146         Package    string
147         Deps       []int     `json:",omitempty"`
148         IgnoreFail bool      `json:",omitempty"`
149         Args       []string  `json:",omitempty"`
150         Link       bool      `json:",omitempty"`
151         Objdir     string    `json:",omitempty"`
152         Target     string    `json:",omitempty"`
153         Priority   int       `json:",omitempty"`
154         Failed     bool      `json:",omitempty"`
155         Built      string    `json:",omitempty"`
156         VetxOnly   bool      `json:",omitempty"`
157         NeedVet    bool      `json:",omitempty"`
158         NeedBuild  bool      `json:",omitempty"`
159         ActionID   string    `json:",omitempty"`
160         BuildID    string    `json:",omitempty"`
161         TimeReady  time.Time `json:",omitempty"`
162         TimeStart  time.Time `json:",omitempty"`
163         TimeDone   time.Time `json:",omitempty"`
164
165         Cmd     []string      // `json:",omitempty"`
166         CmdReal time.Duration `json:",omitempty"`
167         CmdUser time.Duration `json:",omitempty"`
168         CmdSys  time.Duration `json:",omitempty"`
169 }
170
171 // cacheKey is the key for the action cache.
172 type cacheKey struct {
173         mode string
174         p    *load.Package
175 }
176
177 func actionGraphJSON(a *Action) string {
178         var workq []*Action
179         var inWorkq = make(map[*Action]int)
180
181         add := func(a *Action) {
182                 if _, ok := inWorkq[a]; ok {
183                         return
184                 }
185                 inWorkq[a] = len(workq)
186                 workq = append(workq, a)
187         }
188         add(a)
189
190         for i := 0; i < len(workq); i++ {
191                 for _, dep := range workq[i].Deps {
192                         add(dep)
193                 }
194         }
195
196         var list []*actionJSON
197         for id, a := range workq {
198                 if a.json == nil {
199                         a.json = &actionJSON{
200                                 Mode:       a.Mode,
201                                 ID:         id,
202                                 IgnoreFail: a.IgnoreFail,
203                                 Args:       a.Args,
204                                 Objdir:     a.Objdir,
205                                 Target:     a.Target,
206                                 Failed:     a.Failed,
207                                 Priority:   a.priority,
208                                 Built:      a.built,
209                                 VetxOnly:   a.VetxOnly,
210                                 NeedBuild:  a.needBuild,
211                                 NeedVet:    a.needVet,
212                         }
213                         if a.Package != nil {
214                                 // TODO(rsc): Make this a unique key for a.Package somehow.
215                                 a.json.Package = a.Package.ImportPath
216                         }
217                         for _, a1 := range a.Deps {
218                                 a.json.Deps = append(a.json.Deps, inWorkq[a1])
219                         }
220                 }
221                 list = append(list, a.json)
222         }
223
224         js, err := json.MarshalIndent(list, "", "\t")
225         if err != nil {
226                 fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err)
227                 return ""
228         }
229         return string(js)
230 }
231
232 // BuildMode specifies the build mode:
233 // are we just building things or also installing the results?
234 type BuildMode int
235
236 const (
237         ModeBuild BuildMode = iota
238         ModeInstall
239         ModeBuggyInstall
240
241         ModeVetOnly = 1 << 8
242 )
243
244 // NewBuilder returns a new Builder ready for use.
245 //
246 // If workDir is the empty string, NewBuilder creates a WorkDir if needed
247 // and arranges for it to be removed in case of an unclean exit.
248 // The caller must Close the builder explicitly to clean up the WorkDir
249 // before a clean exit.
250 func NewBuilder(workDir string) *Builder {
251         b := new(Builder)
252
253         b.Print = func(a ...any) (int, error) {
254                 return fmt.Fprint(os.Stderr, a...)
255         }
256         b.actionCache = make(map[cacheKey]*Action)
257         b.mkdirCache = make(map[string]bool)
258         b.toolIDCache = make(map[string]string)
259         b.buildIDCache = make(map[string]string)
260
261         if workDir != "" {
262                 b.WorkDir = workDir
263         } else if cfg.BuildN {
264                 b.WorkDir = "$WORK"
265         } else {
266                 if !buildInitStarted {
267                         panic("internal error: NewBuilder called before BuildInit")
268                 }
269                 tmp, err := os.MkdirTemp(cfg.Getenv("GOTMPDIR"), "go-build")
270                 if err != nil {
271                         base.Fatalf("go: creating work dir: %v", err)
272                 }
273                 if !filepath.IsAbs(tmp) {
274                         abs, err := filepath.Abs(tmp)
275                         if err != nil {
276                                 os.RemoveAll(tmp)
277                                 base.Fatalf("go: creating work dir: %v", err)
278                         }
279                         tmp = abs
280                 }
281                 b.WorkDir = tmp
282                 builderWorkDirs.Store(b, b.WorkDir)
283                 if cfg.BuildX || cfg.BuildWork {
284                         fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir)
285                 }
286         }
287
288         if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil {
289                 fmt.Fprintf(os.Stderr, "go: %v\n", err)
290                 base.SetExitStatus(2)
291                 base.Exit()
292         }
293
294         for _, tag := range cfg.BuildContext.BuildTags {
295                 if strings.Contains(tag, ",") {
296                         fmt.Fprintf(os.Stderr, "go: -tags space-separated list contains comma\n")
297                         base.SetExitStatus(2)
298                         base.Exit()
299                 }
300         }
301
302         return b
303 }
304
305 var builderWorkDirs sync.Map // *Builder â†’ WorkDir
306
307 func (b *Builder) Close() error {
308         wd, ok := builderWorkDirs.Load(b)
309         if !ok {
310                 return nil
311         }
312         defer builderWorkDirs.Delete(b)
313
314         if b.WorkDir != wd.(string) {
315                 base.Errorf("go: internal error: Builder WorkDir unexpectedly changed from %s to %s", wd, b.WorkDir)
316         }
317
318         if !cfg.BuildWork {
319                 if err := robustio.RemoveAll(b.WorkDir); err != nil {
320                         return err
321                 }
322         }
323         b.WorkDir = ""
324         return nil
325 }
326
327 func closeBuilders() {
328         leakedBuilders := 0
329         builderWorkDirs.Range(func(bi, _ any) bool {
330                 leakedBuilders++
331                 if err := bi.(*Builder).Close(); err != nil {
332                         base.Errorf("go: %v", err)
333                 }
334                 return true
335         })
336
337         if leakedBuilders > 0 && base.GetExitStatus() == 0 {
338                 fmt.Fprintf(os.Stderr, "go: internal error: Builder leaked on successful exit\n")
339                 base.SetExitStatus(1)
340         }
341 }
342
343 func CheckGOOSARCHPair(goos, goarch string) error {
344         if _, ok := cfg.OSArchSupportsCgo[goos+"/"+goarch]; !ok && cfg.BuildContext.Compiler == "gc" {
345                 return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch)
346         }
347         return nil
348 }
349
350 // NewObjdir returns the name of a fresh object directory under b.WorkDir.
351 // It is up to the caller to call b.Mkdir on the result at an appropriate time.
352 // The result ends in a slash, so that file names in that directory
353 // can be constructed with direct string addition.
354 //
355 // NewObjdir must be called only from a single goroutine at a time,
356 // so it is safe to call during action graph construction, but it must not
357 // be called during action graph execution.
358 func (b *Builder) NewObjdir() string {
359         b.objdirSeq++
360         return filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)) + string(filepath.Separator)
361 }
362
363 // readpkglist returns the list of packages that were built into the shared library
364 // at shlibpath. For the native toolchain this list is stored, newline separated, in
365 // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
366 // .go_export section.
367 func readpkglist(shlibpath string) (pkgs []*load.Package) {
368         var stk load.ImportStack
369         if cfg.BuildToolchainName == "gccgo" {
370                 f, _ := elf.Open(shlibpath)
371                 sect := f.Section(".go_export")
372                 data, _ := sect.Data()
373                 scanner := bufio.NewScanner(bytes.NewBuffer(data))
374                 for scanner.Scan() {
375                         t := scanner.Text()
376                         var found bool
377                         if t, found = strings.CutPrefix(t, "pkgpath "); found {
378                                 t = strings.TrimSuffix(t, ";")
379                                 pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd(), nil, &stk, nil, 0))
380                         }
381                 }
382         } else {
383                 pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1)
384                 if err != nil {
385                         base.Fatalf("readELFNote failed: %v", err)
386                 }
387                 scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
388                 for scanner.Scan() {
389                         t := scanner.Text()
390                         pkgs = append(pkgs, load.LoadImportWithFlags(t, base.Cwd(), nil, &stk, nil, 0))
391                 }
392         }
393         return
394 }
395
396 // cacheAction looks up {mode, p} in the cache and returns the resulting action.
397 // If the cache has no such action, f() is recorded and returned.
398 // TODO(rsc): Change the second key from *load.Package to interface{},
399 // to make the caching in linkShared less awkward?
400 func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action {
401         a := b.actionCache[cacheKey{mode, p}]
402         if a == nil {
403                 a = f()
404                 b.actionCache[cacheKey{mode, p}] = a
405         }
406         return a
407 }
408
409 // AutoAction returns the "right" action for go build or go install of p.
410 func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action {
411         if p.Name == "main" {
412                 return b.LinkAction(mode, depMode, p)
413         }
414         return b.CompileAction(mode, depMode, p)
415 }
416
417 // CompileAction returns the action for compiling and possibly installing
418 // (according to mode) the given package. The resulting action is only
419 // for building packages (archives), never for linking executables.
420 // depMode is the action (build or install) to use when building dependencies.
421 // To turn package main into an executable, call b.Link instead.
422 func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
423         vetOnly := mode&ModeVetOnly != 0
424         mode &^= ModeVetOnly
425
426         if mode != ModeBuild && (p.Internal.Local || p.Module != nil) && p.Target == "" {
427                 // Imported via local path or using modules. No permanent target.
428                 mode = ModeBuild
429         }
430         if mode != ModeBuild && p.Name == "main" {
431                 // We never install the .a file for a main package.
432                 mode = ModeBuild
433         }
434
435         // Construct package build action.
436         a := b.cacheAction("build", p, func() *Action {
437                 a := &Action{
438                         Mode:    "build",
439                         Package: p,
440                         Func:    (*Builder).build,
441                         Objdir:  b.NewObjdir(),
442                 }
443
444                 if p.Error == nil || !p.Error.IsImportCycle {
445                         for _, p1 := range p.Internal.Imports {
446                                 a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
447                         }
448                 }
449
450                 if p.Standard {
451                         switch p.ImportPath {
452                         case "builtin", "unsafe":
453                                 // Fake packages - nothing to build.
454                                 a.Mode = "built-in package"
455                                 a.Func = nil
456                                 return a
457                         }
458
459                         // gccgo standard library is "fake" too.
460                         if cfg.BuildToolchainName == "gccgo" {
461                                 // the target name is needed for cgo.
462                                 a.Mode = "gccgo stdlib"
463                                 a.Target = p.Target
464                                 a.Func = nil
465                                 return a
466                         }
467                 }
468
469                 return a
470         })
471
472         // Find the build action; the cache entry may have been replaced
473         // by the install action during (*Builder).installAction.
474         buildAction := a
475         switch buildAction.Mode {
476         case "build", "built-in package", "gccgo stdlib":
477                 // ok
478         case "build-install":
479                 buildAction = a.Deps[0]
480         default:
481                 panic("lost build action: " + buildAction.Mode)
482         }
483         buildAction.needBuild = buildAction.needBuild || !vetOnly
484
485         // Construct install action.
486         if mode == ModeInstall || mode == ModeBuggyInstall {
487                 a = b.installAction(a, mode)
488         }
489
490         return a
491 }
492
493 // VetAction returns the action for running go vet on package p.
494 // It depends on the action for compiling p.
495 // If the caller may be causing p to be installed, it is up to the caller
496 // to make sure that the install depends on (runs after) vet.
497 func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
498         a := b.vetAction(mode, depMode, p)
499         a.VetxOnly = false
500         return a
501 }
502
503 func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
504         // Construct vet action.
505         a := b.cacheAction("vet", p, func() *Action {
506                 a1 := b.CompileAction(mode|ModeVetOnly, depMode, p)
507
508                 // vet expects to be able to import "fmt".
509                 var stk load.ImportStack
510                 stk.Push("vet")
511                 p1 := load.LoadImportWithFlags("fmt", p.Dir, p, &stk, nil, 0)
512                 stk.Pop()
513                 aFmt := b.CompileAction(ModeBuild, depMode, p1)
514
515                 var deps []*Action
516                 if a1.buggyInstall {
517                         // (*Builder).vet expects deps[0] to be the package
518                         // and deps[1] to be "fmt". If we see buggyInstall
519                         // here then a1 is an install of a shared library,
520                         // and the real package is a1.Deps[0].
521                         deps = []*Action{a1.Deps[0], aFmt, a1}
522                 } else {
523                         deps = []*Action{a1, aFmt}
524                 }
525                 for _, p1 := range p.Internal.Imports {
526                         deps = append(deps, b.vetAction(mode, depMode, p1))
527                 }
528
529                 a := &Action{
530                         Mode:       "vet",
531                         Package:    p,
532                         Deps:       deps,
533                         Objdir:     a1.Objdir,
534                         VetxOnly:   true,
535                         IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems)
536                 }
537                 if a1.Func == nil {
538                         // Built-in packages like unsafe.
539                         return a
540                 }
541                 deps[0].needVet = true
542                 a.Func = (*Builder).vet
543                 return a
544         })
545         return a
546 }
547
548 // LinkAction returns the action for linking p into an executable
549 // and possibly installing the result (according to mode).
550 // depMode is the action (build or install) to use when compiling dependencies.
551 func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action {
552         // Construct link action.
553         a := b.cacheAction("link", p, func() *Action {
554                 a := &Action{
555                         Mode:    "link",
556                         Package: p,
557                 }
558
559                 a1 := b.CompileAction(ModeBuild, depMode, p)
560                 a.Func = (*Builder).link
561                 a.Deps = []*Action{a1}
562                 a.Objdir = a1.Objdir
563
564                 // An executable file. (This is the name of a temporary file.)
565                 // Because we run the temporary file in 'go run' and 'go test',
566                 // the name will show up in ps listings. If the caller has specified
567                 // a name, use that instead of a.out. The binary is generated
568                 // in an otherwise empty subdirectory named exe to avoid
569                 // naming conflicts. The only possible conflict is if we were
570                 // to create a top-level package named exe.
571                 name := "a.out"
572                 if p.Internal.ExeName != "" {
573                         name = p.Internal.ExeName
574                 } else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" {
575                         // On OS X, the linker output name gets recorded in the
576                         // shared library's LC_ID_DYLIB load command.
577                         // The code invoking the linker knows to pass only the final
578                         // path element. Arrange that the path element matches what
579                         // we'll install it as; otherwise the library is only loadable as "a.out".
580                         // On Windows, DLL file name is recorded in PE file
581                         // export section, so do like on OS X.
582                         _, name = filepath.Split(p.Target)
583                 }
584                 a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
585                 a.built = a.Target
586                 b.addTransitiveLinkDeps(a, a1, "")
587
588                 // Sequence the build of the main package (a1) strictly after the build
589                 // of all other dependencies that go into the link. It is likely to be after
590                 // them anyway, but just make sure. This is required by the build ID-based
591                 // shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a).
592                 // In order for that linkActionID call to compute the right action ID, all the
593                 // dependencies of a (except a1) must have completed building and have
594                 // recorded their build IDs.
595                 a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]})
596                 return a
597         })
598
599         if mode == ModeInstall || mode == ModeBuggyInstall {
600                 a = b.installAction(a, mode)
601         }
602
603         return a
604 }
605
606 // installAction returns the action for installing the result of a1.
607 func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action {
608         // Because we overwrite the build action with the install action below,
609         // a1 may already be an install action fetched from the "build" cache key,
610         // and the caller just doesn't realize.
611         if strings.HasSuffix(a1.Mode, "-install") {
612                 if a1.buggyInstall && mode == ModeInstall {
613                         //  Congratulations! The buggy install is now a proper install.
614                         a1.buggyInstall = false
615                 }
616                 return a1
617         }
618
619         // If there's no actual action to build a1,
620         // there's nothing to install either.
621         // This happens if a1 corresponds to reusing an already-built object.
622         if a1.Func == nil {
623                 return a1
624         }
625
626         p := a1.Package
627         return b.cacheAction(a1.Mode+"-install", p, func() *Action {
628                 // The install deletes the temporary build result,
629                 // so we need all other actions, both past and future,
630                 // that attempt to depend on the build to depend instead
631                 // on the install.
632
633                 // Make a private copy of a1 (the build action),
634                 // no longer accessible to any other rules.
635                 buildAction := new(Action)
636                 *buildAction = *a1
637
638                 // Overwrite a1 with the install action.
639                 // This takes care of updating past actions that
640                 // point at a1 for the build action; now they will
641                 // point at a1 and get the install action.
642                 // We also leave a1 in the action cache as the result
643                 // for "build", so that actions not yet created that
644                 // try to depend on the build will instead depend
645                 // on the install.
646                 *a1 = Action{
647                         Mode:    buildAction.Mode + "-install",
648                         Func:    BuildInstallFunc,
649                         Package: p,
650                         Objdir:  buildAction.Objdir,
651                         Deps:    []*Action{buildAction},
652                         Target:  p.Target,
653                         built:   p.Target,
654
655                         buggyInstall: mode == ModeBuggyInstall,
656                 }
657
658                 b.addInstallHeaderAction(a1)
659                 return a1
660         })
661 }
662
663 // addTransitiveLinkDeps adds to the link action a all packages
664 // that are transitive dependencies of a1.Deps.
665 // That is, if a is a link of package main, a1 is the compile of package main
666 // and a1.Deps is the actions for building packages directly imported by
667 // package main (what the compiler needs). The linker needs all packages
668 // transitively imported by the whole program; addTransitiveLinkDeps
669 // makes sure those are present in a.Deps.
670 // If shlib is non-empty, then a corresponds to the build and installation of shlib,
671 // so any rebuild of shlib should not be added as a dependency.
672 func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) {
673         // Expand Deps to include all built packages, for the linker.
674         // Use breadth-first search to find rebuilt-for-test packages
675         // before the standard ones.
676         // TODO(rsc): Eliminate the standard ones from the action graph,
677         // which will require doing a little bit more rebuilding.
678         workq := []*Action{a1}
679         haveDep := map[string]bool{}
680         if a1.Package != nil {
681                 haveDep[a1.Package.ImportPath] = true
682         }
683         for i := 0; i < len(workq); i++ {
684                 a1 := workq[i]
685                 for _, a2 := range a1.Deps {
686                         // TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles.
687                         if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] {
688                                 continue
689                         }
690                         haveDep[a2.Package.ImportPath] = true
691                         a.Deps = append(a.Deps, a2)
692                         if a2.Mode == "build-install" {
693                                 a2 = a2.Deps[0] // walk children of "build" action
694                         }
695                         workq = append(workq, a2)
696                 }
697         }
698
699         // If this is go build -linkshared, then the link depends on the shared libraries
700         // in addition to the packages themselves. (The compile steps do not.)
701         if cfg.BuildLinkshared {
702                 haveShlib := map[string]bool{shlib: true}
703                 for _, a1 := range a.Deps {
704                         p1 := a1.Package
705                         if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] {
706                                 continue
707                         }
708                         haveShlib[filepath.Base(p1.Shlib)] = true
709                         // TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild,
710                         // we'll end up building an overall library or executable that depends at runtime
711                         // on other libraries that are out-of-date, which is clearly not good either.
712                         // We call it ModeBuggyInstall to make clear that this is not right.
713                         a.Deps = append(a.Deps, b.linkSharedAction(ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil))
714                 }
715         }
716 }
717
718 // addInstallHeaderAction adds an install header action to a, if needed.
719 // The action a should be an install action as generated by either
720 // b.CompileAction or b.LinkAction with mode=ModeInstall,
721 // and so a.Deps[0] is the corresponding build action.
722 func (b *Builder) addInstallHeaderAction(a *Action) {
723         // Install header for cgo in c-archive and c-shared modes.
724         p := a.Package
725         if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
726                 hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h"
727                 if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" {
728                         // For the header file, remove the "lib"
729                         // added by go/build, so we generate pkg.h
730                         // rather than libpkg.h.
731                         dir, file := filepath.Split(hdrTarget)
732                         file = strings.TrimPrefix(file, "lib")
733                         hdrTarget = filepath.Join(dir, file)
734                 }
735                 ah := &Action{
736                         Mode:    "install header",
737                         Package: a.Package,
738                         Deps:    []*Action{a.Deps[0]},
739                         Func:    (*Builder).installHeader,
740                         Objdir:  a.Deps[0].Objdir,
741                         Target:  hdrTarget,
742                 }
743                 a.Deps = append(a.Deps, ah)
744         }
745 }
746
747 // buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps.
748 // That is, the input a1 represents "go build pkgs" and the result represents "go build -buildmode=shared pkgs".
749 func (b *Builder) buildmodeShared(mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action {
750         name, err := libname(args, pkgs)
751         if err != nil {
752                 base.Fatalf("%v", err)
753         }
754         return b.linkSharedAction(mode, depMode, name, a1)
755 }
756
757 // linkSharedAction takes a grouping action a1 corresponding to a list of built packages
758 // and returns an action that links them together into a shared library with the name shlib.
759 // If a1 is nil, shlib should be an absolute path to an existing shared library,
760 // and then linkSharedAction reads that library to find out the package list.
761 func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Action) *Action {
762         fullShlib := shlib
763         shlib = filepath.Base(shlib)
764         a := b.cacheAction("build-shlib "+shlib, nil, func() *Action {
765                 if a1 == nil {
766                         // TODO(rsc): Need to find some other place to store config,
767                         // not in pkg directory. See golang.org/issue/22196.
768                         pkgs := readpkglist(fullShlib)
769                         a1 = &Action{
770                                 Mode: "shlib packages",
771                         }
772                         for _, p := range pkgs {
773                                 a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p))
774                         }
775                 }
776
777                 // Fake package to hold ldflags.
778                 // As usual shared libraries are a kludgy, abstraction-violating special case:
779                 // we let them use the flags specified for the command-line arguments.
780                 p := &load.Package{}
781                 p.Internal.CmdlinePkg = true
782                 p.Internal.Ldflags = load.BuildLdflags.For(p)
783                 p.Internal.Gccgoflags = load.BuildGccgoflags.For(p)
784
785                 // Add implicit dependencies to pkgs list.
786                 // Currently buildmode=shared forces external linking mode, and
787                 // external linking mode forces an import of runtime/cgo (and
788                 // math on arm). So if it was not passed on the command line and
789                 // it is not present in another shared library, add it here.
790                 // TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
791                 // TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
792                 // TODO(rsc): We don't add standard library imports for gccgo
793                 // because they are all always linked in anyhow.
794                 // Maybe load.LinkerDeps should be used and updated.
795                 a := &Action{
796                         Mode:    "go build -buildmode=shared",
797                         Package: p,
798                         Objdir:  b.NewObjdir(),
799                         Func:    (*Builder).linkShared,
800                         Deps:    []*Action{a1},
801                 }
802                 a.Target = filepath.Join(a.Objdir, shlib)
803                 if cfg.BuildToolchainName != "gccgo" {
804                         add := func(a1 *Action, pkg string, force bool) {
805                                 for _, a2 := range a1.Deps {
806                                         if a2.Package != nil && a2.Package.ImportPath == pkg {
807                                                 return
808                                         }
809                                 }
810                                 var stk load.ImportStack
811                                 p := load.LoadImportWithFlags(pkg, base.Cwd(), nil, &stk, nil, 0)
812                                 if p.Error != nil {
813                                         base.Fatalf("load %s: %v", pkg, p.Error)
814                                 }
815                                 // Assume that if pkg (runtime/cgo or math)
816                                 // is already accounted for in a different shared library,
817                                 // then that shared library also contains runtime,
818                                 // so that anything we do will depend on that library,
819                                 // so we don't need to include pkg in our shared library.
820                                 if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg {
821                                         a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p))
822                                 }
823                         }
824                         add(a1, "runtime/cgo", false)
825                         if cfg.Goarch == "arm" {
826                                 add(a1, "math", false)
827                         }
828
829                         // The linker step still needs all the usual linker deps.
830                         // (For example, the linker always opens runtime.a.)
831                         for _, dep := range load.LinkerDeps(nil) {
832                                 add(a, dep, true)
833                         }
834                 }
835                 b.addTransitiveLinkDeps(a, a1, shlib)
836                 return a
837         })
838
839         // Install result.
840         if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Func != nil {
841                 buildAction := a
842
843                 a = b.cacheAction("install-shlib "+shlib, nil, func() *Action {
844                         // Determine the eventual install target.
845                         // The install target is root/pkg/shlib, where root is the source root
846                         // in which all the packages lie.
847                         // TODO(rsc): Perhaps this cross-root check should apply to the full
848                         // transitive package dependency list, not just the ones named
849                         // on the command line?
850                         pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot
851                         for _, a2 := range a1.Deps {
852                                 if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir {
853                                         base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s",
854                                                 a1.Deps[0].Package.ImportPath,
855                                                 a2.Package.ImportPath,
856                                                 pkgDir,
857                                                 dir)
858                                 }
859                         }
860                         // TODO(rsc): Find out and explain here why gccgo is different.
861                         if cfg.BuildToolchainName == "gccgo" {
862                                 pkgDir = filepath.Join(pkgDir, "shlibs")
863                         }
864                         target := filepath.Join(pkgDir, shlib)
865
866                         a := &Action{
867                                 Mode:   "go install -buildmode=shared",
868                                 Objdir: buildAction.Objdir,
869                                 Func:   BuildInstallFunc,
870                                 Deps:   []*Action{buildAction},
871                                 Target: target,
872                         }
873                         for _, a2 := range buildAction.Deps[0].Deps {
874                                 p := a2.Package
875                                 if p.Target == "" {
876                                         continue
877                                 }
878                                 a.Deps = append(a.Deps, &Action{
879                                         Mode:    "shlibname",
880                                         Package: p,
881                                         Func:    (*Builder).installShlibname,
882                                         Target:  strings.TrimSuffix(p.Target, ".a") + ".shlibname",
883                                         Deps:    []*Action{a.Deps[0]},
884                                 })
885                         }
886                         return a
887                 })
888         }
889
890         return a
891 }