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