github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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  		copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
   630  			pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
   631  	}
   632  
   633  	// Generate any missing files; regenerate existing ones.
   634  	for _, p := range files {
   635  		elem := filepath.Base(p)
   636  		for _, gt := range gentab {
   637  			if gt.gen == nil {
   638  				continue
   639  			}
   640  			if strings.HasPrefix(elem, gt.nameprefix) {
   641  				if vflag > 1 {
   642  					errprintf("generate %s\n", p)
   643  				}
   644  				gt.gen(path, p)
   645  				// Do not add generated file to clean list.
   646  				// In runtime, we want to be able to
   647  				// build the package with the go tool,
   648  				// and it assumes these generated files already
   649  				// exist (it does not know how to build them).
   650  				// The 'clean' command can remove
   651  				// the generated files.
   652  				goto built
   653  			}
   654  		}
   655  		// Did not rebuild p.
   656  		if find(p, missing) >= 0 {
   657  			fatal("missing file %s", p)
   658  		}
   659  	built:
   660  	}
   661  
   662  	if goos != gohostos || goarch != gohostarch {
   663  		// We've generated the right files; the go command can do the build.
   664  		if vflag > 1 {
   665  			errprintf("skip build for cross-compile %s\n", dir)
   666  		}
   667  		return
   668  	}
   669  
   670  	var archive string
   671  	// The next loop will compile individual non-Go files.
   672  	// Hand the Go files to the compiler en masse.
   673  	// For package runtime, this writes go_asm.h, which
   674  	// the assembly files will need.
   675  	pkg := dir
   676  	if strings.HasPrefix(dir, "cmd/") {
   677  		pkg = "main"
   678  	}
   679  	b := pathf("%s/_go_.a", workdir)
   680  	clean = append(clean, b)
   681  	if !ispackcmd {
   682  		link = append(link, b)
   683  	} else {
   684  		archive = b
   685  	}
   686  	compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
   687  	if dir == "runtime" {
   688  		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
   689  	}
   690  	compile = append(compile, gofiles...)
   691  	run(path, CheckExit|ShowOutput, compile...)
   692  
   693  	// Compile the files.
   694  	var wg sync.WaitGroup
   695  	for _, p := range files {
   696  		if !strings.HasSuffix(p, ".s") {
   697  			continue
   698  		}
   699  
   700  		var compile []string
   701  		// Assembly file for a Go package.
   702  		compile = []string{
   703  			pathf("%s/asm", tooldir),
   704  			"-I", workdir,
   705  			"-I", pathf("%s/pkg/include", goroot),
   706  			"-D", "GOOS_" + goos,
   707  			"-D", "GOARCH_" + goarch,
   708  			"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
   709  		}
   710  
   711  		doclean := true
   712  		b := pathf("%s/%s", workdir, filepath.Base(p))
   713  
   714  		// Change the last character of the output file (which was c or s).
   715  		b = b[:len(b)-1] + "o"
   716  		compile = append(compile, "-o", b, p)
   717  		bgrun(&wg, path, compile...)
   718  
   719  		link = append(link, b)
   720  		if doclean {
   721  			clean = append(clean, b)
   722  		}
   723  	}
   724  	bgwait(&wg)
   725  
   726  	if ispackcmd {
   727  		xremove(link[targ])
   728  		dopack(link[targ], archive, link[targ+1:])
   729  		return
   730  	}
   731  
   732  	// Remove target before writing it.
   733  	xremove(link[targ])
   734  	run("", CheckExit|ShowOutput, link...)
   735  }
   736  
   737  // matchfield reports whether the field (x,y,z) matches this build.
   738  // all the elements in the field must be satisfied.
   739  func matchfield(f string) bool {
   740  	for _, tag := range strings.Split(f, ",") {
   741  		if !matchtag(tag) {
   742  			return false
   743  		}
   744  	}
   745  	return true
   746  }
   747  
   748  // matchtag reports whether the tag (x or !x) matches this build.
   749  func matchtag(tag string) bool {
   750  	if tag == "" {
   751  		return false
   752  	}
   753  	if tag[0] == '!' {
   754  		if len(tag) == 1 || tag[1] == '!' {
   755  			return false
   756  		}
   757  		return !matchtag(tag[1:])
   758  	}
   759  	return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
   760  }
   761  
   762  // shouldbuild reports whether we should build this file.
   763  // It applies the same rules that are used with context tags
   764  // in package go/build, except that the GOOS and GOARCH
   765  // can appear anywhere in the file name, not just after _.
   766  // In particular, they can be the entire file name (like windows.c).
   767  // We also allow the special tag cmd_go_bootstrap.
   768  // See ../go/bootstrap.go and package go/build.
   769  func shouldbuild(file, dir string) bool {
   770  	// Check file name for GOOS or GOARCH.
   771  	name := filepath.Base(file)
   772  	excluded := func(list []string, ok string) bool {
   773  		for _, x := range list {
   774  			if x == ok {
   775  				continue
   776  			}
   777  			i := strings.Index(name, x)
   778  			if i < 0 {
   779  				continue
   780  			}
   781  			i += len(x)
   782  			if i == len(name) || name[i] == '.' || name[i] == '_' {
   783  				return true
   784  			}
   785  		}
   786  		return false
   787  	}
   788  	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
   789  		return false
   790  	}
   791  
   792  	// Omit test files.
   793  	if strings.Contains(name, "_test") {
   794  		return false
   795  	}
   796  
   797  	// Check file contents for // +build lines.
   798  	for _, p := range splitlines(readfile(file)) {
   799  		p = strings.TrimSpace(p)
   800  		if p == "" {
   801  			continue
   802  		}
   803  		if strings.Contains(p, "package documentation") {
   804  			return false
   805  		}
   806  		if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
   807  			return false
   808  		}
   809  		if !strings.HasPrefix(p, "//") {
   810  			break
   811  		}
   812  		if !strings.Contains(p, "+build") {
   813  			continue
   814  		}
   815  		fields := splitfields(p)
   816  		if len(fields) < 2 || fields[1] != "+build" {
   817  			continue
   818  		}
   819  		for _, p := range fields[2:] {
   820  			if matchfield(p) {
   821  				goto fieldmatch
   822  			}
   823  		}
   824  		return false
   825  	fieldmatch:
   826  	}
   827  
   828  	return true
   829  }
   830  
   831  // copy copies the file src to dst, via memory (so only good for small files).
   832  func copyfile(dst, src string, flag int) {
   833  	if vflag > 1 {
   834  		errprintf("cp %s %s\n", src, dst)
   835  	}
   836  	writefile(readfile(src), dst, flag)
   837  }
   838  
   839  // dopack copies the package src to dst,
   840  // appending the files listed in extra.
   841  // The archive format is the traditional Unix ar format.
   842  func dopack(dst, src string, extra []string) {
   843  	bdst := bytes.NewBufferString(readfile(src))
   844  	for _, file := range extra {
   845  		b := readfile(file)
   846  		// find last path element for archive member name
   847  		i := strings.LastIndex(file, "/") + 1
   848  		j := strings.LastIndex(file, `\`) + 1
   849  		if i < j {
   850  			i = j
   851  		}
   852  		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
   853  		bdst.WriteString(b)
   854  		if len(b)&1 != 0 {
   855  			bdst.WriteByte(0)
   856  		}
   857  	}
   858  	writefile(bdst.String(), dst, 0)
   859  }
   860  
   861  // builddeps records the build dependencies for the 'go bootstrap' command.
   862  // It is a map[string][]string and generated by mkdeps.bash into deps.go.
   863  
   864  // buildlist is the list of directories being built, sorted by name.
   865  var buildlist = makeBuildlist()
   866  
   867  func makeBuildlist() []string {
   868  	var all []string
   869  	for dir := range builddeps {
   870  		all = append(all, dir)
   871  	}
   872  	sort.Strings(all)
   873  	return all
   874  }
   875  
   876  var runtimegen = []string{
   877  	"zaexperiment.h",
   878  	"zversion.go",
   879  }
   880  
   881  func clean() {
   882  	for _, name := range buildlist {
   883  		path := pathf("%s/src/%s", goroot, name)
   884  		// Remove generated files.
   885  		for _, elem := range xreaddir(path) {
   886  			for _, gt := range gentab {
   887  				if strings.HasPrefix(elem, gt.nameprefix) {
   888  					xremove(pathf("%s/%s", path, elem))
   889  				}
   890  			}
   891  		}
   892  		// Remove generated binary named for directory.
   893  		if strings.HasPrefix(name, "cmd/") {
   894  			xremove(pathf("%s/%s", path, name[4:]))
   895  		}
   896  	}
   897  
   898  	// remove runtimegen files.
   899  	path := pathf("%s/src/runtime", goroot)
   900  	for _, elem := range runtimegen {
   901  		xremove(pathf("%s/%s", path, elem))
   902  	}
   903  
   904  	if rebuildall {
   905  		// Remove object tree.
   906  		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
   907  
   908  		// Remove installed packages and tools.
   909  		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
   910  		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
   911  		xremoveall(tooldir)
   912  
   913  		// Remove cached version info.
   914  		xremove(pathf("%s/VERSION.cache", goroot))
   915  	}
   916  }
   917  
   918  /*
   919   * command implementations
   920   */
   921  
   922  func usage() {
   923  	xprintf("usage: go tool dist [command]\n" +
   924  		"Commands are:\n" +
   925  		"\n" +
   926  		"banner         print installation banner\n" +
   927  		"bootstrap      rebuild everything\n" +
   928  		"clean          deletes all built files\n" +
   929  		"env [-p]       print environment (-p: include $PATH)\n" +
   930  		"install [dir]  install individual directory\n" +
   931  		"test [-h]      run Go test(s)\n" +
   932  		"version        print Go version\n" +
   933  		"\n" +
   934  		"All commands take -v flags to emit extra information.\n",
   935  	)
   936  	xexit(2)
   937  }
   938  
   939  // The env command prints the default environment.
   940  func cmdenv() {
   941  	path := flag.Bool("p", false, "emit updated PATH")
   942  	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
   943  	windows := flag.Bool("w", false, "emit windows syntax")
   944  	xflagparse(0)
   945  
   946  	format := "%s=\"%s\"\n"
   947  	switch {
   948  	case *plan9:
   949  		format = "%s='%s'\n"
   950  	case *windows:
   951  		format = "set %s=%s\r\n"
   952  	}
   953  
   954  	xprintf(format, "CC", defaultcc)
   955  	xprintf(format, "CC_FOR_TARGET", defaultcctarget)
   956  	xprintf(format, "GOROOT", goroot)
   957  	xprintf(format, "GOBIN", gobin)
   958  	xprintf(format, "GOARCH", goarch)
   959  	xprintf(format, "GOOS", goos)
   960  	xprintf(format, "GOHOSTARCH", gohostarch)
   961  	xprintf(format, "GOHOSTOS", gohostos)
   962  	xprintf(format, "GOTOOLDIR", tooldir)
   963  	if goarch == "arm" {
   964  		xprintf(format, "GOARM", goarm)
   965  	}
   966  	if goarch == "386" {
   967  		xprintf(format, "GO386", go386)
   968  	}
   969  
   970  	if *path {
   971  		sep := ":"
   972  		if gohostos == "windows" {
   973  			sep = ";"
   974  		}
   975  		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
   976  	}
   977  }
   978  
   979  // The bootstrap command runs a build from scratch,
   980  // stopping at having installed the go_bootstrap command.
   981  func cmdbootstrap() {
   982  	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
   983  	flag.BoolVar(&sflag, "s", sflag, "build static binaries")
   984  	xflagparse(0)
   985  
   986  	if isdir(pathf("%s/src/pkg", goroot)) {
   987  		fatal("\n\n"+
   988  			"The Go package sources have moved to $GOROOT/src.\n"+
   989  			"*** %s still exists. ***\n"+
   990  			"It probably contains stale files that may confuse the build.\n"+
   991  			"Please (check what's there and) remove it and try again.\n"+
   992  			"See https://golang.org/s/go14nopkg\n",
   993  			pathf("%s/src/pkg", goroot))
   994  	}
   995  
   996  	if rebuildall {
   997  		clean()
   998  	}
   999  
  1000  	setup()
  1001  
  1002  	checkCC()
  1003  	bootstrapBuildTools()
  1004  
  1005  	// For the main bootstrap, building for host os/arch.
  1006  	oldgoos = goos
  1007  	oldgoarch = goarch
  1008  	goos = gohostos
  1009  	goarch = gohostarch
  1010  	os.Setenv("GOHOSTARCH", gohostarch)
  1011  	os.Setenv("GOHOSTOS", gohostos)
  1012  	os.Setenv("GOARCH", goarch)
  1013  	os.Setenv("GOOS", goos)
  1014  
  1015  	// TODO(rsc): Enable when appropriate.
  1016  	// This step is only needed if we believe that the Go compiler built from Go 1.4
  1017  	// will produce different object files than the Go compiler built from itself.
  1018  	// In the absence of bugs, that should not happen.
  1019  	// And if there are bugs, they're more likely in the current development tree
  1020  	// than in a standard release like Go 1.4, so don't do this rebuild by default.
  1021  	if false {
  1022  		xprintf("##### Building Go toolchain using itself.\n")
  1023  		for _, dir := range buildlist {
  1024  			installed[dir] = make(chan struct{})
  1025  		}
  1026  		var wg sync.WaitGroup
  1027  		for _, dir := range builddeps["cmd/go"] {
  1028  			wg.Add(1)
  1029  			dir := dir
  1030  			go func() {
  1031  				defer wg.Done()
  1032  				install(dir)
  1033  			}()
  1034  		}
  1035  		wg.Wait()
  1036  		xprintf("\n")
  1037  	}
  1038  
  1039  	xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
  1040  	for _, dir := range buildlist {
  1041  		installed[dir] = make(chan struct{})
  1042  	}
  1043  	for _, dir := range buildlist {
  1044  		go install(dir)
  1045  	}
  1046  	<-installed["cmd/go"]
  1047  
  1048  	goos = oldgoos
  1049  	goarch = oldgoarch
  1050  	os.Setenv("GOARCH", goarch)
  1051  	os.Setenv("GOOS", goos)
  1052  
  1053  	// Build runtime for actual goos/goarch too.
  1054  	if goos != gohostos || goarch != gohostarch {
  1055  		installed["runtime"] = make(chan struct{})
  1056  		install("runtime")
  1057  	}
  1058  }
  1059  
  1060  // Copied from go/build/build.go.
  1061  // Cannot use go/build directly because cmd/dist for a new release
  1062  // builds against an old release's go/build, which may be out of sync.
  1063  var cgoEnabled = map[string]bool{
  1064  	"darwin/386":      true,
  1065  	"darwin/amd64":    true,
  1066  	"darwin/arm":      true,
  1067  	"darwin/arm64":    true,
  1068  	"dragonfly/amd64": true,
  1069  	"freebsd/386":     true,
  1070  	"freebsd/amd64":   true,
  1071  	"linux/386":       true,
  1072  	"linux/amd64":     true,
  1073  	"linux/arm":       true,
  1074  	"linux/arm64":     true,
  1075  	"linux/ppc64le":   true,
  1076  	"android/386":     true,
  1077  	"android/amd64":   true,
  1078  	"android/arm":     true,
  1079  	"netbsd/386":      true,
  1080  	"netbsd/amd64":    true,
  1081  	"netbsd/arm":      true,
  1082  	"openbsd/386":     true,
  1083  	"openbsd/amd64":   true,
  1084  	"solaris/amd64":   true,
  1085  	"windows/386":     true,
  1086  	"windows/amd64":   true,
  1087  }
  1088  
  1089  func needCC() bool {
  1090  	switch os.Getenv("CGO_ENABLED") {
  1091  	case "1":
  1092  		return true
  1093  	case "0":
  1094  		return false
  1095  	}
  1096  	return cgoEnabled[gohostos+"/"+gohostarch]
  1097  }
  1098  
  1099  func checkCC() {
  1100  	if !needCC() {
  1101  		return
  1102  	}
  1103  	if _, err := exec.Command(defaultcc, "--help").Output(); err != nil {
  1104  		fatal("cannot invoke C compiler %q: %v\n\n"+
  1105  			"Go needs a system C compiler for use with cgo.\n"+
  1106  			"To set a C compiler, export CC=the-compiler.\n"+
  1107  			"To disable cgo, export CGO_ENABLED=0.\n", defaultcc, err)
  1108  	}
  1109  }
  1110  
  1111  func defaulttarg() string {
  1112  	// xgetwd might return a path with symlinks fully resolved, and if
  1113  	// there happens to be symlinks in goroot, then the hasprefix test
  1114  	// will never succeed. Instead, we use xrealwd to get a canonical
  1115  	// goroot/src before the comparison to avoid this problem.
  1116  	pwd := xgetwd()
  1117  	src := pathf("%s/src/", goroot)
  1118  	real_src := xrealwd(src)
  1119  	if !strings.HasPrefix(pwd, real_src) {
  1120  		fatal("current directory %s is not under %s", pwd, real_src)
  1121  	}
  1122  	pwd = pwd[len(real_src):]
  1123  	// guard againt xrealwd return the directory without the trailing /
  1124  	pwd = strings.TrimPrefix(pwd, "/")
  1125  
  1126  	return pwd
  1127  }
  1128  
  1129  // Install installs the list of packages named on the command line.
  1130  func cmdinstall() {
  1131  	flag.BoolVar(&sflag, "s", sflag, "build static binaries")
  1132  	xflagparse(-1)
  1133  
  1134  	if flag.NArg() == 0 {
  1135  		install(defaulttarg())
  1136  	}
  1137  
  1138  	for _, arg := range flag.Args() {
  1139  		install(arg)
  1140  	}
  1141  }
  1142  
  1143  // Clean deletes temporary objects.
  1144  func cmdclean() {
  1145  	xflagparse(0)
  1146  	clean()
  1147  }
  1148  
  1149  // Banner prints the 'now you've installed Go' banner.
  1150  func cmdbanner() {
  1151  	xflagparse(0)
  1152  
  1153  	xprintf("\n")
  1154  	xprintf("---\n")
  1155  	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
  1156  	xprintf("Installed commands in %s\n", gobin)
  1157  
  1158  	if !xsamefile(goroot_final, goroot) {
  1159  		// If the files are to be moved, don't check that gobin
  1160  		// is on PATH; assume they know what they are doing.
  1161  	} else if gohostos == "plan9" {
  1162  		// Check that gobin is bound before /bin.
  1163  		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
  1164  		ns := fmt.Sprintf("/proc/%s/ns", pid)
  1165  		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
  1166  			xprintf("*** You need to bind %s before /bin.\n", gobin)
  1167  		}
  1168  	} else {
  1169  		// Check that gobin appears in $PATH.
  1170  		pathsep := ":"
  1171  		if gohostos == "windows" {
  1172  			pathsep = ";"
  1173  		}
  1174  		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
  1175  			xprintf("*** You need to add %s to your PATH.\n", gobin)
  1176  		}
  1177  	}
  1178  
  1179  	if !xsamefile(goroot_final, goroot) {
  1180  		xprintf("\n"+
  1181  			"The binaries expect %s to be copied or moved to %s\n",
  1182  			goroot, goroot_final)
  1183  	}
  1184  }
  1185  
  1186  // Version prints the Go version.
  1187  func cmdversion() {
  1188  	xflagparse(0)
  1189  	xprintf("%s\n", findgoversion())
  1190  }