github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/dist/build.go (about)

     1  // Copyright 2012 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  package main
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"log"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"sort"
    18  	"strings"
    19  	"sync"
    20  	"time"
    21  )
    22  
    23  // Initialization for any invocation.
    24  
    25  // The usual variables.
    26  var (
    27  	goarch           string
    28  	gobin            string
    29  	gohostarch       string
    30  	gohostos         string
    31  	goos             string
    32  	goarm            string
    33  	go386            string
    34  	gomips           string
    35  	gomips64         string
    36  	goroot           string
    37  	goroot_final     string
    38  	goextlinkenabled string
    39  	gogcflags        string // For running built compiler
    40  	goldflags        string
    41  	workdir          string
    42  	tooldir          string
    43  	oldgoos          string
    44  	oldgoarch        string
    45  	exe              string
    46  	defaultcc        map[string]string
    47  	defaultcxx       map[string]string
    48  	defaultcflags    string
    49  	defaultldflags   string
    50  	defaultpkgconfig string
    51  
    52  	rebuildall   bool
    53  	defaultclang bool
    54  
    55  	vflag int // verbosity
    56  )
    57  
    58  // The known architectures.
    59  var okgoarch = []string{
    60  	"386",
    61  	"amd64",
    62  	"amd64p32",
    63  	"arm",
    64  	"arm64",
    65  	"mips",
    66  	"mipsle",
    67  	"mips64",
    68  	"mips64le",
    69  	"ppc64",
    70  	"ppc64le",
    71  	"riscv64",
    72  	"s390x",
    73  	"sparc64",
    74  	"wasm",
    75  }
    76  
    77  // The known operating systems.
    78  var okgoos = []string{
    79  	"darwin",
    80  	"dragonfly",
    81  	"js",
    82  	"linux",
    83  	"android",
    84  	"solaris",
    85  	"freebsd",
    86  	"nacl",
    87  	"netbsd",
    88  	"openbsd",
    89  	"plan9",
    90  	"windows",
    91  	"aix",
    92  }
    93  
    94  // find reports the first index of p in l[0:n], or else -1.
    95  func find(p string, l []string) int {
    96  	for i, s := range l {
    97  		if p == s {
    98  			return i
    99  		}
   100  	}
   101  	return -1
   102  }
   103  
   104  // xinit handles initialization of the various global state, like goroot and goarch.
   105  func xinit() {
   106  	b := os.Getenv("GOROOT")
   107  	if b == "" {
   108  		fatalf("$GOROOT must be set")
   109  	}
   110  	goroot = filepath.Clean(b)
   111  
   112  	b = os.Getenv("GOROOT_FINAL")
   113  	if b == "" {
   114  		b = goroot
   115  	}
   116  	goroot_final = b
   117  
   118  	b = os.Getenv("GOBIN")
   119  	if b == "" {
   120  		b = pathf("%s/bin", goroot)
   121  	}
   122  	gobin = b
   123  
   124  	b = os.Getenv("GOOS")
   125  	if b == "" {
   126  		b = gohostos
   127  	}
   128  	goos = b
   129  	if find(goos, okgoos) < 0 {
   130  		fatalf("unknown $GOOS %s", goos)
   131  	}
   132  
   133  	b = os.Getenv("GOARM")
   134  	if b == "" {
   135  		b = xgetgoarm()
   136  	}
   137  	goarm = b
   138  
   139  	b = os.Getenv("GO386")
   140  	if b == "" {
   141  		if cansse2() {
   142  			b = "sse2"
   143  		} else {
   144  			b = "387"
   145  		}
   146  	}
   147  	go386 = b
   148  
   149  	b = os.Getenv("GOMIPS")
   150  	if b == "" {
   151  		b = "hardfloat"
   152  	}
   153  	gomips = b
   154  
   155  	b = os.Getenv("GOMIPS64")
   156  	if b == "" {
   157  		b = "hardfloat"
   158  	}
   159  	gomips64 = b
   160  
   161  	if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
   162  		fatalf("$GOROOT is not set correctly or not exported\n"+
   163  			"\tGOROOT=%s\n"+
   164  			"\t%s does not exist", goroot, p)
   165  	}
   166  
   167  	b = os.Getenv("GOHOSTARCH")
   168  	if b != "" {
   169  		gohostarch = b
   170  	}
   171  	if find(gohostarch, okgoarch) < 0 {
   172  		fatalf("unknown $GOHOSTARCH %s", gohostarch)
   173  	}
   174  
   175  	b = os.Getenv("GOARCH")
   176  	if b == "" {
   177  		b = gohostarch
   178  	}
   179  	goarch = b
   180  	if find(goarch, okgoarch) < 0 {
   181  		fatalf("unknown $GOARCH %s", goarch)
   182  	}
   183  
   184  	b = os.Getenv("GO_EXTLINK_ENABLED")
   185  	if b != "" {
   186  		if b != "0" && b != "1" {
   187  			fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
   188  		}
   189  		goextlinkenabled = b
   190  	}
   191  
   192  	gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
   193  
   194  	cc, cxx := "gcc", "g++"
   195  	if defaultclang {
   196  		cc, cxx = "clang", "clang++"
   197  	}
   198  	defaultcc = compilerEnv("CC", cc)
   199  	defaultcxx = compilerEnv("CXX", cxx)
   200  
   201  	defaultcflags = os.Getenv("CFLAGS")
   202  	defaultldflags = os.Getenv("LDFLAGS")
   203  
   204  	b = os.Getenv("PKG_CONFIG")
   205  	if b == "" {
   206  		b = "pkg-config"
   207  	}
   208  	defaultpkgconfig = b
   209  
   210  	// For tools being invoked but also for os.ExpandEnv.
   211  	os.Setenv("GO386", go386)
   212  	os.Setenv("GOARCH", goarch)
   213  	os.Setenv("GOARM", goarm)
   214  	os.Setenv("GOHOSTARCH", gohostarch)
   215  	os.Setenv("GOHOSTOS", gohostos)
   216  	os.Setenv("GOOS", goos)
   217  	os.Setenv("GOMIPS", gomips)
   218  	os.Setenv("GOMIPS64", gomips64)
   219  	os.Setenv("GOROOT", goroot)
   220  	os.Setenv("GOROOT_FINAL", goroot_final)
   221  
   222  	// Use a build cache separate from the default user one.
   223  	// Also one that will be wiped out during startup, so that
   224  	// make.bash really does start from a clean slate.
   225  	os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
   226  
   227  	// Make the environment more predictable.
   228  	os.Setenv("LANG", "C")
   229  	os.Setenv("LANGUAGE", "en_US.UTF8")
   230  
   231  	workdir = xworkdir()
   232  	xatexit(rmworkdir)
   233  
   234  	tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
   235  }
   236  
   237  // compilerEnv returns a map from "goos/goarch" to the
   238  // compiler setting to use for that platform.
   239  // The entry for key "" covers any goos/goarch not explicitly set in the map.
   240  // For example, compilerEnv("CC", "gcc") returns the C compiler settings
   241  // read from $CC, defaulting to gcc.
   242  //
   243  // The result is a map because additional environment variables
   244  // can be set to change the compiler based on goos/goarch settings.
   245  // The following applies to all envNames but CC is assumed to simplify
   246  // the presentation.
   247  //
   248  // If no environment variables are set, we use def for all goos/goarch.
   249  // $CC, if set, applies to all goos/goarch but is overridden by the following.
   250  // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
   251  // but is overridden by the following.
   252  // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
   253  // $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
   254  func compilerEnv(envName, def string) map[string]string {
   255  	m := map[string]string{"": def}
   256  
   257  	if env := os.Getenv(envName); env != "" {
   258  		m[""] = env
   259  	}
   260  	if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
   261  		if gohostos != goos || gohostarch != goarch {
   262  			m[gohostos+"/"+gohostarch] = m[""]
   263  		}
   264  		m[""] = env
   265  	}
   266  
   267  	for _, goos := range okgoos {
   268  		for _, goarch := range okgoarch {
   269  			if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
   270  				m[goos+"/"+goarch] = env
   271  			}
   272  		}
   273  	}
   274  
   275  	return m
   276  }
   277  
   278  // compilerEnvLookup returns the compiler settings for goos/goarch in map m.
   279  func compilerEnvLookup(m map[string]string, goos, goarch string) string {
   280  	if cc := m[goos+"/"+goarch]; cc != "" {
   281  		return cc
   282  	}
   283  	return m[""]
   284  }
   285  
   286  // rmworkdir deletes the work directory.
   287  func rmworkdir() {
   288  	if vflag > 1 {
   289  		errprintf("rm -rf %s\n", workdir)
   290  	}
   291  	xremoveall(workdir)
   292  }
   293  
   294  // Remove trailing spaces.
   295  func chomp(s string) string {
   296  	return strings.TrimRight(s, " \t\r\n")
   297  }
   298  
   299  func branchtag(branch string) (tag string, precise bool) {
   300  	log := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
   301  	tag = branch
   302  	for row, line := range strings.Split(log, "\n") {
   303  		// Each line is either blank, or looks like
   304  		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
   305  		// We need to find an element starting with refs/tags/.
   306  		const s = " refs/tags/"
   307  		i := strings.Index(line, s)
   308  		if i < 0 {
   309  			continue
   310  		}
   311  		// Trim off known prefix.
   312  		line = line[i+len(s):]
   313  		// The tag name ends at a comma or paren.
   314  		j := strings.IndexAny(line, ",)")
   315  		if j < 0 {
   316  			continue // malformed line; ignore it
   317  		}
   318  		tag = line[:j]
   319  		if row == 0 {
   320  			precise = true // tag denotes HEAD
   321  		}
   322  		break
   323  	}
   324  	return
   325  }
   326  
   327  // findgoversion determines the Go version to use in the version string.
   328  func findgoversion() string {
   329  	// The $GOROOT/VERSION file takes priority, for distributions
   330  	// without the source repo.
   331  	path := pathf("%s/VERSION", goroot)
   332  	if isfile(path) {
   333  		b := chomp(readfile(path))
   334  		// Commands such as "dist version > VERSION" will cause
   335  		// the shell to create an empty VERSION file and set dist's
   336  		// stdout to its fd. dist in turn looks at VERSION and uses
   337  		// its content if available, which is empty at this point.
   338  		// Only use the VERSION file if it is non-empty.
   339  		if b != "" {
   340  			// Some builders cross-compile the toolchain on linux-amd64
   341  			// and then copy the toolchain to the target builder (say, linux-arm)
   342  			// for use there. But on non-release (devel) branches, the compiler
   343  			// used on linux-amd64 will be an amd64 binary, and the compiler
   344  			// shipped to linux-arm will be an arm binary, so they will have different
   345  			// content IDs (they are binaries for different architectures) and so the
   346  			// packages compiled by the running-on-amd64 compiler will appear
   347  			// stale relative to the running-on-arm compiler. Avoid this by setting
   348  			// the version string to something that doesn't begin with devel.
   349  			// Then the version string will be used in place of the content ID,
   350  			// and the packages will look up-to-date.
   351  			// TODO(rsc): Really the builders could be writing out a better VERSION file instead,
   352  			// but it is easier to change cmd/dist than to try to make changes to
   353  			// the builder while Brad is away.
   354  			if strings.HasPrefix(b, "devel") {
   355  				if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") {
   356  					fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType)
   357  					b = "builder " + hostType
   358  				}
   359  			}
   360  			return b
   361  		}
   362  	}
   363  
   364  	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
   365  	// git every time we run this command. Unlike VERSION, it gets
   366  	// deleted by the clean command.
   367  	path = pathf("%s/VERSION.cache", goroot)
   368  	if isfile(path) {
   369  		return chomp(readfile(path))
   370  	}
   371  
   372  	// Show a nicer error message if this isn't a Git repo.
   373  	if !isGitRepo() {
   374  		fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
   375  	}
   376  
   377  	// Otherwise, use Git.
   378  	// What is the current branch?
   379  	branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
   380  
   381  	// What are the tags along the current branch?
   382  	tag := "devel"
   383  	precise := false
   384  
   385  	// If we're on a release branch, use the closest matching tag
   386  	// that is on the release branch (and not on the master branch).
   387  	if strings.HasPrefix(branch, "release-branch.") {
   388  		tag, precise = branchtag(branch)
   389  	}
   390  
   391  	if !precise {
   392  		// Tag does not point at HEAD; add hash and date to version.
   393  		tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
   394  	}
   395  
   396  	// Cache version.
   397  	writefile(tag, path, 0)
   398  
   399  	return tag
   400  }
   401  
   402  // isGitRepo reports whether the working directory is inside a Git repository.
   403  func isGitRepo() bool {
   404  	// NB: simply checking the exit code of `git rev-parse --git-dir` would
   405  	// suffice here, but that requires deviating from the infrastructure
   406  	// provided by `run`.
   407  	gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
   408  	if !filepath.IsAbs(gitDir) {
   409  		gitDir = filepath.Join(goroot, gitDir)
   410  	}
   411  	return isdir(gitDir)
   412  }
   413  
   414  /*
   415   * Initial tree setup.
   416   */
   417  
   418  // The old tools that no longer live in $GOBIN or $GOROOT/bin.
   419  var oldtool = []string{
   420  	"5a", "5c", "5g", "5l",
   421  	"6a", "6c", "6g", "6l",
   422  	"8a", "8c", "8g", "8l",
   423  	"9a", "9c", "9g", "9l",
   424  	"6cov",
   425  	"6nm",
   426  	"6prof",
   427  	"cgo",
   428  	"ebnflint",
   429  	"goapi",
   430  	"gofix",
   431  	"goinstall",
   432  	"gomake",
   433  	"gopack",
   434  	"gopprof",
   435  	"gotest",
   436  	"gotype",
   437  	"govet",
   438  	"goyacc",
   439  	"quietgcc",
   440  }
   441  
   442  // Unreleased directories (relative to $GOROOT) that should
   443  // not be in release branches.
   444  var unreleased = []string{
   445  	"src/cmd/newlink",
   446  	"src/cmd/objwriter",
   447  	"src/debug/goobj",
   448  	"src/old",
   449  }
   450  
   451  // setup sets up the tree for the initial build.
   452  func setup() {
   453  	// Create bin directory.
   454  	if p := pathf("%s/bin", goroot); !isdir(p) {
   455  		xmkdir(p)
   456  	}
   457  
   458  	// Create package directory.
   459  	if p := pathf("%s/pkg", goroot); !isdir(p) {
   460  		xmkdir(p)
   461  	}
   462  
   463  	p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
   464  	if rebuildall {
   465  		xremoveall(p)
   466  	}
   467  	xmkdirall(p)
   468  
   469  	if goos != gohostos || goarch != gohostarch {
   470  		p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
   471  		if rebuildall {
   472  			xremoveall(p)
   473  		}
   474  		xmkdirall(p)
   475  	}
   476  
   477  	// Create object directory.
   478  	// We used to use it for C objects.
   479  	// Now we use it for the build cache, to separate dist's cache
   480  	// from any other cache the user might have.
   481  	p = pathf("%s/pkg/obj/go-build", goroot)
   482  	if rebuildall {
   483  		xremoveall(p)
   484  	}
   485  	xmkdirall(p)
   486  
   487  	// Create tool directory.
   488  	// We keep it in pkg/, just like the object directory above.
   489  	if rebuildall {
   490  		xremoveall(tooldir)
   491  	}
   492  	xmkdirall(tooldir)
   493  
   494  	// Remove tool binaries from before the tool/gohostos_gohostarch
   495  	xremoveall(pathf("%s/bin/tool", goroot))
   496  
   497  	// Remove old pre-tool binaries.
   498  	for _, old := range oldtool {
   499  		xremove(pathf("%s/bin/%s", goroot, old))
   500  	}
   501  
   502  	// If $GOBIN is set and has a Go compiler, it must be cleaned.
   503  	for _, char := range "56789" {
   504  		if isfile(pathf("%s/%c%s", gobin, char, "g")) {
   505  			for _, old := range oldtool {
   506  				xremove(pathf("%s/%s", gobin, old))
   507  			}
   508  			break
   509  		}
   510  	}
   511  
   512  	// For release, make sure excluded things are excluded.
   513  	goversion := findgoversion()
   514  	if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
   515  		for _, dir := range unreleased {
   516  			if p := pathf("%s/%s", goroot, dir); isdir(p) {
   517  				fatalf("%s should not exist in release build", p)
   518  			}
   519  		}
   520  	}
   521  }
   522  
   523  /*
   524   * Tool building
   525   */
   526  
   527  // deptab lists changes to the default dependencies for a given prefix.
   528  // deps ending in /* read the whole directory; deps beginning with -
   529  // exclude files with that prefix.
   530  // Note that this table applies only to the build of cmd/go,
   531  // after the main compiler bootstrap.
   532  var deptab = []struct {
   533  	prefix string   // prefix of target
   534  	dep    []string // dependency tweaks for targets with that prefix
   535  }{
   536  	{"cmd/go/internal/cfg", []string{
   537  		"zdefaultcc.go",
   538  		"zosarch.go",
   539  	}},
   540  	{"runtime/internal/sys", []string{
   541  		"zversion.go",
   542  	}},
   543  	{"go/build", []string{
   544  		"zcgo.go",
   545  	}},
   546  }
   547  
   548  // depsuffix records the allowed suffixes for source files.
   549  var depsuffix = []string{
   550  	".s",
   551  	".go",
   552  }
   553  
   554  // gentab records how to generate some trivial files.
   555  var gentab = []struct {
   556  	nameprefix string
   557  	gen        func(string, string)
   558  }{
   559  	{"zdefaultcc.go", mkzdefaultcc},
   560  	{"zosarch.go", mkzosarch},
   561  	{"zversion.go", mkzversion},
   562  	{"zcgo.go", mkzcgo},
   563  
   564  	// not generated anymore, but delete the file if we see it
   565  	{"enam.c", nil},
   566  	{"anames5.c", nil},
   567  	{"anames6.c", nil},
   568  	{"anames8.c", nil},
   569  	{"anames9.c", nil},
   570  }
   571  
   572  // installed maps from a dir name (as given to install) to a chan
   573  // closed when the dir's package is installed.
   574  var installed = make(map[string]chan struct{})
   575  var installedMu sync.Mutex
   576  
   577  func install(dir string) {
   578  	<-startInstall(dir)
   579  }
   580  
   581  func startInstall(dir string) chan struct{} {
   582  	installedMu.Lock()
   583  	ch := installed[dir]
   584  	if ch == nil {
   585  		ch = make(chan struct{})
   586  		installed[dir] = ch
   587  		go runInstall(dir, ch)
   588  	}
   589  	installedMu.Unlock()
   590  	return ch
   591  }
   592  
   593  // runInstall installs the library, package, or binary associated with dir,
   594  // which is relative to $GOROOT/src.
   595  func runInstall(dir string, ch chan struct{}) {
   596  	if dir == "net" || dir == "os/user" || dir == "crypto/x509" {
   597  		fatalf("go_bootstrap cannot depend on cgo package %s", dir)
   598  	}
   599  
   600  	defer close(ch)
   601  
   602  	if dir == "unsafe" {
   603  		return
   604  	}
   605  
   606  	if vflag > 0 {
   607  		if goos != gohostos || goarch != gohostarch {
   608  			errprintf("%s (%s/%s)\n", dir, goos, goarch)
   609  		} else {
   610  			errprintf("%s\n", dir)
   611  		}
   612  	}
   613  
   614  	workdir := pathf("%s/%s", workdir, dir)
   615  	xmkdirall(workdir)
   616  
   617  	var clean []string
   618  	defer func() {
   619  		for _, name := range clean {
   620  			xremove(name)
   621  		}
   622  	}()
   623  
   624  	// path = full path to dir.
   625  	path := pathf("%s/src/%s", goroot, dir)
   626  	name := filepath.Base(dir)
   627  
   628  	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
   629  
   630  	// Start final link command line.
   631  	// Note: code below knows that link.p[targ] is the target.
   632  	var (
   633  		link      []string
   634  		targ      int
   635  		ispackcmd bool
   636  	)
   637  	if ispkg {
   638  		// Go library (package).
   639  		ispackcmd = true
   640  		link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
   641  		targ = len(link) - 1
   642  		xmkdirall(filepath.Dir(link[targ]))
   643  	} else {
   644  		// Go command.
   645  		elem := name
   646  		if elem == "go" {
   647  			elem = "go_bootstrap"
   648  		}
   649  		link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
   650  		targ = len(link) - 1
   651  	}
   652  	ttarg := mtime(link[targ])
   653  
   654  	// Gather files that are sources for this target.
   655  	// Everything in that directory, and any target-specific
   656  	// additions.
   657  	files := xreaddir(path)
   658  
   659  	// Remove files beginning with . or _,
   660  	// which are likely to be editor temporary files.
   661  	// This is the same heuristic build.ScanDir uses.
   662  	// There do exist real C files beginning with _,
   663  	// so limit that check to just Go files.
   664  	files = filter(files, func(p string) bool {
   665  		return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
   666  	})
   667  
   668  	for _, dt := range deptab {
   669  		if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
   670  			for _, p := range dt.dep {
   671  				p = os.ExpandEnv(p)
   672  				files = append(files, p)
   673  			}
   674  		}
   675  	}
   676  	files = uniq(files)
   677  
   678  	// Convert to absolute paths.
   679  	for i, p := range files {
   680  		if !filepath.IsAbs(p) {
   681  			files[i] = pathf("%s/%s", path, p)
   682  		}
   683  	}
   684  
   685  	// Is the target up-to-date?
   686  	var gofiles, sfiles, missing []string
   687  	stale := rebuildall
   688  	files = filter(files, func(p string) bool {
   689  		for _, suf := range depsuffix {
   690  			if strings.HasSuffix(p, suf) {
   691  				goto ok
   692  			}
   693  		}
   694  		return false
   695  	ok:
   696  		t := mtime(p)
   697  		if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
   698  			return false
   699  		}
   700  		if strings.HasSuffix(p, ".go") {
   701  			gofiles = append(gofiles, p)
   702  		} else if strings.HasSuffix(p, ".s") {
   703  			sfiles = append(sfiles, p)
   704  		}
   705  		if t.After(ttarg) {
   706  			stale = true
   707  		}
   708  		if t.IsZero() {
   709  			missing = append(missing, p)
   710  		}
   711  		return true
   712  	})
   713  
   714  	// If there are no files to compile, we're done.
   715  	if len(files) == 0 {
   716  		return
   717  	}
   718  
   719  	if !stale {
   720  		return
   721  	}
   722  
   723  	// For package runtime, copy some files into the work space.
   724  	if dir == "runtime" {
   725  		xmkdirall(pathf("%s/pkg/include", goroot))
   726  		// For use by assembly and C files.
   727  		copyfile(pathf("%s/pkg/include/textflag.h", goroot),
   728  			pathf("%s/src/runtime/textflag.h", goroot), 0)
   729  		copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
   730  			pathf("%s/src/runtime/funcdata.h", goroot), 0)
   731  		copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
   732  			pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
   733  	}
   734  
   735  	// Generate any missing files; regenerate existing ones.
   736  	for _, p := range files {
   737  		elem := filepath.Base(p)
   738  		for _, gt := range gentab {
   739  			if gt.gen == nil {
   740  				continue
   741  			}
   742  			if strings.HasPrefix(elem, gt.nameprefix) {
   743  				if vflag > 1 {
   744  					errprintf("generate %s\n", p)
   745  				}
   746  				gt.gen(path, p)
   747  				// Do not add generated file to clean list.
   748  				// In runtime, we want to be able to
   749  				// build the package with the go tool,
   750  				// and it assumes these generated files already
   751  				// exist (it does not know how to build them).
   752  				// The 'clean' command can remove
   753  				// the generated files.
   754  				goto built
   755  			}
   756  		}
   757  		// Did not rebuild p.
   758  		if find(p, missing) >= 0 {
   759  			fatalf("missing file %s", p)
   760  		}
   761  	built:
   762  	}
   763  
   764  	// Make sure dependencies are installed.
   765  	var deps []string
   766  	for _, p := range gofiles {
   767  		deps = append(deps, readimports(p)...)
   768  	}
   769  	for _, dir1 := range deps {
   770  		startInstall(dir1)
   771  	}
   772  	for _, dir1 := range deps {
   773  		install(dir1)
   774  	}
   775  
   776  	if goos != gohostos || goarch != gohostarch {
   777  		// We've generated the right files; the go command can do the build.
   778  		if vflag > 1 {
   779  			errprintf("skip build for cross-compile %s\n", dir)
   780  		}
   781  		return
   782  	}
   783  
   784  	asmArgs := []string{
   785  		pathf("%s/asm", tooldir),
   786  		"-I", workdir,
   787  		"-I", pathf("%s/pkg/include", goroot),
   788  		"-D", "GOOS_" + goos,
   789  		"-D", "GOARCH_" + goarch,
   790  		"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
   791  	}
   792  	if goarch == "mips" || goarch == "mipsle" {
   793  		// Define GOMIPS_value from gomips.
   794  		asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
   795  	}
   796  	if goarch == "mips64" || goarch == "mipsle64" {
   797  		// Define GOMIPS64_value from gomips64.
   798  		asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
   799  	}
   800  	goasmh := pathf("%s/go_asm.h", workdir)
   801  
   802  	// Collect symabis from assembly code.
   803  	var symabis string
   804  	if len(sfiles) > 0 {
   805  		symabis = pathf("%s/symabis", workdir)
   806  		var wg sync.WaitGroup
   807  		asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
   808  		asmabis = append(asmabis, sfiles...)
   809  		if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil {
   810  			fatalf("cannot write empty go_asm.h: %s", err)
   811  		}
   812  		bgrun(&wg, path, asmabis...)
   813  		bgwait(&wg)
   814  	}
   815  
   816  	var archive string
   817  	// The next loop will compile individual non-Go files.
   818  	// Hand the Go files to the compiler en masse.
   819  	// For packages containing assembly, this writes go_asm.h, which
   820  	// the assembly files will need.
   821  	pkg := dir
   822  	if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 {
   823  		pkg = "main"
   824  	}
   825  	b := pathf("%s/_go_.a", workdir)
   826  	clean = append(clean, b)
   827  	if !ispackcmd {
   828  		link = append(link, b)
   829  	} else {
   830  		archive = b
   831  	}
   832  
   833  	// Compile Go code.
   834  	compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
   835  	if gogcflags != "" {
   836  		compile = append(compile, strings.Fields(gogcflags)...)
   837  	}
   838  	if dir == "runtime" {
   839  		compile = append(compile, "-+")
   840  	}
   841  	if len(sfiles) > 0 {
   842  		compile = append(compile, "-asmhdr", goasmh)
   843  	}
   844  	if symabis != "" {
   845  		compile = append(compile, "-symabis", symabis)
   846  	}
   847  	if dir == "runtime" || dir == "runtime/internal/atomic" {
   848  		// These packages define symbols referenced by
   849  		// assembly in other packages. In cmd/go, we work out
   850  		// the exact details. For bootstrapping, just tell the
   851  		// compiler to generate ABI wrappers for everything.
   852  		compile = append(compile, "-allabis")
   853  	}
   854  
   855  	compile = append(compile, gofiles...)
   856  	var wg sync.WaitGroup
   857  	// We use bgrun and immediately wait for it instead of calling run() synchronously.
   858  	// This executes all jobs through the bgwork channel and allows the process
   859  	// to exit cleanly in case an error occurs.
   860  	bgrun(&wg, path, compile...)
   861  	bgwait(&wg)
   862  
   863  	// Compile the files.
   864  	for _, p := range sfiles {
   865  		// Assembly file for a Go package.
   866  		compile := asmArgs[:len(asmArgs):len(asmArgs)]
   867  
   868  		doclean := true
   869  		b := pathf("%s/%s", workdir, filepath.Base(p))
   870  
   871  		// Change the last character of the output file (which was c or s).
   872  		b = b[:len(b)-1] + "o"
   873  		compile = append(compile, "-o", b, p)
   874  		bgrun(&wg, path, compile...)
   875  
   876  		link = append(link, b)
   877  		if doclean {
   878  			clean = append(clean, b)
   879  		}
   880  	}
   881  	bgwait(&wg)
   882  
   883  	if ispackcmd {
   884  		xremove(link[targ])
   885  		dopack(link[targ], archive, link[targ+1:])
   886  		return
   887  	}
   888  
   889  	// Remove target before writing it.
   890  	xremove(link[targ])
   891  	bgrun(&wg, "", link...)
   892  	bgwait(&wg)
   893  }
   894  
   895  // matchfield reports whether the field (x,y,z) matches this build.
   896  // all the elements in the field must be satisfied.
   897  func matchfield(f string) bool {
   898  	for _, tag := range strings.Split(f, ",") {
   899  		if !matchtag(tag) {
   900  			return false
   901  		}
   902  	}
   903  	return true
   904  }
   905  
   906  // matchtag reports whether the tag (x or !x) matches this build.
   907  func matchtag(tag string) bool {
   908  	if tag == "" {
   909  		return false
   910  	}
   911  	if tag[0] == '!' {
   912  		if len(tag) == 1 || tag[1] == '!' {
   913  			return false
   914  		}
   915  		return !matchtag(tag[1:])
   916  	}
   917  	return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
   918  }
   919  
   920  // shouldbuild reports whether we should build this file.
   921  // It applies the same rules that are used with context tags
   922  // in package go/build, except it's less picky about the order
   923  // of GOOS and GOARCH.
   924  // We also allow the special tag cmd_go_bootstrap.
   925  // See ../go/bootstrap.go and package go/build.
   926  func shouldbuild(file, dir string) bool {
   927  	// Check file name for GOOS or GOARCH.
   928  	name := filepath.Base(file)
   929  	excluded := func(list []string, ok string) bool {
   930  		for _, x := range list {
   931  			if x == ok || ok == "android" && x == "linux" {
   932  				continue
   933  			}
   934  			i := strings.Index(name, x)
   935  			if i <= 0 || name[i-1] != '_' {
   936  				continue
   937  			}
   938  			i += len(x)
   939  			if i == len(name) || name[i] == '.' || name[i] == '_' {
   940  				return true
   941  			}
   942  		}
   943  		return false
   944  	}
   945  	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
   946  		return false
   947  	}
   948  
   949  	// Omit test files.
   950  	if strings.Contains(name, "_test") {
   951  		return false
   952  	}
   953  
   954  	// Check file contents for // +build lines.
   955  	for _, p := range strings.Split(readfile(file), "\n") {
   956  		p = strings.TrimSpace(p)
   957  		if p == "" {
   958  			continue
   959  		}
   960  		code := p
   961  		i := strings.Index(code, "//")
   962  		if i > 0 {
   963  			code = strings.TrimSpace(code[:i])
   964  		}
   965  		if code == "package documentation" {
   966  			return false
   967  		}
   968  		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
   969  			return false
   970  		}
   971  		if !strings.HasPrefix(p, "//") {
   972  			break
   973  		}
   974  		if !strings.Contains(p, "+build") {
   975  			continue
   976  		}
   977  		fields := strings.Fields(p[2:])
   978  		if len(fields) < 1 || fields[0] != "+build" {
   979  			continue
   980  		}
   981  		for _, p := range fields[1:] {
   982  			if matchfield(p) {
   983  				goto fieldmatch
   984  			}
   985  		}
   986  		return false
   987  	fieldmatch:
   988  	}
   989  
   990  	return true
   991  }
   992  
   993  // copy copies the file src to dst, via memory (so only good for small files).
   994  func copyfile(dst, src string, flag int) {
   995  	if vflag > 1 {
   996  		errprintf("cp %s %s\n", src, dst)
   997  	}
   998  	writefile(readfile(src), dst, flag)
   999  }
  1000  
  1001  // dopack copies the package src to dst,
  1002  // appending the files listed in extra.
  1003  // The archive format is the traditional Unix ar format.
  1004  func dopack(dst, src string, extra []string) {
  1005  	bdst := bytes.NewBufferString(readfile(src))
  1006  	for _, file := range extra {
  1007  		b := readfile(file)
  1008  		// find last path element for archive member name
  1009  		i := strings.LastIndex(file, "/") + 1
  1010  		j := strings.LastIndex(file, `\`) + 1
  1011  		if i < j {
  1012  			i = j
  1013  		}
  1014  		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
  1015  		bdst.WriteString(b)
  1016  		if len(b)&1 != 0 {
  1017  			bdst.WriteByte(0)
  1018  		}
  1019  	}
  1020  	writefile(bdst.String(), dst, 0)
  1021  }
  1022  
  1023  var runtimegen = []string{
  1024  	"zaexperiment.h",
  1025  	"zversion.go",
  1026  }
  1027  
  1028  // cleanlist is a list of packages with generated files and commands.
  1029  var cleanlist = []string{
  1030  	"runtime/internal/sys",
  1031  	"cmd/cgo",
  1032  	"cmd/go/internal/cfg",
  1033  	"go/build",
  1034  }
  1035  
  1036  func clean() {
  1037  	for _, name := range cleanlist {
  1038  		path := pathf("%s/src/%s", goroot, name)
  1039  		// Remove generated files.
  1040  		for _, elem := range xreaddir(path) {
  1041  			for _, gt := range gentab {
  1042  				if strings.HasPrefix(elem, gt.nameprefix) {
  1043  					xremove(pathf("%s/%s", path, elem))
  1044  				}
  1045  			}
  1046  		}
  1047  		// Remove generated binary named for directory.
  1048  		if strings.HasPrefix(name, "cmd/") {
  1049  			xremove(pathf("%s/%s", path, name[4:]))
  1050  		}
  1051  	}
  1052  
  1053  	// remove runtimegen files.
  1054  	path := pathf("%s/src/runtime", goroot)
  1055  	for _, elem := range runtimegen {
  1056  		xremove(pathf("%s/%s", path, elem))
  1057  	}
  1058  
  1059  	if rebuildall {
  1060  		// Remove object tree.
  1061  		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
  1062  
  1063  		// Remove installed packages and tools.
  1064  		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
  1065  		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
  1066  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
  1067  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
  1068  		xremoveall(tooldir)
  1069  
  1070  		// Remove cached version info.
  1071  		xremove(pathf("%s/VERSION.cache", goroot))
  1072  	}
  1073  }
  1074  
  1075  /*
  1076   * command implementations
  1077   */
  1078  
  1079  // The env command prints the default environment.
  1080  func cmdenv() {
  1081  	path := flag.Bool("p", false, "emit updated PATH")
  1082  	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
  1083  	windows := flag.Bool("w", false, "emit windows syntax")
  1084  	xflagparse(0)
  1085  
  1086  	format := "%s=\"%s\"\n"
  1087  	switch {
  1088  	case *plan9:
  1089  		format = "%s='%s'\n"
  1090  	case *windows:
  1091  		format = "set %s=%s\r\n"
  1092  	}
  1093  
  1094  	xprintf(format, "GOARCH", goarch)
  1095  	xprintf(format, "GOBIN", gobin)
  1096  	xprintf(format, "GOCACHE", os.Getenv("GOCACHE"))
  1097  	xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
  1098  	xprintf(format, "GOHOSTARCH", gohostarch)
  1099  	xprintf(format, "GOHOSTOS", gohostos)
  1100  	xprintf(format, "GOOS", goos)
  1101  	xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
  1102  	xprintf(format, "GOROOT", goroot)
  1103  	xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
  1104  	xprintf(format, "GOTOOLDIR", tooldir)
  1105  	if goarch == "arm" {
  1106  		xprintf(format, "GOARM", goarm)
  1107  	}
  1108  	if goarch == "386" {
  1109  		xprintf(format, "GO386", go386)
  1110  	}
  1111  	if goarch == "mips" || goarch == "mipsle" {
  1112  		xprintf(format, "GOMIPS", gomips)
  1113  	}
  1114  	if goarch == "mips64" || goarch == "mips64le" {
  1115  		xprintf(format, "GOMIPS64", gomips64)
  1116  	}
  1117  
  1118  	if *path {
  1119  		sep := ":"
  1120  		if gohostos == "windows" {
  1121  			sep = ";"
  1122  		}
  1123  		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
  1124  	}
  1125  }
  1126  
  1127  var (
  1128  	timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
  1129  	timeLogMu      sync.Mutex
  1130  	timeLogFile    *os.File
  1131  	timeLogStart   time.Time
  1132  )
  1133  
  1134  func timelog(op, name string) {
  1135  	if !timeLogEnabled {
  1136  		return
  1137  	}
  1138  	timeLogMu.Lock()
  1139  	defer timeLogMu.Unlock()
  1140  	if timeLogFile == nil {
  1141  		f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
  1142  		if err != nil {
  1143  			log.Fatal(err)
  1144  		}
  1145  		buf := make([]byte, 100)
  1146  		n, _ := f.Read(buf)
  1147  		s := string(buf[:n])
  1148  		if i := strings.Index(s, "\n"); i >= 0 {
  1149  			s = s[:i]
  1150  		}
  1151  		i := strings.Index(s, " start")
  1152  		if i < 0 {
  1153  			log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE"))
  1154  		}
  1155  		t, err := time.Parse(time.UnixDate, s[:i])
  1156  		if err != nil {
  1157  			log.Fatalf("cannot parse time log line %q: %v", s, err)
  1158  		}
  1159  		timeLogStart = t
  1160  		timeLogFile = f
  1161  	}
  1162  	t := time.Now()
  1163  	fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
  1164  }
  1165  
  1166  var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
  1167  
  1168  // The bootstrap command runs a build from scratch,
  1169  // stopping at having installed the go_bootstrap command.
  1170  //
  1171  // WARNING: This command runs after cmd/dist is built with Go 1.4.
  1172  // It rebuilds and installs cmd/dist with the new toolchain, so other
  1173  // commands (like "go tool dist test" in run.bash) can rely on bug fixes
  1174  // made since Go 1.4, but this function cannot. In particular, the uses
  1175  // of os/exec in this function cannot assume that
  1176  //	cmd.Env = append(os.Environ(), "X=Y")
  1177  // sets $X to Y in the command's environment. That guarantee was
  1178  // added after Go 1.4, and in fact in Go 1.4 it was typically the opposite:
  1179  // if $X was already present in os.Environ(), most systems preferred
  1180  // that setting, not the new one.
  1181  func cmdbootstrap() {
  1182  	timelog("start", "dist bootstrap")
  1183  	defer timelog("end", "dist bootstrap")
  1184  
  1185  	var noBanner bool
  1186  	var debug bool
  1187  	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
  1188  	flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
  1189  	flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
  1190  
  1191  	xflagparse(0)
  1192  
  1193  	if debug {
  1194  		// cmd/buildid is used in debug mode.
  1195  		toolchain = append(toolchain, "cmd/buildid")
  1196  	}
  1197  
  1198  	if isdir(pathf("%s/src/pkg", goroot)) {
  1199  		fatalf("\n\n"+
  1200  			"The Go package sources have moved to $GOROOT/src.\n"+
  1201  			"*** %s still exists. ***\n"+
  1202  			"It probably contains stale files that may confuse the build.\n"+
  1203  			"Please (check what's there and) remove it and try again.\n"+
  1204  			"See https://golang.org/s/go14nopkg\n",
  1205  			pathf("%s/src/pkg", goroot))
  1206  	}
  1207  
  1208  	if rebuildall {
  1209  		clean()
  1210  	}
  1211  
  1212  	setup()
  1213  
  1214  	timelog("build", "toolchain1")
  1215  	checkCC()
  1216  	bootstrapBuildTools()
  1217  
  1218  	// Remember old content of $GOROOT/bin for comparison below.
  1219  	oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
  1220  
  1221  	// For the main bootstrap, building for host os/arch.
  1222  	oldgoos = goos
  1223  	oldgoarch = goarch
  1224  	goos = gohostos
  1225  	goarch = gohostarch
  1226  	os.Setenv("GOHOSTARCH", gohostarch)
  1227  	os.Setenv("GOHOSTOS", gohostos)
  1228  	os.Setenv("GOARCH", goarch)
  1229  	os.Setenv("GOOS", goos)
  1230  
  1231  	timelog("build", "go_bootstrap")
  1232  	xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
  1233  	install("runtime") // dependency not visible in sources; also sets up textflag.h
  1234  	install("cmd/go")
  1235  	if vflag > 0 {
  1236  		xprintf("\n")
  1237  	}
  1238  
  1239  	gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
  1240  	goldflags = os.Getenv("GO_LDFLAGS")
  1241  	goBootstrap := pathf("%s/go_bootstrap", tooldir)
  1242  	cmdGo := pathf("%s/go", gobin)
  1243  	if debug {
  1244  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1245  		copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
  1246  	}
  1247  
  1248  	// To recap, so far we have built the new toolchain
  1249  	// (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
  1250  	// using Go 1.4's toolchain and go command.
  1251  	// Then we built the new go command (as go_bootstrap)
  1252  	// using the new toolchain and our own build logic (above).
  1253  	//
  1254  	//	toolchain1 = mk(new toolchain, go1.4 toolchain, go1.4 cmd/go)
  1255  	//	go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
  1256  	//
  1257  	// The toolchain1 we built earlier is built from the new sources,
  1258  	// but because it was built using cmd/go it has no build IDs.
  1259  	// The eventually installed toolchain needs build IDs, so we need
  1260  	// to do another round:
  1261  	//
  1262  	//	toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
  1263  	//
  1264  	timelog("build", "toolchain2")
  1265  	if vflag > 0 {
  1266  		xprintf("\n")
  1267  	}
  1268  	xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
  1269  	os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
  1270  	goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
  1271  	if debug {
  1272  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1273  		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
  1274  		copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
  1275  	}
  1276  
  1277  	// Toolchain2 should be semantically equivalent to toolchain1,
  1278  	// but it was built using the new compilers instead of the Go 1.4 compilers,
  1279  	// so it should at the least run faster. Also, toolchain1 had no build IDs
  1280  	// in the binaries, while toolchain2 does. In non-release builds, the
  1281  	// toolchain's build IDs feed into constructing the build IDs of built targets,
  1282  	// so in non-release builds, everything now looks out-of-date due to
  1283  	// toolchain2 having build IDs - that is, due to the go command seeing
  1284  	// that there are new compilers. In release builds, the toolchain's reported
  1285  	// version is used in place of the build ID, and the go command does not
  1286  	// see that change from toolchain1 to toolchain2, so in release builds,
  1287  	// nothing looks out of date.
  1288  	// To keep the behavior the same in both non-release and release builds,
  1289  	// we force-install everything here.
  1290  	//
  1291  	//	toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
  1292  	//
  1293  	timelog("build", "toolchain3")
  1294  	if vflag > 0 {
  1295  		xprintf("\n")
  1296  	}
  1297  	xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
  1298  	goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...)
  1299  	if debug {
  1300  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1301  		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
  1302  		copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
  1303  	}
  1304  	checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
  1305  
  1306  	if goos == oldgoos && goarch == oldgoarch {
  1307  		// Common case - not setting up for cross-compilation.
  1308  		timelog("build", "toolchain")
  1309  		if vflag > 0 {
  1310  			xprintf("\n")
  1311  		}
  1312  		xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
  1313  	} else {
  1314  		// GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
  1315  		// Finish GOHOSTOS/GOHOSTARCH installation and then
  1316  		// run GOOS/GOARCH installation.
  1317  		timelog("build", "host toolchain")
  1318  		if vflag > 0 {
  1319  			xprintf("\n")
  1320  		}
  1321  		xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch)
  1322  		goInstall(goBootstrap, "std", "cmd")
  1323  		checkNotStale(goBootstrap, "std", "cmd")
  1324  		checkNotStale(cmdGo, "std", "cmd")
  1325  
  1326  		timelog("build", "target toolchain")
  1327  		if vflag > 0 {
  1328  			xprintf("\n")
  1329  		}
  1330  		goos = oldgoos
  1331  		goarch = oldgoarch
  1332  		os.Setenv("GOOS", goos)
  1333  		os.Setenv("GOARCH", goarch)
  1334  		os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
  1335  		xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
  1336  	}
  1337  	targets := []string{"std", "cmd"}
  1338  	if goos == "js" && goarch == "wasm" {
  1339  		// Skip the cmd tools for js/wasm. They're not usable.
  1340  		targets = targets[:1]
  1341  	}
  1342  	goInstall(goBootstrap, targets...)
  1343  	checkNotStale(goBootstrap, targets...)
  1344  	checkNotStale(cmdGo, targets...)
  1345  	if debug {
  1346  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1347  		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
  1348  		checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
  1349  		copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
  1350  	}
  1351  
  1352  	// Check that there are no new files in $GOROOT/bin other than
  1353  	// go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
  1354  	binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
  1355  	ok := map[string]bool{}
  1356  	for _, f := range oldBinFiles {
  1357  		ok[f] = true
  1358  	}
  1359  	for _, f := range binFiles {
  1360  		elem := strings.TrimSuffix(filepath.Base(f), ".exe")
  1361  		if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
  1362  			fatalf("unexpected new file in $GOROOT/bin: %s", elem)
  1363  		}
  1364  	}
  1365  
  1366  	// Remove go_bootstrap now that we're done.
  1367  	xremove(pathf("%s/go_bootstrap", tooldir))
  1368  
  1369  	// Print trailing banner unless instructed otherwise.
  1370  	if !noBanner {
  1371  		banner()
  1372  	}
  1373  }
  1374  
  1375  func goInstall(goBinary string, args ...string) {
  1376  	installCmd := []string{goBinary, "install", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags}
  1377  	if vflag > 0 {
  1378  		installCmd = append(installCmd, "-v")
  1379  	}
  1380  
  1381  	// Force only one process at a time on vx32 emulation.
  1382  	if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
  1383  		installCmd = append(installCmd, "-p=1")
  1384  	}
  1385  
  1386  	run(goroot, ShowOutput|CheckExit, append(installCmd, args...)...)
  1387  }
  1388  
  1389  func checkNotStale(goBinary string, targets ...string) {
  1390  	out := run(goroot, CheckExit,
  1391  		append([]string{
  1392  			goBinary,
  1393  			"list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags,
  1394  			"-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}",
  1395  		}, targets...)...)
  1396  	if strings.Contains(out, "\tSTALE ") {
  1397  		os.Setenv("GODEBUG", "gocachehash=1")
  1398  		for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
  1399  			if strings.Contains(out, "STALE "+target) {
  1400  				run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
  1401  				break
  1402  			}
  1403  		}
  1404  		fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out)
  1405  	}
  1406  }
  1407  
  1408  // Cannot use go/build directly because cmd/dist for a new release
  1409  // builds against an old release's go/build, which may be out of sync.
  1410  // To reduce duplication, we generate the list for go/build from this.
  1411  //
  1412  // We list all supported platforms in this list, so that this is the
  1413  // single point of truth for supported platforms. This list is used
  1414  // by 'go tool dist list'.
  1415  var cgoEnabled = map[string]bool{
  1416  	"aix/ppc64":       false,
  1417  	"darwin/386":      true,
  1418  	"darwin/amd64":    true,
  1419  	"darwin/arm":      true,
  1420  	"darwin/arm64":    true,
  1421  	"dragonfly/amd64": true,
  1422  	"freebsd/386":     true,
  1423  	"freebsd/amd64":   true,
  1424  	"freebsd/arm":     false,
  1425  	"linux/386":       true,
  1426  	"linux/amd64":     true,
  1427  	"linux/arm":       true,
  1428  	"linux/arm64":     true,
  1429  	"linux/ppc64":     false,
  1430  	"linux/ppc64le":   true,
  1431  	"linux/mips":      true,
  1432  	"linux/mipsle":    true,
  1433  	"linux/mips64":    true,
  1434  	"linux/mips64le":  true,
  1435  	"linux/riscv64":   true,
  1436  	"linux/s390x":     true,
  1437  	"linux/sparc64":   true,
  1438  	"android/386":     true,
  1439  	"android/amd64":   true,
  1440  	"android/arm":     true,
  1441  	"android/arm64":   true,
  1442  	"js/wasm":         false,
  1443  	"nacl/386":        false,
  1444  	"nacl/amd64p32":   false,
  1445  	"nacl/arm":        false,
  1446  	"netbsd/386":      true,
  1447  	"netbsd/amd64":    true,
  1448  	"netbsd/arm":      true,
  1449  	"openbsd/386":     true,
  1450  	"openbsd/amd64":   true,
  1451  	"openbsd/arm":     true,
  1452  	"plan9/386":       false,
  1453  	"plan9/amd64":     false,
  1454  	"plan9/arm":       false,
  1455  	"solaris/amd64":   true,
  1456  	"windows/386":     true,
  1457  	"windows/amd64":   true,
  1458  	"windows/arm":     false,
  1459  }
  1460  
  1461  // List of platforms which are supported but not complete yet. These get
  1462  // filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944
  1463  var incomplete = map[string]bool{
  1464  	"linux/riscv64": true,
  1465  	"linux/sparc64": true,
  1466  }
  1467  
  1468  func needCC() bool {
  1469  	switch os.Getenv("CGO_ENABLED") {
  1470  	case "1":
  1471  		return true
  1472  	case "0":
  1473  		return false
  1474  	}
  1475  	return cgoEnabled[gohostos+"/"+gohostarch]
  1476  }
  1477  
  1478  func checkCC() {
  1479  	if !needCC() {
  1480  		return
  1481  	}
  1482  	if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil {
  1483  		outputHdr := ""
  1484  		if len(output) > 0 {
  1485  			outputHdr = "\nCommand output:\n\n"
  1486  		}
  1487  		fatalf("cannot invoke C compiler %q: %v\n\n"+
  1488  			"Go needs a system C compiler for use with cgo.\n"+
  1489  			"To set a C compiler, set CC=the-compiler.\n"+
  1490  			"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output)
  1491  	}
  1492  }
  1493  
  1494  func defaulttarg() string {
  1495  	// xgetwd might return a path with symlinks fully resolved, and if
  1496  	// there happens to be symlinks in goroot, then the hasprefix test
  1497  	// will never succeed. Instead, we use xrealwd to get a canonical
  1498  	// goroot/src before the comparison to avoid this problem.
  1499  	pwd := xgetwd()
  1500  	src := pathf("%s/src/", goroot)
  1501  	real_src := xrealwd(src)
  1502  	if !strings.HasPrefix(pwd, real_src) {
  1503  		fatalf("current directory %s is not under %s", pwd, real_src)
  1504  	}
  1505  	pwd = pwd[len(real_src):]
  1506  	// guard against xrealwd returning the directory without the trailing /
  1507  	pwd = strings.TrimPrefix(pwd, "/")
  1508  
  1509  	return pwd
  1510  }
  1511  
  1512  // Install installs the list of packages named on the command line.
  1513  func cmdinstall() {
  1514  	xflagparse(-1)
  1515  
  1516  	if flag.NArg() == 0 {
  1517  		install(defaulttarg())
  1518  	}
  1519  
  1520  	for _, arg := range flag.Args() {
  1521  		install(arg)
  1522  	}
  1523  }
  1524  
  1525  // Clean deletes temporary objects.
  1526  func cmdclean() {
  1527  	xflagparse(0)
  1528  	clean()
  1529  }
  1530  
  1531  // Banner prints the 'now you've installed Go' banner.
  1532  func cmdbanner() {
  1533  	xflagparse(0)
  1534  	banner()
  1535  }
  1536  
  1537  func banner() {
  1538  	if vflag > 0 {
  1539  		xprintf("\n")
  1540  	}
  1541  	xprintf("---\n")
  1542  	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
  1543  	xprintf("Installed commands in %s\n", gobin)
  1544  
  1545  	if !xsamefile(goroot_final, goroot) {
  1546  		// If the files are to be moved, don't check that gobin
  1547  		// is on PATH; assume they know what they are doing.
  1548  	} else if gohostos == "plan9" {
  1549  		// Check that gobin is bound before /bin.
  1550  		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
  1551  		ns := fmt.Sprintf("/proc/%s/ns", pid)
  1552  		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
  1553  			xprintf("*** You need to bind %s before /bin.\n", gobin)
  1554  		}
  1555  	} else {
  1556  		// Check that gobin appears in $PATH.
  1557  		pathsep := ":"
  1558  		if gohostos == "windows" {
  1559  			pathsep = ";"
  1560  		}
  1561  		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
  1562  			xprintf("*** You need to add %s to your PATH.\n", gobin)
  1563  		}
  1564  	}
  1565  
  1566  	if !xsamefile(goroot_final, goroot) {
  1567  		xprintf("\n"+
  1568  			"The binaries expect %s to be copied or moved to %s\n",
  1569  			goroot, goroot_final)
  1570  	}
  1571  }
  1572  
  1573  // Version prints the Go version.
  1574  func cmdversion() {
  1575  	xflagparse(0)
  1576  	xprintf("%s\n", findgoversion())
  1577  }
  1578  
  1579  // cmdlist lists all supported platforms.
  1580  func cmdlist() {
  1581  	jsonFlag := flag.Bool("json", false, "produce JSON output")
  1582  	xflagparse(0)
  1583  
  1584  	var plats []string
  1585  	for p := range cgoEnabled {
  1586  		if incomplete[p] {
  1587  			continue
  1588  		}
  1589  		plats = append(plats, p)
  1590  	}
  1591  	sort.Strings(plats)
  1592  
  1593  	if !*jsonFlag {
  1594  		for _, p := range plats {
  1595  			xprintf("%s\n", p)
  1596  		}
  1597  		return
  1598  	}
  1599  
  1600  	type jsonResult struct {
  1601  		GOOS         string
  1602  		GOARCH       string
  1603  		CgoSupported bool
  1604  	}
  1605  	var results []jsonResult
  1606  	for _, p := range plats {
  1607  		fields := strings.Split(p, "/")
  1608  		results = append(results, jsonResult{
  1609  			GOOS:         fields[0],
  1610  			GOARCH:       fields[1],
  1611  			CgoSupported: cgoEnabled[p]})
  1612  	}
  1613  	out, err := json.MarshalIndent(results, "", "\t")
  1614  	if err != nil {
  1615  		fatalf("json marshal error: %v", err)
  1616  	}
  1617  	if _, err := os.Stdout.Write(out); err != nil {
  1618  		fatalf("write failed: %v", err)
  1619  	}
  1620  }