github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/dist/build.go (about)

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