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