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