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