Home | History | Annotate | Download | only in dist
      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 	"log"
     13 	"os"
     14 	"os/exec"
     15 	"path/filepath"
     16 	"sort"
     17 	"strings"
     18 	"sync"
     19 	"time"
     20 )
     21 
     22 // Initialization for any invocation.
     23 
     24 // The usual variables.
     25 var (
     26 	goarch           string
     27 	gobin            string
     28 	gohostarch       string
     29 	gohostos         string
     30 	goos             string
     31 	goarm            string
     32 	go386            string
     33 	gomips           string
     34 	goroot           string
     35 	goroot_final     string
     36 	goextlinkenabled string
     37 	gogcflags        string // For running built compiler
     38 	goldflags        string
     39 	workdir          string
     40 	tooldir          string
     41 	oldgoos          string
     42 	oldgoarch        string
     43 	exe              string
     44 	defaultcc        map[string]string
     45 	defaultcxx       map[string]string
     46 	defaultcflags    string
     47 	defaultldflags   string
     48 	defaultpkgconfig string
     49 
     50 	rebuildall   bool
     51 	defaultclang bool
     52 
     53 	vflag int // verbosity
     54 )
     55 
     56 // The known architectures.
     57 var okgoarch = []string{
     58 	"386",
     59 	"amd64",
     60 	"amd64p32",
     61 	"arm",
     62 	"arm64",
     63 	"mips",
     64 	"mipsle",
     65 	"mips64",
     66 	"mips64le",
     67 	"ppc64",
     68 	"ppc64le",
     69 	"s390x",
     70 }
     71 
     72 // The known operating systems.
     73 var okgoos = []string{
     74 	"darwin",
     75 	"dragonfly",
     76 	"linux",
     77 	"android",
     78 	"solaris",
     79 	"freebsd",
     80 	"nacl",
     81 	"netbsd",
     82 	"openbsd",
     83 	"plan9",
     84 	"windows",
     85 }
     86 
     87 // find reports the first index of p in l[0:n], or else -1.
     88 func find(p string, l []string) int {
     89 	for i, s := range l {
     90 		if p == s {
     91 			return i
     92 		}
     93 	}
     94 	return -1
     95 }
     96 
     97 // xinit handles initialization of the various global state, like goroot and goarch.
     98 func xinit() {
     99 	b := os.Getenv("GOROOT")
    100 	if b == "" {
    101 		fatalf("$GOROOT must be set")
    102 	}
    103 	goroot = filepath.Clean(b)
    104 
    105 	b = os.Getenv("GOROOT_FINAL")
    106 	if b == "" {
    107 		b = goroot
    108 	}
    109 	goroot_final = b
    110 
    111 	b = os.Getenv("GOBIN")
    112 	if b == "" {
    113 		b = pathf("%s/bin", goroot)
    114 	}
    115 	gobin = b
    116 
    117 	b = os.Getenv("GOOS")
    118 	if b == "" {
    119 		b = gohostos
    120 	}
    121 	goos = b
    122 	if find(goos, okgoos) < 0 {
    123 		fatalf("unknown $GOOS %s", goos)
    124 	}
    125 
    126 	b = os.Getenv("GOARM")
    127 	if b == "" {
    128 		b = xgetgoarm()
    129 	}
    130 	goarm = b
    131 
    132 	b = os.Getenv("GO386")
    133 	if b == "" {
    134 		if cansse2() {
    135 			b = "sse2"
    136 		} else {
    137 			b = "387"
    138 		}
    139 	}
    140 	go386 = b
    141 
    142 	b = os.Getenv("GOMIPS")
    143 	if b == "" {
    144 		b = "hardfloat"
    145 	}
    146 	gomips = b
    147 
    148 	if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
    149 		fatalf("$GOROOT is not set correctly or not exported\n"+
    150 			"\tGOROOT=%s\n"+
    151 			"\t%s does not exist", goroot, p)
    152 	}
    153 
    154 	b = os.Getenv("GOHOSTARCH")
    155 	if b != "" {
    156 		gohostarch = b
    157 	}
    158 	if find(gohostarch, okgoarch) < 0 {
    159 		fatalf("unknown $GOHOSTARCH %s", gohostarch)
    160 	}
    161 
    162 	b = os.Getenv("GOARCH")
    163 	if b == "" {
    164 		b = gohostarch
    165 	}
    166 	goarch = b
    167 	if find(goarch, okgoarch) < 0 {
    168 		fatalf("unknown $GOARCH %s", goarch)
    169 	}
    170 
    171 	b = os.Getenv("GO_EXTLINK_ENABLED")
    172 	if b != "" {
    173 		if b != "0" && b != "1" {
    174 			fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
    175 		}
    176 		goextlinkenabled = b
    177 	}
    178 
    179 	gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
    180 
    181 	cc, cxx := "gcc", "g++"
    182 	if defaultclang {
    183 		cc, cxx = "clang", "clang++"
    184 	}
    185 	defaultcc = compilerEnv("CC", cc)
    186 	defaultcxx = compilerEnv("CXX", cxx)
    187 
    188 	defaultcflags = os.Getenv("CFLAGS")
    189 	defaultldflags = os.Getenv("LDFLAGS")
    190 
    191 	b = os.Getenv("PKG_CONFIG")
    192 	if b == "" {
    193 		b = "pkg-config"
    194 	}
    195 	defaultpkgconfig = b
    196 
    197 	// For tools being invoked but also for os.ExpandEnv.
    198 	os.Setenv("GO386", go386)
    199 	os.Setenv("GOARCH", goarch)
    200 	os.Setenv("GOARM", goarm)
    201 	os.Setenv("GOHOSTARCH", gohostarch)
    202 	os.Setenv("GOHOSTOS", gohostos)
    203 	os.Setenv("GOOS", goos)
    204 	os.Setenv("GOMIPS", gomips)
    205 	os.Setenv("GOROOT", goroot)
    206 	os.Setenv("GOROOT_FINAL", goroot_final)
    207 
    208 	// Use a build cache separate from the default user one.
    209 	// Also one that will be wiped out during startup, so that
    210 	// make.bash really does start from a clean slate.
    211 	// But if the user has specified no caching, don't cache.
    212 	if os.Getenv("GOCACHE") != "off" {
    213 		os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
    214 	}
    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 // compilerEnv returns a map from "goos/goarch" to the
    227 // compiler setting to use for that platform.
    228 // The entry for key "" covers any goos/goarch not explicitly set in the map.
    229 // For example, compilerEnv("CC", "gcc") returns the C compiler settings
    230 // read from $CC, defaulting to gcc.
    231 //
    232 // The result is a map because additional environment variables
    233 // can be set to change the compiler based on goos/goarch settings.
    234 // The following applies to all envNames but CC is assumed to simplify
    235 // the presentation.
    236 //
    237 // If no environment variables are set, we use def for all goos/goarch.
    238 // $CC, if set, applies to all goos/goarch but is overridden by the following.
    239 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
    240 // but is overridden by the following.
    241 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
    242 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
    243 func compilerEnv(envName, def string) map[string]string {
    244 	m := map[string]string{"": def}
    245 
    246 	if env := os.Getenv(envName); env != "" {
    247 		m[""] = env
    248 	}
    249 	if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
    250 		if gohostos != goos || gohostarch != goarch {
    251 			m[gohostos+"/"+gohostarch] = m[""]
    252 		}
    253 		m[""] = env
    254 	}
    255 
    256 	for _, goos := range okgoos {
    257 		for _, goarch := range okgoarch {
    258 			if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
    259 				m[goos+"/"+goarch] = env
    260 			}
    261 		}
    262 	}
    263 
    264 	return m
    265 }
    266 
    267 // compilerEnvLookup returns the compiler settings for goos/goarch in map m.
    268 func compilerEnvLookup(m map[string]string, goos, goarch string) string {
    269 	if cc := m[goos+"/"+goarch]; cc != "" {
    270 		return cc
    271 	}
    272 	return m[""]
    273 }
    274 
    275 // rmworkdir deletes the work directory.
    276 func rmworkdir() {
    277 	if vflag > 1 {
    278 		errprintf("rm -rf %s\n", workdir)
    279 	}
    280 	xremoveall(workdir)
    281 }
    282 
    283 // Remove trailing spaces.
    284 func chomp(s string) string {
    285 	return strings.TrimRight(s, " \t\r\n")
    286 }
    287 
    288 func branchtag(branch string) (tag string, precise bool) {
    289 	log := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
    290 	tag = branch
    291 	for row, line := range strings.Split(log, "\n") {
    292 		// Each line is either blank, or looks like
    293 		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
    294 		// We need to find an element starting with refs/tags/.
    295 		const s = " refs/tags/"
    296 		i := strings.Index(line, s)
    297 		if i < 0 {
    298 			continue
    299 		}
    300 		// Trim off known prefix.
    301 		line = line[i+len(s):]
    302 		// The tag name ends at a comma or paren.
    303 		j := strings.IndexAny(line, ",)")
    304 		if j < 0 {
    305 			continue // malformed line; ignore it
    306 		}
    307 		tag = line[:j]
    308 		if row == 0 {
    309 			precise = true // tag denotes HEAD
    310 		}
    311 		break
    312 	}
    313 	return
    314 }
    315 
    316 // findgoversion determines the Go version to use in the version string.
    317 func findgoversion() string {
    318 	// The $GOROOT/VERSION file takes priority, for distributions
    319 	// without the source repo.
    320 	path := pathf("%s/VERSION", goroot)
    321 	if isfile(path) {
    322 		b := chomp(readfile(path))
    323 		// Commands such as "dist version > VERSION" will cause
    324 		// the shell to create an empty VERSION file and set dist's
    325 		// stdout to its fd. dist in turn looks at VERSION and uses
    326 		// its content if available, which is empty at this point.
    327 		// Only use the VERSION file if it is non-empty.
    328 		if b != "" {
    329 			// Some builders cross-compile the toolchain on linux-amd64
    330 			// and then copy the toolchain to the target builder (say, linux-arm)
    331 			// for use there. But on non-release (devel) branches, the compiler
    332 			// used on linux-amd64 will be an amd64 binary, and the compiler
    333 			// shipped to linux-arm will be an arm binary, so they will have different
    334 			// content IDs (they are binaries for different architectures) and so the
    335 			// packages compiled by the running-on-amd64 compiler will appear
    336 			// stale relative to the running-on-arm compiler. Avoid this by setting
    337 			// the version string to something that doesn't begin with devel.
    338 			// Then the version string will be used in place of the content ID,
    339 			// and the packages will look up-to-date.
    340 			// TODO(rsc): Really the builders could be writing out a better VERSION file instead,
    341 			// but it is easier to change cmd/dist than to try to make changes to
    342 			// the builder while Brad is away.
    343 			if strings.HasPrefix(b, "devel") {
    344 				if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") {
    345 					fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType)
    346 					b = "builder " + hostType
    347 				}
    348 			}
    349 			return b
    350 		}
    351 	}
    352 
    353 	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
    354 	// git every time we run this command. Unlike VERSION, it gets
    355 	// deleted by the clean command.
    356 	path = pathf("%s/VERSION.cache", goroot)
    357 	if isfile(path) {
    358 		return chomp(readfile(path))
    359 	}
    360 
    361 	// Show a nicer error message if this isn't a Git repo.
    362 	if !isGitRepo() {
    363 		fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
    364 	}
    365 
    366 	// Otherwise, use Git.
    367 	// What is the current branch?
    368 	branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
    369 
    370 	// What are the tags along the current branch?
    371 	tag := "devel"
    372 	precise := false
    373 
    374 	// If we're on a release branch, use the closest matching tag
    375 	// that is on the release branch (and not on the master branch).
    376 	if strings.HasPrefix(branch, "release-branch.") {
    377 		tag, precise = branchtag(branch)
    378 	}
    379 
    380 	if !precise {
    381 		// Tag does not point at HEAD; add hash and date to version.
    382 		tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
    383 	}
    384 
    385 	// Cache version.
    386 	writefile(tag, path, 0)
    387 
    388 	return tag
    389 }
    390 
    391 // isGitRepo reports whether the working directory is inside a Git repository.
    392 func isGitRepo() bool {
    393 	// NB: simply checking the exit code of `git rev-parse --git-dir` would
    394 	// suffice here, but that requires deviating from the infrastructure
    395 	// provided by `run`.
    396 	gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
    397 	if !filepath.IsAbs(gitDir) {
    398 		gitDir = filepath.Join(goroot, gitDir)
    399 	}
    400 	return isdir(gitDir)
    401 }
    402 
    403 /*
    404  * Initial tree setup.
    405  */
    406 
    407 // The old tools that no longer live in $GOBIN or $GOROOT/bin.
    408 var oldtool = []string{
    409 	"5a", "5c", "5g", "5l",
    410 	"6a", "6c", "6g", "6l",
    411 	"8a", "8c", "8g", "8l",
    412 	"9a", "9c", "9g", "9l",
    413 	"6cov",
    414 	"6nm",
    415 	"6prof",
    416 	"cgo",
    417 	"ebnflint",
    418 	"goapi",
    419 	"gofix",
    420 	"goinstall",
    421 	"gomake",
    422 	"gopack",
    423 	"gopprof",
    424 	"gotest",
    425 	"gotype",
    426 	"govet",
    427 	"goyacc",
    428 	"quietgcc",
    429 }
    430 
    431 // Unreleased directories (relative to $GOROOT) that should
    432 // not be in release branches.
    433 var unreleased = []string{
    434 	"src/cmd/newlink",
    435 	"src/cmd/objwriter",
    436 	"src/debug/goobj",
    437 	"src/old",
    438 }
    439 
    440 // setup sets up the tree for the initial build.
    441 func setup() {
    442 	// Create bin directory.
    443 	if p := pathf("%s/bin", goroot); !isdir(p) {
    444 		xmkdir(p)
    445 	}
    446 
    447 	// Create package directory.
    448 	if p := pathf("%s/pkg", goroot); !isdir(p) {
    449 		xmkdir(p)
    450 	}
    451 
    452 	p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
    453 	if rebuildall {
    454 		xremoveall(p)
    455 	}
    456 	xmkdirall(p)
    457 
    458 	if goos != gohostos || goarch != gohostarch {
    459 		p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
    460 		if rebuildall {
    461 			xremoveall(p)
    462 		}
    463 		xmkdirall(p)
    464 	}
    465 
    466 	// Create object directory.
    467 	// We used to use it for C objects.
    468 	// Now we use it for the build cache, to separate dist's cache
    469 	// from any other cache the user might have.
    470 	p = pathf("%s/pkg/obj/go-build", goroot)
    471 	if rebuildall {
    472 		xremoveall(p)
    473 	}
    474 	xmkdirall(p)
    475 
    476 	// Create tool directory.
    477 	// We keep it in pkg/, just like the object directory above.
    478 	if rebuildall {
    479 		xremoveall(tooldir)
    480 	}
    481 	xmkdirall(tooldir)
    482 
    483 	// Remove tool binaries from before the tool/gohostos_gohostarch
    484 	xremoveall(pathf("%s/bin/tool", goroot))
    485 
    486 	// Remove old pre-tool binaries.
    487 	for _, old := range oldtool {
    488 		xremove(pathf("%s/bin/%s", goroot, old))
    489 	}
    490 
    491 	// If $GOBIN is set and has a Go compiler, it must be cleaned.
    492 	for _, char := range "56789" {
    493 		if isfile(pathf("%s/%c%s", gobin, char, "g")) {
    494 			for _, old := range oldtool {
    495 				xremove(pathf("%s/%s", gobin, old))
    496 			}
    497 			break
    498 		}
    499 	}
    500 
    501 	// For release, make sure excluded things are excluded.
    502 	goversion := findgoversion()
    503 	if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
    504 		for _, dir := range unreleased {
    505 			if p := pathf("%s/%s", goroot, dir); isdir(p) {
    506 				fatalf("%s should not exist in release build", p)
    507 			}
    508 		}
    509 	}
    510 }
    511 
    512 /*
    513  * Tool building
    514  */
    515 
    516 // deptab lists changes to the default dependencies for a given prefix.
    517 // deps ending in /* read the whole directory; deps beginning with -
    518 // exclude files with that prefix.
    519 // Note that this table applies only to the build of cmd/go,
    520 // after the main compiler bootstrap.
    521 var deptab = []struct {
    522 	prefix string   // prefix of target
    523 	dep    []string // dependency tweaks for targets with that prefix
    524 }{
    525 	{"cmd/go/internal/cfg", []string{
    526 		"zdefaultcc.go",
    527 		"zosarch.go",
    528 	}},
    529 	{"runtime/internal/sys", []string{
    530 		"zversion.go",
    531 	}},
    532 	{"go/build", []string{
    533 		"zcgo.go",
    534 	}},
    535 }
    536 
    537 // depsuffix records the allowed suffixes for source files.
    538 var depsuffix = []string{
    539 	".s",
    540 	".go",
    541 }
    542 
    543 // gentab records how to generate some trivial files.
    544 var gentab = []struct {
    545 	nameprefix string
    546 	gen        func(string, string)
    547 }{
    548 	{"zdefaultcc.go", mkzdefaultcc},
    549 	{"zosarch.go", mkzosarch},
    550 	{"zversion.go", mkzversion},
    551 	{"zcgo.go", mkzcgo},
    552 
    553 	// not generated anymore, but delete the file if we see it
    554 	{"enam.c", nil},
    555 	{"anames5.c", nil},
    556 	{"anames6.c", nil},
    557 	{"anames8.c", nil},
    558 	{"anames9.c", nil},
    559 }
    560 
    561 // installed maps from a dir name (as given to install) to a chan
    562 // closed when the dir's package is installed.
    563 var installed = make(map[string]chan struct{})
    564 var installedMu sync.Mutex
    565 
    566 func install(dir string) {
    567 	<-startInstall(dir)
    568 }
    569 
    570 func startInstall(dir string) chan struct{} {
    571 	installedMu.Lock()
    572 	ch := installed[dir]
    573 	if ch == nil {
    574 		ch = make(chan struct{})
    575 		installed[dir] = ch
    576 		go runInstall(dir, ch)
    577 	}
    578 	installedMu.Unlock()
    579 	return ch
    580 }
    581 
    582 // runInstall installs the library, package, or binary associated with dir,
    583 // which is relative to $GOROOT/src.
    584 func runInstall(dir string, ch chan struct{}) {
    585 	if dir == "net" || dir == "os/user" || dir == "crypto/x509" {
    586 		fatalf("go_bootstrap cannot depend on cgo package %s", dir)
    587 	}
    588 
    589 	defer close(ch)
    590 
    591 	if dir == "unsafe" {
    592 		return
    593 	}
    594 
    595 	if vflag > 0 {
    596 		if goos != gohostos || goarch != gohostarch {
    597 			errprintf("%s (%s/%s)\n", dir, goos, goarch)
    598 		} else {
    599 			errprintf("%s\n", dir)
    600 		}
    601 	}
    602 
    603 	workdir := pathf("%s/%s", workdir, dir)
    604 	xmkdirall(workdir)
    605 
    606 	var clean []string
    607 	defer func() {
    608 		for _, name := range clean {
    609 			xremove(name)
    610 		}
    611 	}()
    612 
    613 	// path = full path to dir.
    614 	path := pathf("%s/src/%s", goroot, dir)
    615 	name := filepath.Base(dir)
    616 
    617 	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/")
    618 
    619 	// Start final link command line.
    620 	// Note: code below knows that link.p[targ] is the target.
    621 	var (
    622 		link      []string
    623 		targ      int
    624 		ispackcmd bool
    625 	)
    626 	if ispkg {
    627 		// Go library (package).
    628 		ispackcmd = true
    629 		link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
    630 		targ = len(link) - 1
    631 		xmkdirall(filepath.Dir(link[targ]))
    632 	} else {
    633 		// Go command.
    634 		elem := name
    635 		if elem == "go" {
    636 			elem = "go_bootstrap"
    637 		}
    638 		link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
    639 		targ = len(link) - 1
    640 	}
    641 	ttarg := mtime(link[targ])
    642 
    643 	// Gather files that are sources for this target.
    644 	// Everything in that directory, and any target-specific
    645 	// additions.
    646 	files := xreaddir(path)
    647 
    648 	// Remove files beginning with . or _,
    649 	// which are likely to be editor temporary files.
    650 	// This is the same heuristic build.ScanDir uses.
    651 	// There do exist real C files beginning with _,
    652 	// so limit that check to just Go files.
    653 	files = filter(files, func(p string) bool {
    654 		return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
    655 	})
    656 
    657 	for _, dt := range deptab {
    658 		if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
    659 			for _, p := range dt.dep {
    660 				p = os.ExpandEnv(p)
    661 				files = append(files, p)
    662 			}
    663 		}
    664 	}
    665 	files = uniq(files)
    666 
    667 	// Convert to absolute paths.
    668 	for i, p := range files {
    669 		if !filepath.IsAbs(p) {
    670 			files[i] = pathf("%s/%s", path, p)
    671 		}
    672 	}
    673 
    674 	// Is the target up-to-date?
    675 	var gofiles, missing []string
    676 	stale := rebuildall
    677 	files = filter(files, func(p string) bool {
    678 		for _, suf := range depsuffix {
    679 			if strings.HasSuffix(p, suf) {
    680 				goto ok
    681 			}
    682 		}
    683 		return false
    684 	ok:
    685 		t := mtime(p)
    686 		if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
    687 			return false
    688 		}
    689 		if strings.HasSuffix(p, ".go") {
    690 			gofiles = append(gofiles, p)
    691 		}
    692 		if t.After(ttarg) {
    693 			stale = true
    694 		}
    695 		if t.IsZero() {
    696 			missing = append(missing, p)
    697 		}
    698 		return true
    699 	})
    700 
    701 	// If there are no files to compile, we're done.
    702 	if len(files) == 0 {
    703 		return
    704 	}
    705 
    706 	if !stale {
    707 		return
    708 	}
    709 
    710 	// For package runtime, copy some files into the work space.
    711 	if dir == "runtime" {
    712 		xmkdirall(pathf("%s/pkg/include", goroot))
    713 		// For use by assembly and C files.
    714 		copyfile(pathf("%s/pkg/include/textflag.h", goroot),
    715 			pathf("%s/src/runtime/textflag.h", goroot), 0)
    716 		copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
    717 			pathf("%s/src/runtime/funcdata.h", goroot), 0)
    718 		copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
    719 			pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
    720 	}
    721 
    722 	// Generate any missing files; regenerate existing ones.
    723 	for _, p := range files {
    724 		elem := filepath.Base(p)
    725 		for _, gt := range gentab {
    726 			if gt.gen == nil {
    727 				continue
    728 			}
    729 			if strings.HasPrefix(elem, gt.nameprefix) {
    730 				if vflag > 1 {
    731 					errprintf("generate %s\n", p)
    732 				}
    733 				gt.gen(path, p)
    734 				// Do not add generated file to clean list.
    735 				// In runtime, we want to be able to
    736 				// build the package with the go tool,
    737 				// and it assumes these generated files already
    738 				// exist (it does not know how to build them).
    739 				// The 'clean' command can remove
    740 				// the generated files.
    741 				goto built
    742 			}
    743 		}
    744 		// Did not rebuild p.
    745 		if find(p, missing) >= 0 {
    746 			fatalf("missing file %s", p)
    747 		}
    748 	built:
    749 	}
    750 
    751 	// Make sure dependencies are installed.
    752 	var deps []string
    753 	for _, p := range gofiles {
    754 		deps = append(deps, readimports(p)...)
    755 	}
    756 	for _, dir1 := range deps {
    757 		startInstall(dir1)
    758 	}
    759 	for _, dir1 := range deps {
    760 		install(dir1)
    761 	}
    762 
    763 	if goos != gohostos || goarch != gohostarch {
    764 		// We've generated the right files; the go command can do the build.
    765 		if vflag > 1 {
    766 			errprintf("skip build for cross-compile %s\n", dir)
    767 		}
    768 		return
    769 	}
    770 
    771 	var archive string
    772 	// The next loop will compile individual non-Go files.
    773 	// Hand the Go files to the compiler en masse.
    774 	// For package runtime, this writes go_asm.h, which
    775 	// the assembly files will need.
    776 	pkg := dir
    777 	if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 {
    778 		pkg = "main"
    779 	}
    780 	b := pathf("%s/_go_.a", workdir)
    781 	clean = append(clean, b)
    782 	if !ispackcmd {
    783 		link = append(link, b)
    784 	} else {
    785 		archive = b
    786 	}
    787 	compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
    788 	if gogcflags != "" {
    789 		compile = append(compile, strings.Fields(gogcflags)...)
    790 	}
    791 	if dir == "runtime" {
    792 		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
    793 	}
    794 	compile = append(compile, gofiles...)
    795 	run(path, CheckExit|ShowOutput, compile...)
    796 
    797 	// Compile the files.
    798 	var wg sync.WaitGroup
    799 	for _, p := range files {
    800 		if !strings.HasSuffix(p, ".s") {
    801 			continue
    802 		}
    803 
    804 		var compile []string
    805 		// Assembly file for a Go package.
    806 		compile = []string{
    807 			pathf("%s/asm", tooldir),
    808 			"-I", workdir,
    809 			"-I", pathf("%s/pkg/include", goroot),
    810 			"-D", "GOOS_" + goos,
    811 			"-D", "GOARCH_" + goarch,
    812 			"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
    813 		}
    814 
    815 		if goarch == "mips" || goarch == "mipsle" {
    816 			// Define GOMIPS_value from gomips.
    817 			compile = append(compile, "-D", "GOMIPS_"+gomips)
    818 		}
    819 
    820 		doclean := true
    821 		b := pathf("%s/%s", workdir, filepath.Base(p))
    822 
    823 		// Change the last character of the output file (which was c or s).
    824 		b = b[:len(b)-1] + "o"
    825 		compile = append(compile, "-o", b, p)
    826 		bgrun(&wg, path, compile...)
    827 
    828 		link = append(link, b)
    829 		if doclean {
    830 			clean = append(clean, b)
    831 		}
    832 	}
    833 	bgwait(&wg)
    834 
    835 	if ispackcmd {
    836 		xremove(link[targ])
    837 		dopack(link[targ], archive, link[targ+1:])
    838 		return
    839 	}
    840 
    841 	// Remove target before writing it.
    842 	xremove(link[targ])
    843 	run("", CheckExit|ShowOutput, link...)
    844 }
    845 
    846 // matchfield reports whether the field (x,y,z) matches this build.
    847 // all the elements in the field must be satisfied.
    848 func matchfield(f string) bool {
    849 	for _, tag := range strings.Split(f, ",") {
    850 		if !matchtag(tag) {
    851 			return false
    852 		}
    853 	}
    854 	return true
    855 }
    856 
    857 // matchtag reports whether the tag (x or !x) matches this build.
    858 func matchtag(tag string) bool {
    859 	if tag == "" {
    860 		return false
    861 	}
    862 	if tag[0] == '!' {
    863 		if len(tag) == 1 || tag[1] == '!' {
    864 			return false
    865 		}
    866 		return !matchtag(tag[1:])
    867 	}
    868 	return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
    869 }
    870 
    871 // shouldbuild reports whether we should build this file.
    872 // It applies the same rules that are used with context tags
    873 // in package go/build, except it's less picky about the order
    874 // of GOOS and GOARCH.
    875 // We also allow the special tag cmd_go_bootstrap.
    876 // See ../go/bootstrap.go and package go/build.
    877 func shouldbuild(file, dir string) bool {
    878 	// Check file name for GOOS or GOARCH.
    879 	name := filepath.Base(file)
    880 	excluded := func(list []string, ok string) bool {
    881 		for _, x := range list {
    882 			if x == ok || ok == "android" && x == "linux" {
    883 				continue
    884 			}
    885 			i := strings.Index(name, x)
    886 			if i <= 0 || name[i-1] != '_' {
    887 				continue
    888 			}
    889 			i += len(x)
    890 			if i == len(name) || name[i] == '.' || name[i] == '_' {
    891 				return true
    892 			}
    893 		}
    894 		return false
    895 	}
    896 	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
    897 		return false
    898 	}
    899 
    900 	// Omit test files.
    901 	if strings.Contains(name, "_test") {
    902 		return false
    903 	}
    904 
    905 	// Check file contents for // +build lines.
    906 	for _, p := range strings.Split(readfile(file), "\n") {
    907 		p = strings.TrimSpace(p)
    908 		if p == "" {
    909 			continue
    910 		}
    911 		code := p
    912 		i := strings.Index(code, "//")
    913 		if i > 0 {
    914 			code = strings.TrimSpace(code[:i])
    915 		}
    916 		if code == "package documentation" {
    917 			return false
    918 		}
    919 		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
    920 			return false
    921 		}
    922 		if !strings.HasPrefix(p, "//") {
    923 			break
    924 		}
    925 		if !strings.Contains(p, "+build") {
    926 			continue
    927 		}
    928 		fields := strings.Fields(p[2:])
    929 		if len(fields) < 1 || fields[0] != "+build" {
    930 			continue
    931 		}
    932 		for _, p := range fields[1:] {
    933 			if matchfield(p) {
    934 				goto fieldmatch
    935 			}
    936 		}
    937 		return false
    938 	fieldmatch:
    939 	}
    940 
    941 	return true
    942 }
    943 
    944 // copy copies the file src to dst, via memory (so only good for small files).
    945 func copyfile(dst, src string, flag int) {
    946 	if vflag > 1 {
    947 		errprintf("cp %s %s\n", src, dst)
    948 	}
    949 	writefile(readfile(src), dst, flag)
    950 }
    951 
    952 // dopack copies the package src to dst,
    953 // appending the files listed in extra.
    954 // The archive format is the traditional Unix ar format.
    955 func dopack(dst, src string, extra []string) {
    956 	bdst := bytes.NewBufferString(readfile(src))
    957 	for _, file := range extra {
    958 		b := readfile(file)
    959 		// find last path element for archive member name
    960 		i := strings.LastIndex(file, "/") + 1
    961 		j := strings.LastIndex(file, `\`) + 1
    962 		if i < j {
    963 			i = j
    964 		}
    965 		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
    966 		bdst.WriteString(b)
    967 		if len(b)&1 != 0 {
    968 			bdst.WriteByte(0)
    969 		}
    970 	}
    971 	writefile(bdst.String(), dst, 0)
    972 }
    973 
    974 var runtimegen = []string{
    975 	"zaexperiment.h",
    976 	"zversion.go",
    977 }
    978 
    979 // cleanlist is a list of packages with generated files and commands.
    980 var cleanlist = []string{
    981 	"runtime/internal/sys",
    982 	"cmd/cgo",
    983 	"cmd/go/internal/cfg",
    984 	"go/build",
    985 }
    986 
    987 func clean() {
    988 	for _, name := range cleanlist {
    989 		path := pathf("%s/src/%s", goroot, name)
    990 		// Remove generated files.
    991 		for _, elem := range xreaddir(path) {
    992 			for _, gt := range gentab {
    993 				if strings.HasPrefix(elem, gt.nameprefix) {
    994 					xremove(pathf("%s/%s", path, elem))
    995 				}
    996 			}
    997 		}
    998 		// Remove generated binary named for directory.
    999 		if strings.HasPrefix(name, "cmd/") {
   1000 			xremove(pathf("%s/%s", path, name[4:]))
   1001 		}
   1002 	}
   1003 
   1004 	// remove runtimegen files.
   1005 	path := pathf("%s/src/runtime", goroot)
   1006 	for _, elem := range runtimegen {
   1007 		xremove(pathf("%s/%s", path, elem))
   1008 	}
   1009 
   1010 	if rebuildall {
   1011 		// Remove object tree.
   1012 		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
   1013 
   1014 		// Remove installed packages and tools.
   1015 		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
   1016 		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
   1017 		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
   1018 		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
   1019 		xremoveall(tooldir)
   1020 
   1021 		// Remove cached version info.
   1022 		xremove(pathf("%s/VERSION.cache", goroot))
   1023 	}
   1024 }
   1025 
   1026 /*
   1027  * command implementations
   1028  */
   1029 
   1030 // The env command prints the default environment.
   1031 func cmdenv() {
   1032 	path := flag.Bool("p", false, "emit updated PATH")
   1033 	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
   1034 	windows := flag.Bool("w", false, "emit windows syntax")
   1035 	xflagparse(0)
   1036 
   1037 	format := "%s=\"%s\"\n"
   1038 	switch {
   1039 	case *plan9:
   1040 		format = "%s='%s'\n"
   1041 	case *windows:
   1042 		format = "set %s=%s\r\n"
   1043 	}
   1044 
   1045 	xprintf(format, "GOROOT", goroot)
   1046 	xprintf(format, "GOBIN", gobin)
   1047 	xprintf(format, "GOARCH", goarch)
   1048 	xprintf(format, "GOOS", goos)
   1049 	xprintf(format, "GOHOSTARCH", gohostarch)
   1050 	xprintf(format, "GOHOSTOS", gohostos)
   1051 	xprintf(format, "GOTOOLDIR", tooldir)
   1052 	if goarch == "arm" {
   1053 		xprintf(format, "GOARM", goarm)
   1054 	}
   1055 	if goarch == "386" {
   1056 		xprintf(format, "GO386", go386)
   1057 	}
   1058 	if goarch == "mips" || goarch == "mipsle" {
   1059 		xprintf(format, "GOMIPS", gomips)
   1060 	}
   1061 
   1062 	if *path {
   1063 		sep := ":"
   1064 		if gohostos == "windows" {
   1065 			sep = ";"
   1066 		}
   1067 		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
   1068 	}
   1069 }
   1070 
   1071 var (
   1072 	timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
   1073 	timeLogMu      sync.Mutex
   1074 	timeLogFile    *os.File
   1075 	timeLogStart   time.Time
   1076 )
   1077 
   1078 func timelog(op, name string) {
   1079 	if !timeLogEnabled {
   1080 		return
   1081 	}
   1082 	timeLogMu.Lock()
   1083 	defer timeLogMu.Unlock()
   1084 	if timeLogFile == nil {
   1085 		f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
   1086 		if err != nil {
   1087 			log.Fatal(err)
   1088 		}
   1089 		buf := make([]byte, 100)
   1090 		n, _ := f.Read(buf)
   1091 		s := string(buf[:n])
   1092 		if i := strings.Index(s, "\n"); i >= 0 {
   1093 			s = s[:i]
   1094 		}
   1095 		i := strings.Index(s, " start")
   1096 		if i < 0 {
   1097 			log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE"))
   1098 		}
   1099 		t, err := time.Parse(time.UnixDate, s[:i])
   1100 		if err != nil {
   1101 			log.Fatalf("cannot parse time log line %q: %v", s, err)
   1102 		}
   1103 		timeLogStart = t
   1104 		timeLogFile = f
   1105 	}
   1106 	t := time.Now()
   1107 	fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
   1108 }
   1109 
   1110 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
   1111 
   1112 // The bootstrap command runs a build from scratch,
   1113 // stopping at having installed the go_bootstrap command.
   1114 //
   1115 // WARNING: This command runs after cmd/dist is built with Go 1.4.
   1116 // It rebuilds and installs cmd/dist with the new toolchain, so other
   1117 // commands (like "go tool dist test" in run.bash) can rely on bug fixes
   1118 // made since Go 1.4, but this function cannot. In particular, the uses
   1119 // of os/exec in this function cannot assume that
   1120 //	cmd.Env = append(os.Environ(), "X=Y")
   1121 // sets $X to Y in the command's environment. That guarantee was
   1122 // added after Go 1.4, and in fact in Go 1.4 it was typically the opposite:
   1123 // if $X was already present in os.Environ(), most systems preferred
   1124 // that setting, not the new one.
   1125 func cmdbootstrap() {
   1126 	timelog("start", "dist bootstrap")
   1127 	defer timelog("end", "dist bootstrap")
   1128 
   1129 	var noBanner bool
   1130 	var debug bool
   1131 	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
   1132 	flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
   1133 	flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
   1134 
   1135 	xflagparse(0)
   1136 
   1137 	if debug {
   1138 		// cmd/buildid is used in debug mode.
   1139 		toolchain = append(toolchain, "cmd/buildid")
   1140 	}
   1141 
   1142 	if isdir(pathf("%s/src/pkg", goroot)) {
   1143 		fatalf("\n\n"+
   1144 			"The Go package sources have moved to $GOROOT/src.\n"+
   1145 			"*** %s still exists. ***\n"+
   1146 			"It probably contains stale files that may confuse the build.\n"+
   1147 			"Please (check what's there and) remove it and try again.\n"+
   1148 			"See https://golang.org/s/go14nopkg\n",
   1149 			pathf("%s/src/pkg", goroot))
   1150 	}
   1151 
   1152 	if rebuildall {
   1153 		clean()
   1154 	}
   1155 
   1156 	setup()
   1157 
   1158 	timelog("build", "toolchain1")
   1159 	checkCC()
   1160 	bootstrapBuildTools()
   1161 
   1162 	// Remember old content of $GOROOT/bin for comparison below.
   1163 	oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
   1164 
   1165 	// For the main bootstrap, building for host os/arch.
   1166 	oldgoos = goos
   1167 	oldgoarch = goarch
   1168 	goos = gohostos
   1169 	goarch = gohostarch
   1170 	os.Setenv("GOHOSTARCH", gohostarch)
   1171 	os.Setenv("GOHOSTOS", gohostos)
   1172 	os.Setenv("GOARCH", goarch)
   1173 	os.Setenv("GOOS", goos)
   1174 
   1175 	timelog("build", "go_bootstrap")
   1176 	xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
   1177 	install("runtime") // dependency not visible in sources; also sets up textflag.h
   1178 	install("cmd/go")
   1179 	if vflag > 0 {
   1180 		xprintf("\n")
   1181 	}
   1182 
   1183 	gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
   1184 	goldflags = os.Getenv("GO_LDFLAGS")
   1185 	goBootstrap := pathf("%s/go_bootstrap", tooldir)
   1186 	cmdGo := pathf("%s/go", gobin)
   1187 	if debug {
   1188 		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
   1189 		copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
   1190 	}
   1191 
   1192 	// To recap, so far we have built the new toolchain
   1193 	// (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
   1194 	// using Go 1.4's toolchain and go command.
   1195 	// Then we built the new go command (as go_bootstrap)
   1196 	// using the new toolchain and our own build logic (above).
   1197 	//
   1198 	//	toolchain1 = mk(new toolchain, go1.4 toolchain, go1.4 cmd/go)
   1199 	//	go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
   1200 	//
   1201 	// The toolchain1 we built earlier is built from the new sources,
   1202 	// but because it was built using cmd/go it has no build IDs.
   1203 	// The eventually installed toolchain needs build IDs, so we need
   1204 	// to do another round:
   1205 	//
   1206 	//	toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
   1207 	//
   1208 	timelog("build", "toolchain2")
   1209 	if vflag > 0 {
   1210 		xprintf("\n")
   1211 	}
   1212 	xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
   1213 	os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
   1214 	goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...)
   1215 	if debug {
   1216 		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
   1217 		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
   1218 		copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
   1219 	}
   1220 
   1221 	// Toolchain2 should be semantically equivalent to toolchain1,
   1222 	// but it was built using the new compilers instead of the Go 1.4 compilers,
   1223 	// so it should at the least run faster. Also, toolchain1 had no build IDs
   1224 	// in the binaries, while toolchain2 does. In non-release builds, the
   1225 	// toolchain's build IDs feed into constructing the build IDs of built targets,
   1226 	// so in non-release builds, everything now looks out-of-date due to
   1227 	// toolchain2 having build IDs - that is, due to the go command seeing
   1228 	// that there are new compilers. In release builds, the toolchain's reported
   1229 	// version is used in place of the build ID, and the go command does not
   1230 	// see that change from toolchain1 to toolchain2, so in release builds,
   1231 	// nothing looks out of date.
   1232 	// To keep the behavior the same in both non-release and release builds,
   1233 	// we force-install everything here.
   1234 	//
   1235 	//	toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
   1236 	//
   1237 	timelog("build", "toolchain3")
   1238 	if vflag > 0 {
   1239 		xprintf("\n")
   1240 	}
   1241 	xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
   1242 	goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...)
   1243 	if debug {
   1244 		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
   1245 		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
   1246 		copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
   1247 	}
   1248 	checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
   1249 
   1250 	if goos == oldgoos && goarch == oldgoarch {
   1251 		// Common case - not setting up for cross-compilation.
   1252 		timelog("build", "toolchain")
   1253 		if vflag > 0 {
   1254 			xprintf("\n")
   1255 		}
   1256 		xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
   1257 	} else {
   1258 		// GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
   1259 		// Finish GOHOSTOS/GOHOSTARCH installation and then
   1260 		// run GOOS/GOARCH installation.
   1261 		timelog("build", "host toolchain")
   1262 		if vflag > 0 {
   1263 			xprintf("\n")
   1264 		}
   1265 		xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch)
   1266 		goInstall(goBootstrap, "std", "cmd")
   1267 		checkNotStale(goBootstrap, "std", "cmd")
   1268 		checkNotStale(cmdGo, "std", "cmd")
   1269 
   1270 		timelog("build", "target toolchain")
   1271 		if vflag > 0 {
   1272 			xprintf("\n")
   1273 		}
   1274 		goos = oldgoos
   1275 		goarch = oldgoarch
   1276 		os.Setenv("GOOS", goos)
   1277 		os.Setenv("GOARCH", goarch)
   1278 		os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
   1279 		xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
   1280 	}
   1281 	goInstall(goBootstrap, "std", "cmd")
   1282 	checkNotStale(goBootstrap, "std", "cmd")
   1283 	checkNotStale(cmdGo, "std", "cmd")
   1284 	if debug {
   1285 		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
   1286 		run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch))
   1287 		checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
   1288 		copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
   1289 	}
   1290 
   1291 	// Check that there are no new files in $GOROOT/bin other than
   1292 	// go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
   1293 	binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
   1294 	ok := map[string]bool{}
   1295 	for _, f := range oldBinFiles {
   1296 		ok[f] = true
   1297 	}
   1298 	for _, f := range binFiles {
   1299 		elem := strings.TrimSuffix(filepath.Base(f), ".exe")
   1300 		if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
   1301 			fatalf("unexpected new file in $GOROOT/bin: %s", elem)
   1302 		}
   1303 	}
   1304 
   1305 	// Remove go_bootstrap now that we're done.
   1306 	xremove(pathf("%s/go_bootstrap", tooldir))
   1307 
   1308 	// Print trailing banner unless instructed otherwise.
   1309 	if !noBanner {
   1310 		banner()
   1311 	}
   1312 }
   1313 
   1314 func goInstall(goBinary string, args ...string) {
   1315 	installCmd := []string{goBinary, "install", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags}
   1316 	if vflag > 0 {
   1317 		installCmd = append(installCmd, "-v")
   1318 	}
   1319 
   1320 	// Force only one process at a time on vx32 emulation.
   1321 	if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
   1322 		installCmd = append(installCmd, "-p=1")
   1323 	}
   1324 
   1325 	run(goroot, ShowOutput|CheckExit, append(installCmd, args...)...)
   1326 }
   1327 
   1328 func checkNotStale(goBinary string, targets ...string) {
   1329 	out := run(goroot, CheckExit,
   1330 		append([]string{
   1331 			goBinary,
   1332 			"list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags,
   1333 			"-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}",
   1334 		}, targets...)...)
   1335 	if strings.Contains(out, "\tSTALE ") {
   1336 		os.Setenv("GODEBUG", "gocachehash=1")
   1337 		for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
   1338 			if strings.Contains(out, "STALE "+target) {
   1339 				run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
   1340 				break
   1341 			}
   1342 		}
   1343 		fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out)
   1344 	}
   1345 }
   1346 
   1347 // Cannot use go/build directly because cmd/dist for a new release
   1348 // builds against an old release's go/build, which may be out of sync.
   1349 // To reduce duplication, we generate the list for go/build from this.
   1350 //
   1351 // We list all supported platforms in this list, so that this is the
   1352 // single point of truth for supported platforms. This list is used
   1353 // by 'go tool dist list'.
   1354 var cgoEnabled = map[string]bool{
   1355 	"darwin/386":      true,
   1356 	"darwin/amd64":    true,
   1357 	"darwin/arm":      true,
   1358 	"darwin/arm64":    true,
   1359 	"dragonfly/amd64": true,
   1360 	"freebsd/386":     true,
   1361 	"freebsd/amd64":   true,
   1362 	"freebsd/arm":     false,
   1363 	"linux/386":       true,
   1364 	"linux/amd64":     true,
   1365 	"linux/arm":       true,
   1366 	"linux/arm64":     true,
   1367 	"linux/ppc64":     false,
   1368 	"linux/ppc64le":   true,
   1369 	"linux/mips":      true,
   1370 	"linux/mipsle":    true,
   1371 	"linux/mips64":    true,
   1372 	"linux/mips64le":  true,
   1373 	"linux/s390x":     true,
   1374 	"android/386":     true,
   1375 	"android/amd64":   true,
   1376 	"android/arm":     true,
   1377 	"android/arm64":   true,
   1378 	"nacl/386":        false,
   1379 	"nacl/amd64p32":   false,
   1380 	"nacl/arm":        false,
   1381 	"netbsd/386":      true,
   1382 	"netbsd/amd64":    true,
   1383 	"netbsd/arm":      true,
   1384 	"openbsd/386":     true,
   1385 	"openbsd/amd64":   true,
   1386 	"openbsd/arm":     false,
   1387 	"plan9/386":       false,
   1388 	"plan9/amd64":     false,
   1389 	"plan9/arm":       false,
   1390 	"solaris/amd64":   true,
   1391 	"windows/386":     true,
   1392 	"windows/amd64":   true,
   1393 }
   1394 
   1395 func needCC() bool {
   1396 	switch os.Getenv("CGO_ENABLED") {
   1397 	case "1":
   1398 		return true
   1399 	case "0":
   1400 		return false
   1401 	}
   1402 	return cgoEnabled[gohostos+"/"+gohostarch]
   1403 }
   1404 
   1405 func checkCC() {
   1406 	if !needCC() {
   1407 		return
   1408 	}
   1409 	if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil {
   1410 		outputHdr := ""
   1411 		if len(output) > 0 {
   1412 			outputHdr = "\nCommand output:\n\n"
   1413 		}
   1414 		fatalf("cannot invoke C compiler %q: %v\n\n"+
   1415 			"Go needs a system C compiler for use with cgo.\n"+
   1416 			"To set a C compiler, set CC=the-compiler.\n"+
   1417 			"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
   1418 	}
   1419 }
   1420 
   1421 func defaulttarg() string {
   1422 	// xgetwd might return a path with symlinks fully resolved, and if
   1423 	// there happens to be symlinks in goroot, then the hasprefix test
   1424 	// will never succeed. Instead, we use xrealwd to get a canonical
   1425 	// goroot/src before the comparison to avoid this problem.
   1426 	pwd := xgetwd()
   1427 	src := pathf("%s/src/", goroot)
   1428 	real_src := xrealwd(src)
   1429 	if !strings.HasPrefix(pwd, real_src) {
   1430 		fatalf("current directory %s is not under %s", pwd, real_src)
   1431 	}
   1432 	pwd = pwd[len(real_src):]
   1433 	// guard against xrealwd returning the directory without the trailing /
   1434 	pwd = strings.TrimPrefix(pwd, "/")
   1435 
   1436 	return pwd
   1437 }
   1438 
   1439 // Install installs the list of packages named on the command line.
   1440 func cmdinstall() {
   1441 	xflagparse(-1)
   1442 
   1443 	if flag.NArg() == 0 {
   1444 		install(defaulttarg())
   1445 	}
   1446 
   1447 	for _, arg := range flag.Args() {
   1448 		install(arg)
   1449 	}
   1450 }
   1451 
   1452 // Clean deletes temporary objects.
   1453 func cmdclean() {
   1454 	xflagparse(0)
   1455 	clean()
   1456 }
   1457 
   1458 // Banner prints the 'now you've installed Go' banner.
   1459 func cmdbanner() {
   1460 	xflagparse(0)
   1461 	banner()
   1462 }
   1463 
   1464 func banner() {
   1465 	if vflag > 0 {
   1466 		xprintf("\n")
   1467 	}
   1468 	xprintf("---\n")
   1469 	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
   1470 	xprintf("Installed commands in %s\n", gobin)
   1471 
   1472 	if !xsamefile(goroot_final, goroot) {
   1473 		// If the files are to be moved, don't check that gobin
   1474 		// is on PATH; assume they know what they are doing.
   1475 	} else if gohostos == "plan9" {
   1476 		// Check that gobin is bound before /bin.
   1477 		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
   1478 		ns := fmt.Sprintf("/proc/%s/ns", pid)
   1479 		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
   1480 			xprintf("*** You need to bind %s before /bin.\n", gobin)
   1481 		}
   1482 	} else {
   1483 		// Check that gobin appears in $PATH.
   1484 		pathsep := ":"
   1485 		if gohostos == "windows" {
   1486 			pathsep = ";"
   1487 		}
   1488 		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
   1489 			xprintf("*** You need to add %s to your PATH.\n", gobin)
   1490 		}
   1491 	}
   1492 
   1493 	if !xsamefile(goroot_final, goroot) {
   1494 		xprintf("\n"+
   1495 			"The binaries expect %s to be copied or moved to %s\n",
   1496 			goroot, goroot_final)
   1497 	}
   1498 }
   1499 
   1500 // Version prints the Go version.
   1501 func cmdversion() {
   1502 	xflagparse(0)
   1503 	xprintf("%s\n", findgoversion())
   1504 }
   1505 
   1506 // cmdlist lists all supported platforms.
   1507 func cmdlist() {
   1508 	jsonFlag := flag.Bool("json", false, "produce JSON output")
   1509 	xflagparse(0)
   1510 
   1511 	var plats []string
   1512 	for p := range cgoEnabled {
   1513 		plats = append(plats, p)
   1514 	}
   1515 	sort.Strings(plats)
   1516 
   1517 	if !*jsonFlag {
   1518 		for _, p := range plats {
   1519 			xprintf("%s\n", p)
   1520 		}
   1521 		return
   1522 	}
   1523 
   1524 	type jsonResult struct {
   1525 		GOOS         string
   1526 		GOARCH       string
   1527 		CgoSupported bool
   1528 	}
   1529 	var results []jsonResult
   1530 	for _, p := range plats {
   1531 		fields := strings.Split(p, "/")
   1532 		results = append(results, jsonResult{
   1533 			GOOS:         fields[0],
   1534 			GOARCH:       fields[1],
   1535 			CgoSupported: cgoEnabled[p]})
   1536 	}
   1537 	out, err := json.MarshalIndent(results, "", "\t")
   1538 	if err != nil {
   1539 		fatalf("json marshal error: %v", err)
   1540 	}
   1541 	if _, err := os.Stdout.Write(out); err != nil {
   1542 		fatalf("write failed: %v", err)
   1543 	}
   1544 }
   1545