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