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