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

View as plain text