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