github.com/aloncn/graphics-go@v0.0.1/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 // NB: simply checking the exit code of `git rev-parse --git-dir` would 326 // suffice here, but that requires deviating from the infrastructure 327 // provided by `run`. 328 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir")) 329 if !filepath.IsAbs(gitDir) { 330 gitDir = filepath.Join(goroot, gitDir) 331 } 332 fi, err := os.Stat(gitDir) 333 return err == nil && fi.IsDir() 334 } 335 336 /* 337 * Initial tree setup. 338 */ 339 340 // The old tools that no longer live in $GOBIN or $GOROOT/bin. 341 var oldtool = []string{ 342 "5a", "5c", "5g", "5l", 343 "6a", "6c", "6g", "6l", 344 "8a", "8c", "8g", "8l", 345 "9a", "9c", "9g", "9l", 346 "6cov", 347 "6nm", 348 "6prof", 349 "cgo", 350 "ebnflint", 351 "goapi", 352 "gofix", 353 "goinstall", 354 "gomake", 355 "gopack", 356 "gopprof", 357 "gotest", 358 "gotype", 359 "govet", 360 "goyacc", 361 "quietgcc", 362 } 363 364 // Unreleased directories (relative to $GOROOT) that should 365 // not be in release branches. 366 var unreleased = []string{ 367 "src/cmd/newlink", 368 "src/cmd/objwriter", 369 "src/debug/goobj", 370 "src/old", 371 } 372 373 // setup sets up the tree for the initial build. 374 func setup() { 375 // Create bin directory. 376 if p := pathf("%s/bin", goroot); !isdir(p) { 377 xmkdir(p) 378 } 379 380 // Create package directory. 381 if p := pathf("%s/pkg", goroot); !isdir(p) { 382 xmkdir(p) 383 } 384 385 p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch) 386 if rebuildall { 387 xremoveall(p) 388 } 389 xmkdirall(p) 390 391 if goos != gohostos || goarch != gohostarch { 392 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch) 393 if rebuildall { 394 xremoveall(p) 395 } 396 xmkdirall(p) 397 } 398 399 // Create object directory. 400 // We keep it in pkg/ so that all the generated binaries 401 // are in one tree. If pkg/obj/libgc.a exists, it is a dreg from 402 // before we used subdirectories of obj. Delete all of obj 403 // to clean up. 404 if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) { 405 xremoveall(pathf("%s/pkg/obj", goroot)) 406 } 407 p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch) 408 if rebuildall { 409 xremoveall(p) 410 } 411 xmkdirall(p) 412 413 // Create tool directory. 414 // We keep it in pkg/, just like the object directory above. 415 if rebuildall { 416 xremoveall(tooldir) 417 } 418 xmkdirall(tooldir) 419 420 // Remove tool binaries from before the tool/gohostos_gohostarch 421 xremoveall(pathf("%s/bin/tool", goroot)) 422 423 // Remove old pre-tool binaries. 424 for _, old := range oldtool { 425 xremove(pathf("%s/bin/%s", goroot, old)) 426 } 427 428 // If $GOBIN is set and has a Go compiler, it must be cleaned. 429 for _, char := range "56789" { 430 if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) { 431 for _, old := range oldtool { 432 xremove(pathf("%s/%s", gobin, old)) 433 } 434 break 435 } 436 } 437 438 // For release, make sure excluded things are excluded. 439 goversion := findgoversion() 440 if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) { 441 for _, dir := range unreleased { 442 if p := pathf("%s/%s", goroot, dir); isdir(p) { 443 fatal("%s should not exist in release build", p) 444 } 445 } 446 } 447 } 448 449 /* 450 * Tool building 451 */ 452 453 // deptab lists changes to the default dependencies for a given prefix. 454 // deps ending in /* read the whole directory; deps beginning with - 455 // exclude files with that prefix. 456 var deptab = []struct { 457 prefix string // prefix of target 458 dep []string // dependency tweaks for targets with that prefix 459 }{ 460 {"cmd/go", []string{ 461 "zdefaultcc.go", 462 }}, 463 {"runtime/internal/sys", []string{ 464 "zversion.go", 465 }}, 466 } 467 468 // depsuffix records the allowed suffixes for source files. 469 var depsuffix = []string{ 470 ".s", 471 ".go", 472 } 473 474 // gentab records how to generate some trivial files. 475 var gentab = []struct { 476 nameprefix string 477 gen func(string, string) 478 }{ 479 {"zdefaultcc.go", mkzdefaultcc}, 480 {"zversion.go", mkzversion}, 481 482 // not generated anymore, but delete the file if we see it 483 {"enam.c", nil}, 484 {"anames5.c", nil}, 485 {"anames6.c", nil}, 486 {"anames8.c", nil}, 487 {"anames9.c", nil}, 488 } 489 490 // installed maps from a dir name (as given to install) to a chan 491 // closed when the dir's package is installed. 492 var installed = make(map[string]chan struct{}) 493 494 // install installs the library, package, or binary associated with dir, 495 // which is relative to $GOROOT/src. 496 func install(dir string) { 497 if ch, ok := installed[dir]; ok { 498 defer close(ch) 499 } 500 for _, dep := range builddeps[dir] { 501 <-installed[dep] 502 } 503 504 if vflag > 0 { 505 if goos != gohostos || goarch != gohostarch { 506 errprintf("%s (%s/%s)\n", dir, goos, goarch) 507 } else { 508 errprintf("%s\n", dir) 509 } 510 } 511 512 workdir := pathf("%s/%s", workdir, dir) 513 xmkdirall(workdir) 514 515 var clean []string 516 defer func() { 517 for _, name := range clean { 518 xremove(name) 519 } 520 }() 521 522 // path = full path to dir. 523 path := pathf("%s/src/%s", goroot, dir) 524 name := filepath.Base(dir) 525 526 ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/") 527 528 // Start final link command line. 529 // Note: code below knows that link.p[targ] is the target. 530 var ( 531 link []string 532 targ int 533 ispackcmd bool 534 ) 535 if ispkg { 536 // Go library (package). 537 ispackcmd = true 538 link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)} 539 targ = len(link) - 1 540 xmkdirall(filepath.Dir(link[targ])) 541 } else { 542 // Go command. 543 elem := name 544 if elem == "go" { 545 elem = "go_bootstrap" 546 } 547 link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)} 548 targ = len(link) - 1 549 } 550 ttarg := mtime(link[targ]) 551 552 // Gather files that are sources for this target. 553 // Everything in that directory, and any target-specific 554 // additions. 555 files := xreaddir(path) 556 557 // Remove files beginning with . or _, 558 // which are likely to be editor temporary files. 559 // This is the same heuristic build.ScanDir uses. 560 // There do exist real C files beginning with _, 561 // so limit that check to just Go files. 562 files = filter(files, func(p string) bool { 563 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go")) 564 }) 565 566 for _, dt := range deptab { 567 if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) { 568 for _, p := range dt.dep { 569 p = os.ExpandEnv(p) 570 files = append(files, p) 571 } 572 } 573 } 574 files = uniq(files) 575 576 // Convert to absolute paths. 577 for i, p := range files { 578 if !isabs(p) { 579 files[i] = pathf("%s/%s", path, p) 580 } 581 } 582 583 // Is the target up-to-date? 584 var gofiles, missing []string 585 stale := rebuildall 586 files = filter(files, func(p string) bool { 587 for _, suf := range depsuffix { 588 if strings.HasSuffix(p, suf) { 589 goto ok 590 } 591 } 592 return false 593 ok: 594 t := mtime(p) 595 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) { 596 return false 597 } 598 if strings.HasSuffix(p, ".go") { 599 gofiles = append(gofiles, p) 600 } 601 if t.After(ttarg) { 602 stale = true 603 } 604 if t.IsZero() { 605 missing = append(missing, p) 606 } 607 return true 608 }) 609 610 // If there are no files to compile, we're done. 611 if len(files) == 0 { 612 return 613 } 614 615 if !stale { 616 return 617 } 618 619 // For package runtime, copy some files into the work space. 620 if dir == "runtime" || strings.HasPrefix(dir, "runtime/internal/") { 621 xmkdirall(pathf("%s/pkg/include", goroot)) 622 // For use by assembly and C files. 623 copyfile(pathf("%s/pkg/include/textflag.h", goroot), 624 pathf("%s/src/runtime/textflag.h", goroot), 0) 625 copyfile(pathf("%s/pkg/include/funcdata.h", goroot), 626 pathf("%s/src/runtime/funcdata.h", goroot), 0) 627 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot), 628 pathf("%s/src/runtime/asm_ppc64x.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(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch)) 910 xremoveall(pathf("%s/pkg/%s_%s_race", 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 xflagparse(0) 984 985 if isdir(pathf("%s/src/pkg", goroot)) { 986 fatal("\n\n"+ 987 "The Go package sources have moved to $GOROOT/src.\n"+ 988 "*** %s still exists. ***\n"+ 989 "It probably contains stale files that may confuse the build.\n"+ 990 "Please (check what's there and) remove it and try again.\n"+ 991 "See https://golang.org/s/go14nopkg\n", 992 pathf("%s/src/pkg", goroot)) 993 } 994 995 if rebuildall { 996 clean() 997 } 998 999 setup() 1000 1001 checkCC() 1002 bootstrapBuildTools() 1003 1004 // For the main bootstrap, building for host os/arch. 1005 oldgoos = goos 1006 oldgoarch = goarch 1007 goos = gohostos 1008 goarch = gohostarch 1009 os.Setenv("GOHOSTARCH", gohostarch) 1010 os.Setenv("GOHOSTOS", gohostos) 1011 os.Setenv("GOARCH", goarch) 1012 os.Setenv("GOOS", goos) 1013 1014 // TODO(rsc): Enable when appropriate. 1015 // This step is only needed if we believe that the Go compiler built from Go 1.4 1016 // will produce different object files than the Go compiler built from itself. 1017 // In the absence of bugs, that should not happen. 1018 // And if there are bugs, they're more likely in the current development tree 1019 // than in a standard release like Go 1.4, so don't do this rebuild by default. 1020 if false { 1021 xprintf("##### Building Go toolchain using itself.\n") 1022 for _, dir := range buildlist { 1023 installed[dir] = make(chan struct{}) 1024 } 1025 var wg sync.WaitGroup 1026 for _, dir := range builddeps["cmd/go"] { 1027 wg.Add(1) 1028 dir := dir 1029 go func() { 1030 defer wg.Done() 1031 install(dir) 1032 }() 1033 } 1034 wg.Wait() 1035 xprintf("\n") 1036 } 1037 1038 xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch) 1039 for _, dir := range buildlist { 1040 installed[dir] = make(chan struct{}) 1041 } 1042 for _, dir := range buildlist { 1043 go install(dir) 1044 } 1045 <-installed["cmd/go"] 1046 1047 goos = oldgoos 1048 goarch = oldgoarch 1049 os.Setenv("GOARCH", goarch) 1050 os.Setenv("GOOS", goos) 1051 1052 // Build runtime for actual goos/goarch too. 1053 if goos != gohostos || goarch != gohostarch { 1054 installed["runtime"] = make(chan struct{}) 1055 install("runtime") 1056 } 1057 } 1058 1059 // Copied from go/build/build.go. 1060 // Cannot use go/build directly because cmd/dist for a new release 1061 // builds against an old release's go/build, which may be out of sync. 1062 var cgoEnabled = map[string]bool{ 1063 "darwin/386": true, 1064 "darwin/amd64": true, 1065 "darwin/arm": true, 1066 "darwin/arm64": true, 1067 "dragonfly/amd64": true, 1068 "freebsd/386": true, 1069 "freebsd/amd64": true, 1070 "linux/386": true, 1071 "linux/amd64": true, 1072 "linux/arm": true, 1073 "linux/arm64": true, 1074 "linux/ppc64le": true, 1075 "android/386": true, 1076 "android/amd64": true, 1077 "android/arm": true, 1078 "netbsd/386": true, 1079 "netbsd/amd64": true, 1080 "netbsd/arm": true, 1081 "openbsd/386": true, 1082 "openbsd/amd64": true, 1083 "solaris/amd64": true, 1084 "windows/386": true, 1085 "windows/amd64": true, 1086 } 1087 1088 func needCC() bool { 1089 switch os.Getenv("CGO_ENABLED") { 1090 case "1": 1091 return true 1092 case "0": 1093 return false 1094 } 1095 return cgoEnabled[gohostos+"/"+gohostarch] 1096 } 1097 1098 func checkCC() { 1099 if !needCC() { 1100 return 1101 } 1102 if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil { 1103 outputHdr := "" 1104 if len(output) > 0 { 1105 outputHdr = "\nCommand output:\n\n" 1106 } 1107 fatal("cannot invoke C compiler %q: %v\n\n"+ 1108 "Go needs a system C compiler for use with cgo.\n"+ 1109 "To set a C compiler, export CC=the-compiler.\n"+ 1110 "To disable cgo, export CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) 1111 } 1112 } 1113 1114 func defaulttarg() string { 1115 // xgetwd might return a path with symlinks fully resolved, and if 1116 // there happens to be symlinks in goroot, then the hasprefix test 1117 // will never succeed. Instead, we use xrealwd to get a canonical 1118 // goroot/src before the comparison to avoid this problem. 1119 pwd := xgetwd() 1120 src := pathf("%s/src/", goroot) 1121 real_src := xrealwd(src) 1122 if !strings.HasPrefix(pwd, real_src) { 1123 fatal("current directory %s is not under %s", pwd, real_src) 1124 } 1125 pwd = pwd[len(real_src):] 1126 // guard againt xrealwd return the directory without the trailing / 1127 pwd = strings.TrimPrefix(pwd, "/") 1128 1129 return pwd 1130 } 1131 1132 // Install installs the list of packages named on the command line. 1133 func cmdinstall() { 1134 xflagparse(-1) 1135 1136 if flag.NArg() == 0 { 1137 install(defaulttarg()) 1138 } 1139 1140 for _, arg := range flag.Args() { 1141 install(arg) 1142 } 1143 } 1144 1145 // Clean deletes temporary objects. 1146 func cmdclean() { 1147 xflagparse(0) 1148 clean() 1149 } 1150 1151 // Banner prints the 'now you've installed Go' banner. 1152 func cmdbanner() { 1153 xflagparse(0) 1154 1155 xprintf("\n") 1156 xprintf("---\n") 1157 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1158 xprintf("Installed commands in %s\n", gobin) 1159 1160 if !xsamefile(goroot_final, goroot) { 1161 // If the files are to be moved, don't check that gobin 1162 // is on PATH; assume they know what they are doing. 1163 } else if gohostos == "plan9" { 1164 // Check that gobin is bound before /bin. 1165 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1166 ns := fmt.Sprintf("/proc/%s/ns", pid) 1167 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) { 1168 xprintf("*** You need to bind %s before /bin.\n", gobin) 1169 } 1170 } else { 1171 // Check that gobin appears in $PATH. 1172 pathsep := ":" 1173 if gohostos == "windows" { 1174 pathsep = ";" 1175 } 1176 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) { 1177 xprintf("*** You need to add %s to your PATH.\n", gobin) 1178 } 1179 } 1180 1181 if !xsamefile(goroot_final, goroot) { 1182 xprintf("\n"+ 1183 "The binaries expect %s to be copied or moved to %s\n", 1184 goroot, goroot_final) 1185 } 1186 } 1187 1188 // Version prints the Go version. 1189 func cmdversion() { 1190 xflagparse(0) 1191 xprintf("%s\n", findgoversion()) 1192 }