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