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