github.com/aloncn/graphics-go@v0.0.1/src/cmd/dist/build.go (about)

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