github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 "io/ioutil" 13 "log" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "sort" 18 "strings" 19 "sync" 20 "time" 21 ) 22 23 // Initialization for any invocation. 24 25 // The usual variables. 26 var ( 27 goarch string 28 gobin string 29 gohostarch string 30 gohostos string 31 goos string 32 goarm string 33 go386 string 34 gomips string 35 gomips64 string 36 goroot string 37 goroot_final string 38 goextlinkenabled string 39 gogcflags string // For running built compiler 40 goldflags string 41 workdir string 42 tooldir string 43 oldgoos string 44 oldgoarch string 45 exe string 46 defaultcc map[string]string 47 defaultcxx map[string]string 48 defaultcflags string 49 defaultldflags string 50 defaultpkgconfig string 51 52 rebuildall bool 53 defaultclang bool 54 55 vflag int // verbosity 56 ) 57 58 // The known architectures. 59 var okgoarch = []string{ 60 "386", 61 "amd64", 62 "amd64p32", 63 "arm", 64 "arm64", 65 "mips", 66 "mipsle", 67 "mips64", 68 "mips64le", 69 "ppc64", 70 "ppc64le", 71 "riscv64", 72 "s390x", 73 "sparc64", 74 "wasm", 75 } 76 77 // The known operating systems. 78 var okgoos = []string{ 79 "darwin", 80 "dragonfly", 81 "js", 82 "linux", 83 "android", 84 "solaris", 85 "freebsd", 86 "nacl", 87 "netbsd", 88 "openbsd", 89 "plan9", 90 "windows", 91 "aix", 92 } 93 94 // find reports the first index of p in l[0:n], or else -1. 95 func find(p string, l []string) int { 96 for i, s := range l { 97 if p == s { 98 return i 99 } 100 } 101 return -1 102 } 103 104 // xinit handles initialization of the various global state, like goroot and goarch. 105 func xinit() { 106 b := os.Getenv("GOROOT") 107 if b == "" { 108 fatalf("$GOROOT must be set") 109 } 110 goroot = filepath.Clean(b) 111 112 b = os.Getenv("GOROOT_FINAL") 113 if b == "" { 114 b = goroot 115 } 116 goroot_final = b 117 118 b = os.Getenv("GOBIN") 119 if b == "" { 120 b = pathf("%s/bin", goroot) 121 } 122 gobin = b 123 124 b = os.Getenv("GOOS") 125 if b == "" { 126 b = gohostos 127 } 128 goos = b 129 if find(goos, okgoos) < 0 { 130 fatalf("unknown $GOOS %s", goos) 131 } 132 133 b = os.Getenv("GOARM") 134 if b == "" { 135 b = xgetgoarm() 136 } 137 goarm = b 138 139 b = os.Getenv("GO386") 140 if b == "" { 141 if cansse2() { 142 b = "sse2" 143 } else { 144 b = "387" 145 } 146 } 147 go386 = b 148 149 b = os.Getenv("GOMIPS") 150 if b == "" { 151 b = "hardfloat" 152 } 153 gomips = b 154 155 b = os.Getenv("GOMIPS64") 156 if b == "" { 157 b = "hardfloat" 158 } 159 gomips64 = b 160 161 if p := pathf("%s/src/all.bash", goroot); !isfile(p) { 162 fatalf("$GOROOT is not set correctly or not exported\n"+ 163 "\tGOROOT=%s\n"+ 164 "\t%s does not exist", goroot, p) 165 } 166 167 b = os.Getenv("GOHOSTARCH") 168 if b != "" { 169 gohostarch = b 170 } 171 if find(gohostarch, okgoarch) < 0 { 172 fatalf("unknown $GOHOSTARCH %s", gohostarch) 173 } 174 175 b = os.Getenv("GOARCH") 176 if b == "" { 177 b = gohostarch 178 } 179 goarch = b 180 if find(goarch, okgoarch) < 0 { 181 fatalf("unknown $GOARCH %s", goarch) 182 } 183 184 b = os.Getenv("GO_EXTLINK_ENABLED") 185 if b != "" { 186 if b != "0" && b != "1" { 187 fatalf("unknown $GO_EXTLINK_ENABLED %s", b) 188 } 189 goextlinkenabled = b 190 } 191 192 gogcflags = os.Getenv("BOOT_GO_GCFLAGS") 193 194 cc, cxx := "gcc", "g++" 195 if defaultclang { 196 cc, cxx = "clang", "clang++" 197 } 198 defaultcc = compilerEnv("CC", cc) 199 defaultcxx = compilerEnv("CXX", cxx) 200 201 defaultcflags = os.Getenv("CFLAGS") 202 defaultldflags = os.Getenv("LDFLAGS") 203 204 b = os.Getenv("PKG_CONFIG") 205 if b == "" { 206 b = "pkg-config" 207 } 208 defaultpkgconfig = b 209 210 // For tools being invoked but also for os.ExpandEnv. 211 os.Setenv("GO386", go386) 212 os.Setenv("GOARCH", goarch) 213 os.Setenv("GOARM", goarm) 214 os.Setenv("GOHOSTARCH", gohostarch) 215 os.Setenv("GOHOSTOS", gohostos) 216 os.Setenv("GOOS", goos) 217 os.Setenv("GOMIPS", gomips) 218 os.Setenv("GOMIPS64", gomips64) 219 os.Setenv("GOROOT", goroot) 220 os.Setenv("GOROOT_FINAL", goroot_final) 221 222 // Use a build cache separate from the default user one. 223 // Also one that will be wiped out during startup, so that 224 // make.bash really does start from a clean slate. 225 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) 226 227 // Make the environment more predictable. 228 os.Setenv("LANG", "C") 229 os.Setenv("LANGUAGE", "en_US.UTF8") 230 231 workdir = xworkdir() 232 xatexit(rmworkdir) 233 234 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) 235 } 236 237 // compilerEnv returns a map from "goos/goarch" to the 238 // compiler setting to use for that platform. 239 // The entry for key "" covers any goos/goarch not explicitly set in the map. 240 // For example, compilerEnv("CC", "gcc") returns the C compiler settings 241 // read from $CC, defaulting to gcc. 242 // 243 // The result is a map because additional environment variables 244 // can be set to change the compiler based on goos/goarch settings. 245 // The following applies to all envNames but CC is assumed to simplify 246 // the presentation. 247 // 248 // If no environment variables are set, we use def for all goos/goarch. 249 // $CC, if set, applies to all goos/goarch but is overridden by the following. 250 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch, 251 // but is overridden by the following. 252 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch. 253 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch. 254 func compilerEnv(envName, def string) map[string]string { 255 m := map[string]string{"": def} 256 257 if env := os.Getenv(envName); env != "" { 258 m[""] = env 259 } 260 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" { 261 if gohostos != goos || gohostarch != goarch { 262 m[gohostos+"/"+gohostarch] = m[""] 263 } 264 m[""] = env 265 } 266 267 for _, goos := range okgoos { 268 for _, goarch := range okgoarch { 269 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" { 270 m[goos+"/"+goarch] = env 271 } 272 } 273 } 274 275 return m 276 } 277 278 // compilerEnvLookup returns the compiler settings for goos/goarch in map m. 279 func compilerEnvLookup(m map[string]string, goos, goarch string) string { 280 if cc := m[goos+"/"+goarch]; cc != "" { 281 return cc 282 } 283 return m[""] 284 } 285 286 // rmworkdir deletes the work directory. 287 func rmworkdir() { 288 if vflag > 1 { 289 errprintf("rm -rf %s\n", workdir) 290 } 291 xremoveall(workdir) 292 } 293 294 // Remove trailing spaces. 295 func chomp(s string) string { 296 return strings.TrimRight(s, " \t\r\n") 297 } 298 299 func branchtag(branch string) (tag string, precise bool) { 300 log := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch) 301 tag = branch 302 for row, line := range strings.Split(log, "\n") { 303 // Each line is either blank, or looks like 304 // (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4) 305 // We need to find an element starting with refs/tags/. 306 const s = " refs/tags/" 307 i := strings.Index(line, s) 308 if i < 0 { 309 continue 310 } 311 // Trim off known prefix. 312 line = line[i+len(s):] 313 // The tag name ends at a comma or paren. 314 j := strings.IndexAny(line, ",)") 315 if j < 0 { 316 continue // malformed line; ignore it 317 } 318 tag = line[:j] 319 if row == 0 { 320 precise = true // tag denotes HEAD 321 } 322 break 323 } 324 return 325 } 326 327 // findgoversion determines the Go version to use in the version string. 328 func findgoversion() string { 329 // The $GOROOT/VERSION file takes priority, for distributions 330 // without the source repo. 331 path := pathf("%s/VERSION", goroot) 332 if isfile(path) { 333 b := chomp(readfile(path)) 334 // Commands such as "dist version > VERSION" will cause 335 // the shell to create an empty VERSION file and set dist's 336 // stdout to its fd. dist in turn looks at VERSION and uses 337 // its content if available, which is empty at this point. 338 // Only use the VERSION file if it is non-empty. 339 if b != "" { 340 // Some builders cross-compile the toolchain on linux-amd64 341 // and then copy the toolchain to the target builder (say, linux-arm) 342 // for use there. But on non-release (devel) branches, the compiler 343 // used on linux-amd64 will be an amd64 binary, and the compiler 344 // shipped to linux-arm will be an arm binary, so they will have different 345 // content IDs (they are binaries for different architectures) and so the 346 // packages compiled by the running-on-amd64 compiler will appear 347 // stale relative to the running-on-arm compiler. Avoid this by setting 348 // the version string to something that doesn't begin with devel. 349 // Then the version string will be used in place of the content ID, 350 // and the packages will look up-to-date. 351 // TODO(rsc): Really the builders could be writing out a better VERSION file instead, 352 // but it is easier to change cmd/dist than to try to make changes to 353 // the builder while Brad is away. 354 if strings.HasPrefix(b, "devel") { 355 if hostType := os.Getenv("META_BUILDLET_HOST_TYPE"); strings.Contains(hostType, "-cross") { 356 fmt.Fprintf(os.Stderr, "warning: changing VERSION from %q to %q\n", b, "builder "+hostType) 357 b = "builder " + hostType 358 } 359 } 360 return b 361 } 362 } 363 364 // The $GOROOT/VERSION.cache file is a cache to avoid invoking 365 // git every time we run this command. Unlike VERSION, it gets 366 // deleted by the clean command. 367 path = pathf("%s/VERSION.cache", goroot) 368 if isfile(path) { 369 return chomp(readfile(path)) 370 } 371 372 // Show a nicer error message if this isn't a Git repo. 373 if !isGitRepo() { 374 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT") 375 } 376 377 // Otherwise, use Git. 378 // What is the current branch? 379 branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD")) 380 381 // What are the tags along the current branch? 382 tag := "devel" 383 precise := false 384 385 // If we're on a release branch, use the closest matching tag 386 // that is on the release branch (and not on the master branch). 387 if strings.HasPrefix(branch, "release-branch.") { 388 tag, precise = branchtag(branch) 389 } 390 391 if !precise { 392 // Tag does not point at HEAD; add hash and date to version. 393 tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD")) 394 } 395 396 // Cache version. 397 writefile(tag, path, 0) 398 399 return tag 400 } 401 402 // isGitRepo reports whether the working directory is inside a Git repository. 403 func isGitRepo() bool { 404 // NB: simply checking the exit code of `git rev-parse --git-dir` would 405 // suffice here, but that requires deviating from the infrastructure 406 // provided by `run`. 407 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir")) 408 if !filepath.IsAbs(gitDir) { 409 gitDir = filepath.Join(goroot, gitDir) 410 } 411 return isdir(gitDir) 412 } 413 414 /* 415 * Initial tree setup. 416 */ 417 418 // The old tools that no longer live in $GOBIN or $GOROOT/bin. 419 var oldtool = []string{ 420 "5a", "5c", "5g", "5l", 421 "6a", "6c", "6g", "6l", 422 "8a", "8c", "8g", "8l", 423 "9a", "9c", "9g", "9l", 424 "6cov", 425 "6nm", 426 "6prof", 427 "cgo", 428 "ebnflint", 429 "goapi", 430 "gofix", 431 "goinstall", 432 "gomake", 433 "gopack", 434 "gopprof", 435 "gotest", 436 "gotype", 437 "govet", 438 "goyacc", 439 "quietgcc", 440 } 441 442 // Unreleased directories (relative to $GOROOT) that should 443 // not be in release branches. 444 var unreleased = []string{ 445 "src/cmd/newlink", 446 "src/cmd/objwriter", 447 "src/debug/goobj", 448 "src/old", 449 } 450 451 // setup sets up the tree for the initial build. 452 func setup() { 453 // Create bin directory. 454 if p := pathf("%s/bin", goroot); !isdir(p) { 455 xmkdir(p) 456 } 457 458 // Create package directory. 459 if p := pathf("%s/pkg", goroot); !isdir(p) { 460 xmkdir(p) 461 } 462 463 p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch) 464 if rebuildall { 465 xremoveall(p) 466 } 467 xmkdirall(p) 468 469 if goos != gohostos || goarch != gohostarch { 470 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch) 471 if rebuildall { 472 xremoveall(p) 473 } 474 xmkdirall(p) 475 } 476 477 // Create object directory. 478 // We used to use it for C objects. 479 // Now we use it for the build cache, to separate dist's cache 480 // from any other cache the user might have. 481 p = pathf("%s/pkg/obj/go-build", goroot) 482 if rebuildall { 483 xremoveall(p) 484 } 485 xmkdirall(p) 486 487 // Create tool directory. 488 // We keep it in pkg/, just like the object directory above. 489 if rebuildall { 490 xremoveall(tooldir) 491 } 492 xmkdirall(tooldir) 493 494 // Remove tool binaries from before the tool/gohostos_gohostarch 495 xremoveall(pathf("%s/bin/tool", goroot)) 496 497 // Remove old pre-tool binaries. 498 for _, old := range oldtool { 499 xremove(pathf("%s/bin/%s", goroot, old)) 500 } 501 502 // If $GOBIN is set and has a Go compiler, it must be cleaned. 503 for _, char := range "56789" { 504 if isfile(pathf("%s/%c%s", gobin, char, "g")) { 505 for _, old := range oldtool { 506 xremove(pathf("%s/%s", gobin, old)) 507 } 508 break 509 } 510 } 511 512 // For release, make sure excluded things are excluded. 513 goversion := findgoversion() 514 if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) { 515 for _, dir := range unreleased { 516 if p := pathf("%s/%s", goroot, dir); isdir(p) { 517 fatalf("%s should not exist in release build", p) 518 } 519 } 520 } 521 } 522 523 /* 524 * Tool building 525 */ 526 527 // deptab lists changes to the default dependencies for a given prefix. 528 // deps ending in /* read the whole directory; deps beginning with - 529 // exclude files with that prefix. 530 // Note that this table applies only to the build of cmd/go, 531 // after the main compiler bootstrap. 532 var deptab = []struct { 533 prefix string // prefix of target 534 dep []string // dependency tweaks for targets with that prefix 535 }{ 536 {"cmd/go/internal/cfg", []string{ 537 "zdefaultcc.go", 538 "zosarch.go", 539 }}, 540 {"runtime/internal/sys", []string{ 541 "zversion.go", 542 }}, 543 {"go/build", []string{ 544 "zcgo.go", 545 }}, 546 } 547 548 // depsuffix records the allowed suffixes for source files. 549 var depsuffix = []string{ 550 ".s", 551 ".go", 552 } 553 554 // gentab records how to generate some trivial files. 555 var gentab = []struct { 556 nameprefix string 557 gen func(string, string) 558 }{ 559 {"zdefaultcc.go", mkzdefaultcc}, 560 {"zosarch.go", mkzosarch}, 561 {"zversion.go", mkzversion}, 562 {"zcgo.go", mkzcgo}, 563 564 // not generated anymore, but delete the file if we see it 565 {"enam.c", nil}, 566 {"anames5.c", nil}, 567 {"anames6.c", nil}, 568 {"anames8.c", nil}, 569 {"anames9.c", nil}, 570 } 571 572 // installed maps from a dir name (as given to install) to a chan 573 // closed when the dir's package is installed. 574 var installed = make(map[string]chan struct{}) 575 var installedMu sync.Mutex 576 577 func install(dir string) { 578 <-startInstall(dir) 579 } 580 581 func startInstall(dir string) chan struct{} { 582 installedMu.Lock() 583 ch := installed[dir] 584 if ch == nil { 585 ch = make(chan struct{}) 586 installed[dir] = ch 587 go runInstall(dir, ch) 588 } 589 installedMu.Unlock() 590 return ch 591 } 592 593 // runInstall installs the library, package, or binary associated with dir, 594 // which is relative to $GOROOT/src. 595 func runInstall(dir string, ch chan struct{}) { 596 if dir == "net" || dir == "os/user" || dir == "crypto/x509" { 597 fatalf("go_bootstrap cannot depend on cgo package %s", dir) 598 } 599 600 defer close(ch) 601 602 if dir == "unsafe" { 603 return 604 } 605 606 if vflag > 0 { 607 if goos != gohostos || goarch != gohostarch { 608 errprintf("%s (%s/%s)\n", dir, goos, goarch) 609 } else { 610 errprintf("%s\n", dir) 611 } 612 } 613 614 workdir := pathf("%s/%s", workdir, dir) 615 xmkdirall(workdir) 616 617 var clean []string 618 defer func() { 619 for _, name := range clean { 620 xremove(name) 621 } 622 }() 623 624 // path = full path to dir. 625 path := pathf("%s/src/%s", goroot, dir) 626 name := filepath.Base(dir) 627 628 ispkg := !strings.HasPrefix(dir, "cmd/") || strings.Contains(dir, "/internal/") 629 630 // Start final link command line. 631 // Note: code below knows that link.p[targ] is the target. 632 var ( 633 link []string 634 targ int 635 ispackcmd bool 636 ) 637 if ispkg { 638 // Go library (package). 639 ispackcmd = true 640 link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)} 641 targ = len(link) - 1 642 xmkdirall(filepath.Dir(link[targ])) 643 } else { 644 // Go command. 645 elem := name 646 if elem == "go" { 647 elem = "go_bootstrap" 648 } 649 link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)} 650 targ = len(link) - 1 651 } 652 ttarg := mtime(link[targ]) 653 654 // Gather files that are sources for this target. 655 // Everything in that directory, and any target-specific 656 // additions. 657 files := xreaddir(path) 658 659 // Remove files beginning with . or _, 660 // which are likely to be editor temporary files. 661 // This is the same heuristic build.ScanDir uses. 662 // There do exist real C files beginning with _, 663 // so limit that check to just Go files. 664 files = filter(files, func(p string) bool { 665 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go")) 666 }) 667 668 for _, dt := range deptab { 669 if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) { 670 for _, p := range dt.dep { 671 p = os.ExpandEnv(p) 672 files = append(files, p) 673 } 674 } 675 } 676 files = uniq(files) 677 678 // Convert to absolute paths. 679 for i, p := range files { 680 if !filepath.IsAbs(p) { 681 files[i] = pathf("%s/%s", path, p) 682 } 683 } 684 685 // Is the target up-to-date? 686 var gofiles, sfiles, missing []string 687 stale := rebuildall 688 files = filter(files, func(p string) bool { 689 for _, suf := range depsuffix { 690 if strings.HasSuffix(p, suf) { 691 goto ok 692 } 693 } 694 return false 695 ok: 696 t := mtime(p) 697 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) { 698 return false 699 } 700 if strings.HasSuffix(p, ".go") { 701 gofiles = append(gofiles, p) 702 } else if strings.HasSuffix(p, ".s") { 703 sfiles = append(sfiles, p) 704 } 705 if t.After(ttarg) { 706 stale = true 707 } 708 if t.IsZero() { 709 missing = append(missing, p) 710 } 711 return true 712 }) 713 714 // If there are no files to compile, we're done. 715 if len(files) == 0 { 716 return 717 } 718 719 if !stale { 720 return 721 } 722 723 // For package runtime, copy some files into the work space. 724 if dir == "runtime" { 725 xmkdirall(pathf("%s/pkg/include", goroot)) 726 // For use by assembly and C files. 727 copyfile(pathf("%s/pkg/include/textflag.h", goroot), 728 pathf("%s/src/runtime/textflag.h", goroot), 0) 729 copyfile(pathf("%s/pkg/include/funcdata.h", goroot), 730 pathf("%s/src/runtime/funcdata.h", goroot), 0) 731 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot), 732 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0) 733 } 734 735 // Generate any missing files; regenerate existing ones. 736 for _, p := range files { 737 elem := filepath.Base(p) 738 for _, gt := range gentab { 739 if gt.gen == nil { 740 continue 741 } 742 if strings.HasPrefix(elem, gt.nameprefix) { 743 if vflag > 1 { 744 errprintf("generate %s\n", p) 745 } 746 gt.gen(path, p) 747 // Do not add generated file to clean list. 748 // In runtime, we want to be able to 749 // build the package with the go tool, 750 // and it assumes these generated files already 751 // exist (it does not know how to build them). 752 // The 'clean' command can remove 753 // the generated files. 754 goto built 755 } 756 } 757 // Did not rebuild p. 758 if find(p, missing) >= 0 { 759 fatalf("missing file %s", p) 760 } 761 built: 762 } 763 764 // Make sure dependencies are installed. 765 var deps []string 766 for _, p := range gofiles { 767 deps = append(deps, readimports(p)...) 768 } 769 for _, dir1 := range deps { 770 startInstall(dir1) 771 } 772 for _, dir1 := range deps { 773 install(dir1) 774 } 775 776 if goos != gohostos || goarch != gohostarch { 777 // We've generated the right files; the go command can do the build. 778 if vflag > 1 { 779 errprintf("skip build for cross-compile %s\n", dir) 780 } 781 return 782 } 783 784 asmArgs := []string{ 785 pathf("%s/asm", tooldir), 786 "-I", workdir, 787 "-I", pathf("%s/pkg/include", goroot), 788 "-D", "GOOS_" + goos, 789 "-D", "GOARCH_" + goarch, 790 "-D", "GOOS_GOARCH_" + goos + "_" + goarch, 791 } 792 if goarch == "mips" || goarch == "mipsle" { 793 // Define GOMIPS_value from gomips. 794 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips) 795 } 796 if goarch == "mips64" || goarch == "mipsle64" { 797 // Define GOMIPS64_value from gomips64. 798 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64) 799 } 800 goasmh := pathf("%s/go_asm.h", workdir) 801 802 // Collect symabis from assembly code. 803 var symabis string 804 if len(sfiles) > 0 { 805 symabis = pathf("%s/symabis", workdir) 806 var wg sync.WaitGroup 807 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis) 808 asmabis = append(asmabis, sfiles...) 809 if err := ioutil.WriteFile(goasmh, nil, 0666); err != nil { 810 fatalf("cannot write empty go_asm.h: %s", err) 811 } 812 bgrun(&wg, path, asmabis...) 813 bgwait(&wg) 814 } 815 816 var archive string 817 // The next loop will compile individual non-Go files. 818 // Hand the Go files to the compiler en masse. 819 // For packages containing assembly, this writes go_asm.h, which 820 // the assembly files will need. 821 pkg := dir 822 if strings.HasPrefix(dir, "cmd/") && strings.Count(dir, "/") == 1 { 823 pkg = "main" 824 } 825 b := pathf("%s/_go_.a", workdir) 826 clean = append(clean, b) 827 if !ispackcmd { 828 link = append(link, b) 829 } else { 830 archive = b 831 } 832 833 // Compile Go code. 834 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg} 835 if gogcflags != "" { 836 compile = append(compile, strings.Fields(gogcflags)...) 837 } 838 if dir == "runtime" { 839 compile = append(compile, "-+") 840 } 841 if len(sfiles) > 0 { 842 compile = append(compile, "-asmhdr", goasmh) 843 } 844 if symabis != "" { 845 compile = append(compile, "-symabis", symabis) 846 } 847 if dir == "runtime" || dir == "runtime/internal/atomic" { 848 // These packages define symbols referenced by 849 // assembly in other packages. In cmd/go, we work out 850 // the exact details. For bootstrapping, just tell the 851 // compiler to generate ABI wrappers for everything. 852 compile = append(compile, "-allabis") 853 } 854 855 compile = append(compile, gofiles...) 856 var wg sync.WaitGroup 857 // We use bgrun and immediately wait for it instead of calling run() synchronously. 858 // This executes all jobs through the bgwork channel and allows the process 859 // to exit cleanly in case an error occurs. 860 bgrun(&wg, path, compile...) 861 bgwait(&wg) 862 863 // Compile the files. 864 for _, p := range sfiles { 865 // Assembly file for a Go package. 866 compile := asmArgs[:len(asmArgs):len(asmArgs)] 867 868 doclean := true 869 b := pathf("%s/%s", workdir, filepath.Base(p)) 870 871 // Change the last character of the output file (which was c or s). 872 b = b[:len(b)-1] + "o" 873 compile = append(compile, "-o", b, p) 874 bgrun(&wg, path, compile...) 875 876 link = append(link, b) 877 if doclean { 878 clean = append(clean, b) 879 } 880 } 881 bgwait(&wg) 882 883 if ispackcmd { 884 xremove(link[targ]) 885 dopack(link[targ], archive, link[targ+1:]) 886 return 887 } 888 889 // Remove target before writing it. 890 xremove(link[targ]) 891 bgrun(&wg, "", link...) 892 bgwait(&wg) 893 } 894 895 // matchfield reports whether the field (x,y,z) matches this build. 896 // all the elements in the field must be satisfied. 897 func matchfield(f string) bool { 898 for _, tag := range strings.Split(f, ",") { 899 if !matchtag(tag) { 900 return false 901 } 902 } 903 return true 904 } 905 906 // matchtag reports whether the tag (x or !x) matches this build. 907 func matchtag(tag string) bool { 908 if tag == "" { 909 return false 910 } 911 if tag[0] == '!' { 912 if len(tag) == 1 || tag[1] == '!' { 913 return false 914 } 915 return !matchtag(tag[1:]) 916 } 917 return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux") 918 } 919 920 // shouldbuild reports whether we should build this file. 921 // It applies the same rules that are used with context tags 922 // in package go/build, except it's less picky about the order 923 // of GOOS and GOARCH. 924 // We also allow the special tag cmd_go_bootstrap. 925 // See ../go/bootstrap.go and package go/build. 926 func shouldbuild(file, dir string) bool { 927 // Check file name for GOOS or GOARCH. 928 name := filepath.Base(file) 929 excluded := func(list []string, ok string) bool { 930 for _, x := range list { 931 if x == ok || ok == "android" && x == "linux" { 932 continue 933 } 934 i := strings.Index(name, x) 935 if i <= 0 || name[i-1] != '_' { 936 continue 937 } 938 i += len(x) 939 if i == len(name) || name[i] == '.' || name[i] == '_' { 940 return true 941 } 942 } 943 return false 944 } 945 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 946 return false 947 } 948 949 // Omit test files. 950 if strings.Contains(name, "_test") { 951 return false 952 } 953 954 // Check file contents for // +build lines. 955 for _, p := range strings.Split(readfile(file), "\n") { 956 p = strings.TrimSpace(p) 957 if p == "" { 958 continue 959 } 960 code := p 961 i := strings.Index(code, "//") 962 if i > 0 { 963 code = strings.TrimSpace(code[:i]) 964 } 965 if code == "package documentation" { 966 return false 967 } 968 if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" { 969 return false 970 } 971 if !strings.HasPrefix(p, "//") { 972 break 973 } 974 if !strings.Contains(p, "+build") { 975 continue 976 } 977 fields := strings.Fields(p[2:]) 978 if len(fields) < 1 || fields[0] != "+build" { 979 continue 980 } 981 for _, p := range fields[1:] { 982 if matchfield(p) { 983 goto fieldmatch 984 } 985 } 986 return false 987 fieldmatch: 988 } 989 990 return true 991 } 992 993 // copy copies the file src to dst, via memory (so only good for small files). 994 func copyfile(dst, src string, flag int) { 995 if vflag > 1 { 996 errprintf("cp %s %s\n", src, dst) 997 } 998 writefile(readfile(src), dst, flag) 999 } 1000 1001 // dopack copies the package src to dst, 1002 // appending the files listed in extra. 1003 // The archive format is the traditional Unix ar format. 1004 func dopack(dst, src string, extra []string) { 1005 bdst := bytes.NewBufferString(readfile(src)) 1006 for _, file := range extra { 1007 b := readfile(file) 1008 // find last path element for archive member name 1009 i := strings.LastIndex(file, "/") + 1 1010 j := strings.LastIndex(file, `\`) + 1 1011 if i < j { 1012 i = j 1013 } 1014 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 1015 bdst.WriteString(b) 1016 if len(b)&1 != 0 { 1017 bdst.WriteByte(0) 1018 } 1019 } 1020 writefile(bdst.String(), dst, 0) 1021 } 1022 1023 var runtimegen = []string{ 1024 "zaexperiment.h", 1025 "zversion.go", 1026 } 1027 1028 // cleanlist is a list of packages with generated files and commands. 1029 var cleanlist = []string{ 1030 "runtime/internal/sys", 1031 "cmd/cgo", 1032 "cmd/go/internal/cfg", 1033 "go/build", 1034 } 1035 1036 func clean() { 1037 for _, name := range cleanlist { 1038 path := pathf("%s/src/%s", goroot, name) 1039 // Remove generated files. 1040 for _, elem := range xreaddir(path) { 1041 for _, gt := range gentab { 1042 if strings.HasPrefix(elem, gt.nameprefix) { 1043 xremove(pathf("%s/%s", path, elem)) 1044 } 1045 } 1046 } 1047 // Remove generated binary named for directory. 1048 if strings.HasPrefix(name, "cmd/") { 1049 xremove(pathf("%s/%s", path, name[4:])) 1050 } 1051 } 1052 1053 // remove runtimegen files. 1054 path := pathf("%s/src/runtime", goroot) 1055 for _, elem := range runtimegen { 1056 xremove(pathf("%s/%s", path, elem)) 1057 } 1058 1059 if rebuildall { 1060 // Remove object tree. 1061 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)) 1062 1063 // Remove installed packages and tools. 1064 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)) 1065 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch)) 1066 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch)) 1067 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch)) 1068 xremoveall(tooldir) 1069 1070 // Remove cached version info. 1071 xremove(pathf("%s/VERSION.cache", goroot)) 1072 } 1073 } 1074 1075 /* 1076 * command implementations 1077 */ 1078 1079 // The env command prints the default environment. 1080 func cmdenv() { 1081 path := flag.Bool("p", false, "emit updated PATH") 1082 plan9 := flag.Bool("9", false, "emit plan 9 syntax") 1083 windows := flag.Bool("w", false, "emit windows syntax") 1084 xflagparse(0) 1085 1086 format := "%s=\"%s\"\n" 1087 switch { 1088 case *plan9: 1089 format = "%s='%s'\n" 1090 case *windows: 1091 format = "set %s=%s\r\n" 1092 } 1093 1094 xprintf(format, "GOARCH", goarch) 1095 xprintf(format, "GOBIN", gobin) 1096 xprintf(format, "GOCACHE", os.Getenv("GOCACHE")) 1097 xprintf(format, "GODEBUG", os.Getenv("GODEBUG")) 1098 xprintf(format, "GOHOSTARCH", gohostarch) 1099 xprintf(format, "GOHOSTOS", gohostos) 1100 xprintf(format, "GOOS", goos) 1101 xprintf(format, "GOPROXY", os.Getenv("GOPROXY")) 1102 xprintf(format, "GOROOT", goroot) 1103 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR")) 1104 xprintf(format, "GOTOOLDIR", tooldir) 1105 if goarch == "arm" { 1106 xprintf(format, "GOARM", goarm) 1107 } 1108 if goarch == "386" { 1109 xprintf(format, "GO386", go386) 1110 } 1111 if goarch == "mips" || goarch == "mipsle" { 1112 xprintf(format, "GOMIPS", gomips) 1113 } 1114 if goarch == "mips64" || goarch == "mips64le" { 1115 xprintf(format, "GOMIPS64", gomips64) 1116 } 1117 1118 if *path { 1119 sep := ":" 1120 if gohostos == "windows" { 1121 sep = ";" 1122 } 1123 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH"))) 1124 } 1125 } 1126 1127 var ( 1128 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != "" 1129 timeLogMu sync.Mutex 1130 timeLogFile *os.File 1131 timeLogStart time.Time 1132 ) 1133 1134 func timelog(op, name string) { 1135 if !timeLogEnabled { 1136 return 1137 } 1138 timeLogMu.Lock() 1139 defer timeLogMu.Unlock() 1140 if timeLogFile == nil { 1141 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666) 1142 if err != nil { 1143 log.Fatal(err) 1144 } 1145 buf := make([]byte, 100) 1146 n, _ := f.Read(buf) 1147 s := string(buf[:n]) 1148 if i := strings.Index(s, "\n"); i >= 0 { 1149 s = s[:i] 1150 } 1151 i := strings.Index(s, " start") 1152 if i < 0 { 1153 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBULDTIMELOGFILE")) 1154 } 1155 t, err := time.Parse(time.UnixDate, s[:i]) 1156 if err != nil { 1157 log.Fatalf("cannot parse time log line %q: %v", s, err) 1158 } 1159 timeLogStart = t 1160 timeLogFile = f 1161 } 1162 t := time.Now() 1163 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name) 1164 } 1165 1166 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"} 1167 1168 // The bootstrap command runs a build from scratch, 1169 // stopping at having installed the go_bootstrap command. 1170 // 1171 // WARNING: This command runs after cmd/dist is built with Go 1.4. 1172 // It rebuilds and installs cmd/dist with the new toolchain, so other 1173 // commands (like "go tool dist test" in run.bash) can rely on bug fixes 1174 // made since Go 1.4, but this function cannot. In particular, the uses 1175 // of os/exec in this function cannot assume that 1176 // cmd.Env = append(os.Environ(), "X=Y") 1177 // sets $X to Y in the command's environment. That guarantee was 1178 // added after Go 1.4, and in fact in Go 1.4 it was typically the opposite: 1179 // if $X was already present in os.Environ(), most systems preferred 1180 // that setting, not the new one. 1181 func cmdbootstrap() { 1182 timelog("start", "dist bootstrap") 1183 defer timelog("end", "dist bootstrap") 1184 1185 var noBanner bool 1186 var debug bool 1187 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 1188 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process") 1189 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner") 1190 1191 xflagparse(0) 1192 1193 if debug { 1194 // cmd/buildid is used in debug mode. 1195 toolchain = append(toolchain, "cmd/buildid") 1196 } 1197 1198 if isdir(pathf("%s/src/pkg", goroot)) { 1199 fatalf("\n\n"+ 1200 "The Go package sources have moved to $GOROOT/src.\n"+ 1201 "*** %s still exists. ***\n"+ 1202 "It probably contains stale files that may confuse the build.\n"+ 1203 "Please (check what's there and) remove it and try again.\n"+ 1204 "See https://golang.org/s/go14nopkg\n", 1205 pathf("%s/src/pkg", goroot)) 1206 } 1207 1208 if rebuildall { 1209 clean() 1210 } 1211 1212 setup() 1213 1214 timelog("build", "toolchain1") 1215 checkCC() 1216 bootstrapBuildTools() 1217 1218 // Remember old content of $GOROOT/bin for comparison below. 1219 oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot)) 1220 1221 // For the main bootstrap, building for host os/arch. 1222 oldgoos = goos 1223 oldgoarch = goarch 1224 goos = gohostos 1225 goarch = gohostarch 1226 os.Setenv("GOHOSTARCH", gohostarch) 1227 os.Setenv("GOHOSTOS", gohostos) 1228 os.Setenv("GOARCH", goarch) 1229 os.Setenv("GOOS", goos) 1230 1231 timelog("build", "go_bootstrap") 1232 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n") 1233 install("runtime") // dependency not visible in sources; also sets up textflag.h 1234 install("cmd/go") 1235 if vflag > 0 { 1236 xprintf("\n") 1237 } 1238 1239 gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now 1240 goldflags = os.Getenv("GO_LDFLAGS") 1241 goBootstrap := pathf("%s/go_bootstrap", tooldir) 1242 cmdGo := pathf("%s/go", gobin) 1243 if debug { 1244 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1245 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec) 1246 } 1247 1248 // To recap, so far we have built the new toolchain 1249 // (cmd/asm, cmd/cgo, cmd/compile, cmd/link) 1250 // using Go 1.4's toolchain and go command. 1251 // Then we built the new go command (as go_bootstrap) 1252 // using the new toolchain and our own build logic (above). 1253 // 1254 // toolchain1 = mk(new toolchain, go1.4 toolchain, go1.4 cmd/go) 1255 // go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist) 1256 // 1257 // The toolchain1 we built earlier is built from the new sources, 1258 // but because it was built using cmd/go it has no build IDs. 1259 // The eventually installed toolchain needs build IDs, so we need 1260 // to do another round: 1261 // 1262 // toolchain2 = mk(new toolchain, toolchain1, go_bootstrap) 1263 // 1264 timelog("build", "toolchain2") 1265 if vflag > 0 { 1266 xprintf("\n") 1267 } 1268 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n") 1269 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 1270 goInstall(goBootstrap, append([]string{"-i"}, toolchain...)...) 1271 if debug { 1272 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1273 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1274 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec) 1275 } 1276 1277 // Toolchain2 should be semantically equivalent to toolchain1, 1278 // but it was built using the new compilers instead of the Go 1.4 compilers, 1279 // so it should at the least run faster. Also, toolchain1 had no build IDs 1280 // in the binaries, while toolchain2 does. In non-release builds, the 1281 // toolchain's build IDs feed into constructing the build IDs of built targets, 1282 // so in non-release builds, everything now looks out-of-date due to 1283 // toolchain2 having build IDs - that is, due to the go command seeing 1284 // that there are new compilers. In release builds, the toolchain's reported 1285 // version is used in place of the build ID, and the go command does not 1286 // see that change from toolchain1 to toolchain2, so in release builds, 1287 // nothing looks out of date. 1288 // To keep the behavior the same in both non-release and release builds, 1289 // we force-install everything here. 1290 // 1291 // toolchain3 = mk(new toolchain, toolchain2, go_bootstrap) 1292 // 1293 timelog("build", "toolchain3") 1294 if vflag > 0 { 1295 xprintf("\n") 1296 } 1297 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n") 1298 goInstall(goBootstrap, append([]string{"-a", "-i"}, toolchain...)...) 1299 if debug { 1300 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1301 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1302 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec) 1303 } 1304 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 1305 1306 if goos == oldgoos && goarch == oldgoarch { 1307 // Common case - not setting up for cross-compilation. 1308 timelog("build", "toolchain") 1309 if vflag > 0 { 1310 xprintf("\n") 1311 } 1312 xprintf("Building packages and commands for %s/%s.\n", goos, goarch) 1313 } else { 1314 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH. 1315 // Finish GOHOSTOS/GOHOSTARCH installation and then 1316 // run GOOS/GOARCH installation. 1317 timelog("build", "host toolchain") 1318 if vflag > 0 { 1319 xprintf("\n") 1320 } 1321 xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch) 1322 goInstall(goBootstrap, "std", "cmd") 1323 checkNotStale(goBootstrap, "std", "cmd") 1324 checkNotStale(cmdGo, "std", "cmd") 1325 1326 timelog("build", "target toolchain") 1327 if vflag > 0 { 1328 xprintf("\n") 1329 } 1330 goos = oldgoos 1331 goarch = oldgoarch 1332 os.Setenv("GOOS", goos) 1333 os.Setenv("GOARCH", goarch) 1334 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) 1335 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) 1336 } 1337 targets := []string{"std", "cmd"} 1338 if goos == "js" && goarch == "wasm" { 1339 // Skip the cmd tools for js/wasm. They're not usable. 1340 targets = targets[:1] 1341 } 1342 goInstall(goBootstrap, targets...) 1343 checkNotStale(goBootstrap, targets...) 1344 checkNotStale(cmdGo, targets...) 1345 if debug { 1346 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1347 run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) 1348 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...) 1349 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec) 1350 } 1351 1352 // Check that there are no new files in $GOROOT/bin other than 1353 // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling). 1354 binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot)) 1355 ok := map[string]bool{} 1356 for _, f := range oldBinFiles { 1357 ok[f] = true 1358 } 1359 for _, f := range binFiles { 1360 elem := strings.TrimSuffix(filepath.Base(f), ".exe") 1361 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch { 1362 fatalf("unexpected new file in $GOROOT/bin: %s", elem) 1363 } 1364 } 1365 1366 // Remove go_bootstrap now that we're done. 1367 xremove(pathf("%s/go_bootstrap", tooldir)) 1368 1369 // Print trailing banner unless instructed otherwise. 1370 if !noBanner { 1371 banner() 1372 } 1373 } 1374 1375 func goInstall(goBinary string, args ...string) { 1376 installCmd := []string{goBinary, "install", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags} 1377 if vflag > 0 { 1378 installCmd = append(installCmd, "-v") 1379 } 1380 1381 // Force only one process at a time on vx32 emulation. 1382 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" { 1383 installCmd = append(installCmd, "-p=1") 1384 } 1385 1386 run(goroot, ShowOutput|CheckExit, append(installCmd, args...)...) 1387 } 1388 1389 func checkNotStale(goBinary string, targets ...string) { 1390 out := run(goroot, CheckExit, 1391 append([]string{ 1392 goBinary, 1393 "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags, 1394 "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}", 1395 }, targets...)...) 1396 if strings.Contains(out, "\tSTALE ") { 1397 os.Setenv("GODEBUG", "gocachehash=1") 1398 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} { 1399 if strings.Contains(out, "STALE "+target) { 1400 run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) 1401 break 1402 } 1403 } 1404 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out) 1405 } 1406 } 1407 1408 // Cannot use go/build directly because cmd/dist for a new release 1409 // builds against an old release's go/build, which may be out of sync. 1410 // To reduce duplication, we generate the list for go/build from this. 1411 // 1412 // We list all supported platforms in this list, so that this is the 1413 // single point of truth for supported platforms. This list is used 1414 // by 'go tool dist list'. 1415 var cgoEnabled = map[string]bool{ 1416 "aix/ppc64": false, 1417 "darwin/386": true, 1418 "darwin/amd64": true, 1419 "darwin/arm": true, 1420 "darwin/arm64": true, 1421 "dragonfly/amd64": true, 1422 "freebsd/386": true, 1423 "freebsd/amd64": true, 1424 "freebsd/arm": false, 1425 "linux/386": true, 1426 "linux/amd64": true, 1427 "linux/arm": true, 1428 "linux/arm64": true, 1429 "linux/ppc64": false, 1430 "linux/ppc64le": true, 1431 "linux/mips": true, 1432 "linux/mipsle": true, 1433 "linux/mips64": true, 1434 "linux/mips64le": true, 1435 "linux/riscv64": true, 1436 "linux/s390x": true, 1437 "linux/sparc64": true, 1438 "android/386": true, 1439 "android/amd64": true, 1440 "android/arm": true, 1441 "android/arm64": true, 1442 "js/wasm": false, 1443 "nacl/386": false, 1444 "nacl/amd64p32": false, 1445 "nacl/arm": false, 1446 "netbsd/386": true, 1447 "netbsd/amd64": true, 1448 "netbsd/arm": true, 1449 "openbsd/386": true, 1450 "openbsd/amd64": true, 1451 "openbsd/arm": true, 1452 "plan9/386": false, 1453 "plan9/amd64": false, 1454 "plan9/arm": false, 1455 "solaris/amd64": true, 1456 "windows/386": true, 1457 "windows/amd64": true, 1458 "windows/arm": false, 1459 } 1460 1461 // List of platforms which are supported but not complete yet. These get 1462 // filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944 1463 var incomplete = map[string]bool{ 1464 "linux/riscv64": true, 1465 "linux/sparc64": true, 1466 } 1467 1468 func needCC() bool { 1469 switch os.Getenv("CGO_ENABLED") { 1470 case "1": 1471 return true 1472 case "0": 1473 return false 1474 } 1475 return cgoEnabled[gohostos+"/"+gohostarch] 1476 } 1477 1478 func checkCC() { 1479 if !needCC() { 1480 return 1481 } 1482 if output, err := exec.Command(defaultcc[""], "--help").CombinedOutput(); err != nil { 1483 outputHdr := "" 1484 if len(output) > 0 { 1485 outputHdr = "\nCommand output:\n\n" 1486 } 1487 fatalf("cannot invoke C compiler %q: %v\n\n"+ 1488 "Go needs a system C compiler for use with cgo.\n"+ 1489 "To set a C compiler, set CC=the-compiler.\n"+ 1490 "To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc[""], err, outputHdr, output) 1491 } 1492 } 1493 1494 func defaulttarg() string { 1495 // xgetwd might return a path with symlinks fully resolved, and if 1496 // there happens to be symlinks in goroot, then the hasprefix test 1497 // will never succeed. Instead, we use xrealwd to get a canonical 1498 // goroot/src before the comparison to avoid this problem. 1499 pwd := xgetwd() 1500 src := pathf("%s/src/", goroot) 1501 real_src := xrealwd(src) 1502 if !strings.HasPrefix(pwd, real_src) { 1503 fatalf("current directory %s is not under %s", pwd, real_src) 1504 } 1505 pwd = pwd[len(real_src):] 1506 // guard against xrealwd returning the directory without the trailing / 1507 pwd = strings.TrimPrefix(pwd, "/") 1508 1509 return pwd 1510 } 1511 1512 // Install installs the list of packages named on the command line. 1513 func cmdinstall() { 1514 xflagparse(-1) 1515 1516 if flag.NArg() == 0 { 1517 install(defaulttarg()) 1518 } 1519 1520 for _, arg := range flag.Args() { 1521 install(arg) 1522 } 1523 } 1524 1525 // Clean deletes temporary objects. 1526 func cmdclean() { 1527 xflagparse(0) 1528 clean() 1529 } 1530 1531 // Banner prints the 'now you've installed Go' banner. 1532 func cmdbanner() { 1533 xflagparse(0) 1534 banner() 1535 } 1536 1537 func banner() { 1538 if vflag > 0 { 1539 xprintf("\n") 1540 } 1541 xprintf("---\n") 1542 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1543 xprintf("Installed commands in %s\n", gobin) 1544 1545 if !xsamefile(goroot_final, goroot) { 1546 // If the files are to be moved, don't check that gobin 1547 // is on PATH; assume they know what they are doing. 1548 } else if gohostos == "plan9" { 1549 // Check that gobin is bound before /bin. 1550 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1551 ns := fmt.Sprintf("/proc/%s/ns", pid) 1552 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) { 1553 xprintf("*** You need to bind %s before /bin.\n", gobin) 1554 } 1555 } else { 1556 // Check that gobin appears in $PATH. 1557 pathsep := ":" 1558 if gohostos == "windows" { 1559 pathsep = ";" 1560 } 1561 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) { 1562 xprintf("*** You need to add %s to your PATH.\n", gobin) 1563 } 1564 } 1565 1566 if !xsamefile(goroot_final, goroot) { 1567 xprintf("\n"+ 1568 "The binaries expect %s to be copied or moved to %s\n", 1569 goroot, goroot_final) 1570 } 1571 } 1572 1573 // Version prints the Go version. 1574 func cmdversion() { 1575 xflagparse(0) 1576 xprintf("%s\n", findgoversion()) 1577 } 1578 1579 // cmdlist lists all supported platforms. 1580 func cmdlist() { 1581 jsonFlag := flag.Bool("json", false, "produce JSON output") 1582 xflagparse(0) 1583 1584 var plats []string 1585 for p := range cgoEnabled { 1586 if incomplete[p] { 1587 continue 1588 } 1589 plats = append(plats, p) 1590 } 1591 sort.Strings(plats) 1592 1593 if !*jsonFlag { 1594 for _, p := range plats { 1595 xprintf("%s\n", p) 1596 } 1597 return 1598 } 1599 1600 type jsonResult struct { 1601 GOOS string 1602 GOARCH string 1603 CgoSupported bool 1604 } 1605 var results []jsonResult 1606 for _, p := range plats { 1607 fields := strings.Split(p, "/") 1608 results = append(results, jsonResult{ 1609 GOOS: fields[0], 1610 GOARCH: fields[1], 1611 CgoSupported: cgoEnabled[p]}) 1612 } 1613 out, err := json.MarshalIndent(results, "", "\t") 1614 if err != nil { 1615 fatalf("json marshal error: %v", err) 1616 } 1617 if _, err := os.Stdout.Write(out); err != nil { 1618 fatalf("write failed: %v", err) 1619 } 1620 }