github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/cmd/dist/build.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "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 }