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