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 5package main 6 7import ( 8 "bytes" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "io" 13 "io/fs" 14 "log" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "regexp" 19 "sort" 20 "strings" 21 "sync" 22 "time" 23) 24 25// Initialization for any invocation. 26 27// The usual variables. 28var ( 29 goarch string 30 gorootBin string 31 gorootBinGo string 32 gohostarch string 33 gohostos string 34 goos string 35 goarm string 36 goarm64 string 37 go386 string 38 goamd64 string 39 gomips string 40 gomips64 string 41 goppc64 string 42 goriscv64 string 43 goroot string 44 goextlinkenabled string 45 gogcflags string // For running built compiler 46 goldflags string 47 goexperiment string 48 workdir string 49 tooldir string 50 oldgoos string 51 oldgoarch string 52 oldgocache string 53 exe string 54 defaultcc map[string]string 55 defaultcxx map[string]string 56 defaultpkgconfig string 57 defaultldso string 58 59 rebuildall bool 60 noOpt bool 61 isRelease bool 62 63 vflag int // verbosity 64) 65 66// The known architectures. 67var okgoarch = []string{ 68 "386", 69 "amd64", 70 "arm", 71 "arm64", 72 "loong64", 73 "mips", 74 "mipsle", 75 "mips64", 76 "mips64le", 77 "ppc64", 78 "ppc64le", 79 "riscv64", 80 "s390x", 81 "sparc64", 82 "wasm", 83} 84 85// The known operating systems. 86var okgoos = []string{ 87 "darwin", 88 "dragonfly", 89 "illumos", 90 "ios", 91 "js", 92 "wasip1", 93 "linux", 94 "android", 95 "solaris", 96 "freebsd", 97 "nacl", // keep; 98 "netbsd", 99 "openbsd", 100 "plan9", 101 "windows", 102 "aix", 103} 104 105// find reports the first index of p in l[0:n], or else -1. 106func find(p string, l []string) int { 107 for i, s := range l { 108 if p == s { 109 return i 110 } 111 } 112 return -1 113} 114 115// xinit handles initialization of the various global state, like goroot and goarch. 116func xinit() { 117 b := os.Getenv("GOROOT") 118 if b == "" { 119 fatalf("$GOROOT must be set") 120 } 121 goroot = filepath.Clean(b) 122 gorootBin = pathf("%s/bin", goroot) 123 124 // Don't run just 'go' because the build infrastructure 125 // runs cmd/dist inside go/bin often, and on Windows 126 // it will be found in the current directory and refuse to exec. 127 // All exec calls rewrite "go" into gorootBinGo. 128 gorootBinGo = pathf("%s/bin/go", goroot) 129 130 b = os.Getenv("GOOS") 131 if b == "" { 132 b = gohostos 133 } 134 goos = b 135 if find(goos, okgoos) < 0 { 136 fatalf("unknown $GOOS %s", goos) 137 } 138 139 b = os.Getenv("GOARM") 140 if b == "" { 141 b = xgetgoarm() 142 } 143 goarm = b 144 145 b = os.Getenv("GOARM64") 146 if b == "" { 147 b = "v8.0" 148 } 149 goarm64 = b 150 151 b = os.Getenv("GO386") 152 if b == "" { 153 b = "sse2" 154 } 155 go386 = b 156 157 b = os.Getenv("GOAMD64") 158 if b == "" { 159 b = "v1" 160 } 161 goamd64 = b 162 163 b = os.Getenv("GOMIPS") 164 if b == "" { 165 b = "hardfloat" 166 } 167 gomips = b 168 169 b = os.Getenv("GOMIPS64") 170 if b == "" { 171 b = "hardfloat" 172 } 173 gomips64 = b 174 175 b = os.Getenv("GOPPC64") 176 if b == "" { 177 b = "power8" 178 } 179 goppc64 = b 180 181 b = os.Getenv("GORISCV64") 182 if b == "" { 183 b = "rva20u64" 184 } 185 goriscv64 = b 186 187 if p := pathf("%s/src/all.bash", goroot); !isfile(p) { 188 fatalf("$GOROOT is not set correctly or not exported\n"+ 189 "\tGOROOT=%s\n"+ 190 "\t%s does not exist", goroot, p) 191 } 192 193 b = os.Getenv("GOHOSTARCH") 194 if b != "" { 195 gohostarch = b 196 } 197 if find(gohostarch, okgoarch) < 0 { 198 fatalf("unknown $GOHOSTARCH %s", gohostarch) 199 } 200 201 b = os.Getenv("GOARCH") 202 if b == "" { 203 b = gohostarch 204 } 205 goarch = b 206 if find(goarch, okgoarch) < 0 { 207 fatalf("unknown $GOARCH %s", goarch) 208 } 209 210 b = os.Getenv("GO_EXTLINK_ENABLED") 211 if b != "" { 212 if b != "0" && b != "1" { 213 fatalf("unknown $GO_EXTLINK_ENABLED %s", b) 214 } 215 goextlinkenabled = b 216 } 217 218 goexperiment = os.Getenv("GOEXPERIMENT") 219 // TODO(mdempsky): Validate known experiments? 220 221 gogcflags = os.Getenv("BOOT_GO_GCFLAGS") 222 goldflags = os.Getenv("BOOT_GO_LDFLAGS") 223 224 defaultcc = compilerEnv("CC", "") 225 defaultcxx = compilerEnv("CXX", "") 226 227 b = os.Getenv("PKG_CONFIG") 228 if b == "" { 229 b = "pkg-config" 230 } 231 defaultpkgconfig = b 232 233 defaultldso = os.Getenv("GO_LDSO") 234 235 // For tools being invoked but also for os.ExpandEnv. 236 os.Setenv("GO386", go386) 237 os.Setenv("GOAMD64", goamd64) 238 os.Setenv("GOARCH", goarch) 239 os.Setenv("GOARM", goarm) 240 os.Setenv("GOARM64", goarm64) 241 os.Setenv("GOHOSTARCH", gohostarch) 242 os.Setenv("GOHOSTOS", gohostos) 243 os.Setenv("GOOS", goos) 244 os.Setenv("GOMIPS", gomips) 245 os.Setenv("GOMIPS64", gomips64) 246 os.Setenv("GOPPC64", goppc64) 247 os.Setenv("GORISCV64", goriscv64) 248 os.Setenv("GOROOT", goroot) 249 250 // Set GOBIN to GOROOT/bin. The meaning of GOBIN has drifted over time 251 // (see https://go.dev/issue/3269, https://go.dev/cl/183058, 252 // https://go.dev/issue/31576). Since we want binaries installed by 'dist' to 253 // always go to GOROOT/bin anyway. 254 os.Setenv("GOBIN", gorootBin) 255 256 // Make the environment more predictable. 257 os.Setenv("LANG", "C") 258 os.Setenv("LANGUAGE", "en_US.UTF8") 259 os.Unsetenv("GO111MODULE") 260 os.Setenv("GOENV", "off") 261 os.Unsetenv("GOFLAGS") 262 os.Setenv("GOWORK", "off") 263 264 workdir = xworkdir() 265 if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap"), 0666); err != nil { 266 fatalf("cannot write stub go.mod: %s", err) 267 } 268 xatexit(rmworkdir) 269 270 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch) 271 272 goversion := findgoversion() 273 isRelease = strings.HasPrefix(goversion, "release.") || strings.HasPrefix(goversion, "go") 274} 275 276// compilerEnv returns a map from "goos/goarch" to the 277// compiler setting to use for that platform. 278// The entry for key "" covers any goos/goarch not explicitly set in the map. 279// For example, compilerEnv("CC", "gcc") returns the C compiler settings 280// read from $CC, defaulting to gcc. 281// 282// The result is a map because additional environment variables 283// can be set to change the compiler based on goos/goarch settings. 284// The following applies to all envNames but CC is assumed to simplify 285// the presentation. 286// 287// If no environment variables are set, we use def for all goos/goarch. 288// $CC, if set, applies to all goos/goarch but is overridden by the following. 289// $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch, 290// but is overridden by the following. 291// If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch. 292// $CC_FOR_goos_goarch, if set, applies only to goos/goarch. 293func compilerEnv(envName, def string) map[string]string { 294 m := map[string]string{"": def} 295 296 if env := os.Getenv(envName); env != "" { 297 m[""] = env 298 } 299 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" { 300 if gohostos != goos || gohostarch != goarch { 301 m[gohostos+"/"+gohostarch] = m[""] 302 } 303 m[""] = env 304 } 305 306 for _, goos := range okgoos { 307 for _, goarch := range okgoarch { 308 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" { 309 m[goos+"/"+goarch] = env 310 } 311 } 312 } 313 314 return m 315} 316 317// clangos lists the operating systems where we prefer clang to gcc. 318var clangos = []string{ 319 "darwin", "ios", // macOS 10.9 and later require clang 320 "freebsd", // FreeBSD 10 and later do not ship gcc 321 "openbsd", // OpenBSD ships with GCC 4.2, which is now quite old. 322} 323 324// compilerEnvLookup returns the compiler settings for goos/goarch in map m. 325// kind is "CC" or "CXX". 326func compilerEnvLookup(kind string, m map[string]string, goos, goarch string) string { 327 if !needCC() { 328 return "" 329 } 330 if cc := m[goos+"/"+goarch]; cc != "" { 331 return cc 332 } 333 if cc := m[""]; cc != "" { 334 return cc 335 } 336 for _, os := range clangos { 337 if goos == os { 338 if kind == "CXX" { 339 return "clang++" 340 } 341 return "clang" 342 } 343 } 344 if kind == "CXX" { 345 return "g++" 346 } 347 return "gcc" 348} 349 350// rmworkdir deletes the work directory. 351func rmworkdir() { 352 if vflag > 1 { 353 errprintf("rm -rf %s\n", workdir) 354 } 355 xremoveall(workdir) 356} 357 358// Remove trailing spaces. 359func chomp(s string) string { 360 return strings.TrimRight(s, " \t\r\n") 361} 362 363// findgoversion determines the Go version to use in the version string. 364// It also parses any other metadata found in the version file. 365func findgoversion() string { 366 // The $GOROOT/VERSION file takes priority, for distributions 367 // without the source repo. 368 path := pathf("%s/VERSION", goroot) 369 if isfile(path) { 370 b := chomp(readfile(path)) 371 372 // Starting in Go 1.21 the VERSION file starts with the 373 // version on a line by itself but then can contain other 374 // metadata about the release, one item per line. 375 if i := strings.Index(b, "\n"); i >= 0 { 376 rest := b[i+1:] 377 b = chomp(b[:i]) 378 for _, line := range strings.Split(rest, "\n") { 379 f := strings.Fields(line) 380 if len(f) == 0 { 381 continue 382 } 383 switch f[0] { 384 default: 385 fatalf("VERSION: unexpected line: %s", line) 386 case "time": 387 if len(f) != 2 { 388 fatalf("VERSION: unexpected time line: %s", line) 389 } 390 _, err := time.Parse(time.RFC3339, f[1]) 391 if err != nil { 392 fatalf("VERSION: bad time: %s", err) 393 } 394 } 395 } 396 } 397 398 // Commands such as "dist version > VERSION" will cause 399 // the shell to create an empty VERSION file and set dist's 400 // stdout to its fd. dist in turn looks at VERSION and uses 401 // its content if available, which is empty at this point. 402 // Only use the VERSION file if it is non-empty. 403 if b != "" { 404 return b 405 } 406 } 407 408 // The $GOROOT/VERSION.cache file is a cache to avoid invoking 409 // git every time we run this command. Unlike VERSION, it gets 410 // deleted by the clean command. 411 path = pathf("%s/VERSION.cache", goroot) 412 if isfile(path) { 413 return chomp(readfile(path)) 414 } 415 416 // Show a nicer error message if this isn't a Git repo. 417 if !isGitRepo() { 418 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT") 419 } 420 421 // Otherwise, use Git. 422 // 423 // Include 1.x base version, hash, and date in the version. 424 // 425 // Note that we lightly parse internal/goversion/goversion.go to 426 // obtain the base version. We can't just import the package, 427 // because cmd/dist is built with a bootstrap GOROOT which could 428 // be an entirely different version of Go. We assume 429 // that the file contains "const Version = <Integer>". 430 goversionSource := readfile(pathf("%s/src/internal/goversion/goversion.go", goroot)) 431 m := regexp.MustCompile(`(?m)^const Version = (\d+)`).FindStringSubmatch(goversionSource) 432 if m == nil { 433 fatalf("internal/goversion/goversion.go does not contain 'const Version = ...'") 434 } 435 version := fmt.Sprintf("devel go1.%s-", m[1]) 436 version += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format:%h %cd", "HEAD")) 437 438 // Cache version. 439 writefile(version, path, 0) 440 441 return version 442} 443 444// isGitRepo reports whether the working directory is inside a Git repository. 445func isGitRepo() bool { 446 // NB: simply checking the exit code of `git rev-parse --git-dir` would 447 // suffice here, but that requires deviating from the infrastructure 448 // provided by `run`. 449 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir")) 450 if !filepath.IsAbs(gitDir) { 451 gitDir = filepath.Join(goroot, gitDir) 452 } 453 return isdir(gitDir) 454} 455 456/* 457 * Initial tree setup. 458 */ 459 460// The old tools that no longer live in $GOBIN or $GOROOT/bin. 461var oldtool = []string{ 462 "5a", "5c", "5g", "5l", 463 "6a", "6c", "6g", "6l", 464 "8a", "8c", "8g", "8l", 465 "9a", "9c", "9g", "9l", 466 "6cov", 467 "6nm", 468 "6prof", 469 "cgo", 470 "ebnflint", 471 "goapi", 472 "gofix", 473 "goinstall", 474 "gomake", 475 "gopack", 476 "gopprof", 477 "gotest", 478 "gotype", 479 "govet", 480 "goyacc", 481 "quietgcc", 482} 483 484// Unreleased directories (relative to $GOROOT) that should 485// not be in release branches. 486var unreleased = []string{ 487 "src/cmd/newlink", 488 "src/cmd/objwriter", 489 "src/debug/goobj", 490 "src/old", 491} 492 493// setup sets up the tree for the initial build. 494func setup() { 495 // Create bin directory. 496 if p := pathf("%s/bin", goroot); !isdir(p) { 497 xmkdir(p) 498 } 499 500 // Create package directory. 501 if p := pathf("%s/pkg", goroot); !isdir(p) { 502 xmkdir(p) 503 } 504 505 goosGoarch := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch) 506 if rebuildall { 507 xremoveall(goosGoarch) 508 } 509 xmkdirall(goosGoarch) 510 xatexit(func() { 511 if files := xreaddir(goosGoarch); len(files) == 0 { 512 xremove(goosGoarch) 513 } 514 }) 515 516 if goos != gohostos || goarch != gohostarch { 517 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch) 518 if rebuildall { 519 xremoveall(p) 520 } 521 xmkdirall(p) 522 } 523 524 // Create object directory. 525 // We used to use it for C objects. 526 // Now we use it for the build cache, to separate dist's cache 527 // from any other cache the user might have, and for the location 528 // to build the bootstrap versions of the standard library. 529 obj := pathf("%s/pkg/obj", goroot) 530 if !isdir(obj) { 531 xmkdir(obj) 532 } 533 xatexit(func() { xremove(obj) }) 534 535 // Create build cache directory. 536 objGobuild := pathf("%s/pkg/obj/go-build", goroot) 537 if rebuildall { 538 xremoveall(objGobuild) 539 } 540 xmkdirall(objGobuild) 541 xatexit(func() { xremoveall(objGobuild) }) 542 543 // Create directory for bootstrap versions of standard library .a files. 544 objGoBootstrap := pathf("%s/pkg/obj/go-bootstrap", goroot) 545 if rebuildall { 546 xremoveall(objGoBootstrap) 547 } 548 xmkdirall(objGoBootstrap) 549 xatexit(func() { xremoveall(objGoBootstrap) }) 550 551 // Create tool directory. 552 // We keep it in pkg/, just like the object directory above. 553 if rebuildall { 554 xremoveall(tooldir) 555 } 556 xmkdirall(tooldir) 557 558 // Remove tool binaries from before the tool/gohostos_gohostarch 559 xremoveall(pathf("%s/bin/tool", goroot)) 560 561 // Remove old pre-tool binaries. 562 for _, old := range oldtool { 563 xremove(pathf("%s/bin/%s", goroot, old)) 564 } 565 566 // Special release-specific setup. 567 if isRelease { 568 // Make sure release-excluded things are excluded. 569 for _, dir := range unreleased { 570 if p := pathf("%s/%s", goroot, dir); isdir(p) { 571 fatalf("%s should not exist in release build", p) 572 } 573 } 574 } 575} 576 577/* 578 * Tool building 579 */ 580 581// mustLinkExternal is a copy of internal/platform.MustLinkExternal, 582// duplicated here to avoid version skew in the MustLinkExternal function 583// during bootstrapping. 584func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool { 585 if cgoEnabled { 586 switch goarch { 587 case "loong64", "mips", "mipsle", "mips64", "mips64le": 588 // Internally linking cgo is incomplete on some architectures. 589 // https://golang.org/issue/14449 590 return true 591 case "arm64": 592 if goos == "windows" { 593 // windows/arm64 internal linking is not implemented. 594 return true 595 } 596 case "ppc64": 597 // Big Endian PPC64 cgo internal linking is not implemented for aix or linux. 598 if goos == "aix" || goos == "linux" { 599 return true 600 } 601 } 602 603 switch goos { 604 case "android": 605 return true 606 case "dragonfly": 607 // It seems that on Dragonfly thread local storage is 608 // set up by the dynamic linker, so internal cgo linking 609 // doesn't work. Test case is "go test runtime/cgo". 610 return true 611 } 612 } 613 614 switch goos { 615 case "android": 616 if goarch != "arm64" { 617 return true 618 } 619 case "ios": 620 if goarch == "arm64" { 621 return true 622 } 623 } 624 return false 625} 626 627// depsuffix records the allowed suffixes for source files. 628var depsuffix = []string{ 629 ".s", 630 ".go", 631} 632 633// gentab records how to generate some trivial files. 634// Files listed here should also be listed in ../distpack/pack.go's srcArch.Remove list. 635var gentab = []struct { 636 pkg string // Relative to $GOROOT/src 637 file string 638 gen func(dir, file string) 639}{ 640 {"go/build", "zcgo.go", mkzcgo}, 641 {"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc}, 642 {"runtime/internal/sys", "zversion.go", mkzversion}, 643 {"time/tzdata", "zzipdata.go", mktzdata}, 644} 645 646// installed maps from a dir name (as given to install) to a chan 647// closed when the dir's package is installed. 648var installed = make(map[string]chan struct{}) 649var installedMu sync.Mutex 650 651func install(dir string) { 652 <-startInstall(dir) 653} 654 655func startInstall(dir string) chan struct{} { 656 installedMu.Lock() 657 ch := installed[dir] 658 if ch == nil { 659 ch = make(chan struct{}) 660 installed[dir] = ch 661 go runInstall(dir, ch) 662 } 663 installedMu.Unlock() 664 return ch 665} 666 667// runInstall installs the library, package, or binary associated with pkg, 668// which is relative to $GOROOT/src. 669func runInstall(pkg string, ch chan struct{}) { 670 if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" { 671 fatalf("go_bootstrap cannot depend on cgo package %s", pkg) 672 } 673 674 defer close(ch) 675 676 if pkg == "unsafe" { 677 return 678 } 679 680 if vflag > 0 { 681 if goos != gohostos || goarch != gohostarch { 682 errprintf("%s (%s/%s)\n", pkg, goos, goarch) 683 } else { 684 errprintf("%s\n", pkg) 685 } 686 } 687 688 workdir := pathf("%s/%s", workdir, pkg) 689 xmkdirall(workdir) 690 691 var clean []string 692 defer func() { 693 for _, name := range clean { 694 xremove(name) 695 } 696 }() 697 698 // dir = full path to pkg. 699 dir := pathf("%s/src/%s", goroot, pkg) 700 name := filepath.Base(dir) 701 702 // ispkg predicts whether the package should be linked as a binary, based 703 // on the name. There should be no "main" packages in vendor, since 704 // 'go mod vendor' will only copy imported packages there. 705 ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/") 706 707 // Start final link command line. 708 // Note: code below knows that link.p[targ] is the target. 709 var ( 710 link []string 711 targ int 712 ispackcmd bool 713 ) 714 if ispkg { 715 // Go library (package). 716 ispackcmd = true 717 link = []string{"pack", packagefile(pkg)} 718 targ = len(link) - 1 719 xmkdirall(filepath.Dir(link[targ])) 720 } else { 721 // Go command. 722 elem := name 723 if elem == "go" { 724 elem = "go_bootstrap" 725 } 726 link = []string{pathf("%s/link", tooldir)} 727 if goos == "android" { 728 link = append(link, "-buildmode=pie") 729 } 730 if goldflags != "" { 731 link = append(link, goldflags) 732 } 733 link = append(link, "-extld="+compilerEnvLookup("CC", defaultcc, goos, goarch)) 734 link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch)) 735 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe)) 736 targ = len(link) - 1 737 } 738 ttarg := mtime(link[targ]) 739 740 // Gather files that are sources for this target. 741 // Everything in that directory, and any target-specific 742 // additions. 743 files := xreaddir(dir) 744 745 // Remove files beginning with . or _, 746 // which are likely to be editor temporary files. 747 // This is the same heuristic build.ScanDir uses. 748 // There do exist real C files beginning with _, 749 // so limit that check to just Go files. 750 files = filter(files, func(p string) bool { 751 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go")) 752 }) 753 754 // Add generated files for this package. 755 for _, gt := range gentab { 756 if gt.pkg == pkg { 757 files = append(files, gt.file) 758 } 759 } 760 files = uniq(files) 761 762 // Convert to absolute paths. 763 for i, p := range files { 764 if !filepath.IsAbs(p) { 765 files[i] = pathf("%s/%s", dir, p) 766 } 767 } 768 769 // Is the target up-to-date? 770 var gofiles, sfiles []string 771 stale := rebuildall 772 files = filter(files, func(p string) bool { 773 for _, suf := range depsuffix { 774 if strings.HasSuffix(p, suf) { 775 goto ok 776 } 777 } 778 return false 779 ok: 780 t := mtime(p) 781 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) { 782 return false 783 } 784 if strings.HasSuffix(p, ".go") { 785 gofiles = append(gofiles, p) 786 } else if strings.HasSuffix(p, ".s") { 787 sfiles = append(sfiles, p) 788 } 789 if t.After(ttarg) { 790 stale = true 791 } 792 return true 793 }) 794 795 // If there are no files to compile, we're done. 796 if len(files) == 0 { 797 return 798 } 799 800 if !stale { 801 return 802 } 803 804 // For package runtime, copy some files into the work space. 805 if pkg == "runtime" { 806 xmkdirall(pathf("%s/pkg/include", goroot)) 807 // For use by assembly and C files. 808 copyfile(pathf("%s/pkg/include/textflag.h", goroot), 809 pathf("%s/src/runtime/textflag.h", goroot), 0) 810 copyfile(pathf("%s/pkg/include/funcdata.h", goroot), 811 pathf("%s/src/runtime/funcdata.h", goroot), 0) 812 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot), 813 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0) 814 copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot), 815 pathf("%s/src/runtime/asm_amd64.h", goroot), 0) 816 } 817 818 // Generate any missing files; regenerate existing ones. 819 for _, gt := range gentab { 820 if gt.pkg != pkg { 821 continue 822 } 823 p := pathf("%s/%s", dir, gt.file) 824 if vflag > 1 { 825 errprintf("generate %s\n", p) 826 } 827 gt.gen(dir, p) 828 // Do not add generated file to clean list. 829 // In runtime, we want to be able to 830 // build the package with the go tool, 831 // and it assumes these generated files already 832 // exist (it does not know how to build them). 833 // The 'clean' command can remove 834 // the generated files. 835 } 836 837 // Resolve imported packages to actual package paths. 838 // Make sure they're installed. 839 importMap := make(map[string]string) 840 for _, p := range gofiles { 841 for _, imp := range readimports(p) { 842 if imp == "C" { 843 fatalf("%s imports C", p) 844 } 845 importMap[imp] = resolveVendor(imp, dir) 846 } 847 } 848 sortedImports := make([]string, 0, len(importMap)) 849 for imp := range importMap { 850 sortedImports = append(sortedImports, imp) 851 } 852 sort.Strings(sortedImports) 853 854 for _, dep := range importMap { 855 if dep == "C" { 856 fatalf("%s imports C", pkg) 857 } 858 startInstall(dep) 859 } 860 for _, dep := range importMap { 861 install(dep) 862 } 863 864 if goos != gohostos || goarch != gohostarch { 865 // We've generated the right files; the go command can do the build. 866 if vflag > 1 { 867 errprintf("skip build for cross-compile %s\n", pkg) 868 } 869 return 870 } 871 872 asmArgs := []string{ 873 pathf("%s/asm", tooldir), 874 "-I", workdir, 875 "-I", pathf("%s/pkg/include", goroot), 876 "-D", "GOOS_" + goos, 877 "-D", "GOARCH_" + goarch, 878 "-D", "GOOS_GOARCH_" + goos + "_" + goarch, 879 "-p", pkg, 880 } 881 if goarch == "mips" || goarch == "mipsle" { 882 // Define GOMIPS_value from gomips. 883 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips) 884 } 885 if goarch == "mips64" || goarch == "mips64le" { 886 // Define GOMIPS64_value from gomips64. 887 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64) 888 } 889 if goarch == "ppc64" || goarch == "ppc64le" { 890 // We treat each powerpc version as a superset of functionality. 891 switch goppc64 { 892 case "power10": 893 asmArgs = append(asmArgs, "-D", "GOPPC64_power10") 894 fallthrough 895 case "power9": 896 asmArgs = append(asmArgs, "-D", "GOPPC64_power9") 897 fallthrough 898 default: // This should always be power8. 899 asmArgs = append(asmArgs, "-D", "GOPPC64_power8") 900 } 901 } 902 if goarch == "riscv64" { 903 // Define GORISCV64_value from goriscv64 904 asmArgs = append(asmArgs, "-D", "GORISCV64_"+goriscv64) 905 } 906 if goarch == "arm" { 907 // Define GOARM_value from goarm, which can be either a version 908 // like "6", or a version and a FP mode, like "7,hardfloat". 909 switch { 910 case strings.Contains(goarm, "7"): 911 asmArgs = append(asmArgs, "-D", "GOARM_7") 912 fallthrough 913 case strings.Contains(goarm, "6"): 914 asmArgs = append(asmArgs, "-D", "GOARM_6") 915 fallthrough 916 default: 917 asmArgs = append(asmArgs, "-D", "GOARM_5") 918 } 919 } 920 goasmh := pathf("%s/go_asm.h", workdir) 921 922 // Collect symabis from assembly code. 923 var symabis string 924 if len(sfiles) > 0 { 925 symabis = pathf("%s/symabis", workdir) 926 var wg sync.WaitGroup 927 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis) 928 asmabis = append(asmabis, sfiles...) 929 if err := os.WriteFile(goasmh, nil, 0666); err != nil { 930 fatalf("cannot write empty go_asm.h: %s", err) 931 } 932 bgrun(&wg, dir, asmabis...) 933 bgwait(&wg) 934 } 935 936 // Build an importcfg file for the compiler. 937 buf := &bytes.Buffer{} 938 for _, imp := range sortedImports { 939 if imp == "unsafe" { 940 continue 941 } 942 dep := importMap[imp] 943 if imp != dep { 944 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep) 945 } 946 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep)) 947 } 948 importcfg := pathf("%s/importcfg", workdir) 949 if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil { 950 fatalf("cannot write importcfg file: %v", err) 951 } 952 953 var archive string 954 // The next loop will compile individual non-Go files. 955 // Hand the Go files to the compiler en masse. 956 // For packages containing assembly, this writes go_asm.h, which 957 // the assembly files will need. 958 pkgName := pkg 959 if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 { 960 pkgName = "main" 961 } 962 b := pathf("%s/_go_.a", workdir) 963 clean = append(clean, b) 964 if !ispackcmd { 965 link = append(link, b) 966 } else { 967 archive = b 968 } 969 970 // Compile Go code. 971 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg} 972 if gogcflags != "" { 973 compile = append(compile, strings.Fields(gogcflags)...) 974 } 975 if len(sfiles) > 0 { 976 compile = append(compile, "-asmhdr", goasmh) 977 } 978 if symabis != "" { 979 compile = append(compile, "-symabis", symabis) 980 } 981 if goos == "android" { 982 compile = append(compile, "-shared") 983 } 984 985 compile = append(compile, gofiles...) 986 var wg sync.WaitGroup 987 // We use bgrun and immediately wait for it instead of calling run() synchronously. 988 // This executes all jobs through the bgwork channel and allows the process 989 // to exit cleanly in case an error occurs. 990 bgrun(&wg, dir, compile...) 991 bgwait(&wg) 992 993 // Compile the files. 994 for _, p := range sfiles { 995 // Assembly file for a Go package. 996 compile := asmArgs[:len(asmArgs):len(asmArgs)] 997 998 doclean := true 999 b := pathf("%s/%s", workdir, filepath.Base(p)) 1000 1001 // Change the last character of the output file (which was c or s). 1002 b = b[:len(b)-1] + "o" 1003 compile = append(compile, "-o", b, p) 1004 bgrun(&wg, dir, compile...) 1005 1006 link = append(link, b) 1007 if doclean { 1008 clean = append(clean, b) 1009 } 1010 } 1011 bgwait(&wg) 1012 1013 if ispackcmd { 1014 xremove(link[targ]) 1015 dopack(link[targ], archive, link[targ+1:]) 1016 return 1017 } 1018 1019 // Remove target before writing it. 1020 xremove(link[targ]) 1021 bgrun(&wg, "", link...) 1022 bgwait(&wg) 1023} 1024 1025// packagefile returns the path to a compiled .a file for the given package 1026// path. Paths may need to be resolved with resolveVendor first. 1027func packagefile(pkg string) string { 1028 return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg) 1029} 1030 1031// unixOS is the set of GOOS values matched by the "unix" build tag. 1032// This is the same list as in go/build/syslist.go and 1033// cmd/go/internal/imports/build.go. 1034var unixOS = map[string]bool{ 1035 "aix": true, 1036 "android": true, 1037 "darwin": true, 1038 "dragonfly": true, 1039 "freebsd": true, 1040 "hurd": true, 1041 "illumos": true, 1042 "ios": true, 1043 "linux": true, 1044 "netbsd": true, 1045 "openbsd": true, 1046 "solaris": true, 1047} 1048 1049// matchtag reports whether the tag matches this build. 1050func matchtag(tag string) bool { 1051 switch tag { 1052 case "gc", "cmd_go_bootstrap", "go1.1": 1053 return true 1054 case "linux": 1055 return goos == "linux" || goos == "android" 1056 case "solaris": 1057 return goos == "solaris" || goos == "illumos" 1058 case "darwin": 1059 return goos == "darwin" || goos == "ios" 1060 case goos, goarch: 1061 return true 1062 case "unix": 1063 return unixOS[goos] 1064 default: 1065 return false 1066 } 1067} 1068 1069// shouldbuild reports whether we should build this file. 1070// It applies the same rules that are used with context tags 1071// in package go/build, except it's less picky about the order 1072// of GOOS and GOARCH. 1073// We also allow the special tag cmd_go_bootstrap. 1074// See ../go/bootstrap.go and package go/build. 1075func shouldbuild(file, pkg string) bool { 1076 // Check file name for GOOS or GOARCH. 1077 name := filepath.Base(file) 1078 excluded := func(list []string, ok string) bool { 1079 for _, x := range list { 1080 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") { 1081 continue 1082 } 1083 i := strings.Index(name, x) 1084 if i <= 0 || name[i-1] != '_' { 1085 continue 1086 } 1087 i += len(x) 1088 if i == len(name) || name[i] == '.' || name[i] == '_' { 1089 return true 1090 } 1091 } 1092 return false 1093 } 1094 if excluded(okgoos, goos) || excluded(okgoarch, goarch) { 1095 return false 1096 } 1097 1098 // Omit test files. 1099 if strings.Contains(name, "_test") { 1100 return false 1101 } 1102 1103 // Check file contents for //go:build lines. 1104 for _, p := range strings.Split(readfile(file), "\n") { 1105 p = strings.TrimSpace(p) 1106 if p == "" { 1107 continue 1108 } 1109 code := p 1110 i := strings.Index(code, "//") 1111 if i > 0 { 1112 code = strings.TrimSpace(code[:i]) 1113 } 1114 if code == "package documentation" { 1115 return false 1116 } 1117 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" { 1118 return false 1119 } 1120 if !strings.HasPrefix(p, "//") { 1121 break 1122 } 1123 if strings.HasPrefix(p, "//go:build ") { 1124 matched, err := matchexpr(p[len("//go:build "):]) 1125 if err != nil { 1126 errprintf("%s: %v", file, err) 1127 } 1128 return matched 1129 } 1130 } 1131 1132 return true 1133} 1134 1135// copyfile copies the file src to dst, via memory (so only good for small files). 1136func copyfile(dst, src string, flag int) { 1137 if vflag > 1 { 1138 errprintf("cp %s %s\n", src, dst) 1139 } 1140 writefile(readfile(src), dst, flag) 1141} 1142 1143// dopack copies the package src to dst, 1144// appending the files listed in extra. 1145// The archive format is the traditional Unix ar format. 1146func dopack(dst, src string, extra []string) { 1147 bdst := bytes.NewBufferString(readfile(src)) 1148 for _, file := range extra { 1149 b := readfile(file) 1150 // find last path element for archive member name 1151 i := strings.LastIndex(file, "/") + 1 1152 j := strings.LastIndex(file, `\`) + 1 1153 if i < j { 1154 i = j 1155 } 1156 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b)) 1157 bdst.WriteString(b) 1158 if len(b)&1 != 0 { 1159 bdst.WriteByte(0) 1160 } 1161 } 1162 writefile(bdst.String(), dst, 0) 1163} 1164 1165func clean() { 1166 generated := []byte(generatedHeader) 1167 1168 // Remove generated source files. 1169 filepath.WalkDir(pathf("%s/src", goroot), func(path string, d fs.DirEntry, err error) error { 1170 switch { 1171 case err != nil: 1172 // ignore 1173 case d.IsDir() && (d.Name() == "vendor" || d.Name() == "testdata"): 1174 return filepath.SkipDir 1175 case d.IsDir() && d.Name() != "dist": 1176 // Remove generated binary named for directory, but not dist out from under us. 1177 exe := filepath.Join(path, d.Name()) 1178 if info, err := os.Stat(exe); err == nil && !info.IsDir() { 1179 xremove(exe) 1180 } 1181 xremove(exe + ".exe") 1182 case !d.IsDir() && strings.HasPrefix(d.Name(), "z"): 1183 // Remove generated file, identified by marker string. 1184 head := make([]byte, 512) 1185 if f, err := os.Open(path); err == nil { 1186 io.ReadFull(f, head) 1187 f.Close() 1188 } 1189 if bytes.HasPrefix(head, generated) { 1190 xremove(path) 1191 } 1192 } 1193 return nil 1194 }) 1195 1196 if rebuildall { 1197 // Remove object tree. 1198 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)) 1199 1200 // Remove installed packages and tools. 1201 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)) 1202 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch)) 1203 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch)) 1204 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch)) 1205 xremoveall(tooldir) 1206 1207 // Remove cached version info. 1208 xremove(pathf("%s/VERSION.cache", goroot)) 1209 1210 // Remove distribution packages. 1211 xremoveall(pathf("%s/pkg/distpack", goroot)) 1212 } 1213} 1214 1215/* 1216 * command implementations 1217 */ 1218 1219// The env command prints the default environment. 1220func cmdenv() { 1221 path := flag.Bool("p", false, "emit updated PATH") 1222 plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax") 1223 windows := flag.Bool("w", gohostos == "windows", "emit windows syntax") 1224 xflagparse(0) 1225 1226 format := "%s=\"%s\";\n" // Include ; to separate variables when 'dist env' output is used with eval. 1227 switch { 1228 case *plan9: 1229 format = "%s='%s'\n" 1230 case *windows: 1231 format = "set %s=%s\r\n" 1232 } 1233 1234 xprintf(format, "GO111MODULE", "") 1235 xprintf(format, "GOARCH", goarch) 1236 xprintf(format, "GOBIN", gorootBin) 1237 xprintf(format, "GODEBUG", os.Getenv("GODEBUG")) 1238 xprintf(format, "GOENV", "off") 1239 xprintf(format, "GOFLAGS", "") 1240 xprintf(format, "GOHOSTARCH", gohostarch) 1241 xprintf(format, "GOHOSTOS", gohostos) 1242 xprintf(format, "GOOS", goos) 1243 xprintf(format, "GOPROXY", os.Getenv("GOPROXY")) 1244 xprintf(format, "GOROOT", goroot) 1245 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR")) 1246 xprintf(format, "GOTOOLDIR", tooldir) 1247 if goarch == "arm" { 1248 xprintf(format, "GOARM", goarm) 1249 } 1250 if goarch == "arm64" { 1251 xprintf(format, "GOARM64", goarm64) 1252 } 1253 if goarch == "386" { 1254 xprintf(format, "GO386", go386) 1255 } 1256 if goarch == "amd64" { 1257 xprintf(format, "GOAMD64", goamd64) 1258 } 1259 if goarch == "mips" || goarch == "mipsle" { 1260 xprintf(format, "GOMIPS", gomips) 1261 } 1262 if goarch == "mips64" || goarch == "mips64le" { 1263 xprintf(format, "GOMIPS64", gomips64) 1264 } 1265 if goarch == "ppc64" || goarch == "ppc64le" { 1266 xprintf(format, "GOPPC64", goppc64) 1267 } 1268 if goarch == "riscv64" { 1269 xprintf(format, "GORISCV64", goriscv64) 1270 } 1271 xprintf(format, "GOWORK", "off") 1272 1273 if *path { 1274 sep := ":" 1275 if gohostos == "windows" { 1276 sep = ";" 1277 } 1278 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH"))) 1279 1280 // Also include $DIST_UNMODIFIED_PATH with the original $PATH 1281 // for the internal needs of "dist banner", along with export 1282 // so that it reaches the dist process. See its comment below. 1283 var exportFormat string 1284 if !*windows && !*plan9 { 1285 exportFormat = "export " + format 1286 } else { 1287 exportFormat = format 1288 } 1289 xprintf(exportFormat, "DIST_UNMODIFIED_PATH", os.Getenv("PATH")) 1290 } 1291} 1292 1293var ( 1294 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != "" 1295 timeLogMu sync.Mutex 1296 timeLogFile *os.File 1297 timeLogStart time.Time 1298) 1299 1300func timelog(op, name string) { 1301 if !timeLogEnabled { 1302 return 1303 } 1304 timeLogMu.Lock() 1305 defer timeLogMu.Unlock() 1306 if timeLogFile == nil { 1307 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666) 1308 if err != nil { 1309 log.Fatal(err) 1310 } 1311 buf := make([]byte, 100) 1312 n, _ := f.Read(buf) 1313 s := string(buf[:n]) 1314 if i := strings.Index(s, "\n"); i >= 0 { 1315 s = s[:i] 1316 } 1317 i := strings.Index(s, " start") 1318 if i < 0 { 1319 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE")) 1320 } 1321 t, err := time.Parse(time.UnixDate, s[:i]) 1322 if err != nil { 1323 log.Fatalf("cannot parse time log line %q: %v", s, err) 1324 } 1325 timeLogStart = t 1326 timeLogFile = f 1327 } 1328 t := time.Now() 1329 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name) 1330} 1331 1332// toolenv returns the environment to use when building commands in cmd. 1333// 1334// This is a function instead of a variable because the exact toolenv depends 1335// on the GOOS and GOARCH, and (at least for now) those are modified in place 1336// to switch between the host and target configurations when cross-compiling. 1337func toolenv() []string { 1338 var env []string 1339 if !mustLinkExternal(goos, goarch, false) { 1340 // Unless the platform requires external linking, 1341 // we disable cgo to get static binaries for cmd/go and cmd/pprof, 1342 // so that they work on systems without the same dynamic libraries 1343 // as the original build system. 1344 env = append(env, "CGO_ENABLED=0") 1345 } 1346 if isRelease || os.Getenv("GO_BUILDER_NAME") != "" { 1347 // Add -trimpath for reproducible builds of releases. 1348 // Include builders so that -trimpath is well-tested ahead of releases. 1349 // Do not include local development, so that people working in the 1350 // main branch for day-to-day work on the Go toolchain itself can 1351 // still have full paths for stack traces for compiler crashes and the like. 1352 env = append(env, "GOFLAGS=-trimpath -ldflags=-w -gcflags=cmd/...=-dwarf=false") 1353 } 1354 return env 1355} 1356 1357var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link", "cmd/preprofile"} 1358 1359// The bootstrap command runs a build from scratch, 1360// stopping at having installed the go_bootstrap command. 1361// 1362// WARNING: This command runs after cmd/dist is built with the Go bootstrap toolchain. 1363// It rebuilds and installs cmd/dist with the new toolchain, so other 1364// commands (like "go tool dist test" in run.bash) can rely on bug fixes 1365// made since the Go bootstrap version, but this function cannot. 1366func cmdbootstrap() { 1367 timelog("start", "dist bootstrap") 1368 defer timelog("end", "dist bootstrap") 1369 1370 var debug, distpack, force, noBanner, noClean bool 1371 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all") 1372 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process") 1373 flag.BoolVar(&distpack, "distpack", distpack, "write distribution files to pkg/distpack") 1374 flag.BoolVar(&force, "force", force, "build even if the port is marked as broken") 1375 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner") 1376 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning") 1377 1378 xflagparse(0) 1379 1380 if noClean { 1381 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n") 1382 } 1383 1384 // Don't build broken ports by default. 1385 if broken[goos+"/"+goarch] && !force { 1386 fatalf("build stopped because the port %s/%s is marked as broken\n\n"+ 1387 "Use the -force flag to build anyway.\n", goos, goarch) 1388 } 1389 1390 // Set GOPATH to an internal directory. We shouldn't actually 1391 // need to store files here, since the toolchain won't 1392 // depend on modules outside of vendor directories, but if 1393 // GOPATH points somewhere else (e.g., to GOROOT), the 1394 // go tool may complain. 1395 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot)) 1396 1397 // Set GOPROXY=off to avoid downloading modules to the modcache in 1398 // the GOPATH set above to be inside GOROOT. The modcache is read 1399 // only so if we downloaded to the modcache, we'd create readonly 1400 // files in GOROOT, which is undesirable. See #67463) 1401 os.Setenv("GOPROXY", "off") 1402 1403 // Use a build cache separate from the default user one. 1404 // Also one that will be wiped out during startup, so that 1405 // make.bash really does start from a clean slate. 1406 oldgocache = os.Getenv("GOCACHE") 1407 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) 1408 1409 // Disable GOEXPERIMENT when building toolchain1 and 1410 // go_bootstrap. We don't need any experiments for the 1411 // bootstrap toolchain, and this lets us avoid duplicating the 1412 // GOEXPERIMENT-related build logic from cmd/go here. If the 1413 // bootstrap toolchain is < Go 1.17, it will ignore this 1414 // anyway since GOEXPERIMENT is baked in; otherwise it will 1415 // pick it up from the environment we set here. Once we're 1416 // using toolchain1 with dist as the build system, we need to 1417 // override this to keep the experiments assumed by the 1418 // toolchain and by dist consistent. Once go_bootstrap takes 1419 // over the build process, we'll set this back to the original 1420 // GOEXPERIMENT. 1421 os.Setenv("GOEXPERIMENT", "none") 1422 1423 if debug { 1424 // cmd/buildid is used in debug mode. 1425 toolchain = append(toolchain, "cmd/buildid") 1426 } 1427 1428 if isdir(pathf("%s/src/pkg", goroot)) { 1429 fatalf("\n\n"+ 1430 "The Go package sources have moved to $GOROOT/src.\n"+ 1431 "*** %s still exists. ***\n"+ 1432 "It probably contains stale files that may confuse the build.\n"+ 1433 "Please (check what's there and) remove it and try again.\n"+ 1434 "See https://golang.org/s/go14nopkg\n", 1435 pathf("%s/src/pkg", goroot)) 1436 } 1437 1438 if rebuildall { 1439 clean() 1440 } 1441 1442 setup() 1443 1444 timelog("build", "toolchain1") 1445 checkCC() 1446 bootstrapBuildTools() 1447 1448 // Remember old content of $GOROOT/bin for comparison below. 1449 oldBinFiles, err := filepath.Glob(pathf("%s/bin/*", goroot)) 1450 if err != nil { 1451 fatalf("glob: %v", err) 1452 } 1453 1454 // For the main bootstrap, building for host os/arch. 1455 oldgoos = goos 1456 oldgoarch = goarch 1457 goos = gohostos 1458 goarch = gohostarch 1459 os.Setenv("GOHOSTARCH", gohostarch) 1460 os.Setenv("GOHOSTOS", gohostos) 1461 os.Setenv("GOARCH", goarch) 1462 os.Setenv("GOOS", goos) 1463 1464 timelog("build", "go_bootstrap") 1465 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n") 1466 install("runtime") // dependency not visible in sources; also sets up textflag.h 1467 install("time/tzdata") // no dependency in sources; creates generated file 1468 install("cmd/go") 1469 if vflag > 0 { 1470 xprintf("\n") 1471 } 1472 1473 gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now 1474 setNoOpt() 1475 goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now 1476 goBootstrap := pathf("%s/go_bootstrap", tooldir) 1477 if debug { 1478 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1479 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec) 1480 } 1481 1482 // To recap, so far we have built the new toolchain 1483 // (cmd/asm, cmd/cgo, cmd/compile, cmd/link) 1484 // using the Go bootstrap toolchain and go command. 1485 // Then we built the new go command (as go_bootstrap) 1486 // using the new toolchain and our own build logic (above). 1487 // 1488 // toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go) 1489 // go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist) 1490 // 1491 // The toolchain1 we built earlier is built from the new sources, 1492 // but because it was built using cmd/go it has no build IDs. 1493 // The eventually installed toolchain needs build IDs, so we need 1494 // to do another round: 1495 // 1496 // toolchain2 = mk(new toolchain, toolchain1, go_bootstrap) 1497 // 1498 timelog("build", "toolchain2") 1499 if vflag > 0 { 1500 xprintf("\n") 1501 } 1502 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n") 1503 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch)) 1504 // Now that cmd/go is in charge of the build process, enable GOEXPERIMENT. 1505 os.Setenv("GOEXPERIMENT", goexperiment) 1506 // No need to enable PGO for toolchain2. 1507 goInstall(toolenv(), goBootstrap, append([]string{"-pgo=off"}, toolchain...)...) 1508 if debug { 1509 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1510 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec) 1511 } 1512 1513 // Toolchain2 should be semantically equivalent to toolchain1, 1514 // but it was built using the newly built compiler instead of the Go bootstrap compiler, 1515 // so it should at the least run faster. Also, toolchain1 had no build IDs 1516 // in the binaries, while toolchain2 does. In non-release builds, the 1517 // toolchain's build IDs feed into constructing the build IDs of built targets, 1518 // so in non-release builds, everything now looks out-of-date due to 1519 // toolchain2 having build IDs - that is, due to the go command seeing 1520 // that there are new compilers. In release builds, the toolchain's reported 1521 // version is used in place of the build ID, and the go command does not 1522 // see that change from toolchain1 to toolchain2, so in release builds, 1523 // nothing looks out of date. 1524 // To keep the behavior the same in both non-release and release builds, 1525 // we force-install everything here. 1526 // 1527 // toolchain3 = mk(new toolchain, toolchain2, go_bootstrap) 1528 // 1529 timelog("build", "toolchain3") 1530 if vflag > 0 { 1531 xprintf("\n") 1532 } 1533 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n") 1534 goInstall(toolenv(), goBootstrap, append([]string{"-a"}, toolchain...)...) 1535 if debug { 1536 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1537 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec) 1538 } 1539 1540 // Now that toolchain3 has been built from scratch, its compiler and linker 1541 // should have accurate build IDs suitable for caching. 1542 // Now prime the build cache with the rest of the standard library for 1543 // testing, and so that the user can run 'go install std cmd' to quickly 1544 // iterate on local changes without waiting for a full rebuild. 1545 if _, err := os.Stat(pathf("%s/VERSION", goroot)); err == nil { 1546 // If we have a VERSION file, then we use the Go version 1547 // instead of build IDs as a cache key, and there is no guarantee 1548 // that code hasn't changed since the last time we ran a build 1549 // with this exact VERSION file (especially if someone is working 1550 // on a release branch). We must not fall back to the shared build cache 1551 // in this case. Leave $GOCACHE alone. 1552 } else { 1553 os.Setenv("GOCACHE", oldgocache) 1554 } 1555 1556 if goos == oldgoos && goarch == oldgoarch { 1557 // Common case - not setting up for cross-compilation. 1558 timelog("build", "toolchain") 1559 if vflag > 0 { 1560 xprintf("\n") 1561 } 1562 xprintf("Building packages and commands for %s/%s.\n", goos, goarch) 1563 } else { 1564 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH. 1565 // Finish GOHOSTOS/GOHOSTARCH installation and then 1566 // run GOOS/GOARCH installation. 1567 timelog("build", "host toolchain") 1568 if vflag > 0 { 1569 xprintf("\n") 1570 } 1571 xprintf("Building commands for host, %s/%s.\n", goos, goarch) 1572 goInstall(toolenv(), goBootstrap, "cmd") 1573 checkNotStale(toolenv(), goBootstrap, "cmd") 1574 checkNotStale(toolenv(), gorootBinGo, "cmd") 1575 1576 timelog("build", "target toolchain") 1577 if vflag > 0 { 1578 xprintf("\n") 1579 } 1580 goos = oldgoos 1581 goarch = oldgoarch 1582 os.Setenv("GOOS", goos) 1583 os.Setenv("GOARCH", goarch) 1584 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch)) 1585 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) 1586 } 1587 goInstall(nil, goBootstrap, "std") 1588 goInstall(toolenv(), goBootstrap, "cmd") 1589 checkNotStale(toolenv(), goBootstrap, toolchain...) 1590 checkNotStale(nil, goBootstrap, "std") 1591 checkNotStale(toolenv(), goBootstrap, "cmd") 1592 checkNotStale(nil, gorootBinGo, "std") 1593 checkNotStale(toolenv(), gorootBinGo, "cmd") 1594 if debug { 1595 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") 1596 checkNotStale(toolenv(), goBootstrap, toolchain...) 1597 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec) 1598 } 1599 1600 // Check that there are no new files in $GOROOT/bin other than 1601 // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling). 1602 binFiles, err := filepath.Glob(pathf("%s/bin/*", goroot)) 1603 if err != nil { 1604 fatalf("glob: %v", err) 1605 } 1606 1607 ok := map[string]bool{} 1608 for _, f := range oldBinFiles { 1609 ok[f] = true 1610 } 1611 for _, f := range binFiles { 1612 if gohostos == "darwin" && filepath.Base(f) == ".DS_Store" { 1613 continue // unfortunate but not unexpected 1614 } 1615 elem := strings.TrimSuffix(filepath.Base(f), ".exe") 1616 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch { 1617 fatalf("unexpected new file in $GOROOT/bin: %s", elem) 1618 } 1619 } 1620 1621 // Remove go_bootstrap now that we're done. 1622 xremove(pathf("%s/go_bootstrap"+exe, tooldir)) 1623 1624 if goos == "android" { 1625 // Make sure the exec wrapper will sync a fresh $GOROOT to the device. 1626 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir())) 1627 } 1628 1629 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" { 1630 oldcc := os.Getenv("CC") 1631 os.Setenv("GOOS", gohostos) 1632 os.Setenv("GOARCH", gohostarch) 1633 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, gohostos, gohostarch)) 1634 goCmd(nil, gorootBinGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath) 1635 // Restore environment. 1636 // TODO(elias.naur): support environment variables in goCmd? 1637 os.Setenv("GOOS", goos) 1638 os.Setenv("GOARCH", goarch) 1639 os.Setenv("CC", oldcc) 1640 } 1641 1642 if distpack { 1643 xprintf("Packaging archives for %s/%s.\n", goos, goarch) 1644 run("", ShowOutput|CheckExit, pathf("%s/distpack", tooldir)) 1645 } 1646 1647 // Print trailing banner unless instructed otherwise. 1648 if !noBanner { 1649 banner() 1650 } 1651} 1652 1653func wrapperPathFor(goos, goarch string) string { 1654 switch { 1655 case goos == "android": 1656 if gohostos != "android" { 1657 return pathf("%s/misc/go_android_exec/main.go", goroot) 1658 } 1659 case goos == "ios": 1660 if gohostos != "ios" { 1661 return pathf("%s/misc/ios/go_ios_exec.go", goroot) 1662 } 1663 } 1664 return "" 1665} 1666 1667func goInstall(env []string, goBinary string, args ...string) { 1668 goCmd(env, goBinary, "install", args...) 1669} 1670 1671func appendCompilerFlags(args []string) []string { 1672 if gogcflags != "" { 1673 args = append(args, "-gcflags=all="+gogcflags) 1674 } 1675 if goldflags != "" { 1676 args = append(args, "-ldflags=all="+goldflags) 1677 } 1678 return args 1679} 1680 1681func goCmd(env []string, goBinary string, cmd string, args ...string) { 1682 goCmd := []string{goBinary, cmd} 1683 if noOpt { 1684 goCmd = append(goCmd, "-tags=noopt") 1685 } 1686 goCmd = appendCompilerFlags(goCmd) 1687 if vflag > 0 { 1688 goCmd = append(goCmd, "-v") 1689 } 1690 1691 // Force only one process at a time on vx32 emulation. 1692 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" { 1693 goCmd = append(goCmd, "-p=1") 1694 } 1695 1696 runEnv(workdir, ShowOutput|CheckExit, env, append(goCmd, args...)...) 1697} 1698 1699func checkNotStale(env []string, goBinary string, targets ...string) { 1700 goCmd := []string{goBinary, "list"} 1701 if noOpt { 1702 goCmd = append(goCmd, "-tags=noopt") 1703 } 1704 goCmd = appendCompilerFlags(goCmd) 1705 goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}") 1706 1707 out := runEnv(workdir, CheckExit, env, append(goCmd, targets...)...) 1708 if strings.Contains(out, "\tSTALE ") { 1709 os.Setenv("GODEBUG", "gocachehash=1") 1710 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} { 1711 if strings.Contains(out, "STALE "+target) { 1712 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target) 1713 break 1714 } 1715 } 1716 fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v (consider rerunning with GOMAXPROCS=1 GODEBUG=gocachehash=1):\n%s", goBinary, gogcflags, goldflags, targets, out) 1717 } 1718} 1719 1720// Cannot use go/build directly because cmd/dist for a new release 1721// builds against an old release's go/build, which may be out of sync. 1722// To reduce duplication, we generate the list for go/build from this. 1723// 1724// We list all supported platforms in this list, so that this is the 1725// single point of truth for supported platforms. This list is used 1726// by 'go tool dist list'. 1727var cgoEnabled = map[string]bool{ 1728 "aix/ppc64": true, 1729 "darwin/amd64": true, 1730 "darwin/arm64": true, 1731 "dragonfly/amd64": true, 1732 "freebsd/386": true, 1733 "freebsd/amd64": true, 1734 "freebsd/arm": true, 1735 "freebsd/arm64": true, 1736 "freebsd/riscv64": true, 1737 "illumos/amd64": true, 1738 "linux/386": true, 1739 "linux/amd64": true, 1740 "linux/arm": true, 1741 "linux/arm64": true, 1742 "linux/loong64": true, 1743 "linux/ppc64": false, 1744 "linux/ppc64le": true, 1745 "linux/mips": true, 1746 "linux/mipsle": true, 1747 "linux/mips64": true, 1748 "linux/mips64le": true, 1749 "linux/riscv64": true, 1750 "linux/s390x": true, 1751 "linux/sparc64": true, 1752 "android/386": true, 1753 "android/amd64": true, 1754 "android/arm": true, 1755 "android/arm64": true, 1756 "ios/arm64": true, 1757 "ios/amd64": true, 1758 "js/wasm": false, 1759 "wasip1/wasm": false, 1760 "netbsd/386": true, 1761 "netbsd/amd64": true, 1762 "netbsd/arm": true, 1763 "netbsd/arm64": true, 1764 "openbsd/386": true, 1765 "openbsd/amd64": true, 1766 "openbsd/arm": true, 1767 "openbsd/arm64": true, 1768 "openbsd/mips64": true, 1769 "openbsd/ppc64": false, 1770 "openbsd/riscv64": true, 1771 "plan9/386": false, 1772 "plan9/amd64": false, 1773 "plan9/arm": false, 1774 "solaris/amd64": true, 1775 "windows/386": true, 1776 "windows/amd64": true, 1777 "windows/arm": false, 1778 "windows/arm64": true, 1779} 1780 1781// List of platforms that are marked as broken ports. 1782// These require -force flag to build, and also 1783// get filtered out of cgoEnabled for 'dist list'. 1784// See go.dev/issue/56679. 1785var broken = map[string]bool{ 1786 "linux/sparc64": true, // An incomplete port. See CL 132155. 1787 "openbsd/mips64": true, // Broken: go.dev/issue/58110. 1788} 1789 1790// List of platforms which are first class ports. See go.dev/issue/38874. 1791var firstClass = map[string]bool{ 1792 "darwin/amd64": true, 1793 "darwin/arm64": true, 1794 "linux/386": true, 1795 "linux/amd64": true, 1796 "linux/arm": true, 1797 "linux/arm64": true, 1798 "windows/386": true, 1799 "windows/amd64": true, 1800} 1801 1802// We only need CC if cgo is forced on, or if the platform requires external linking. 1803// Otherwise the go command will automatically disable it. 1804func needCC() bool { 1805 return os.Getenv("CGO_ENABLED") == "1" || mustLinkExternal(gohostos, gohostarch, false) 1806} 1807 1808func checkCC() { 1809 if !needCC() { 1810 return 1811 } 1812 cc1 := defaultcc[""] 1813 if cc1 == "" { 1814 cc1 = "gcc" 1815 for _, os := range clangos { 1816 if gohostos == os { 1817 cc1 = "clang" 1818 break 1819 } 1820 } 1821 } 1822 cc, err := quotedSplit(cc1) 1823 if err != nil { 1824 fatalf("split CC: %v", err) 1825 } 1826 var ccHelp = append(cc, "--help") 1827 1828 if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil { 1829 outputHdr := "" 1830 if len(output) > 0 { 1831 outputHdr = "\nCommand output:\n\n" 1832 } 1833 fatalf("cannot invoke C compiler %q: %v\n\n"+ 1834 "Go needs a system C compiler for use with cgo.\n"+ 1835 "To set a C compiler, set CC=the-compiler.\n"+ 1836 "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output) 1837 } 1838} 1839 1840func defaulttarg() string { 1841 // xgetwd might return a path with symlinks fully resolved, and if 1842 // there happens to be symlinks in goroot, then the hasprefix test 1843 // will never succeed. Instead, we use xrealwd to get a canonical 1844 // goroot/src before the comparison to avoid this problem. 1845 pwd := xgetwd() 1846 src := pathf("%s/src/", goroot) 1847 real_src := xrealwd(src) 1848 if !strings.HasPrefix(pwd, real_src) { 1849 fatalf("current directory %s is not under %s", pwd, real_src) 1850 } 1851 pwd = pwd[len(real_src):] 1852 // guard against xrealwd returning the directory without the trailing / 1853 pwd = strings.TrimPrefix(pwd, "/") 1854 1855 return pwd 1856} 1857 1858// Install installs the list of packages named on the command line. 1859func cmdinstall() { 1860 xflagparse(-1) 1861 1862 if flag.NArg() == 0 { 1863 install(defaulttarg()) 1864 } 1865 1866 for _, arg := range flag.Args() { 1867 install(arg) 1868 } 1869} 1870 1871// Clean deletes temporary objects. 1872func cmdclean() { 1873 xflagparse(0) 1874 clean() 1875} 1876 1877// Banner prints the 'now you've installed Go' banner. 1878func cmdbanner() { 1879 xflagparse(0) 1880 banner() 1881} 1882 1883func banner() { 1884 if vflag > 0 { 1885 xprintf("\n") 1886 } 1887 xprintf("---\n") 1888 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot) 1889 xprintf("Installed commands in %s\n", gorootBin) 1890 1891 if gohostos == "plan9" { 1892 // Check that GOROOT/bin is bound before /bin. 1893 pid := strings.Replace(readfile("#c/pid"), " ", "", -1) 1894 ns := fmt.Sprintf("/proc/%s/ns", pid) 1895 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) { 1896 xprintf("*** You need to bind %s before /bin.\n", gorootBin) 1897 } 1898 } else { 1899 // Check that GOROOT/bin appears in $PATH. 1900 pathsep := ":" 1901 if gohostos == "windows" { 1902 pathsep = ";" 1903 } 1904 path := os.Getenv("PATH") 1905 if p, ok := os.LookupEnv("DIST_UNMODIFIED_PATH"); ok { 1906 // Scripts that modify $PATH and then run dist should also provide 1907 // dist with an unmodified copy of $PATH via $DIST_UNMODIFIED_PATH. 1908 // Use it here when determining if the user still needs to update 1909 // their $PATH. See go.dev/issue/42563. 1910 path = p 1911 } 1912 if !strings.Contains(pathsep+path+pathsep, pathsep+gorootBin+pathsep) { 1913 xprintf("*** You need to add %s to your PATH.\n", gorootBin) 1914 } 1915 } 1916} 1917 1918// Version prints the Go version. 1919func cmdversion() { 1920 xflagparse(0) 1921 xprintf("%s\n", findgoversion()) 1922} 1923 1924// cmdlist lists all supported platforms. 1925func cmdlist() { 1926 jsonFlag := flag.Bool("json", false, "produce JSON output") 1927 brokenFlag := flag.Bool("broken", false, "include broken ports") 1928 xflagparse(0) 1929 1930 var plats []string 1931 for p := range cgoEnabled { 1932 if broken[p] && !*brokenFlag { 1933 continue 1934 } 1935 plats = append(plats, p) 1936 } 1937 sort.Strings(plats) 1938 1939 if !*jsonFlag { 1940 for _, p := range plats { 1941 xprintf("%s\n", p) 1942 } 1943 return 1944 } 1945 1946 type jsonResult struct { 1947 GOOS string 1948 GOARCH string 1949 CgoSupported bool 1950 FirstClass bool 1951 Broken bool `json:",omitempty"` 1952 } 1953 var results []jsonResult 1954 for _, p := range plats { 1955 fields := strings.Split(p, "/") 1956 results = append(results, jsonResult{ 1957 GOOS: fields[0], 1958 GOARCH: fields[1], 1959 CgoSupported: cgoEnabled[p], 1960 FirstClass: firstClass[p], 1961 Broken: broken[p], 1962 }) 1963 } 1964 out, err := json.MarshalIndent(results, "", "\t") 1965 if err != nil { 1966 fatalf("json marshal error: %v", err) 1967 } 1968 if _, err := os.Stdout.Write(out); err != nil { 1969 fatalf("write failed: %v", err) 1970 } 1971} 1972 1973func setNoOpt() { 1974 for _, gcflag := range strings.Split(gogcflags, " ") { 1975 if gcflag == "-N" || gcflag == "-l" { 1976 noOpt = true 1977 break 1978 } 1979 } 1980} 1981