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