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