github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot), 630 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0) 631 } 632 633 // Generate any missing files; regenerate existing ones. 634 for _, p := range files { 635 elem := filepath.Base(p) 636 for _, gt := range gentab { 637 if gt.gen == nil { 638 continue 639 } 640 if strings.HasPrefix(elem, gt.nameprefix) { 641 if vflag > 1 { 642 errprintf("generate %s\n", p) 643 } 644 gt.gen(path, p) 645 // Do not add generated file to clean list. 646 // In runtime, we want to be able to 647 // build the package with the go tool, 648 // and it assumes these generated files already 649 // exist (it does not know how to build them). 650 // The 'clean' command can remove 651 // the generated files. 652 goto built 653 } 654 } 655 // Did not rebuild p. 656 if find(p, missing) >= 0 { 657 fatal("missing file %s", p) 658 } 659 built: 660 } 661 662 if goos != gohostos || goarch != gohostarch { 663 // We've generated the right files; the go command can do the build. 664 if vflag > 1 { 665 errprintf("skip build for cross-compile %s\n", dir) 666 } 667 return 668 } 669 670 var archive string 671 // The next loop will compile individual non-Go files. 672 // Hand the Go files to the compiler en masse. 673 // For package runtime, this writes go_asm.h, which 674 // the assembly files will need. 675 pkg := dir 676 if strings.HasPrefix(dir, "cmd/") { 677 pkg = "main" 678 } 679 b := pathf("%s/_go_.a", workdir) 680 clean = append(clean, b) 681 if !ispackcmd { 682 link = append(link, b) 683 } else { 684 archive = b 685 } 686 compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg} 687 if dir == "runtime" { 688 compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir)) 689 } 690 compile = append(compile, gofiles...) 691 run(path, CheckExit|ShowOutput, compile...) 692 693 // Compile the files. 694 var wg sync.WaitGroup 695 for _, p := range files { 696 if !strings.HasSuffix(p, ".s") { 697 continue 698 } 699 700 var compile []string 701 // Assembly file for a Go package. 702 compile = []string{ 703 pathf("%s/asm", tooldir), 704 "-I", workdir, 705 "-I", pathf("%s/pkg/include", goroot), 706 "-D", "GOOS_" + goos, 707 "-D", "GOARCH_" + goarch, 708 "-D", "GOOS_GOARCH_" + goos + "_" + goarch, 709 } 710 711 doclean := true 712 b := pathf("%s/%s", workdir, filepath.Base(p)) 713 714 // Change the last character of the output file (which was c or s). 715 b = b[:len(b)-1] + "o" 716 compile = append(compile, "-o", b, p) 717 bgrun(&wg, path, compile...) 718 719 link = append(link, b) 720 if doclean { 721 clean = append(clean, b) 722 } 723 } 724 bgwait(&wg) 725 726 if ispackcmd { 727 xremove(link[targ]) 728 dopack(link[targ], archive, link[targ+1:]) 729 return 730 } 731 732 // Remove target before writing it. 733 xremove(link[targ]) 734 run("", CheckExit|ShowOutput, link...) 735 } 736 737 // matchfield reports whether the field (x,y,z) matches this build. 738 // all the elements in the field must be satisfied. 739 func matchfield(f string) bool { 740 for _, tag := range strings.Split(f, ",") { 741 if !matchtag(tag) { 742 return false 743 } 744 } 745 return true 746 } 747 748 // matchtag reports whether the tag (x or !x) matches this build. 749 func matchtag(tag string) bool { 750 if tag == "" { 751 return false 752 } 753 if tag[0] == '!' { 754 if len(tag) == 1 || tag[1] == '!' { 755 return false 756 } 757 return !matchtag(tag[1:]) 758 } 759 return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") 760 } 761 762 // shouldbuild reports whether we should build this file. 763 // It applies the same rules that are used with context tags 764 // in package go/build, except that the GOOS and GOARCH 765 // can appear anywhere in the file name, not just after _. 766 // In particular, they can be the entire file name (like windows.c). 767 // We also allow the special tag cmd_go_bootstrap. 768 // See ../go/bootstrap.go and package go/build. 769 func shouldbuild(file, dir string) bool { 770 // Check file name for GOOS or GOARCH. 771 name := filepath.Base(file) 772 excluded := func(list []string, ok string) bool { 773 for _, x := range list { 774 if x == ok { 775 continue 776 } 777 i := strings.Index(name, x) 778 if i < 0 { 779 continue 780 } 781 i += len(x) 782 if i == len(name) || name[i] == '.' || name[i] == '_' { 783 return true 784 } 785 } 786 return false 787 } 788 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 789 return false 790 } 791 792 // Omit test files. 793 if strings.Contains(name, "_test") { 794 return false 795 } 796 797 // Check file contents for // +build lines. 798 for _, p := range splitlines(readfile(file)) { 799 p = strings.TrimSpace(p) 800 if p == "" { 801 continue 802 } 803 if strings.Contains(p, "package documentation") { 804 return false 805 } 806 if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" { 807 return false 808 } 809 if !strings.HasPrefix(p, "//") { 810 break 811 } 812 if !strings.Contains(p, "+build") { 813 continue 814 } 815 fields := splitfields(p) 816 if len(fields) < 2 || fields[1] != "+build" { 817 continue 818 } 819 for _, p := range fields[2:] { 820 if matchfield(p) { 821 goto fieldmatch 822 } 823 } 824 return false 825 fieldmatch: 826 } 827 828 return true 829 } 830 831 // copy copies the file src to dst, via memory (so only good for small files). 832 func copyfile(dst, src string, flag int) { 833 if vflag > 1 { 834 errprintf("cp %s %s\n", src, dst) 835 } 836 writefile(readfile(src), dst, flag) 837 } 838 839 // dopack copies the package src to dst, 840 // appending the files listed in extra. 841 // The archive format is the traditional Unix ar format. 842 func dopack(dst, src string, extra []string) { 843 bdst := bytes.NewBufferString(readfile(src)) 844 for _, file := range extra { 845 b := readfile(file) 846 // find last path element for archive member name 847 i := strings.LastIndex(file, "/") + 1 848 j := strings.LastIndex(file, `\`) + 1 849 if i < j { 850 i = j 851 } 852 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 853 bdst.WriteString(b) 854 if len(b)&1 != 0 { 855 bdst.WriteByte(0) 856 } 857 } 858 writefile(bdst.String(), dst, 0) 859 } 860 861 // builddeps records the build dependencies for the 'go bootstrap' command. 862 // It is a map[string][]string and generated by mkdeps.bash into deps.go. 863 864 // buildlist is the list of directories being built, sorted by name. 865 var buildlist = makeBuildlist() 866 867 func makeBuildlist() []string { 868 var all []string 869 for dir := range builddeps { 870 all = append(all, dir) 871 } 872 sort.Strings(all) 873 return all 874 } 875 876 var runtimegen = []string{ 877 "zaexperiment.h", 878 "zversion.go", 879 } 880 881 func clean() { 882 for _, name := range buildlist { 883 path := pathf("%s/src/%s", goroot, name) 884 // Remove generated files. 885 for _, elem := range xreaddir(path) { 886 for _, gt := range gentab { 887 if strings.HasPrefix(elem, gt.nameprefix) { 888 xremove(pathf("%s/%s", path, elem)) 889 } 890 } 891 } 892 // Remove generated binary named for directory. 893 if strings.HasPrefix(name, "cmd/") { 894 xremove(pathf("%s/%s", path, name[4:])) 895 } 896 } 897 898 // remove runtimegen files. 899 path := pathf("%s/src/runtime", goroot) 900 for _, elem := range runtimegen { 901 xremove(pathf("%s/%s", path, elem)) 902 } 903 904 if rebuildall { 905 // Remove object tree. 906 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)) 907 908 // Remove installed packages and tools. 909 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)) 910 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch)) 911 xremoveall(tooldir) 912 913 // Remove cached version info. 914 xremove(pathf("%s/VERSION.cache", goroot)) 915 } 916 } 917 918 /* 919 * command implementations 920 */ 921 922 func usage() { 923 xprintf("usage: go tool dist [command]\n" + 924 "Commands are:\n" + 925 "\n" + 926 "banner print installation banner\n" + 927 "bootstrap rebuild everything\n" + 928 "clean deletes all built files\n" + 929 "env [-p] print environment (-p: include $PATH)\n" + 930 "install [dir] install individual directory\n" + 931 "test [-h] run Go test(s)\n" + 932 "version print Go version\n" + 933 "\n" + 934 "All commands take -v flags to emit extra information.\n", 935 ) 936 xexit(2) 937 } 938 939 // The env command prints the default environment. 940 func cmdenv() { 941 path := flag.Bool("p", false, "emit updated PATH") 942 plan9 := flag.Bool("9", false, "emit plan 9 syntax") 943 windows := flag.Bool("w", false, "emit windows syntax") 944 xflagparse(0) 945 946 format := "%s=\"%s\"\n" 947 switch { 948 case *plan9: 949 format = "%s='%s'\n" 950 case *windows: 951 format = "set %s=%s\r\n" 952 } 953 954 xprintf(format, "CC", defaultcc) 955 xprintf(format, "CC_FOR_TARGET", defaultcctarget) 956 xprintf(format, "GOROOT", goroot) 957 xprintf(format, "GOBIN", gobin) 958 xprintf(format, "GOARCH", goarch) 959 xprintf(format, "GOOS", goos) 960 xprintf(format, "GOHOSTARCH", gohostarch) 961 xprintf(format, "GOHOSTOS", gohostos) 962 xprintf(format, "GOTOOLDIR", tooldir) 963 if goarch == "arm" { 964 xprintf(format, "GOARM", goarm) 965 } 966 if goarch == "386" { 967 xprintf(format, "GO386", go386) 968 } 969 970 if *path { 971 sep := ":" 972 if gohostos == "windows" { 973 sep = ";" 974 } 975 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH"))) 976 } 977 } 978 979 // The bootstrap command runs a build from scratch, 980 // stopping at having installed the go_bootstrap command. 981 func cmdbootstrap() { 982 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 983 flag.BoolVar(&sflag, "s", sflag, "build static binaries") 984 xflagparse(0) 985 986 if isdir(pathf("%s/src/pkg", goroot)) { 987 fatal("\n\n"+ 988 "The Go package sources have moved to $GOROOT/src.\n"+ 989 "*** %s still exists. ***\n"+ 990 "It probably contains stale files that may confuse the build.\n"+ 991 "Please (check what's there and) remove it and try again.\n"+ 992 "See https://golang.org/s/go14nopkg\n", 993 pathf("%s/src/pkg", goroot)) 994 } 995 996 if rebuildall { 997 clean() 998 } 999 1000 setup() 1001 1002 checkCC() 1003 bootstrapBuildTools() 1004 1005 // For the main bootstrap, building for host os/arch. 1006 oldgoos = goos 1007 oldgoarch = goarch 1008 goos = gohostos 1009 goarch = gohostarch 1010 os.Setenv("GOHOSTARCH", gohostarch) 1011 os.Setenv("GOHOSTOS", gohostos) 1012 os.Setenv("GOARCH", goarch) 1013 os.Setenv("GOOS", goos) 1014 1015 // TODO(rsc): Enable when appropriate. 1016 // This step is only needed if we believe that the Go compiler built from Go 1.4 1017 // will produce different object files than the Go compiler built from itself. 1018 // In the absence of bugs, that should not happen. 1019 // And if there are bugs, they're more likely in the current development tree 1020 // than in a standard release like Go 1.4, so don't do this rebuild by default. 1021 if false { 1022 xprintf("##### Building Go toolchain using itself.\n") 1023 for _, dir := range buildlist { 1024 installed[dir] = make(chan struct{}) 1025 } 1026 var wg sync.WaitGroup 1027 for _, dir := range builddeps["cmd/go"] { 1028 wg.Add(1) 1029 dir := dir 1030 go func() { 1031 defer wg.Done() 1032 install(dir) 1033 }() 1034 } 1035 wg.Wait() 1036 xprintf("\n") 1037 } 1038 1039 xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch) 1040 for _, dir := range buildlist { 1041 installed[dir] = make(chan struct{}) 1042 } 1043 for _, dir := range buildlist { 1044 go install(dir) 1045 } 1046 <-installed["cmd/go"] 1047 1048 goos = oldgoos 1049 goarch = oldgoarch 1050 os.Setenv("GOARCH", goarch) 1051 os.Setenv("GOOS", goos) 1052 1053 // Build runtime for actual goos/goarch too. 1054 if goos != gohostos || goarch != gohostarch { 1055 installed["runtime"] = make(chan struct{}) 1056 install("runtime") 1057 } 1058 } 1059 1060 // Copied from go/build/build.go. 1061 // Cannot use go/build directly because cmd/dist for a new release 1062 // builds against an old release's go/build, which may be out of sync. 1063 var cgoEnabled = map[string]bool{ 1064 "darwin/386": true, 1065 "darwin/amd64": true, 1066 "darwin/arm": true, 1067 "darwin/arm64": true, 1068 "dragonfly/amd64": true, 1069 "freebsd/386": true, 1070 "freebsd/amd64": true, 1071 "linux/386": true, 1072 "linux/amd64": true, 1073 "linux/arm": true, 1074 "linux/arm64": true, 1075 "linux/ppc64le": true, 1076 "android/386": true, 1077 "android/amd64": true, 1078 "android/arm": true, 1079 "netbsd/386": true, 1080 "netbsd/amd64": true, 1081 "netbsd/arm": true, 1082 "openbsd/386": true, 1083 "openbsd/amd64": true, 1084 "solaris/amd64": true, 1085 "windows/386": true, 1086 "windows/amd64": true, 1087 } 1088 1089 func needCC() bool { 1090 switch os.Getenv("CGO_ENABLED") { 1091 case "1": 1092 return true 1093 case "0": 1094 return false 1095 } 1096 return cgoEnabled[gohostos+"/"+gohostarch] 1097 } 1098 1099 func checkCC() { 1100 if !needCC() { 1101 return 1102 } 1103 if _, err := exec.Command(defaultcc, "--help").Output(); err != nil { 1104 fatal("cannot invoke C compiler %q: %v\n\n"+ 1105 "Go needs a system C compiler for use with cgo.\n"+ 1106 "To set a C compiler, export CC=the-compiler.\n"+ 1107 "To disable cgo, export CGO_ENABLED=0.\n", defaultcc, err) 1108 } 1109 } 1110 1111 func defaulttarg() string { 1112 // xgetwd might return a path with symlinks fully resolved, and if 1113 // there happens to be symlinks in goroot, then the hasprefix test 1114 // will never succeed. Instead, we use xrealwd to get a canonical 1115 // goroot/src before the comparison to avoid this problem. 1116 pwd := xgetwd() 1117 src := pathf("%s/src/", goroot) 1118 real_src := xrealwd(src) 1119 if !strings.HasPrefix(pwd, real_src) { 1120 fatal("current directory %s is not under %s", pwd, real_src) 1121 } 1122 pwd = pwd[len(real_src):] 1123 // guard againt xrealwd return the directory without the trailing / 1124 pwd = strings.TrimPrefix(pwd, "/") 1125 1126 return pwd 1127 } 1128 1129 // Install installs the list of packages named on the command line. 1130 func cmdinstall() { 1131 flag.BoolVar(&sflag, "s", sflag, "build static binaries") 1132 xflagparse(-1) 1133 1134 if flag.NArg() == 0 { 1135 install(defaulttarg()) 1136 } 1137 1138 for _, arg := range flag.Args() { 1139 install(arg) 1140 } 1141 } 1142 1143 // Clean deletes temporary objects. 1144 func cmdclean() { 1145 xflagparse(0) 1146 clean() 1147 } 1148 1149 // Banner prints the 'now you've installed Go' banner. 1150 func cmdbanner() { 1151 xflagparse(0) 1152 1153 xprintf("\n") 1154 xprintf("---\n") 1155 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1156 xprintf("Installed commands in %s\n", gobin) 1157 1158 if !xsamefile(goroot_final, goroot) { 1159 // If the files are to be moved, don't check that gobin 1160 // is on PATH; assume they know what they are doing. 1161 } else if gohostos == "plan9" { 1162 // Check that gobin is bound before /bin. 1163 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1164 ns := fmt.Sprintf("/proc/%s/ns", pid) 1165 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) { 1166 xprintf("*** You need to bind %s before /bin.\n", gobin) 1167 } 1168 } else { 1169 // Check that gobin appears in $PATH. 1170 pathsep := ":" 1171 if gohostos == "windows" { 1172 pathsep = ";" 1173 } 1174 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) { 1175 xprintf("*** You need to add %s to your PATH.\n", gobin) 1176 } 1177 } 1178 1179 if !xsamefile(goroot_final, goroot) { 1180 xprintf("\n"+ 1181 "The binaries expect %s to be copied or moved to %s\n", 1182 goroot, goroot_final) 1183 } 1184 } 1185 1186 // Version prints the Go version. 1187 func cmdversion() { 1188 xflagparse(0) 1189 xprintf("%s\n", findgoversion()) 1190 }