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