github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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", []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.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/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), "-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 that the GOOS and GOARCH
   786  // can appear anywhere in the file name, not just after _.
   787  // In particular, they can be the entire file name (like windows.c).
   788  // We also allow the special tag cmd_go_bootstrap.
   789  // See ../go/bootstrap.go and package go/build.
   790  func shouldbuild(file, dir string) bool {
   791  	// Check file name for GOOS or GOARCH.
   792  	name := filepath.Base(file)
   793  	excluded := func(list []string, ok string) bool {
   794  		for _, x := range list {
   795  			if x == ok {
   796  				continue
   797  			}
   798  			i := strings.Index(name, x)
   799  			if i < 0 {
   800  				continue
   801  			}
   802  			i += len(x)
   803  			if i == len(name) || name[i] == '.' || name[i] == '_' {
   804  				return true
   805  			}
   806  		}
   807  		return false
   808  	}
   809  	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
   810  		return false
   811  	}
   812  
   813  	// Omit test files.
   814  	if strings.Contains(name, "_test") {
   815  		return false
   816  	}
   817  
   818  	// Check file contents for // +build lines.
   819  	for _, p := range splitlines(readfile(file)) {
   820  		p = strings.TrimSpace(p)
   821  		if p == "" {
   822  			continue
   823  		}
   824  		code := p
   825  		i := strings.Index(code, "//")
   826  		if i > 0 {
   827  			code = strings.TrimSpace(code[:i])
   828  		}
   829  		if code == "package documentation" {
   830  			return false
   831  		}
   832  		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
   833  			return false
   834  		}
   835  		if !strings.HasPrefix(p, "//") {
   836  			break
   837  		}
   838  		if !strings.Contains(p, "+build") {
   839  			continue
   840  		}
   841  		fields := splitfields(p[2:])
   842  		if len(fields) < 1 || fields[0] != "+build" {
   843  			continue
   844  		}
   845  		for _, p := range fields[1:] {
   846  			if matchfield(p) {
   847  				goto fieldmatch
   848  			}
   849  		}
   850  		return false
   851  	fieldmatch:
   852  	}
   853  
   854  	return true
   855  }
   856  
   857  // copy copies the file src to dst, via memory (so only good for small files).
   858  func copyfile(dst, src string, flag int) {
   859  	if vflag > 1 {
   860  		errprintf("cp %s %s\n", src, dst)
   861  	}
   862  	writefile(readfile(src), dst, flag)
   863  }
   864  
   865  // dopack copies the package src to dst,
   866  // appending the files listed in extra.
   867  // The archive format is the traditional Unix ar format.
   868  func dopack(dst, src string, extra []string) {
   869  	bdst := bytes.NewBufferString(readfile(src))
   870  	for _, file := range extra {
   871  		b := readfile(file)
   872  		// find last path element for archive member name
   873  		i := strings.LastIndex(file, "/") + 1
   874  		j := strings.LastIndex(file, `\`) + 1
   875  		if i < j {
   876  			i = j
   877  		}
   878  		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
   879  		bdst.WriteString(b)
   880  		if len(b)&1 != 0 {
   881  			bdst.WriteByte(0)
   882  		}
   883  	}
   884  	writefile(bdst.String(), dst, 0)
   885  }
   886  
   887  // builddeps records the build dependencies for the 'go bootstrap' command.
   888  // It is a map[string][]string and generated by mkdeps.bash into deps.go.
   889  
   890  // buildlist is the list of directories being built, sorted by name.
   891  var buildlist = makeBuildlist()
   892  
   893  func makeBuildlist() []string {
   894  	var all []string
   895  	for dir := range builddeps {
   896  		all = append(all, dir)
   897  	}
   898  	sort.Strings(all)
   899  	return all
   900  }
   901  
   902  var runtimegen = []string{
   903  	"zaexperiment.h",
   904  	"zversion.go",
   905  }
   906  
   907  func clean() {
   908  	for _, name := range buildlist {
   909  		path := pathf("%s/src/%s", goroot, name)
   910  		// Remove generated files.
   911  		for _, elem := range xreaddir(path) {
   912  			for _, gt := range gentab {
   913  				if strings.HasPrefix(elem, gt.nameprefix) {
   914  					xremove(pathf("%s/%s", path, elem))
   915  				}
   916  			}
   917  		}
   918  		// Remove generated binary named for directory.
   919  		if strings.HasPrefix(name, "cmd/") {
   920  			xremove(pathf("%s/%s", path, name[4:]))
   921  		}
   922  	}
   923  
   924  	// remove runtimegen files.
   925  	path := pathf("%s/src/runtime", goroot)
   926  	for _, elem := range runtimegen {
   927  		xremove(pathf("%s/%s", path, elem))
   928  	}
   929  
   930  	if rebuildall {
   931  		// Remove object tree.
   932  		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
   933  
   934  		// Remove installed packages and tools.
   935  		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
   936  		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
   937  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
   938  		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
   939  		xremoveall(tooldir)
   940  
   941  		// Remove cached version info.
   942  		xremove(pathf("%s/VERSION.cache", goroot))
   943  	}
   944  }
   945  
   946  /*
   947   * command implementations
   948   */
   949  
   950  func usage() {
   951  	xprintf("usage: go tool dist [command]\n" +
   952  		"Commands are:\n" +
   953  		"\n" +
   954  		"banner         print installation banner\n" +
   955  		"bootstrap      rebuild everything\n" +
   956  		"clean          deletes all built files\n" +
   957  		"env [-p]       print environment (-p: include $PATH)\n" +
   958  		"install [dir]  install individual directory\n" +
   959  		"list [-json]   list all supported platforms\n" +
   960  		"test [-h]      run Go test(s)\n" +
   961  		"version        print Go version\n" +
   962  		"\n" +
   963  		"All commands take -v flags to emit extra information.\n",
   964  	)
   965  	xexit(2)
   966  }
   967  
   968  // The env command prints the default environment.
   969  func cmdenv() {
   970  	path := flag.Bool("p", false, "emit updated PATH")
   971  	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
   972  	windows := flag.Bool("w", false, "emit windows syntax")
   973  	xflagparse(0)
   974  
   975  	format := "%s=\"%s\"\n"
   976  	switch {
   977  	case *plan9:
   978  		format = "%s='%s'\n"
   979  	case *windows:
   980  		format = "set %s=%s\r\n"
   981  	}
   982  
   983  	xprintf(format, "CC", defaultcc)
   984  	xprintf(format, "CC_FOR_TARGET", defaultcctarget)
   985  	xprintf(format, "GOROOT", goroot)
   986  	xprintf(format, "GOBIN", gobin)
   987  	xprintf(format, "GOARCH", goarch)
   988  	xprintf(format, "GOOS", goos)
   989  	xprintf(format, "GOHOSTARCH", gohostarch)
   990  	xprintf(format, "GOHOSTOS", gohostos)
   991  	xprintf(format, "GOTOOLDIR", tooldir)
   992  	if goarch == "arm" {
   993  		xprintf(format, "GOARM", goarm)
   994  	}
   995  	if goarch == "386" {
   996  		xprintf(format, "GO386", go386)
   997  	}
   998  
   999  	if *path {
  1000  		sep := ":"
  1001  		if gohostos == "windows" {
  1002  			sep = ";"
  1003  		}
  1004  		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
  1005  	}
  1006  }
  1007  
  1008  // The bootstrap command runs a build from scratch,
  1009  // stopping at having installed the go_bootstrap command.
  1010  func cmdbootstrap() {
  1011  	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
  1012  	xflagparse(0)
  1013  
  1014  	if isdir(pathf("%s/src/pkg", goroot)) {
  1015  		fatal("\n\n"+
  1016  			"The Go package sources have moved to $GOROOT/src.\n"+
  1017  			"*** %s still exists. ***\n"+
  1018  			"It probably contains stale files that may confuse the build.\n"+
  1019  			"Please (check what's there and) remove it and try again.\n"+
  1020  			"See https://golang.org/s/go14nopkg\n",
  1021  			pathf("%s/src/pkg", goroot))
  1022  	}
  1023  
  1024  	if rebuildall {
  1025  		clean()
  1026  	}
  1027  
  1028  	setup()
  1029  
  1030  	checkCC()
  1031  	bootstrapBuildTools()
  1032  
  1033  	// For the main bootstrap, building for host os/arch.
  1034  	oldgoos = goos
  1035  	oldgoarch = goarch
  1036  	goos = gohostos
  1037  	goarch = gohostarch
  1038  	os.Setenv("GOHOSTARCH", gohostarch)
  1039  	os.Setenv("GOHOSTOS", gohostos)
  1040  	os.Setenv("GOARCH", goarch)
  1041  	os.Setenv("GOOS", goos)
  1042  
  1043  	// TODO(rsc): Enable when appropriate.
  1044  	// This step is only needed if we believe that the Go compiler built from Go 1.4
  1045  	// will produce different object files than the Go compiler built from itself.
  1046  	// In the absence of bugs, that should not happen.
  1047  	// And if there are bugs, they're more likely in the current development tree
  1048  	// than in a standard release like Go 1.4, so don't do this rebuild by default.
  1049  	if false {
  1050  		xprintf("##### Building Go toolchain using itself.\n")
  1051  		for _, dir := range buildlist {
  1052  			installed[dir] = make(chan struct{})
  1053  		}
  1054  		var wg sync.WaitGroup
  1055  		for _, dir := range builddeps["cmd/go"] {
  1056  			wg.Add(1)
  1057  			dir := dir
  1058  			go func() {
  1059  				defer wg.Done()
  1060  				install(dir)
  1061  			}()
  1062  		}
  1063  		wg.Wait()
  1064  		xprintf("\n")
  1065  	}
  1066  
  1067  	xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
  1068  	for _, dir := range buildlist {
  1069  		installed[dir] = make(chan struct{})
  1070  	}
  1071  	for _, dir := range buildlist {
  1072  		go install(dir)
  1073  	}
  1074  	<-installed["cmd/go"]
  1075  
  1076  	goos = oldgoos
  1077  	goarch = oldgoarch
  1078  	os.Setenv("GOARCH", goarch)
  1079  	os.Setenv("GOOS", goos)
  1080  
  1081  	// Build runtime for actual goos/goarch too.
  1082  	if goos != gohostos || goarch != gohostarch {
  1083  		installed["runtime"] = make(chan struct{})
  1084  		install("runtime")
  1085  	}
  1086  }
  1087  
  1088  // Cannot use go/build directly because cmd/dist for a new release
  1089  // builds against an old release's go/build, which may be out of sync.
  1090  // To reduce duplication, we generate the list for go/build from this.
  1091  //
  1092  // We list all supported platforms in this list, so that this is the
  1093  // single point of truth for supported platforms. This list is used
  1094  // by 'go tool dist list'.
  1095  var cgoEnabled = map[string]bool{
  1096  	"darwin/386":      true,
  1097  	"darwin/amd64":    true,
  1098  	"darwin/arm":      true,
  1099  	"darwin/arm64":    true,
  1100  	"dragonfly/amd64": true,
  1101  	"freebsd/386":     true,
  1102  	"freebsd/amd64":   true,
  1103  	"freebsd/arm":     false,
  1104  	"linux/386":       true,
  1105  	"linux/amd64":     true,
  1106  	"linux/arm":       true,
  1107  	"linux/arm64":     true,
  1108  	"linux/ppc64":     false,
  1109  	"linux/ppc64le":   true,
  1110  	"linux/mips":      true,
  1111  	"linux/mipsle":    true,
  1112  	"linux/mips64":    true,
  1113  	"linux/mips64le":  true,
  1114  	"linux/s390x":     true,
  1115  	"android/386":     true,
  1116  	"android/amd64":   true,
  1117  	"android/arm":     true,
  1118  	"android/arm64":   true,
  1119  	"nacl/386":        false,
  1120  	"nacl/amd64p32":   false,
  1121  	"nacl/arm":        false,
  1122  	"netbsd/386":      true,
  1123  	"netbsd/amd64":    true,
  1124  	"netbsd/arm":      true,
  1125  	"openbsd/386":     true,
  1126  	"openbsd/amd64":   true,
  1127  	"openbsd/arm":     false,
  1128  	"plan9/386":       false,
  1129  	"plan9/amd64":     false,
  1130  	"plan9/arm":       false,
  1131  	"solaris/amd64":   true,
  1132  	"windows/386":     true,
  1133  	"windows/amd64":   true,
  1134  }
  1135  
  1136  func needCC() bool {
  1137  	switch os.Getenv("CGO_ENABLED") {
  1138  	case "1":
  1139  		return true
  1140  	case "0":
  1141  		return false
  1142  	}
  1143  	return cgoEnabled[gohostos+"/"+gohostarch]
  1144  }
  1145  
  1146  func checkCC() {
  1147  	if !needCC() {
  1148  		return
  1149  	}
  1150  	if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil {
  1151  		outputHdr := ""
  1152  		if len(output) > 0 {
  1153  			outputHdr = "\nCommand output:\n\n"
  1154  		}
  1155  		fatal("cannot invoke C compiler %q: %v\n\n"+
  1156  			"Go needs a system C compiler for use with cgo.\n"+
  1157  			"To set a C compiler, set CC=the-compiler.\n"+
  1158  			"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
  1159  	}
  1160  }
  1161  
  1162  func defaulttarg() string {
  1163  	// xgetwd might return a path with symlinks fully resolved, and if
  1164  	// there happens to be symlinks in goroot, then the hasprefix test
  1165  	// will never succeed. Instead, we use xrealwd to get a canonical
  1166  	// goroot/src before the comparison to avoid this problem.
  1167  	pwd := xgetwd()
  1168  	src := pathf("%s/src/", goroot)
  1169  	real_src := xrealwd(src)
  1170  	if !strings.HasPrefix(pwd, real_src) {
  1171  		fatal("current directory %s is not under %s", pwd, real_src)
  1172  	}
  1173  	pwd = pwd[len(real_src):]
  1174  	// guard against xrealwd returning the directory without the trailing /
  1175  	pwd = strings.TrimPrefix(pwd, "/")
  1176  
  1177  	return pwd
  1178  }
  1179  
  1180  // Install installs the list of packages named on the command line.
  1181  func cmdinstall() {
  1182  	xflagparse(-1)
  1183  
  1184  	if flag.NArg() == 0 {
  1185  		install(defaulttarg())
  1186  	}
  1187  
  1188  	for _, arg := range flag.Args() {
  1189  		install(arg)
  1190  	}
  1191  }
  1192  
  1193  // Clean deletes temporary objects.
  1194  func cmdclean() {
  1195  	xflagparse(0)
  1196  	clean()
  1197  }
  1198  
  1199  // Banner prints the 'now you've installed Go' banner.
  1200  func cmdbanner() {
  1201  	xflagparse(0)
  1202  
  1203  	xprintf("\n")
  1204  	xprintf("---\n")
  1205  	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
  1206  	xprintf("Installed commands in %s\n", gobin)
  1207  
  1208  	if !xsamefile(goroot_final, goroot) {
  1209  		// If the files are to be moved, don't check that gobin
  1210  		// is on PATH; assume they know what they are doing.
  1211  	} else if gohostos == "plan9" {
  1212  		// Check that gobin is bound before /bin.
  1213  		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
  1214  		ns := fmt.Sprintf("/proc/%s/ns", pid)
  1215  		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
  1216  			xprintf("*** You need to bind %s before /bin.\n", gobin)
  1217  		}
  1218  	} else {
  1219  		// Check that gobin appears in $PATH.
  1220  		pathsep := ":"
  1221  		if gohostos == "windows" {
  1222  			pathsep = ";"
  1223  		}
  1224  		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
  1225  			xprintf("*** You need to add %s to your PATH.\n", gobin)
  1226  		}
  1227  	}
  1228  
  1229  	if !xsamefile(goroot_final, goroot) {
  1230  		xprintf("\n"+
  1231  			"The binaries expect %s to be copied or moved to %s\n",
  1232  			goroot, goroot_final)
  1233  	}
  1234  }
  1235  
  1236  // Version prints the Go version.
  1237  func cmdversion() {
  1238  	xflagparse(0)
  1239  	xprintf("%s\n", findgoversion())
  1240  }
  1241  
  1242  // cmdlist lists all supported platforms.
  1243  func cmdlist() {
  1244  	jsonFlag := flag.Bool("json", false, "produce JSON output")
  1245  	xflagparse(0)
  1246  
  1247  	var plats []string
  1248  	for p := range cgoEnabled {
  1249  		plats = append(plats, p)
  1250  	}
  1251  	sort.Strings(plats)
  1252  
  1253  	if !*jsonFlag {
  1254  		for _, p := range plats {
  1255  			xprintf("%s\n", p)
  1256  		}
  1257  		return
  1258  	}
  1259  
  1260  	type jsonResult struct {
  1261  		GOOS         string
  1262  		GOARCH       string
  1263  		CgoSupported bool
  1264  	}
  1265  	var results []jsonResult
  1266  	for _, p := range plats {
  1267  		fields := strings.Split(p, "/")
  1268  		results = append(results, jsonResult{
  1269  			GOOS:         fields[0],
  1270  			GOARCH:       fields[1],
  1271  			CgoSupported: cgoEnabled[p]})
  1272  	}
  1273  	out, err := json.MarshalIndent(results, "", "\t")
  1274  	if err != nil {
  1275  		fatal("json marshal error: %v", err)
  1276  	}
  1277  	if _, err := os.Stdout.Write(out); err != nil {
  1278  		fatal("write failed: %v", err)
  1279  	}
  1280  }