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