github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/work/action.go (about)

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