github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"sort"
    16  	"strings"
    17  	"sync"
    18  )
    19  
    20  // Initialization for any invocation.
    21  
    22  // The usual variables.
    23  var (
    24  	goarch                 string
    25  	gobin                  string
    26  	gohostarch             string
    27  	gohostos               string
    28  	goos                   string
    29  	goarm                  string
    30  	go386                  string
    31  	goroot                 string
    32  	goroot_final           string
    33  	goextlinkenabled       string
    34  	gogcflags              string // For running built compiler
    35  	workdir                string
    36  	tooldir                string
    37  	oldgoos                string
    38  	oldgoarch              string
    39  	slash                  string
    40  	exe                    string
    41  	defaultcc              string
    42  	defaultcflags          string
    43  	defaultldflags         string
    44  	defaultcxxtarget       string
    45  	defaultcctarget        string
    46  	defaultpkgconfigtarget string
    47  	rebuildall             bool
    48  	defaultclang           bool
    49  
    50  	vflag int // verbosity
    51  )
    52  
    53  // The known architectures.
    54  var okgoarch = []string{
    55  	"386",
    56  	"amd64",
    57  	"amd64p32",
    58  	"arm",
    59  	"arm64",
    60  	"mips",
    61  	"mipsle",
    62  	"mips64",
    63  	"mips64le",
    64  	"ppc64",
    65  	"ppc64le",
    66  	"riscv",
    67  	"s390x",
    68  }
    69  
    70  // The known operating systems.
    71  var okgoos = []string{
    72  	"darwin",
    73  	"dragonfly",
    74  	"linux",
    75  	"android",
    76  	"solaris",
    77  	"freebsd",
    78  	"nacl",
    79  	"netbsd",
    80  	"openbsd",
    81  	"plan9",
    82  	"windows",
    83  }
    84  
    85  // find reports the first index of p in l[0:n], or else -1.
    86  func find(p string, l []string) int {
    87  	for i, s := range l {
    88  		if p == s {
    89  			return i
    90  		}
    91  	}
    92  	return -1
    93  }
    94  
    95  // xinit handles initialization of the various global state, like goroot and goarch.
    96  func xinit() {
    97  	goroot = os.Getenv("GOROOT")
    98  	if slash == "/" && len(goroot) > 1 || slash == `\` && len(goroot) > 3 {
    99  		// if not "/" or "c:\", then strip trailing path separator
   100  		goroot = strings.TrimSuffix(goroot, slash)
   101  	}
   102  	if goroot == "" {
   103  		fatal("$GOROOT must be set")
   104  	}
   105  
   106  	goroot_final = os.Getenv("GOROOT_FINAL")
   107  	if goroot_final == "" {
   108  		goroot_final = goroot
   109  	}
   110  
   111  	b := os.Getenv("GOBIN")
   112  	if b == "" {
   113  		b = goroot + slash + "bin"
   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  		fatal("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  	p := pathf("%s/src/all.bash", goroot)
   143  	if !isfile(p) {
   144  		fatal("$GOROOT is not set correctly or not exported\n"+
   145  			"\tGOROOT=%s\n"+
   146  			"\t%s does not exist", goroot, p)
   147  	}
   148  
   149  	b = os.Getenv("GOHOSTARCH")
   150  	if b != "" {
   151  		gohostarch = b
   152  	}
   153  
   154  	if find(gohostarch, okgoarch) < 0 {
   155  		fatal("unknown $GOHOSTARCH %s", gohostarch)
   156  	}
   157  
   158  	b = os.Getenv("GOARCH")
   159  	if b == "" {
   160  		b = gohostarch
   161  	}
   162  	goarch = b
   163  	if find(goarch, okgoarch) < 0 {
   164  		fatal("unknown $GOARCH %s", goarch)
   165  	}
   166  
   167  	b = os.Getenv("GO_EXTLINK_ENABLED")
   168  	if b != "" {
   169  		if b != "0" && b != "1" {
   170  			fatal("unknown $GO_EXTLINK_ENABLED %s", b)
   171  		}
   172  		goextlinkenabled = b
   173  	}
   174  
   175  	gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
   176  
   177  	b = os.Getenv("CC")
   178  	if b == "" {
   179  		// Use clang on OS X, because gcc is deprecated there.
   180  		// Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
   181  		// actually runs clang. We prepare different command
   182  		// lines for the two binaries, so it matters what we call it.
   183  		// See golang.org/issue/5822.
   184  		if defaultclang {
   185  			b = "clang"
   186  		} else {
   187  			b = "gcc"
   188  		}
   189  	}
   190  	defaultcc = b
   191  
   192  	defaultcflags = os.Getenv("CFLAGS")
   193  
   194  	defaultldflags = os.Getenv("LDFLAGS")
   195  
   196  	b = os.Getenv("CC_FOR_TARGET")
   197  	if b == "" {
   198  		b = defaultcc
   199  	}
   200  	defaultcctarget = b
   201  
   202  	b = os.Getenv("CXX_FOR_TARGET")
   203  	if b == "" {
   204  		b = os.Getenv("CXX")
   205  		if b == "" {
   206  			if defaultclang {
   207  				b = "clang++"
   208  			} else {
   209  				b = "g++"
   210  			}
   211  		}
   212  	}
   213  	defaultcxxtarget = b
   214  
   215  	b = os.Getenv("PKG_CONFIG")
   216  	if b == "" {
   217  		b = "pkg-config"
   218  	}
   219  	defaultpkgconfigtarget = b
   220  
   221  	// For tools being invoked but also for os.ExpandEnv.
   222  	os.Setenv("GO386", go386)
   223  	os.Setenv("GOARCH", goarch)
   224  	os.Setenv("GOARM", goarm)
   225  	os.Setenv("GOHOSTARCH", gohostarch)
   226  	os.Setenv("GOHOSTOS", gohostos)
   227  	os.Setenv("GOOS", goos)
   228  	os.Setenv("GOROOT", goroot)
   229  	os.Setenv("GOROOT_FINAL", goroot_final)
   230  
   231  	// Make the environment more predictable.
   232  	os.Setenv("LANG", "C")
   233  	os.Setenv("LANGUAGE", "en_US.UTF8")
   234  
   235  	workdir = xworkdir()
   236  	xatexit(rmworkdir)
   237  
   238  	tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
   239  }
   240  
   241  // rmworkdir deletes the work directory.
   242  func rmworkdir() {
   243  	if vflag > 1 {
   244  		errprintf("rm -rf %s\n", workdir)
   245  	}
   246  	xremoveall(workdir)
   247  }
   248  
   249  // Remove trailing spaces.
   250  func chomp(s string) string {
   251  	return strings.TrimRight(s, " \t\r\n")
   252  }
   253  
   254  func branchtag(branch string) (tag string, precise bool) {
   255  	b := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
   256  	tag = branch
   257  	for _, line := range splitlines(b) {
   258  		// Each line is either blank, or looks like
   259  		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
   260  		// We need to find an element starting with refs/tags/.
   261  		i := strings.Index(line, " refs/tags/")
   262  		if i < 0 {
   263  			continue
   264  		}
   265  		i += len(" refs/tags/")
   266  		// The tag name ends at a comma or paren (prefer the first).
   267  		j := strings.Index(line[i:], ",")
   268  		if j < 0 {
   269  			j = strings.Index(line[i:], ")")
   270  		}
   271  		if j < 0 {
   272  			continue // malformed line; ignore it
   273  		}
   274  		tag = line[i : i+j]
   275  		if i == 0 {
   276  			precise = true // tag denotes HEAD
   277  		}
   278  		break
   279  	}
   280  	return
   281  }
   282  
   283  // findgoversion determines the Go version to use in the version string.
   284  func findgoversion() string {
   285  	// The $GOROOT/VERSION file takes priority, for distributions
   286  	// without the source repo.
   287  	path := pathf("%s/VERSION", goroot)
   288  	if isfile(path) {
   289  		b := chomp(readfile(path))
   290  		// Commands such as "dist version > VERSION" will cause
   291  		// the shell to create an empty VERSION file and set dist's
   292  		// stdout to its fd. dist in turn looks at VERSION and uses
   293  		// its content if available, which is empty at this point.
   294  		// Only use the VERSION file if it is non-empty.
   295  		if b != "" {
   296  			return b
   297  		}
   298  	}
   299  
   300  	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
   301  	// git every time we run this command. Unlike VERSION, it gets
   302  	// deleted by the clean command.
   303  	path = pathf("%s/VERSION.cache", goroot)
   304  	if isfile(path) {
   305  		return chomp(readfile(path))
   306  	}
   307  
   308  	// Show a nicer error message if this isn't a Git repo.
   309  	if !isGitRepo() {
   310  		fatal("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
   311  	}
   312  
   313  	// Otherwise, use Git.
   314  	// What is the current branch?
   315  	branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
   316  
   317  	// What are the tags along the current branch?
   318  	tag := "devel"
   319  	precise := false
   320  
   321  	// If we're on a release branch, use the closest matching tag
   322  	// that is on the release branch (and not on the master branch).
   323  	if strings.HasPrefix(branch, "release-branch.") {
   324  		tag, precise = branchtag(branch)
   325  	}
   326  
   327  	if !precise {
   328  		// Tag does not point at HEAD; add hash and date to version.
   329  		tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
   330  	}
   331  
   332  	// Cache version.
   333  	writefile(tag, path, 0)
   334  
   335  	return tag
   336  }
   337  
   338  // isGitRepo reports whether the working directory is inside a Git repository.
   339  func isGitRepo() bool {
   340  	// NB: simply checking the exit code of `git rev-parse --git-dir` would
   341  	// suffice here, but that requires deviating from the infrastructure
   342  	// provided by `run`.
   343  	gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
   344  	if !filepath.IsAbs(gitDir) {
   345  		gitDir = filepath.Join(goroot, gitDir)
   346  	}
   347  	fi, err := os.Stat(gitDir)
   348  	return err == nil && fi.IsDir()
   349  }
   350  
   351  /*
   352   * Initial tree setup.
   353   */
   354  
   355  // The old tools that no longer live in $GOBIN or $GOROOT/bin.
   356  var oldtool = []string{
   357  	"5a", "5c", "5g", "5l",
   358  	"6a", "6c", "6g", "6l",
   359  	"8a", "8c", "8g", "8l",
   360  	"9a", "9c", "9g", "9l",
   361  	"6cov",
   362  	"6nm",
   363  	"6prof",
   364  	"cgo",
   365  	"ebnflint",
   366  	"goapi",
   367  	"gofix",
   368  	"goinstall",
   369  	"gomake",
   370  	"gopack",
   371  	"gopprof",
   372  	"gotest",
   373  	"gotype",
   374  	"govet",
   375  	"goyacc",
   376  	"quietgcc",
   377  }
   378  
   379  // Unreleased directories (relative to $GOROOT) that should
   380  // not be in release branches.
   381  var unreleased = []string{
   382  	"src/cmd/newlink",
   383  	"src/cmd/objwriter",
   384  	"src/debug/goobj",
   385  	"src/old",
   386  }
   387  
   388  // setup sets up the tree for the initial build.
   389  func setup() {
   390  	// Create bin directory.
   391  	if p := pathf("%s/bin", goroot); !isdir(p) {
   392  		xmkdir(p)
   393  	}
   394  
   395  	// Create package directory.
   396  	if p := pathf("%s/pkg", goroot); !isdir(p) {
   397  		xmkdir(p)
   398  	}
   399  
   400  	p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
   401  	if rebuildall {
   402  		xremoveall(p)
   403  	}
   404  	xmkdirall(p)
   405  
   406  	if goos != gohostos || goarch != gohostarch {
   407  		p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
   408  		if rebuildall {
   409  			xremoveall(p)
   410  		}
   411  		xmkdirall(p)
   412  	}
   413  
   414  	// Create object directory.
   415  	// We keep it in pkg/ so that all the generated binaries
   416  	// are in one tree. If pkg/obj/libgc.a exists, it is a dreg from
   417  	// before we used subdirectories of obj. Delete all of obj
   418  	// to clean up.
   419  	if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) {
   420  		xremoveall(pathf("%s/pkg/obj", goroot))
   421  	}
   422  	p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)
   423  	if rebuildall {
   424  		xremoveall(p)
   425  	}
   426  	xmkdirall(p)
   427  
   428  	// Create tool directory.
   429  	// We keep it in pkg/, just like the object directory above.
   430  	if rebuildall {
   431  		xremoveall(tooldir)
   432  	}
   433  	xmkdirall(tooldir)
   434  
   435  	// Remove tool binaries from before the tool/gohostos_gohostarch
   436  	xremoveall(pathf("%s/bin/tool", goroot))
   437  
   438  	// Remove old pre-tool binaries.
   439  	for _, old := range oldtool {
   440  		xremove(pathf("%s/bin/%s", goroot, old))
   441  	}
   442  
   443  	// If $GOBIN is set and has a Go compiler, it must be cleaned.
   444  	for _, char := range "56789" {
   445  		if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
   446  			for _, old := range oldtool {
   447  				xremove(pathf("%s/%s", gobin, old))
   448  			}
   449  			break
   450  		}
   451  	}
   452  
   453  	// For release, make sure excluded things are excluded.
   454  	goversion := findgoversion()
   455  	if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
   456  		for _, dir := range unreleased {
   457  			if p := pathf("%s/%s", goroot, dir); isdir(p) {
   458  				fatal("%s should not exist in release build", p)
   459  			}
   460  		}
   461  	}
   462  }
   463  
   464  /*
   465   * Tool building
   466   */
   467  
   468  // deptab lists changes to the default dependencies for a given prefix.
   469  // deps ending in /* read the whole directory; deps beginning with -
   470  // exclude files with that prefix.
   471  var deptab = []struct {
   472  	prefix string   // prefix of target
   473  	dep    []string // dependency tweaks for targets with that prefix
   474  }{
   475  	{"cmd/go/internal/cfg", []string{
   476  		"zdefaultcc.go",
   477  		"zosarch.go",
   478  	}},
   479  	{"runtime/internal/sys", []string{
   480  		"zversion.go",
   481  	}},
   482  	{"go/build", []string{
   483  		"zcgo.go",
   484  	}},
   485  }
   486  
   487  // depsuffix records the allowed suffixes for source files.
   488  var depsuffix = []string{
   489  	".s",
   490  	".go",
   491  }
   492  
   493  // gentab records how to generate some trivial files.
   494  var gentab = []struct {
   495  	nameprefix string
   496  	gen        func(string, string)
   497  }{
   498  	{"zdefaultcc.go", mkzdefaultcc},
   499  	{"zosarch.go", mkzosarch},
   500  	{"zversion.go", mkzversion},
   501  	{"zcgo.go", mkzcgo},
   502  
   503  	// not generated anymore, but delete the file if we see it
   504  	{"enam.c", nil},
   505  	{"anames5.c", nil},
   506  	{"anames6.c", nil},
   507  	{"anames8.c", nil},
   508  	{"anames9.c", nil},
   509  }
   510  
   511  // installed maps from a dir name (as given to install) to a chan
   512  // closed when the dir's package is installed.
   513  var installed = make(map[string]chan struct{})
   514  
   515  // install installs the library, package, or binary associated with dir,
   516  // which is relative to $GOROOT/src.
   517  func install(dir string) {
   518  	if ch, ok := installed[dir]; ok {
   519  		defer close(ch)
   520  	}
   521  	for _, dep := range builddeps[dir] {
   522  		<-installed[dep]
   523  	}
   524  
   525  	if vflag > 0 {
   526  		if goos != gohostos || goarch != gohostarch {
   527  			errprintf("%s (%s/%s)\n", dir, goos, goarch)
   528  		} else {
   529  			errprintf("%s\n", dir)
   530  		}
   531  	}
   532  
   533  	workdir := pathf("%s/%s", workdir, dir)
   534  	xmkdirall(workdir)
   535  
   536  	var clean []string
   537  	defer func() {
   538  		for _, name := range clean {
   539  			xremove(name)
   540  		}
   541  	}()
   542  
   543  	// path = full path to dir.
   544  	path := pathf("%s/src/%s", goroot, dir)
   545  	name := filepath.Base(dir)
   546  
   547  	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
   548  
   549  	// Start final link command line.
   550  	// Note: code below knows that link.p[targ] is the target.
   551  	var (
   552  		link      []string
   553  		targ      int
   554  		ispackcmd bool
   555  	)
   556  	if ispkg {
   557  		// Go library (package).
   558  		ispackcmd = true
   559  		link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
   560  		targ = len(link) - 1
   561  		xmkdirall(filepath.Dir(link[targ]))
   562  	} else {
   563  		// Go command.
   564  		elem := name
   565  		if elem == "go" {
   566  			elem = "go_bootstrap"
   567  		}
   568  		link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
   569  		targ = len(link) - 1
   570  	}
   571  	ttarg := mtime(link[targ])
   572  
   573  	// Gather files that are sources for this target.
   574  	// Everything in that directory, and any target-specific
   575  	// additions.
   576  	files := xreaddir(path)
   577  
   578  	// Remove files beginning with . or _,
   579  	// which are likely to be editor temporary files.
   580  	// This is the same heuristic build.ScanDir uses.
   581  	// There do exist real C files beginning with _,
   582  	// so limit that check to just Go files.
   583  	files = filter(files, func(p string) bool {
   584  		return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
   585  	})
   586  
   587  	for _, dt := range deptab {
   588  		if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
   589  			for _, p := range dt.dep {
   590  				p = os.ExpandEnv(p)
   591  				files = append(files, p)
   592  			}
   593  		}
   594  	}
   595  	files = uniq(files)
   596  
   597  	// Convert to absolute paths.
   598  	for i, p := range files {
   599  		if !isabs(p) {
   600  			files[i] = pathf("%s/%s", path, p)
   601  		}
   602  	}
   603  
   604  	// Is the target up-to-date?
   605  	var gofiles, missing []string
   606  	stale := rebuildall
   607  	files = filter(files, func(p string) bool {
   608  		for _, suf := range depsuffix {
   609  			if strings.HasSuffix(p, suf) {
   610  				goto ok
   611  			}
   612  		}
   613  		return false
   614  	ok:
   615  		t := mtime(p)
   616  		if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
   617  			return false
   618  		}
   619  		if strings.HasSuffix(p, ".go") {
   620  			gofiles = append(gofiles, p)
   621  		}
   622  		if t.After(ttarg) {
   623  			stale = true
   624  		}
   625  		if t.IsZero() {
   626  			missing = append(missing, p)
   627  		}
   628  		return true
   629  	})
   630  
   631  	// If there are no files to compile, we're done.
   632  	if len(files) == 0 {
   633  		return
   634  	}
   635  
   636  	if !stale {
   637  		return
   638  	}
   639  
   640  	// For package runtime, copy some files into the work space.
   641  	if dir == "runtime" || strings.HasPrefix(dir, "runtime/internal/") {
   642  		xmkdirall(pathf("%s/pkg/include", goroot))
   643  		// For use by assembly and C files.
   644  		copyfile(pathf("%s/pkg/include/textflag.h", goroot),
   645  			pathf("%s/src/runtime/textflag.h", goroot), 0)
   646  		copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
   647  			pathf("%s/src/runtime/funcdata.h", goroot), 0)
   648  		copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
   649  			pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
   650  	}
   651  
   652  	// Generate any missing files; regenerate existing ones.
   653  	for _, p := range files {
   654  		elem := filepath.Base(p)
   655  		for _, gt := range gentab {
   656  			if gt.gen == nil {
   657  				continue
   658  			}
   659  			if strings.HasPrefix(elem, gt.nameprefix) {
   660  				if vflag > 1 {
   661  					errprintf("generate %s\n", p)
   662  				}
   663  				gt.gen(path, p)
   664  				// Do not add generated file to clean list.
   665  				// In runtime, we want to be able to
   666  				// build the package with the go tool,
   667  				// and it assumes these generated files already
   668  				// exist (it does not know how to build them).
   669  				// The 'clean' command can remove
   670  				// the generated files.
   671  				goto built
   672  			}
   673  		}
   674  		// Did not rebuild p.
   675  		if find(p, missing) >= 0 {
   676  			fatal("missing file %s", p)
   677  		}
   678  	built:
   679  	}
   680  
   681  	if goos != gohostos || goarch != gohostarch {
   682  		// We've generated the right files; the go command can do the build.
   683  		if vflag > 1 {
   684  			errprintf("skip build for cross-compile %s\n", dir)
   685  		}
   686  		return
   687  	}
   688  
   689  	var archive string
   690  	// The next loop will compile individual non-Go files.
   691  	// Hand the Go files to the compiler en masse.
   692  	// For package runtime, this writes go_asm.h, which
   693  	// the assembly files will need.
   694  	pkg := dir
   695  	if strings.HasPrefix(dir, "cmd/") {
   696  		pkg = "main"
   697  	}
   698  	b := pathf("%s/_go_.a", workdir)
   699  	clean = append(clean, b)
   700  	if !ispackcmd {
   701  		link = append(link, b)
   702  	} else {
   703  		archive = b
   704  	}
   705  	compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
   706  	if gogcflags != "" {
   707  		compile = append(compile, strings.Fields(gogcflags)...)
   708  	}
   709  	if dir == "runtime" {
   710  		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
   711  	}
   712  	compile = append(compile, gofiles...)
   713  	run(path, CheckExit|ShowOutput, compile...)
   714  
   715  	// Compile the files.
   716  	var wg sync.WaitGroup
   717  	for _, p := range files {
   718  		if !strings.HasSuffix(p, ".s") {
   719  			continue
   720  		}
   721  
   722  		var compile []string
   723  		// Assembly file for a Go package.
   724  		compile = []string{
   725  			pathf("%s/asm", tooldir),
   726  			"-I", workdir,
   727  			"-I", pathf("%s/pkg/include", goroot),
   728  			"-D", "GOOS_" + goos,
   729  			"-D", "GOARCH_" + goarch,
   730  			"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
   731  		}
   732  
   733  		doclean := true
   734  		b := pathf("%s/%s", workdir, filepath.Base(p))
   735  
   736  		// Change the last character of the output file (which was c or s).
   737  		b = b[:len(b)-1] + "o"
   738  		compile = append(compile, "-o", b, p)
   739  		bgrun(&wg, path, compile...)
   740  
   741  		link = append(link, b)
   742  		if doclean {
   743  			clean = append(clean, b)
   744  		}
   745  	}
   746  	bgwait(&wg)
   747  
   748  	if ispackcmd {
   749  		xremove(link[targ])
   750  		dopack(link[targ], archive, link[targ+1:])
   751  		return
   752  	}
   753  
   754  	// Remove target before writing it.
   755  	xremove(link[targ])
   756  	run("", CheckExit|ShowOutput, link...)
   757  }
   758  
   759  // matchfield reports whether the field (x,y,z) matches this build.
   760  // all the elements in the field must be satisfied.
   761  func matchfield(f string) bool {
   762  	for _, tag := range strings.Split(f, ",") {
   763  		if !matchtag(tag) {
   764  			return false
   765  		}
   766  	}
   767  	return true
   768  }
   769  
   770  // matchtag reports whether the tag (x or !x) matches this build.
   771  func matchtag(tag string) bool {
   772  	if tag == "" {
   773  		return false
   774  	}
   775  	if tag[0] == '!' {
   776  		if len(tag) == 1 || tag[1] == '!' {
   777  			return false
   778  		}
   779  		return !matchtag(tag[1:])
   780  	}
   781  	return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
   782  }
   783  
   784  // shouldbuild reports whether we should build this file.
   785  // It applies the same rules that are used with context tags
   786  // in package go/build, except that the GOOS and GOARCH
   787  // can appear anywhere in the file name, not just after _.
   788  // In particular, they can be the entire file name (like windows.c).
   789  // We also allow the special tag cmd_go_bootstrap.
   790  // See ../go/bootstrap.go and package go/build.
   791  func shouldbuild(file, dir string) bool {
   792  	// Check file name for GOOS or GOARCH.
   793  	name := filepath.Base(file)
   794  	excluded := func(list []string, ok string) bool {
   795  		for _, x := range list {
   796  			if x == ok {
   797  				continue
   798  			}
   799  			i := strings.Index(name, x)
   800  			if i < 0 {
   801  				continue
   802  			}
   803  			i += len(x)
   804  			if i == len(name) || name[i] == '.' || name[i] == '_' {
   805  				return true
   806  			}
   807  		}
   808  		return false
   809  	}
   810  	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
   811  		return false
   812  	}
   813  
   814  	// Omit test files.
   815  	if strings.Contains(name, "_test") {
   816  		return false
   817  	}
   818  
   819  	// Check file contents for // +build lines.
   820  	for _, p := range splitlines(readfile(file)) {
   821  		p = strings.TrimSpace(p)
   822  		if p == "" {
   823  			continue
   824  		}
   825  		code := p
   826  		i := strings.Index(code, "//")
   827  		if i > 0 {
   828  			code = strings.TrimSpace(code[:i])
   829  		}
   830  		if code == "package documentation" {
   831  			return false
   832  		}
   833  		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
   834  			return false
   835  		}
   836  		if !strings.HasPrefix(p, "//") {
   837  			break
   838  		}
   839  		if !strings.Contains(p, "+build") {
   840  			continue
   841  		}
   842  		fields := splitfields(p[2:])
   843  		if len(fields) < 1 || fields[0] != "+build" {
   844  			continue
   845  		}
   846  		for _, p := range fields[1:] {
   847  			if matchfield(p) {
   848  				goto fieldmatch
   849  			}
   850  		}
   851  		return false
   852  	fieldmatch:
   853  	}
   854  
   855  	return true
   856  }
   857  
   858  // copy copies the file src to dst, via memory (so only good for small files).
   859  func copyfile(dst, src string, flag int) {
   860  	if vflag > 1 {
   861  		errprintf("cp %s %s\n", src, dst)
   862  	}
   863  	writefile(readfile(src), dst, flag)
   864  }
   865  
   866  // dopack copies the package src to dst,
   867  // appending the files listed in extra.
   868  // The archive format is the traditional Unix ar format.
   869  func dopack(dst, src string, extra []string) {
   870  	bdst := bytes.NewBufferString(readfile(src))
   871  	for _, file := range extra {
   872  		b := readfile(file)
   873  		// find last path element for archive member name
   874  		i := strings.LastIndex(file, "/") + 1
   875  		j := strings.LastIndex(file, `\`) + 1
   876  		if i < j {
   877  			i = j
   878  		}
   879  		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
   880  		bdst.WriteString(b)
   881  		if len(b)&1 != 0 {
   882  			bdst.WriteByte(0)
   883  		}
   884  	}
   885  	writefile(bdst.String(), dst, 0)
   886  }
   887  
   888  // builddeps records the build dependencies for the 'go bootstrap' command.
   889  // It is a map[string][]string and generated by mkdeps.bash into deps.go.
   890  
   891  // buildlist is the list of directories being built, sorted by name.
   892  var buildlist = makeBuildlist()
   893  
   894  func makeBuildlist() []string {
   895  	var all []string
   896  	for dir := range builddeps {
   897  		all = append(all, dir)
   898  	}
   899  	sort.Strings(all)
   900  	return all
   901  }
   902  
   903  var runtimegen = []string{
   904  	"zaexperiment.h",
   905  	"zversion.go",
   906  }
   907  
   908  func clean() {
   909  	for _, name := range buildlist {
   910  		path := pathf("%s/src/%s", goroot, name)
   911  		// Remove generated files.
   912  		for _, elem := range xreaddir(path) {
   913  			for _, gt := range gentab {
   914  				if strings.HasPrefix(elem, gt.nameprefix) {
   915  					xremove(pathf("%s/%s", path, elem))
   916  				}
   917  			}
   918  		}
   919  		// Remove generated binary named for directory.
   920  		if strings.HasPrefix(name, "cmd/") {
   921  			xremove(pathf("%s/%s", path, name[4:]))
   922  		}
   923  	}
   924  
   925  	// remove runtimegen files.
   926  	path := pathf("%s/src/runtime", goroot)
   927  	for _, elem := range runtimegen {
   928  		xremove(pathf("%s/%s", path, elem))
   929  	}
   930  
   931  	if rebuildall {
   932  		// Remove object tree.
   933  		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
   934  
   935  		// Remove installed packages and tools.
   936  		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
   937  		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
   938  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
   939  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
   940  		xremoveall(tooldir)
   941  
   942  		// Remove cached version info.
   943  		xremove(pathf("%s/VERSION.cache", goroot))
   944  	}
   945  }
   946  
   947  /*
   948   * command implementations
   949   */
   950  
   951  func usage() {
   952  	xprintf("usage: go tool dist [command]\n" +
   953  		"Commands are:\n" +
   954  		"\n" +
   955  		"banner         print installation banner\n" +
   956  		"bootstrap      rebuild everything\n" +
   957  		"clean          deletes all built files\n" +
   958  		"env [-p]       print environment (-p: include $PATH)\n" +
   959  		"install [dir]  install individual directory\n" +
   960  		"list [-json]   list all supported platforms\n" +
   961  		"test [-h]      run Go test(s)\n" +
   962  		"version        print Go version\n" +
   963  		"\n" +
   964  		"All commands take -v flags to emit extra information.\n",
   965  	)
   966  	xexit(2)
   967  }
   968  
   969  // The env command prints the default environment.
   970  func cmdenv() {
   971  	path := flag.Bool("p", false, "emit updated PATH")
   972  	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
   973  	windows := flag.Bool("w", false, "emit windows syntax")
   974  	xflagparse(0)
   975  
   976  	format := "%s=\"%s\"\n"
   977  	switch {
   978  	case *plan9:
   979  		format = "%s='%s'\n"
   980  	case *windows:
   981  		format = "set %s=%s\r\n"
   982  	}
   983  
   984  	xprintf(format, "CC", defaultcc)
   985  	xprintf(format, "CC_FOR_TARGET", defaultcctarget)
   986  	xprintf(format, "GOROOT", goroot)
   987  	xprintf(format, "GOBIN", gobin)
   988  	xprintf(format, "GOARCH", goarch)
   989  	xprintf(format, "GOOS", goos)
   990  	xprintf(format, "GOHOSTARCH", gohostarch)
   991  	xprintf(format, "GOHOSTOS", gohostos)
   992  	xprintf(format, "GOTOOLDIR", tooldir)
   993  	if goarch == "arm" {
   994  		xprintf(format, "GOARM", goarm)
   995  	}
   996  	if goarch == "386" {
   997  		xprintf(format, "GO386", go386)
   998  	}
   999  
  1000  	if *path {
  1001  		sep := ":"
  1002  		if gohostos == "windows" {
  1003  			sep = ";"
  1004  		}
  1005  		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
  1006  	}
  1007  }
  1008  
  1009  // The bootstrap command runs a build from scratch,
  1010  // stopping at having installed the go_bootstrap command.
  1011  func cmdbootstrap() {
  1012  	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
  1013  	xflagparse(0)
  1014  
  1015  	if isdir(pathf("%s/src/pkg", goroot)) {
  1016  		fatal("\n\n"+
  1017  			"The Go package sources have moved to $GOROOT/src.\n"+
  1018  			"*** %s still exists. ***\n"+
  1019  			"It probably contains stale files that may confuse the build.\n"+
  1020  			"Please (check what's there and) remove it and try again.\n"+
  1021  			"See https://golang.org/s/go14nopkg\n",
  1022  			pathf("%s/src/pkg", goroot))
  1023  	}
  1024  
  1025  	if rebuildall {
  1026  		clean()
  1027  	}
  1028  
  1029  	setup()
  1030  
  1031  	checkCC()
  1032  	bootstrapBuildTools()
  1033  
  1034  	// For the main bootstrap, building for host os/arch.
  1035  	oldgoos = goos
  1036  	oldgoarch = goarch
  1037  	goos = gohostos
  1038  	goarch = gohostarch
  1039  	os.Setenv("GOHOSTARCH", gohostarch)
  1040  	os.Setenv("GOHOSTOS", gohostos)
  1041  	os.Setenv("GOARCH", goarch)
  1042  	os.Setenv("GOOS", goos)
  1043  
  1044  	// TODO(rsc): Enable when appropriate.
  1045  	// This step is only needed if we believe that the Go compiler built from Go 1.4
  1046  	// will produce different object files than the Go compiler built from itself.
  1047  	// In the absence of bugs, that should not happen.
  1048  	// And if there are bugs, they're more likely in the current development tree
  1049  	// than in a standard release like Go 1.4, so don't do this rebuild by default.
  1050  	if false {
  1051  		xprintf("##### Building Go toolchain using itself.\n")
  1052  		for _, dir := range buildlist {
  1053  			installed[dir] = make(chan struct{})
  1054  		}
  1055  		var wg sync.WaitGroup
  1056  		for _, dir := range builddeps["cmd/go"] {
  1057  			wg.Add(1)
  1058  			dir := dir
  1059  			go func() {
  1060  				defer wg.Done()
  1061  				install(dir)
  1062  			}()
  1063  		}
  1064  		wg.Wait()
  1065  		xprintf("\n")
  1066  	}
  1067  
  1068  	xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
  1069  	for _, dir := range buildlist {
  1070  		installed[dir] = make(chan struct{})
  1071  	}
  1072  	for _, dir := range buildlist {
  1073  		go install(dir)
  1074  	}
  1075  	<-installed["cmd/go"]
  1076  
  1077  	goos = oldgoos
  1078  	goarch = oldgoarch
  1079  	os.Setenv("GOARCH", goarch)
  1080  	os.Setenv("GOOS", goos)
  1081  
  1082  	// Build runtime for actual goos/goarch too.
  1083  	if goos != gohostos || goarch != gohostarch {
  1084  		installed["runtime"] = make(chan struct{})
  1085  		install("runtime")
  1086  	}
  1087  }
  1088  
  1089  // Cannot use go/build directly because cmd/dist for a new release
  1090  // builds against an old release's go/build, which may be out of sync.
  1091  // To reduce duplication, we generate the list for go/build from this.
  1092  //
  1093  // We list all supported platforms in this list, so that this is the
  1094  // single point of truth for supported platforms. This list is used
  1095  // by 'go tool dist list'.
  1096  var cgoEnabled = map[string]bool{
  1097  	"darwin/386":      true,
  1098  	"darwin/amd64":    true,
  1099  	"darwin/arm":      true,
  1100  	"darwin/arm64":    true,
  1101  	"dragonfly/amd64": true,
  1102  	"freebsd/386":     true,
  1103  	"freebsd/amd64":   true,
  1104  	"freebsd/arm":     false,
  1105  	"linux/386":       true,
  1106  	"linux/amd64":     true,
  1107  	"linux/arm":       true,
  1108  	"linux/arm64":     true,
  1109  	"linux/ppc64":     false,
  1110  	"linux/ppc64le":   true,
  1111  	"linux/mips":      true,
  1112  	"linux/mipsle":    true,
  1113  	"linux/mips64":    true,
  1114  	"linux/mips64le":  true,
  1115  	"linux/riscv":     false,
  1116  	"linux/s390x":     true,
  1117  	"android/386":     true,
  1118  	"android/amd64":   true,
  1119  	"android/arm":     true,
  1120  	"android/arm64":   true,
  1121  	"nacl/386":        false,
  1122  	"nacl/amd64p32":   false,
  1123  	"nacl/arm":        false,
  1124  	"netbsd/386":      true,
  1125  	"netbsd/amd64":    true,
  1126  	"netbsd/arm":      true,
  1127  	"openbsd/386":     true,
  1128  	"openbsd/amd64":   true,
  1129  	"openbsd/arm":     false,
  1130  	"plan9/386":       false,
  1131  	"plan9/amd64":     false,
  1132  	"plan9/arm":       false,
  1133  	"solaris/amd64":   true,
  1134  	"windows/386":     true,
  1135  	"windows/amd64":   true,
  1136  }
  1137  
  1138  func needCC() bool {
  1139  	switch os.Getenv("CGO_ENABLED") {
  1140  	case "1":
  1141  		return true
  1142  	case "0":
  1143  		return false
  1144  	}
  1145  	return cgoEnabled[gohostos+"/"+gohostarch]
  1146  }
  1147  
  1148  func checkCC() {
  1149  	if !needCC() {
  1150  		return
  1151  	}
  1152  	if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil {
  1153  		outputHdr := ""
  1154  		if len(output) > 0 {
  1155  			outputHdr = "\nCommand output:\n\n"
  1156  		}
  1157  		fatal("cannot invoke C compiler %q: %v\n\n"+
  1158  			"Go needs a system C compiler for use with cgo.\n"+
  1159  			"To set a C compiler, set CC=the-compiler.\n"+
  1160  			"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
  1161  	}
  1162  }
  1163  
  1164  func defaulttarg() string {
  1165  	// xgetwd might return a path with symlinks fully resolved, and if
  1166  	// there happens to be symlinks in goroot, then the hasprefix test
  1167  	// will never succeed. Instead, we use xrealwd to get a canonical
  1168  	// goroot/src before the comparison to avoid this problem.
  1169  	pwd := xgetwd()
  1170  	src := pathf("%s/src/", goroot)
  1171  	real_src := xrealwd(src)
  1172  	if !strings.HasPrefix(pwd, real_src) {
  1173  		fatal("current directory %s is not under %s", pwd, real_src)
  1174  	}
  1175  	pwd = pwd[len(real_src):]
  1176  	// guard against xrealwd returning the directory without the trailing /
  1177  	pwd = strings.TrimPrefix(pwd, "/")
  1178  
  1179  	return pwd
  1180  }
  1181  
  1182  // Install installs the list of packages named on the command line.
  1183  func cmdinstall() {
  1184  	xflagparse(-1)
  1185  
  1186  	if flag.NArg() == 0 {
  1187  		install(defaulttarg())
  1188  	}
  1189  
  1190  	for _, arg := range flag.Args() {
  1191  		install(arg)
  1192  	}
  1193  }
  1194  
  1195  // Clean deletes temporary objects.
  1196  func cmdclean() {
  1197  	xflagparse(0)
  1198  	clean()
  1199  }
  1200  
  1201  // Banner prints the 'now you've installed Go' banner.
  1202  func cmdbanner() {
  1203  	xflagparse(0)
  1204  
  1205  	xprintf("\n")
  1206  	xprintf("---\n")
  1207  	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
  1208  	xprintf("Installed commands in %s\n", gobin)
  1209  
  1210  	if !xsamefile(goroot_final, goroot) {
  1211  		// If the files are to be moved, don't check that gobin
  1212  		// is on PATH; assume they know what they are doing.
  1213  	} else if gohostos == "plan9" {
  1214  		// Check that gobin is bound before /bin.
  1215  		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
  1216  		ns := fmt.Sprintf("/proc/%s/ns", pid)
  1217  		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
  1218  			xprintf("*** You need to bind %s before /bin.\n", gobin)
  1219  		}
  1220  	} else {
  1221  		// Check that gobin appears in $PATH.
  1222  		pathsep := ":"
  1223  		if gohostos == "windows" {
  1224  			pathsep = ";"
  1225  		}
  1226  		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
  1227  			xprintf("*** You need to add %s to your PATH.\n", gobin)
  1228  		}
  1229  	}
  1230  
  1231  	if !xsamefile(goroot_final, goroot) {
  1232  		xprintf("\n"+
  1233  			"The binaries expect %s to be copied or moved to %s\n",
  1234  			goroot, goroot_final)
  1235  	}
  1236  }
  1237  
  1238  // Version prints the Go version.
  1239  func cmdversion() {
  1240  	xflagparse(0)
  1241  	xprintf("%s\n", findgoversion())
  1242  }
  1243  
  1244  // cmdlist lists all supported platforms.
  1245  func cmdlist() {
  1246  	jsonFlag := flag.Bool("json", false, "produce JSON output")
  1247  	xflagparse(0)
  1248  
  1249  	var plats []string
  1250  	for p := range cgoEnabled {
  1251  		plats = append(plats, p)
  1252  	}
  1253  	sort.Strings(plats)
  1254  
  1255  	if !*jsonFlag {
  1256  		for _, p := range plats {
  1257  			xprintf("%s\n", p)
  1258  		}
  1259  		return
  1260  	}
  1261  
  1262  	type jsonResult struct {
  1263  		GOOS         string
  1264  		GOARCH       string
  1265  		CgoSupported bool
  1266  	}
  1267  	var results []jsonResult
  1268  	for _, p := range plats {
  1269  		fields := strings.Split(p, "/")
  1270  		results = append(results, jsonResult{
  1271  			GOOS:         fields[0],
  1272  			GOARCH:       fields[1],
  1273  			CgoSupported: cgoEnabled[p]})
  1274  	}
  1275  	out, err := json.MarshalIndent(results, "", "\t")
  1276  	if err != nil {
  1277  		fatal("json marshal error: %v", err)
  1278  	}
  1279  	if _, err := os.Stdout.Write(out); err != nil {
  1280  		fatal("write failed: %v", err)
  1281  	}
  1282  }