...
Run Format

Source file src/cmd/dist/build.go

Documentation: cmd/dist

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

View as plain text