github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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/internal/cfg", []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.Contains(dir, "/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), "-std", "-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 it's less picky about the order 786 // of GOOS and GOARCH. 787 // We also allow the special tag cmd_go_bootstrap. 788 // See ../go/bootstrap.go and package go/build. 789 func shouldbuild(file, dir string) bool { 790 // Check file name for GOOS or GOARCH. 791 name := filepath.Base(file) 792 excluded := func(list []string, ok string) bool { 793 for _, x := range list { 794 if x == ok || ok == "android" && x == "linux" { 795 continue 796 } 797 i := strings.Index(name, x) 798 if i <= 0 || name[i-1] != '_' { 799 continue 800 } 801 i += len(x) 802 if i == len(name) || name[i] == '.' || name[i] == '_' { 803 return true 804 } 805 } 806 return false 807 } 808 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 809 return false 810 } 811 812 // Omit test files. 813 if strings.Contains(name, "_test") { 814 return false 815 } 816 817 // Check file contents for // +build lines. 818 for _, p := range splitlines(readfile(file)) { 819 p = strings.TrimSpace(p) 820 if p == "" { 821 continue 822 } 823 code := p 824 i := strings.Index(code, "//") 825 if i > 0 { 826 code = strings.TrimSpace(code[:i]) 827 } 828 if code == "package documentation" { 829 return false 830 } 831 if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" { 832 return false 833 } 834 if !strings.HasPrefix(p, "//") { 835 break 836 } 837 if !strings.Contains(p, "+build") { 838 continue 839 } 840 fields := splitfields(p[2:]) 841 if len(fields) < 1 || fields[0] != "+build" { 842 continue 843 } 844 for _, p := range fields[1:] { 845 if matchfield(p) { 846 goto fieldmatch 847 } 848 } 849 return false 850 fieldmatch: 851 } 852 853 return true 854 } 855 856 // copy copies the file src to dst, via memory (so only good for small files). 857 func copyfile(dst, src string, flag int) { 858 if vflag > 1 { 859 errprintf("cp %s %s\n", src, dst) 860 } 861 writefile(readfile(src), dst, flag) 862 } 863 864 // dopack copies the package src to dst, 865 // appending the files listed in extra. 866 // The archive format is the traditional Unix ar format. 867 func dopack(dst, src string, extra []string) { 868 bdst := bytes.NewBufferString(readfile(src)) 869 for _, file := range extra { 870 b := readfile(file) 871 // find last path element for archive member name 872 i := strings.LastIndex(file, "/") + 1 873 j := strings.LastIndex(file, `\`) + 1 874 if i < j { 875 i = j 876 } 877 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 878 bdst.WriteString(b) 879 if len(b)&1 != 0 { 880 bdst.WriteByte(0) 881 } 882 } 883 writefile(bdst.String(), dst, 0) 884 } 885 886 // builddeps records the build dependencies for the 'go bootstrap' command. 887 // It is a map[string][]string and generated by mkdeps.bash into deps.go. 888 889 // buildlist is the list of directories being built, sorted by name. 890 var buildlist = makeBuildlist() 891 892 func makeBuildlist() []string { 893 var all []string 894 for dir := range builddeps { 895 all = append(all, dir) 896 } 897 sort.Strings(all) 898 return all 899 } 900 901 var runtimegen = []string{ 902 "zaexperiment.h", 903 "zversion.go", 904 } 905 906 func clean() { 907 for _, name := range buildlist { 908 path := pathf("%s/src/%s", goroot, name) 909 // Remove generated files. 910 for _, elem := range xreaddir(path) { 911 for _, gt := range gentab { 912 if strings.HasPrefix(elem, gt.nameprefix) { 913 xremove(pathf("%s/%s", path, elem)) 914 } 915 } 916 } 917 // Remove generated binary named for directory. 918 if strings.HasPrefix(name, "cmd/") { 919 xremove(pathf("%s/%s", path, name[4:])) 920 } 921 } 922 923 // remove runtimegen files. 924 path := pathf("%s/src/runtime", goroot) 925 for _, elem := range runtimegen { 926 xremove(pathf("%s/%s", path, elem)) 927 } 928 929 if rebuildall { 930 // Remove object tree. 931 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)) 932 933 // Remove installed packages and tools. 934 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)) 935 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch)) 936 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch)) 937 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch)) 938 xremoveall(tooldir) 939 940 // Remove cached version info. 941 xremove(pathf("%s/VERSION.cache", goroot)) 942 } 943 } 944 945 /* 946 * command implementations 947 */ 948 949 func usage() { 950 xprintf("usage: go tool dist [command]\n" + 951 "Commands are:\n" + 952 "\n" + 953 "banner print installation banner\n" + 954 "bootstrap rebuild everything\n" + 955 "clean deletes all built files\n" + 956 "env [-p] print environment (-p: include $PATH)\n" + 957 "install [dir] install individual directory\n" + 958 "list [-json] list all supported platforms\n" + 959 "test [-h] run Go test(s)\n" + 960 "version print Go version\n" + 961 "\n" + 962 "All commands take -v flags to emit extra information.\n", 963 ) 964 xexit(2) 965 } 966 967 // The env command prints the default environment. 968 func cmdenv() { 969 path := flag.Bool("p", false, "emit updated PATH") 970 plan9 := flag.Bool("9", false, "emit plan 9 syntax") 971 windows := flag.Bool("w", false, "emit windows syntax") 972 xflagparse(0) 973 974 format := "%s=\"%s\"\n" 975 switch { 976 case *plan9: 977 format = "%s='%s'\n" 978 case *windows: 979 format = "set %s=%s\r\n" 980 } 981 982 xprintf(format, "CC", defaultcc) 983 xprintf(format, "CC_FOR_TARGET", defaultcctarget) 984 xprintf(format, "GOROOT", goroot) 985 xprintf(format, "GOBIN", gobin) 986 xprintf(format, "GOARCH", goarch) 987 xprintf(format, "GOOS", goos) 988 xprintf(format, "GOHOSTARCH", gohostarch) 989 xprintf(format, "GOHOSTOS", gohostos) 990 xprintf(format, "GOTOOLDIR", tooldir) 991 if goarch == "arm" { 992 xprintf(format, "GOARM", goarm) 993 } 994 if goarch == "386" { 995 xprintf(format, "GO386", go386) 996 } 997 998 if *path { 999 sep := ":" 1000 if gohostos == "windows" { 1001 sep = ";" 1002 } 1003 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH"))) 1004 } 1005 } 1006 1007 // The bootstrap command runs a build from scratch, 1008 // stopping at having installed the go_bootstrap command. 1009 func cmdbootstrap() { 1010 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 1011 xflagparse(0) 1012 1013 if isdir(pathf("%s/src/pkg", goroot)) { 1014 fatal("\n\n"+ 1015 "The Go package sources have moved to $GOROOT/src.\n"+ 1016 "*** %s still exists. ***\n"+ 1017 "It probably contains stale files that may confuse the build.\n"+ 1018 "Please (check what's there and) remove it and try again.\n"+ 1019 "See https://golang.org/s/go14nopkg\n", 1020 pathf("%s/src/pkg", goroot)) 1021 } 1022 1023 if rebuildall { 1024 clean() 1025 } 1026 1027 setup() 1028 1029 checkCC() 1030 bootstrapBuildTools() 1031 1032 // For the main bootstrap, building for host os/arch. 1033 oldgoos = goos 1034 oldgoarch = goarch 1035 goos = gohostos 1036 goarch = gohostarch 1037 os.Setenv("GOHOSTARCH", gohostarch) 1038 os.Setenv("GOHOSTOS", gohostos) 1039 os.Setenv("GOARCH", goarch) 1040 os.Setenv("GOOS", goos) 1041 1042 // TODO(rsc): Enable when appropriate. 1043 // This step is only needed if we believe that the Go compiler built from Go 1.4 1044 // will produce different object files than the Go compiler built from itself. 1045 // In the absence of bugs, that should not happen. 1046 // And if there are bugs, they're more likely in the current development tree 1047 // than in a standard release like Go 1.4, so don't do this rebuild by default. 1048 if false { 1049 xprintf("##### Building Go toolchain using itself.\n") 1050 for _, dir := range buildlist { 1051 installed[dir] = make(chan struct{}) 1052 } 1053 var wg sync.WaitGroup 1054 for _, dir := range builddeps["cmd/go"] { 1055 wg.Add(1) 1056 dir := dir 1057 go func() { 1058 defer wg.Done() 1059 install(dir) 1060 }() 1061 } 1062 wg.Wait() 1063 xprintf("\n") 1064 } 1065 1066 xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch) 1067 for _, dir := range buildlist { 1068 installed[dir] = make(chan struct{}) 1069 } 1070 for _, dir := range buildlist { 1071 go install(dir) 1072 } 1073 <-installed["cmd/go"] 1074 1075 goos = oldgoos 1076 goarch = oldgoarch 1077 os.Setenv("GOARCH", goarch) 1078 os.Setenv("GOOS", goos) 1079 1080 // Build runtime for actual goos/goarch too. 1081 if goos != gohostos || goarch != gohostarch { 1082 installed["runtime"] = make(chan struct{}) 1083 install("runtime") 1084 } 1085 } 1086 1087 // Cannot use go/build directly because cmd/dist for a new release 1088 // builds against an old release's go/build, which may be out of sync. 1089 // To reduce duplication, we generate the list for go/build from this. 1090 // 1091 // We list all supported platforms in this list, so that this is the 1092 // single point of truth for supported platforms. This list is used 1093 // by 'go tool dist list'. 1094 var cgoEnabled = map[string]bool{ 1095 "darwin/386": true, 1096 "darwin/amd64": true, 1097 "darwin/arm": true, 1098 "darwin/arm64": true, 1099 "dragonfly/amd64": true, 1100 "freebsd/386": true, 1101 "freebsd/amd64": true, 1102 "freebsd/arm": false, 1103 "linux/386": true, 1104 "linux/amd64": true, 1105 "linux/arm": true, 1106 "linux/arm64": true, 1107 "linux/ppc64": false, 1108 "linux/ppc64le": true, 1109 "linux/mips": true, 1110 "linux/mipsle": true, 1111 "linux/mips64": true, 1112 "linux/mips64le": true, 1113 "linux/s390x": true, 1114 "android/386": true, 1115 "android/amd64": true, 1116 "android/arm": true, 1117 "android/arm64": true, 1118 "nacl/386": false, 1119 "nacl/amd64p32": false, 1120 "nacl/arm": false, 1121 "netbsd/386": true, 1122 "netbsd/amd64": true, 1123 "netbsd/arm": true, 1124 "openbsd/386": true, 1125 "openbsd/amd64": true, 1126 "openbsd/arm": false, 1127 "plan9/386": false, 1128 "plan9/amd64": false, 1129 "plan9/arm": false, 1130 "solaris/amd64": true, 1131 "windows/386": true, 1132 "windows/amd64": true, 1133 } 1134 1135 func needCC() bool { 1136 switch os.Getenv("CGO_ENABLED") { 1137 case "1": 1138 return true 1139 case "0": 1140 return false 1141 } 1142 return cgoEnabled[gohostos+"/"+gohostarch] 1143 } 1144 1145 func checkCC() { 1146 if !needCC() { 1147 return 1148 } 1149 if output, err := exec.Command(defaultcc, "--help").CombinedOutput(); err != nil { 1150 outputHdr := "" 1151 if len(output) > 0 { 1152 outputHdr = "\nCommand output:\n\n" 1153 } 1154 fatal("cannot invoke C compiler %q: %v\n\n"+ 1155 "Go needs a system C compiler for use with cgo.\n"+ 1156 "To set a C compiler, set CC=the-compiler.\n"+ 1157 "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output) 1158 } 1159 } 1160 1161 func defaulttarg() string { 1162 // xgetwd might return a path with symlinks fully resolved, and if 1163 // there happens to be symlinks in goroot, then the hasprefix test 1164 // will never succeed. Instead, we use xrealwd to get a canonical 1165 // goroot/src before the comparison to avoid this problem. 1166 pwd := xgetwd() 1167 src := pathf("%s/src/", goroot) 1168 real_src := xrealwd(src) 1169 if !strings.HasPrefix(pwd, real_src) { 1170 fatal("current directory %s is not under %s", pwd, real_src) 1171 } 1172 pwd = pwd[len(real_src):] 1173 // guard against xrealwd returning the directory without the trailing / 1174 pwd = strings.TrimPrefix(pwd, "/") 1175 1176 return pwd 1177 } 1178 1179 // Install installs the list of packages named on the command line. 1180 func cmdinstall() { 1181 xflagparse(-1) 1182 1183 if flag.NArg() == 0 { 1184 install(defaulttarg()) 1185 } 1186 1187 for _, arg := range flag.Args() { 1188 install(arg) 1189 } 1190 } 1191 1192 // Clean deletes temporary objects. 1193 func cmdclean() { 1194 xflagparse(0) 1195 clean() 1196 } 1197 1198 // Banner prints the 'now you've installed Go' banner. 1199 func cmdbanner() { 1200 xflagparse(0) 1201 1202 xprintf("\n") 1203 xprintf("---\n") 1204 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1205 xprintf("Installed commands in %s\n", gobin) 1206 1207 if !xsamefile(goroot_final, goroot) { 1208 // If the files are to be moved, don't check that gobin 1209 // is on PATH; assume they know what they are doing. 1210 } else if gohostos == "plan9" { 1211 // Check that gobin is bound before /bin. 1212 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1213 ns := fmt.Sprintf("/proc/%s/ns", pid) 1214 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) { 1215 xprintf("*** You need to bind %s before /bin.\n", gobin) 1216 } 1217 } else { 1218 // Check that gobin appears in $PATH. 1219 pathsep := ":" 1220 if gohostos == "windows" { 1221 pathsep = ";" 1222 } 1223 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) { 1224 xprintf("*** You need to add %s to your PATH.\n", gobin) 1225 } 1226 } 1227 1228 if !xsamefile(goroot_final, goroot) { 1229 xprintf("\n"+ 1230 "The binaries expect %s to be copied or moved to %s\n", 1231 goroot, goroot_final) 1232 } 1233 } 1234 1235 // Version prints the Go version. 1236 func cmdversion() { 1237 xflagparse(0) 1238 xprintf("%s\n", findgoversion()) 1239 } 1240 1241 // cmdlist lists all supported platforms. 1242 func cmdlist() { 1243 jsonFlag := flag.Bool("json", false, "produce JSON output") 1244 xflagparse(0) 1245 1246 var plats []string 1247 for p := range cgoEnabled { 1248 plats = append(plats, p) 1249 } 1250 sort.Strings(plats) 1251 1252 if !*jsonFlag { 1253 for _, p := range plats { 1254 xprintf("%s\n", p) 1255 } 1256 return 1257 } 1258 1259 type jsonResult struct { 1260 GOOS string 1261 GOARCH string 1262 CgoSupported bool 1263 } 1264 var results []jsonResult 1265 for _, p := range plats { 1266 fields := strings.Split(p, "/") 1267 results = append(results, jsonResult{ 1268 GOOS: fields[0], 1269 GOARCH: fields[1], 1270 CgoSupported: cgoEnabled[p]}) 1271 } 1272 out, err := json.MarshalIndent(results, "", "\t") 1273 if err != nil { 1274 fatal("json marshal error: %v", err) 1275 } 1276 if _, err := os.Stdout.Write(out); err != nil { 1277 fatal("write failed: %v", err) 1278 } 1279 }