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