Source file 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  	"cmd/internal/cov/covcmd"
    13  	"cmd/internal/par"
    14  	"container/heap"
    15  	"context"
    16  	"debug/elf"
    17  	"encoding/json"
    18  	"fmt"
    19  	"internal/platform"
    20  	"os"
    21  	"path/filepath"
    22  	"slices"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  
    27  	"cmd/go/internal/base"
    28  	"cmd/go/internal/cache"
    29  	"cmd/go/internal/cfg"
    30  	"cmd/go/internal/load"
    31  	"cmd/go/internal/modload"
    32  	"cmd/go/internal/str"
    33  	"cmd/go/internal/trace"
    34  	"cmd/internal/buildid"
    35  	"cmd/internal/robustio"
    36  )
    37  
    38  // A Builder holds global state about a build.
    39  // It does not hold per-package state, because we
    40  // build packages in parallel, and the builder is shared.
    41  type Builder struct {
    42  	WorkDir            string                    // the temporary work directory (ends in filepath.Separator)
    43  	getVendorDir       func() string             // TODO(jitsu): remove this after we eliminate global module state
    44  	actionCache        map[cacheKey]*Action      // a cache of already-constructed actions
    45  	flagCache          map[[2]string]bool        // a cache of supported compiler flags
    46  	gccCompilerIDCache map[string]cache.ActionID // cache for gccCompilerID
    47  
    48  	IsCmdList           bool // running as part of go list; set p.Stale and additional fields below
    49  	NeedError           bool // list needs p.Error
    50  	NeedExport          bool // list needs p.Export
    51  	NeedCompiledGoFiles bool // list needs p.CompiledGoFiles
    52  	AllowErrors         bool // errors don't immediately exit the program
    53  
    54  	objdirSeq int // counter for NewObjdir
    55  	pkgSeq    int
    56  
    57  	backgroundSh *Shell // Shell that per-Action Shells are derived from
    58  
    59  	exec      sync.Mutex
    60  	readySema chan bool
    61  	ready     actionQueue
    62  
    63  	id             sync.Mutex
    64  	toolIDCache    par.Cache[string, string] // tool name -> tool ID
    65  	gccToolIDCache map[string]string         // tool name -> tool ID
    66  	buildIDCache   map[string]string         // file name -> build ID
    67  }
    68  
    69  // NOTE: Much of Action would not need to be exported if not for test.
    70  // Maybe test functionality should move into this package too?
    71  
    72  // An Actor runs an action.
    73  type Actor interface {
    74  	Act(*Builder, context.Context, *Action) error
    75  }
    76  
    77  // An ActorFunc is an Actor that calls the function.
    78  type ActorFunc func(*Builder, context.Context, *Action) error
    79  
    80  func (f ActorFunc) Act(b *Builder, ctx context.Context, a *Action) error {
    81  	return f(b, ctx, a)
    82  }
    83  
    84  // An Action represents a single action in the action graph.
    85  type Action struct {
    86  	Mode       string        // description of action operation
    87  	Package    *load.Package // the package this action works on
    88  	Deps       []*Action     // actions that must happen before this one
    89  	Actor      Actor         // the action itself (nil = no-op)
    90  	IgnoreFail bool          // whether to run f even if dependencies fail
    91  	TestOutput *bytes.Buffer // test output buffer
    92  	Args       []string      // additional args for runProgram
    93  
    94  	Provider any // Additional information to be passed to successive actions. Similar to a Bazel provider.
    95  
    96  	triggers []*Action // inverse of deps
    97  
    98  	buggyInstall bool // is this a buggy install (see -linkshared)?
    99  
   100  	TryCache func(*Builder, *Action, *Action) bool // callback for cache bypass
   101  
   102  	CacheExecutable bool // Whether to cache executables produced by link steps
   103  
   104  	// Generated files, directories.
   105  	Objdir           string         // directory for intermediate objects
   106  	Target           string         // goal of the action: the created package or executable
   107  	built            string         // the actual created package or executable
   108  	cachedExecutable string         // the cached executable, if CacheExecutable was set
   109  	actionID         cache.ActionID // cache ID of action input
   110  	buildID          string         // build ID of action output
   111  
   112  	VetxOnly   bool       // Mode=="vet": only being called to supply info about dependencies
   113  	needVet    bool       // Mode=="build": need to fill in vet config
   114  	needBuild  bool       // Mode=="build": need to do actual build (can be false if needVet is true)
   115  	needFix    bool       // Mode=="vet": need secondary target, a .zip file containing fixes
   116  	vetCfg     *vetConfig // vet config
   117  	FixArchive string     // the created .zip file containing fixes (if needFix)
   118  	output     []byte     // output redirect buffer (nil means use b.Print)
   119  
   120  	sh *Shell // lazily created per-Action shell; see Builder.Shell
   121  
   122  	// Execution state.
   123  	pending      int               // number of deps yet to complete
   124  	priority     int               // relative execution priority
   125  	Failed       *Action           // set to root cause if the action failed
   126  	json         *actionJSON       // action graph information
   127  	nonGoOverlay map[string]string // map from non-.go source files to copied files in objdir. Nil if no overlay is used.
   128  	traceSpan    *trace.Span
   129  }
   130  
   131  // BuildActionID returns the action ID section of a's build ID.
   132  func (a *Action) BuildActionID() string { return actionID(a.buildID) }
   133  
   134  // BuildContentID returns the content ID section of a's build ID.
   135  func (a *Action) BuildContentID() string { return contentID(a.buildID) }
   136  
   137  // BuildID returns a's build ID.
   138  func (a *Action) BuildID() string { return a.buildID }
   139  
   140  // BuiltTarget returns the actual file that was built. This differs
   141  // from Target when the result was cached.
   142  func (a *Action) BuiltTarget() string { return a.built }
   143  
   144  // CachedExecutable returns the cached executable, if CacheExecutable
   145  // was set and the executable could be cached, and "" otherwise.
   146  func (a *Action) CachedExecutable() string { return a.cachedExecutable }
   147  
   148  // An actionQueue is a priority queue of actions.
   149  type actionQueue []*Action
   150  
   151  // Implement heap.Interface
   152  func (q *actionQueue) Len() int           { return len(*q) }
   153  func (q *actionQueue) Swap(i, j int)      { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
   154  func (q *actionQueue) Less(i, j int) bool { return (*q)[i].priority < (*q)[j].priority }
   155  func (q *actionQueue) Push(x any)         { *q = append(*q, x.(*Action)) }
   156  func (q *actionQueue) Pop() any {
   157  	n := len(*q) - 1
   158  	x := (*q)[n]
   159  	*q = (*q)[:n]
   160  	return x
   161  }
   162  
   163  func (q *actionQueue) push(a *Action) {
   164  	if a.json != nil {
   165  		a.json.TimeReady = time.Now()
   166  	}
   167  	heap.Push(q, a)
   168  }
   169  
   170  func (q *actionQueue) pop() *Action {
   171  	return heap.Pop(q).(*Action)
   172  }
   173  
   174  type actionJSON struct {
   175  	ID         int
   176  	Mode       string
   177  	Package    string
   178  	Deps       []int     `json:",omitempty"`
   179  	IgnoreFail bool      `json:",omitempty"`
   180  	Args       []string  `json:",omitempty"`
   181  	Link       bool      `json:",omitempty"`
   182  	Objdir     string    `json:",omitempty"`
   183  	Target     string    `json:",omitempty"`
   184  	Priority   int       `json:",omitempty"`
   185  	Failed     bool      `json:",omitempty"`
   186  	Built      string    `json:",omitempty"`
   187  	VetxOnly   bool      `json:",omitempty"`
   188  	NeedVet    bool      `json:",omitempty"`
   189  	NeedBuild  bool      `json:",omitempty"`
   190  	ActionID   string    `json:",omitempty"`
   191  	BuildID    string    `json:",omitempty"`
   192  	TimeReady  time.Time `json:",omitempty"`
   193  	TimeStart  time.Time `json:",omitempty"`
   194  	TimeDone   time.Time `json:",omitempty"`
   195  
   196  	Cmd     []string      // `json:",omitempty"`
   197  	CmdReal time.Duration `json:",omitempty"`
   198  	CmdUser time.Duration `json:",omitempty"`
   199  	CmdSys  time.Duration `json:",omitempty"`
   200  }
   201  
   202  // cacheKey is the key for the action cache.
   203  type cacheKey struct {
   204  	mode string
   205  	p    *load.Package
   206  }
   207  
   208  func actionGraphJSON(a *Action) string {
   209  	var workq []*Action
   210  	var inWorkq = make(map[*Action]int)
   211  
   212  	add := func(a *Action) {
   213  		if _, ok := inWorkq[a]; ok {
   214  			return
   215  		}
   216  		inWorkq[a] = len(workq)
   217  		workq = append(workq, a)
   218  	}
   219  	add(a)
   220  
   221  	for i := 0; i < len(workq); i++ {
   222  		for _, dep := range workq[i].Deps {
   223  			add(dep)
   224  		}
   225  	}
   226  
   227  	list := make([]*actionJSON, 0, len(workq))
   228  	for id, a := range workq {
   229  		if a.json == nil {
   230  			a.json = &actionJSON{
   231  				Mode:       a.Mode,
   232  				ID:         id,
   233  				IgnoreFail: a.IgnoreFail,
   234  				Args:       a.Args,
   235  				Objdir:     a.Objdir,
   236  				Target:     a.Target,
   237  				Failed:     a.Failed != nil,
   238  				Priority:   a.priority,
   239  				Built:      a.built,
   240  				VetxOnly:   a.VetxOnly,
   241  				NeedBuild:  a.needBuild,
   242  				NeedVet:    a.needVet,
   243  			}
   244  			if a.Package != nil {
   245  				// TODO(rsc): Make this a unique key for a.Package somehow.
   246  				a.json.Package = a.Package.ImportPath
   247  			}
   248  			for _, a1 := range a.Deps {
   249  				a.json.Deps = append(a.json.Deps, inWorkq[a1])
   250  			}
   251  		}
   252  		list = append(list, a.json)
   253  	}
   254  
   255  	js, err := json.MarshalIndent(list, "", "\t")
   256  	if err != nil {
   257  		fmt.Fprintf(os.Stderr, "go: writing debug action graph: %v\n", err)
   258  		return ""
   259  	}
   260  	return string(js)
   261  }
   262  
   263  // BuildMode specifies the build mode:
   264  // are we just building things or also installing the results?
   265  type BuildMode int
   266  
   267  const (
   268  	ModeBuild BuildMode = iota
   269  	ModeInstall
   270  	ModeBuggyInstall
   271  
   272  	ModeVetOnly = 1 << 8
   273  )
   274  
   275  // NewBuilder returns a new Builder ready for use.
   276  //
   277  // If workDir is the empty string, NewBuilder creates a WorkDir if needed
   278  // and arranges for it to be removed in case of an unclean exit.
   279  // The caller must Close the builder explicitly to clean up the WorkDir
   280  // before a clean exit.
   281  func NewBuilder(workDir string, getVendorDir func() string) *Builder {
   282  	b := new(Builder)
   283  	b.getVendorDir = getVendorDir
   284  
   285  	b.actionCache = make(map[cacheKey]*Action)
   286  	b.gccToolIDCache = make(map[string]string)
   287  	b.buildIDCache = make(map[string]string)
   288  
   289  	printWorkDir := false
   290  	if workDir != "" {
   291  		b.WorkDir = workDir
   292  	} else if cfg.BuildN {
   293  		b.WorkDir = "$WORK"
   294  	} else {
   295  		if !buildInitStarted {
   296  			panic("internal error: NewBuilder called before BuildInit")
   297  		}
   298  		tmp, err := os.MkdirTemp(cfg.Getenv("GOTMPDIR"), "go-build")
   299  		if err != nil {
   300  			base.Fatalf("go: creating work dir: %v", err)
   301  		}
   302  		if !filepath.IsAbs(tmp) {
   303  			abs, err := filepath.Abs(tmp)
   304  			if err != nil {
   305  				os.RemoveAll(tmp)
   306  				base.Fatalf("go: creating work dir: %v", err)
   307  			}
   308  			tmp = abs
   309  		}
   310  		b.WorkDir = tmp
   311  		builderWorkDirs.Store(b, b.WorkDir)
   312  		printWorkDir = cfg.BuildX || cfg.BuildWork
   313  	}
   314  
   315  	b.backgroundSh = NewShell(b.WorkDir, nil)
   316  
   317  	if printWorkDir {
   318  		b.BackgroundShell().Printf("WORK=%s\n", b.WorkDir)
   319  	}
   320  
   321  	if err := CheckGOOSARCHPair(cfg.Goos, cfg.Goarch); err != nil {
   322  		fmt.Fprintf(os.Stderr, "go: %v\n", err)
   323  		base.SetExitStatus(2)
   324  		base.Exit()
   325  	}
   326  
   327  	for _, tag := range cfg.BuildContext.BuildTags {
   328  		if strings.Contains(tag, ",") {
   329  			fmt.Fprintf(os.Stderr, "go: -tags space-separated list contains comma\n")
   330  			base.SetExitStatus(2)
   331  			base.Exit()
   332  		}
   333  	}
   334  
   335  	return b
   336  }
   337  
   338  var builderWorkDirs sync.Map // *Builder → WorkDir
   339  
   340  func (b *Builder) Close() error {
   341  	wd, ok := builderWorkDirs.Load(b)
   342  	if !ok {
   343  		return nil
   344  	}
   345  	defer builderWorkDirs.Delete(b)
   346  
   347  	if b.WorkDir != wd.(string) {
   348  		base.Errorf("go: internal error: Builder WorkDir unexpectedly changed from %s to %s", wd, b.WorkDir)
   349  	}
   350  
   351  	if !cfg.BuildWork {
   352  		if err := robustio.RemoveAll(b.WorkDir); err != nil {
   353  			return err
   354  		}
   355  	}
   356  	b.WorkDir = ""
   357  	return nil
   358  }
   359  
   360  func closeBuilders() {
   361  	leakedBuilders := 0
   362  	builderWorkDirs.Range(func(bi, _ any) bool {
   363  		leakedBuilders++
   364  		if err := bi.(*Builder).Close(); err != nil {
   365  			base.Error(err)
   366  		}
   367  		return true
   368  	})
   369  
   370  	if leakedBuilders > 0 && base.GetExitStatus() == 0 {
   371  		fmt.Fprintf(os.Stderr, "go: internal error: Builder leaked on successful exit\n")
   372  		base.SetExitStatus(1)
   373  	}
   374  }
   375  
   376  func CheckGOOSARCHPair(goos, goarch string) error {
   377  	if !platform.BuildModeSupported(cfg.BuildContext.Compiler, "default", goos, goarch) {
   378  		return fmt.Errorf("unsupported GOOS/GOARCH pair %s/%s", goos, goarch)
   379  	}
   380  	return nil
   381  }
   382  
   383  // NewObjdir returns the name of a fresh object directory under b.WorkDir.
   384  // It is up to the caller to call b.Mkdir on the result at an appropriate time.
   385  // The result ends in a slash, so that file names in that directory
   386  // can be constructed with direct string addition.
   387  //
   388  // NewObjdir must be called only from a single goroutine at a time,
   389  // so it is safe to call during action graph construction, but it must not
   390  // be called during action graph execution.
   391  func (b *Builder) NewObjdir() string {
   392  	b.objdirSeq++
   393  	return str.WithFilePathSeparator(filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)))
   394  }
   395  
   396  // readpkglist returns the list of packages that were built into the shared library
   397  // at shlibpath. For the native toolchain this list is stored, newline separated, in
   398  // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
   399  // .go_export section.
   400  func readpkglist(s *modload.State, shlibpath string) (pkgs []*load.Package) {
   401  	var stk load.ImportStack
   402  	if cfg.BuildToolchainName == "gccgo" {
   403  		f, err := elf.Open(shlibpath)
   404  		if err != nil {
   405  			base.Fatal(fmt.Errorf("failed to open shared library: %v", err))
   406  		}
   407  		defer f.Close()
   408  		sect := f.Section(".go_export")
   409  		if sect == nil {
   410  			base.Fatal(fmt.Errorf("%s: missing .go_export section", shlibpath))
   411  		}
   412  		data, err := sect.Data()
   413  		if err != nil {
   414  			base.Fatal(fmt.Errorf("%s: failed to read .go_export section: %v", shlibpath, err))
   415  		}
   416  		pkgpath := []byte("pkgpath ")
   417  		for _, line := range bytes.Split(data, []byte{'\n'}) {
   418  			if path, found := bytes.CutPrefix(line, pkgpath); found {
   419  				path = bytes.TrimSuffix(path, []byte{';'})
   420  				pkgs = append(pkgs, load.LoadPackageWithFlags(s, string(path), base.Cwd(), &stk, nil, 0))
   421  			}
   422  		}
   423  	} else {
   424  		pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1)
   425  		if err != nil {
   426  			base.Fatalf("readELFNote failed: %v", err)
   427  		}
   428  		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
   429  		for scanner.Scan() {
   430  			t := scanner.Text()
   431  			pkgs = append(pkgs, load.LoadPackageWithFlags(s, t, base.Cwd(), &stk, nil, 0))
   432  		}
   433  	}
   434  	return
   435  }
   436  
   437  // cacheAction looks up {mode, p} in the cache and returns the resulting action.
   438  // If the cache has no such action, f() is recorded and returned.
   439  // TODO(rsc): Change the second key from *load.Package to interface{},
   440  // to make the caching in linkShared less awkward?
   441  func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *Action {
   442  	a := b.actionCache[cacheKey{mode, p}]
   443  	if a == nil {
   444  		a = f()
   445  		b.actionCache[cacheKey{mode, p}] = a
   446  	}
   447  	return a
   448  }
   449  
   450  // AutoAction returns the "right" action for go build or go install of p.
   451  func (b *Builder) AutoAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
   452  	if p.Name == "main" {
   453  		return b.LinkAction(s, mode, depMode, p)
   454  	}
   455  	return b.CompileAction(mode, depMode, p)
   456  }
   457  
   458  // buildActor implements the Actor interface for package build
   459  // actions. For most package builds this simply means invoking the
   460  // *Builder.build method.
   461  type buildActor struct{}
   462  
   463  func (ba *buildActor) Act(b *Builder, ctx context.Context, a *Action) error {
   464  	return b.build(ctx, a)
   465  }
   466  
   467  // pgoActionID computes the action ID for a preprocess PGO action.
   468  func (b *Builder) pgoActionID(input string) cache.ActionID {
   469  	h := cache.NewHash("preprocess PGO profile " + input)
   470  
   471  	fmt.Fprintf(h, "preprocess PGO profile\n")
   472  	fmt.Fprintf(h, "preprofile %s\n", b.toolID("preprofile"))
   473  	fmt.Fprintf(h, "input %q\n", b.fileHash(input))
   474  
   475  	return h.Sum()
   476  }
   477  
   478  // pgoActor implements the Actor interface for preprocessing PGO profiles.
   479  type pgoActor struct {
   480  	// input is the path to the original pprof profile.
   481  	input string
   482  }
   483  
   484  func (p *pgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
   485  	if b.useCache(a, b.pgoActionID(p.input), a.Target, !b.IsCmdList) || b.IsCmdList {
   486  		return nil
   487  	}
   488  	defer b.flushOutput(a)
   489  
   490  	sh := b.Shell(a)
   491  
   492  	if err := sh.Mkdir(a.Objdir); err != nil {
   493  		return err
   494  	}
   495  
   496  	if err := sh.run(".", p.input, nil, cfg.BuildToolexec, base.Tool("preprofile"), "-o", a.Target, "-i", p.input); err != nil {
   497  		return err
   498  	}
   499  
   500  	// N.B. Builder.build looks for the out in a.built, regardless of
   501  	// whether this came from cache.
   502  	a.built = a.Target
   503  
   504  	if !cfg.BuildN {
   505  		// Cache the output.
   506  		//
   507  		// N.B. We don't use updateBuildID here, as preprocessed PGO profiles
   508  		// do not contain a build ID. updateBuildID is typically responsible
   509  		// for adding to the cache, thus we must do so ourselves instead.
   510  
   511  		r, err := os.Open(a.Target)
   512  		if err != nil {
   513  			return fmt.Errorf("error opening target for caching: %w", err)
   514  		}
   515  
   516  		c := cache.Default()
   517  		outputID, _, err := c.Put(a.actionID, r)
   518  		r.Close()
   519  		if err != nil {
   520  			return fmt.Errorf("error adding target to cache: %w", err)
   521  		}
   522  		if cfg.BuildX {
   523  			sh.ShowCmd("", "%s # internal", joinUnambiguously(str.StringList("cp", a.Target, c.OutputFile(outputID))))
   524  		}
   525  	}
   526  
   527  	return nil
   528  }
   529  
   530  type checkCacheProvider struct {
   531  	need uint32 // What work do successive actions within this package's build need to do? Combination of need bits used in build actions.
   532  }
   533  
   534  // The actor to check the cache to determine what work needs to be done for the action.
   535  // It checks the cache and sets the need bits depending on the build mode and what's available
   536  // in the cache, so the cover and compile actions know what to do.
   537  // Currently, we don't cache the outputs of the individual actions composing the build
   538  // for a single package (such as the output of the cover actor) separately from the
   539  // output of the final build, but if we start doing so, we could schedule the run cgo
   540  // and cgo compile actions earlier because they wouldn't depend on the builds of the
   541  // dependencies of the package they belong to.
   542  type checkCacheActor struct {
   543  	covMetaFileName string
   544  	buildAction     *Action
   545  }
   546  
   547  func (cca *checkCacheActor) Act(b *Builder, ctx context.Context, a *Action) error {
   548  	buildAction := cca.buildAction
   549  	if buildAction.Mode == "build-install" {
   550  		// (*Builder).installAction can rewrite the build action with its install action,
   551  		// making the true build action its dependency. Fetch the build action in that case.
   552  		buildAction = buildAction.Deps[0]
   553  	}
   554  	pr, err := b.checkCacheForBuild(a, buildAction, cca.covMetaFileName)
   555  	if err != nil {
   556  		return err
   557  	}
   558  	a.Provider = pr
   559  	return nil
   560  }
   561  
   562  type coverProvider struct {
   563  	goSources, cgoSources []string // The go and cgo sources generated by the cover tool, which should be used instead of the raw sources on the package.
   564  }
   565  
   566  // The actor to run the cover tool to produce instrumented source files for cover
   567  // builds. In the case of a package with no test files, we store some additional state
   568  // information in the build actor to help with reporting.
   569  type coverActor struct {
   570  	// name of static meta-data file fragment emitted by the cover
   571  	// tool as part of the package cover action, for selected
   572  	// "go test -cover" runs.
   573  	covMetaFileName string
   574  
   575  	buildAction *Action
   576  }
   577  
   578  func (ca *coverActor) Act(b *Builder, ctx context.Context, a *Action) error {
   579  	pr, err := b.runCover(a, ca.buildAction, a.Objdir, a.Package.GoFiles, a.Package.CgoFiles)
   580  	if err != nil {
   581  		return err
   582  	}
   583  	a.Provider = pr
   584  	return nil
   585  }
   586  
   587  // runCgoActor implements the Actor interface for running the cgo command for the package.
   588  type runCgoActor struct {
   589  }
   590  
   591  func (c runCgoActor) Act(b *Builder, ctx context.Context, a *Action) error {
   592  	var cacheProvider *checkCacheProvider
   593  	for _, a1 := range a.Deps {
   594  		if pr, ok := a1.Provider.(*checkCacheProvider); ok {
   595  			cacheProvider = pr
   596  			break
   597  		}
   598  	}
   599  	need := cacheProvider.need
   600  	need &^= needCovMetaFile // handled by cover action
   601  	if need == 0 {
   602  		return nil
   603  	}
   604  	return b.runCgo(ctx, a)
   605  }
   606  
   607  type cgoCompileActor struct {
   608  	file string
   609  
   610  	compileFunc  func(*Action, string, string, []string, string) error
   611  	getFlagsFunc func(*runCgoProvider) []string
   612  
   613  	flags *[]string
   614  }
   615  
   616  func (c cgoCompileActor) Act(b *Builder, ctx context.Context, a *Action) error {
   617  	pr, ok := a.Deps[0].Provider.(*runCgoProvider)
   618  	if !ok {
   619  		return nil // cgo was not needed. do nothing.
   620  	}
   621  	a.nonGoOverlay = pr.nonGoOverlay
   622  	buildAction := a.triggers[0].triggers[0] // cgo compile -> cgo collect -> build
   623  
   624  	a.actionID = cache.Subkey(buildAction.actionID, "cgo compile "+c.file) // buildAction's action id was computed by the check cache action.
   625  	return c.compileFunc(a, a.Objdir, a.Target, c.getFlagsFunc(pr), c.file)
   626  }
   627  
   628  // CompileAction returns the action for compiling and possibly installing
   629  // (according to mode) the given package. The resulting action is only
   630  // for building packages (archives), never for linking executables.
   631  // depMode is the action (build or install) to use when building dependencies.
   632  // To turn package main into an executable, call b.Link instead.
   633  func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action {
   634  	vetOnly := mode&ModeVetOnly != 0
   635  	mode &^= ModeVetOnly
   636  
   637  	if mode != ModeBuild && p.Target == "" {
   638  		// No permanent target.
   639  		mode = ModeBuild
   640  	}
   641  	if mode != ModeBuild && p.Name == "main" {
   642  		// We never install the .a file for a main package.
   643  		mode = ModeBuild
   644  	}
   645  
   646  	// Construct package build action.
   647  	a := b.cacheAction("build", p, func() *Action {
   648  		a := &Action{
   649  			Mode:    "build",
   650  			Package: p,
   651  			Actor:   &buildActor{},
   652  			Objdir:  b.NewObjdir(),
   653  		}
   654  
   655  		if p.Error == nil || !p.Error.IsImportCycle {
   656  			for _, p1 := range p.Internal.Imports {
   657  				a.Deps = append(a.Deps, b.CompileAction(depMode, depMode, p1))
   658  			}
   659  		}
   660  
   661  		if p.Internal.PGOProfile != "" {
   662  			pgoAction := b.cacheAction("preprocess PGO profile "+p.Internal.PGOProfile, nil, func() *Action {
   663  				a := &Action{
   664  					Mode:   "preprocess PGO profile",
   665  					Actor:  &pgoActor{input: p.Internal.PGOProfile},
   666  					Objdir: b.NewObjdir(),
   667  				}
   668  				a.Target = filepath.Join(a.Objdir, "pgo.preprofile")
   669  
   670  				return a
   671  			})
   672  			a.Deps = append(a.Deps, pgoAction)
   673  		}
   674  
   675  		if p.Standard {
   676  			switch p.ImportPath {
   677  			case "builtin", "unsafe":
   678  				// Fake packages - nothing to build.
   679  				a.Mode = "built-in package"
   680  				a.Actor = nil
   681  				return a
   682  			}
   683  
   684  			// gccgo standard library is "fake" too.
   685  			if cfg.BuildToolchainName == "gccgo" {
   686  				// the target name is needed for cgo.
   687  				a.Mode = "gccgo stdlib"
   688  				a.Target = p.Target
   689  				a.Actor = nil
   690  				return a
   691  			}
   692  		}
   693  
   694  		// Determine the covmeta file name.
   695  		var covMetaFileName string
   696  		if p.Internal.Cover.GenMeta {
   697  			covMetaFileName = covcmd.MetaFileForPackage(p.ImportPath)
   698  		}
   699  
   700  		// Create a cache action.
   701  		cacheAction := &Action{
   702  			Mode:    "build check cache",
   703  			Package: p,
   704  			Actor:   &checkCacheActor{buildAction: a, covMetaFileName: covMetaFileName},
   705  			Objdir:  a.Objdir,
   706  			Deps:    a.Deps, // Need outputs of dependency build actions to generate action id.
   707  		}
   708  		a.Deps = append(a.Deps, cacheAction)
   709  
   710  		// Create a cover action if we need to instrument the code for coverage.
   711  		// The cover action always runs in the same go build invocation as the build,
   712  		// and is not cached separately, so it can use the same objdir.
   713  		var coverAction *Action
   714  		if p.Internal.Cover.Mode != "" {
   715  			coverAction = b.cacheAction("cover", p, func() *Action {
   716  				return &Action{
   717  					Mode:    "cover",
   718  					Package: p,
   719  					Actor:   &coverActor{buildAction: a, covMetaFileName: covMetaFileName},
   720  					Objdir:  a.Objdir,
   721  					Deps:    []*Action{cacheAction},
   722  				}
   723  			})
   724  			a.Deps = append(a.Deps, coverAction)
   725  		}
   726  
   727  		// Create actions to run swig and cgo if needed. These actions always run in the
   728  		// same go build invocation as the build action and their actions are not cached
   729  		// separately, so they can use the same objdir.
   730  		if p.UsesCgo() || p.UsesSwig() {
   731  			deps := []*Action{cacheAction}
   732  			if coverAction != nil {
   733  				deps = append(deps, coverAction)
   734  			}
   735  			a.Deps = append(a.Deps, b.cgoAction(p, a.Objdir, deps, coverAction != nil))
   736  		}
   737  
   738  		return a
   739  	})
   740  
   741  	// Find the build action; the cache entry may have been replaced
   742  	// by the install action during (*Builder).installAction.
   743  	buildAction := a
   744  	switch buildAction.Mode {
   745  	case "build", "built-in package", "gccgo stdlib":
   746  		// ok
   747  	case "build-install":
   748  		buildAction = a.Deps[0]
   749  	default:
   750  		panic("lost build action: " + buildAction.Mode)
   751  	}
   752  	buildAction.needBuild = buildAction.needBuild || !vetOnly
   753  
   754  	// Construct install action.
   755  	if mode == ModeInstall || mode == ModeBuggyInstall {
   756  		a = b.installAction(a, mode)
   757  	}
   758  
   759  	return a
   760  }
   761  
   762  func (b *Builder) cgoAction(p *load.Package, objdir string, deps []*Action, hasCover bool) *Action {
   763  	cgoCollectAction := b.cacheAction("cgo collect", p, func() *Action {
   764  		// Run cgo
   765  		runCgo := b.cacheAction("cgo run", p, func() *Action {
   766  			return &Action{
   767  				Package: p,
   768  				Mode:    "cgo run",
   769  				Actor:   &runCgoActor{},
   770  				Objdir:  objdir,
   771  				Deps:    deps,
   772  			}
   773  		})
   774  
   775  		// Determine which files swig will produce in the cgo run action. We'll need to create
   776  		// actions to compile the C and C++ files produced by swig, as well as the C file
   777  		// produced by cgo processing swig's Go file outputs.
   778  		swigGo, swigC, swigCXX := b.swigOutputs(p, objdir)
   779  
   780  		oseq := 0
   781  		nextOfile := func() string {
   782  			oseq++
   783  			return objdir + fmt.Sprintf("_x%03d.o", oseq)
   784  		}
   785  		compileAction := func(file string, getFlagsFunc func(*runCgoProvider) []string, compileFunc func(*Action, string, string, []string, string) error) *Action {
   786  			mode := "cgo compile " + file
   787  			return b.cacheAction(mode, p, func() *Action {
   788  				return &Action{
   789  					Package: p,
   790  					Mode:    mode,
   791  					Actor:   &cgoCompileActor{file: file, getFlagsFunc: getFlagsFunc, compileFunc: compileFunc},
   792  					Deps:    []*Action{runCgo},
   793  					Objdir:  objdir,
   794  					Target:  nextOfile(),
   795  				}
   796  			})
   797  		}
   798  
   799  		var collectDeps []*Action
   800  
   801  		// Add compile actions for C files generated by cgo.
   802  		cgoFiles := p.CgoFiles
   803  		if hasCover {
   804  			cgoFiles = slices.Clone(cgoFiles)
   805  			for i := range cgoFiles {
   806  				cgoFiles[i] = strings.TrimSuffix(cgoFiles[i], ".go") + ".cover.go"
   807  			}
   808  		}
   809  		cfiles := []string{"_cgo_export.c"}
   810  		for _, fn := range slices.Concat(cgoFiles, swigGo) {
   811  			cfiles = append(cfiles, strings.TrimSuffix(filepath.Base(fn), ".go")+".cgo2.c")
   812  		}
   813  		for _, f := range cfiles {
   814  			collectDeps = append(collectDeps, compileAction(objdir+f, (*runCgoProvider).cflags, b.gcc))
   815  		}
   816  
   817  		// Add compile actions for S files.
   818  		var sfiles []string
   819  		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
   820  		// There is one exception: runtime/cgo's job is to bridge the
   821  		// cgo and non-cgo worlds, so it necessarily has files in both.
   822  		// In that case gcc only gets the gcc_* files.
   823  		if p.Standard && p.ImportPath == "runtime/cgo" {
   824  			for _, f := range p.SFiles {
   825  				if strings.HasPrefix(f, "gcc_") {
   826  					sfiles = append(sfiles, f)
   827  				}
   828  			}
   829  		} else {
   830  			sfiles = p.SFiles
   831  		}
   832  		for _, f := range sfiles {
   833  			collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cflags, b.gas))
   834  		}
   835  
   836  		// Add compile actions for C files in the package, M files, and those generated by swig.
   837  		for _, f := range slices.Concat(p.CFiles, p.MFiles, swigC) {
   838  			collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cflags, b.gcc))
   839  		}
   840  
   841  		// Add compile actions for C++ files in the package, and those generated by swig.
   842  		for _, f := range slices.Concat(p.CXXFiles, swigCXX) {
   843  			collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).cxxflags, b.gxx))
   844  		}
   845  
   846  		// Add compile actions for Fortran files in the package.
   847  		for _, f := range p.FFiles {
   848  			collectDeps = append(collectDeps, compileAction(f, (*runCgoProvider).fflags, b.gfortran))
   849  		}
   850  
   851  		// Add a single convenience action that does nothing to join the previous action,
   852  		// and better separate the cgo action dependencies of the build action from the
   853  		// build actions for its package dependencies.
   854  		return &Action{
   855  			Mode: "collect cgo",
   856  			Actor: ActorFunc(func(b *Builder, ctx context.Context, a *Action) error {
   857  				// Use the cgo run action's provider as our provider output,
   858  				// so it can be easily accessed by the build action.
   859  				a.Provider = a.Deps[0].Deps[0].Provider
   860  				return nil
   861  			}),
   862  			Deps:   collectDeps,
   863  			Objdir: objdir,
   864  		}
   865  	})
   866  
   867  	return cgoCollectAction
   868  }
   869  
   870  // VetAction returns the action for running go vet on package p.
   871  // It depends on the action for compiling p.
   872  // If the caller may be causing p to be installed, it is up to the caller
   873  // to make sure that the install depends on (runs after) vet.
   874  func (b *Builder) VetAction(s *modload.State, mode, depMode BuildMode, needFix bool, p *load.Package) *Action {
   875  	a := b.vetAction(s, mode, depMode, p)
   876  	a.VetxOnly = false
   877  	a.needFix = needFix
   878  	return a
   879  }
   880  
   881  func (b *Builder) vetAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
   882  	// Construct vet action.
   883  	a := b.cacheAction("vet", p, func() *Action {
   884  		a1 := b.CompileAction(mode|ModeVetOnly, depMode, p)
   885  
   886  		var deps []*Action
   887  		if a1.buggyInstall {
   888  			// (*Builder).vet expects deps[0] to be the package.
   889  			// If we see buggyInstall
   890  			// here then a1 is an install of a shared library,
   891  			// and the real package is a1.Deps[0].
   892  			deps = []*Action{a1.Deps[0], a1}
   893  		} else {
   894  			deps = []*Action{a1}
   895  		}
   896  		for _, p1 := range p.Internal.Imports {
   897  			deps = append(deps, b.vetAction(s, mode, depMode, p1))
   898  		}
   899  
   900  		a := &Action{
   901  			Mode:       "vet",
   902  			Package:    p,
   903  			Deps:       deps,
   904  			Objdir:     a1.Objdir,
   905  			VetxOnly:   true,
   906  			IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems)
   907  		}
   908  		if a1.Actor == nil {
   909  			// Built-in packages like unsafe.
   910  			return a
   911  		}
   912  		deps[0].needVet = true
   913  		a.Actor = ActorFunc((*Builder).vet)
   914  		return a
   915  	})
   916  	return a
   917  }
   918  
   919  // LinkAction returns the action for linking p into an executable
   920  // and possibly installing the result (according to mode).
   921  // depMode is the action (build or install) to use when compiling dependencies.
   922  func (b *Builder) LinkAction(s *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
   923  	// Construct link action.
   924  	a := b.cacheAction("link", p, func() *Action {
   925  		a := &Action{
   926  			Mode:    "link",
   927  			Package: p,
   928  		}
   929  
   930  		a1 := b.CompileAction(ModeBuild, depMode, p)
   931  		a.Actor = ActorFunc((*Builder).link)
   932  		a.Deps = []*Action{a1}
   933  		a.Objdir = a1.Objdir
   934  
   935  		// An executable file. (This is the name of a temporary file.)
   936  		// Because we run the temporary file in 'go run' and 'go test',
   937  		// the name will show up in ps listings. If the caller has specified
   938  		// a name, use that instead of a.out. The binary is generated
   939  		// in an otherwise empty subdirectory named exe to avoid
   940  		// naming conflicts. The only possible conflict is if we were
   941  		// to create a top-level package named exe.
   942  		name := "a.out"
   943  		if p.Internal.ExeName != "" {
   944  			name = p.Internal.ExeName
   945  		} else if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" && p.Target != "" {
   946  			// On OS X, the linker output name gets recorded in the
   947  			// shared library's LC_ID_DYLIB load command.
   948  			// The code invoking the linker knows to pass only the final
   949  			// path element. Arrange that the path element matches what
   950  			// we'll install it as; otherwise the library is only loadable as "a.out".
   951  			// On Windows, DLL file name is recorded in PE file
   952  			// export section, so do like on OS X.
   953  			_, name = filepath.Split(p.Target)
   954  		}
   955  		a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
   956  		a.built = a.Target
   957  		b.addTransitiveLinkDeps(s, a, a1, "")
   958  
   959  		// Sequence the build of the main package (a1) strictly after the build
   960  		// of all other dependencies that go into the link. It is likely to be after
   961  		// them anyway, but just make sure. This is required by the build ID-based
   962  		// shortcut in (*Builder).useCache(a1), which will call b.linkActionID(a).
   963  		// In order for that linkActionID call to compute the right action ID, all the
   964  		// dependencies of a (except a1) must have completed building and have
   965  		// recorded their build IDs.
   966  		a1.Deps = append(a1.Deps, &Action{Mode: "nop", Deps: a.Deps[1:]})
   967  		return a
   968  	})
   969  
   970  	if mode == ModeInstall || mode == ModeBuggyInstall {
   971  		a = b.installAction(a, mode)
   972  	}
   973  
   974  	return a
   975  }
   976  
   977  // installAction returns the action for installing the result of a1.
   978  func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action {
   979  	// Because we overwrite the build action with the install action below,
   980  	// a1 may already be an install action fetched from the "build" cache key,
   981  	// and the caller just doesn't realize.
   982  	if strings.HasSuffix(a1.Mode, "-install") {
   983  		if a1.buggyInstall && mode == ModeInstall {
   984  			//  Congratulations! The buggy install is now a proper install.
   985  			a1.buggyInstall = false
   986  		}
   987  		return a1
   988  	}
   989  
   990  	// If there's no actual action to build a1,
   991  	// there's nothing to install either.
   992  	// This happens if a1 corresponds to reusing an already-built object.
   993  	if a1.Actor == nil {
   994  		return a1
   995  	}
   996  
   997  	p := a1.Package
   998  	return b.cacheAction(a1.Mode+"-install", p, func() *Action {
   999  		// The install deletes the temporary build result,
  1000  		// so we need all other actions, both past and future,
  1001  		// that attempt to depend on the build to depend instead
  1002  		// on the install.
  1003  
  1004  		// Make a private copy of a1 (the build action),
  1005  		// no longer accessible to any other rules.
  1006  		buildAction := new(Action)
  1007  		*buildAction = *a1
  1008  
  1009  		// Overwrite a1 with the install action.
  1010  		// This takes care of updating past actions that
  1011  		// point at a1 for the build action; now they will
  1012  		// point at a1 and get the install action.
  1013  		// We also leave a1 in the action cache as the result
  1014  		// for "build", so that actions not yet created that
  1015  		// try to depend on the build will instead depend
  1016  		// on the install.
  1017  		*a1 = Action{
  1018  			Mode:    buildAction.Mode + "-install",
  1019  			Actor:   ActorFunc(BuildInstallFunc),
  1020  			Package: p,
  1021  			Objdir:  buildAction.Objdir,
  1022  			Deps:    []*Action{buildAction},
  1023  			Target:  p.Target,
  1024  			built:   p.Target,
  1025  
  1026  			buggyInstall: mode == ModeBuggyInstall,
  1027  		}
  1028  
  1029  		b.addInstallHeaderAction(a1)
  1030  		return a1
  1031  	})
  1032  }
  1033  
  1034  // addTransitiveLinkDeps adds to the link action a all packages
  1035  // that are transitive dependencies of a1.Deps.
  1036  // That is, if a is a link of package main, a1 is the compile of package main
  1037  // and a1.Deps is the actions for building packages directly imported by
  1038  // package main (what the compiler needs). The linker needs all packages
  1039  // transitively imported by the whole program; addTransitiveLinkDeps
  1040  // makes sure those are present in a.Deps.
  1041  // If shlib is non-empty, then a corresponds to the build and installation of shlib,
  1042  // so any rebuild of shlib should not be added as a dependency.
  1043  func (b *Builder) addTransitiveLinkDeps(s *modload.State, a, a1 *Action, shlib string) {
  1044  	// Expand Deps to include all built packages, for the linker.
  1045  	// Use breadth-first search to find rebuilt-for-test packages
  1046  	// before the standard ones.
  1047  	// TODO(rsc): Eliminate the standard ones from the action graph,
  1048  	// which will require doing a little bit more rebuilding.
  1049  	workq := []*Action{a1}
  1050  	haveDep := map[string]bool{}
  1051  	if a1.Package != nil {
  1052  		haveDep[a1.Package.ImportPath] = true
  1053  	}
  1054  	for i := 0; i < len(workq); i++ {
  1055  		a1 := workq[i]
  1056  		for _, a2 := range a1.Deps {
  1057  			// TODO(rsc): Find a better discriminator than the Mode strings, once the dust settles.
  1058  			if a2.Package == nil || (a2.Mode != "build-install" && a2.Mode != "build") || haveDep[a2.Package.ImportPath] {
  1059  				continue
  1060  			}
  1061  			haveDep[a2.Package.ImportPath] = true
  1062  			a.Deps = append(a.Deps, a2)
  1063  			if a2.Mode == "build-install" {
  1064  				a2 = a2.Deps[0] // walk children of "build" action
  1065  			}
  1066  			workq = append(workq, a2)
  1067  		}
  1068  	}
  1069  
  1070  	// If this is go build -linkshared, then the link depends on the shared libraries
  1071  	// in addition to the packages themselves. (The compile steps do not.)
  1072  	if cfg.BuildLinkshared {
  1073  		haveShlib := map[string]bool{shlib: true}
  1074  		for _, a1 := range a.Deps {
  1075  			p1 := a1.Package
  1076  			if p1 == nil || p1.Shlib == "" || haveShlib[filepath.Base(p1.Shlib)] {
  1077  				continue
  1078  			}
  1079  			haveShlib[filepath.Base(p1.Shlib)] = true
  1080  			// TODO(rsc): The use of ModeInstall here is suspect, but if we only do ModeBuild,
  1081  			// we'll end up building an overall library or executable that depends at runtime
  1082  			// on other libraries that are out-of-date, which is clearly not good either.
  1083  			// We call it ModeBuggyInstall to make clear that this is not right.
  1084  			a.Deps = append(a.Deps, b.linkSharedAction(s, ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil))
  1085  		}
  1086  	}
  1087  }
  1088  
  1089  // addInstallHeaderAction adds an install header action to a, if needed.
  1090  // The action a should be an install action as generated by either
  1091  // b.CompileAction or b.LinkAction with mode=ModeInstall,
  1092  // and so a.Deps[0] is the corresponding build action.
  1093  func (b *Builder) addInstallHeaderAction(a *Action) {
  1094  	// Install header for cgo in c-archive and c-shared modes.
  1095  	p := a.Package
  1096  	if p.UsesCgo() && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
  1097  		hdrTarget := a.Target[:len(a.Target)-len(filepath.Ext(a.Target))] + ".h"
  1098  		if cfg.BuildContext.Compiler == "gccgo" && cfg.BuildO == "" {
  1099  			// For the header file, remove the "lib"
  1100  			// added by go/build, so we generate pkg.h
  1101  			// rather than libpkg.h.
  1102  			dir, file := filepath.Split(hdrTarget)
  1103  			file = strings.TrimPrefix(file, "lib")
  1104  			hdrTarget = filepath.Join(dir, file)
  1105  		}
  1106  		ah := &Action{
  1107  			Mode:    "install header",
  1108  			Package: a.Package,
  1109  			Deps:    []*Action{a.Deps[0]},
  1110  			Actor:   ActorFunc((*Builder).installHeader),
  1111  			Objdir:  a.Deps[0].Objdir,
  1112  			Target:  hdrTarget,
  1113  		}
  1114  		a.Deps = append(a.Deps, ah)
  1115  	}
  1116  }
  1117  
  1118  // buildmodeShared takes the "go build" action a1 into the building of a shared library of a1.Deps.
  1119  // That is, the input a1 represents "go build pkgs" and the result represents "go build -buildmode=shared pkgs".
  1120  func (b *Builder) buildmodeShared(s *modload.State, mode, depMode BuildMode, args []string, pkgs []*load.Package, a1 *Action) *Action {
  1121  	name, err := libname(args, pkgs)
  1122  	if err != nil {
  1123  		base.Fatalf("%v", err)
  1124  	}
  1125  	return b.linkSharedAction(s, mode, depMode, name, a1)
  1126  }
  1127  
  1128  // linkSharedAction takes a grouping action a1 corresponding to a list of built packages
  1129  // and returns an action that links them together into a shared library with the name shlib.
  1130  // If a1 is nil, shlib should be an absolute path to an existing shared library,
  1131  // and then linkSharedAction reads that library to find out the package list.
  1132  func (b *Builder) linkSharedAction(s *modload.State, mode, depMode BuildMode, shlib string, a1 *Action) *Action {
  1133  	fullShlib := shlib
  1134  	shlib = filepath.Base(shlib)
  1135  	a := b.cacheAction("build-shlib "+shlib, nil, func() *Action {
  1136  		if a1 == nil {
  1137  			// TODO(rsc): Need to find some other place to store config,
  1138  			// not in pkg directory. See golang.org/issue/22196.
  1139  			pkgs := readpkglist(s, fullShlib)
  1140  			a1 = &Action{
  1141  				Mode: "shlib packages",
  1142  			}
  1143  			for _, p := range pkgs {
  1144  				a1.Deps = append(a1.Deps, b.CompileAction(mode, depMode, p))
  1145  			}
  1146  		}
  1147  
  1148  		// Fake package to hold ldflags.
  1149  		// As usual shared libraries are a kludgy, abstraction-violating special case:
  1150  		// we let them use the flags specified for the command-line arguments.
  1151  		p := &load.Package{}
  1152  		p.Internal.CmdlinePkg = true
  1153  		p.Internal.Ldflags = load.BuildLdflags.For(s, p)
  1154  		p.Internal.Gccgoflags = load.BuildGccgoflags.For(s, p)
  1155  
  1156  		// Add implicit dependencies to pkgs list.
  1157  		// Currently buildmode=shared forces external linking mode, and
  1158  		// external linking mode forces an import of runtime/cgo (and
  1159  		// math on arm). So if it was not passed on the command line and
  1160  		// it is not present in another shared library, add it here.
  1161  		// TODO(rsc): Maybe this should only happen if "runtime" is in the original package set.
  1162  		// TODO(rsc): This should probably be changed to use load.LinkerDeps(p).
  1163  		// TODO(rsc): We don't add standard library imports for gccgo
  1164  		// because they are all always linked in anyhow.
  1165  		// Maybe load.LinkerDeps should be used and updated.
  1166  		a := &Action{
  1167  			Mode:    "go build -buildmode=shared",
  1168  			Package: p,
  1169  			Objdir:  b.NewObjdir(),
  1170  			Actor:   ActorFunc((*Builder).linkShared),
  1171  			Deps:    []*Action{a1},
  1172  		}
  1173  		a.Target = filepath.Join(a.Objdir, shlib)
  1174  		if cfg.BuildToolchainName != "gccgo" {
  1175  			add := func(a1 *Action, pkg string, force bool) {
  1176  				for _, a2 := range a1.Deps {
  1177  					if a2.Package != nil && a2.Package.ImportPath == pkg {
  1178  						return
  1179  					}
  1180  				}
  1181  				var stk load.ImportStack
  1182  				p := load.LoadPackageWithFlags(s, pkg, base.Cwd(), &stk, nil, 0)
  1183  				if p.Error != nil {
  1184  					base.Fatalf("load %s: %v", pkg, p.Error)
  1185  				}
  1186  				// Assume that if pkg (runtime/cgo or math)
  1187  				// is already accounted for in a different shared library,
  1188  				// then that shared library also contains runtime,
  1189  				// so that anything we do will depend on that library,
  1190  				// so we don't need to include pkg in our shared library.
  1191  				if force || p.Shlib == "" || filepath.Base(p.Shlib) == pkg {
  1192  					a1.Deps = append(a1.Deps, b.CompileAction(depMode, depMode, p))
  1193  				}
  1194  			}
  1195  			add(a1, "runtime/cgo", false)
  1196  			if cfg.Goarch == "arm" {
  1197  				add(a1, "math", false)
  1198  			}
  1199  
  1200  			// The linker step still needs all the usual linker deps.
  1201  			// (For example, the linker always opens runtime.a.)
  1202  			ldDeps, err := load.LinkerDeps(s, nil)
  1203  			if err != nil {
  1204  				base.Error(err)
  1205  			}
  1206  			for _, dep := range ldDeps {
  1207  				add(a, dep, true)
  1208  			}
  1209  		}
  1210  		b.addTransitiveLinkDeps(s, a, a1, shlib)
  1211  		return a
  1212  	})
  1213  
  1214  	// Install result.
  1215  	if (mode == ModeInstall || mode == ModeBuggyInstall) && a.Actor != nil {
  1216  		buildAction := a
  1217  
  1218  		a = b.cacheAction("install-shlib "+shlib, nil, func() *Action {
  1219  			// Determine the eventual install target.
  1220  			// The install target is root/pkg/shlib, where root is the source root
  1221  			// in which all the packages lie.
  1222  			// TODO(rsc): Perhaps this cross-root check should apply to the full
  1223  			// transitive package dependency list, not just the ones named
  1224  			// on the command line?
  1225  			pkgDir := a1.Deps[0].Package.Internal.Build.PkgTargetRoot
  1226  			for _, a2 := range a1.Deps {
  1227  				if dir := a2.Package.Internal.Build.PkgTargetRoot; dir != pkgDir {
  1228  					base.Fatalf("installing shared library: cannot use packages %s and %s from different roots %s and %s",
  1229  						a1.Deps[0].Package.ImportPath,
  1230  						a2.Package.ImportPath,
  1231  						pkgDir,
  1232  						dir)
  1233  				}
  1234  			}
  1235  			// TODO(rsc): Find out and explain here why gccgo is different.
  1236  			if cfg.BuildToolchainName == "gccgo" {
  1237  				pkgDir = filepath.Join(pkgDir, "shlibs")
  1238  			}
  1239  			target := filepath.Join(pkgDir, shlib)
  1240  
  1241  			a := &Action{
  1242  				Mode:   "go install -buildmode=shared",
  1243  				Objdir: buildAction.Objdir,
  1244  				Actor:  ActorFunc(BuildInstallFunc),
  1245  				Deps:   []*Action{buildAction},
  1246  				Target: target,
  1247  			}
  1248  			for _, a2 := range buildAction.Deps[0].Deps {
  1249  				p := a2.Package
  1250  				pkgTargetRoot := p.Internal.Build.PkgTargetRoot
  1251  				if pkgTargetRoot == "" {
  1252  					continue
  1253  				}
  1254  				a.Deps = append(a.Deps, &Action{
  1255  					Mode:    "shlibname",
  1256  					Package: p,
  1257  					Actor:   ActorFunc((*Builder).installShlibname),
  1258  					Target:  filepath.Join(pkgTargetRoot, p.ImportPath+".shlibname"),
  1259  					Deps:    []*Action{a.Deps[0]},
  1260  				})
  1261  			}
  1262  			return a
  1263  		})
  1264  	}
  1265  
  1266  	return a
  1267  }
  1268  

View as plain text