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