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