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