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