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.
25 // Initialization for any invocation.
27 // The usual variables.
43 goextlinkenabled string
44 gogcflags string // For running built compiler
53 defaultcc map[string]string
54 defaultcxx map[string]string
55 defaultpkgconfig string
62 vflag int // verbosity
65 // The known architectures.
66 var okgoarch = []string{
84 // The known operating systems.
85 var okgoos = []string{
104 // find reports the first index of p in l[0:n], or else -1.
105 func find(p string, l []string) int {
106 for i, s := range l {
114 // xinit handles initialization of the various global state, like goroot and goarch.
116 b := os.Getenv("GOROOT")
118 fatalf("$GOROOT must be set")
120 goroot = filepath.Clean(b)
121 gorootBin = pathf("%s/bin", goroot)
123 // Don't run just 'go' because the build infrastructure
124 // runs cmd/dist inside go/bin often, and on Windows
125 // it will be found in the current directory and refuse to exec.
126 // All exec calls rewrite "go" into gorootBinGo.
127 gorootBinGo = pathf("%s/bin/go", goroot)
129 b = os.Getenv("GOROOT_FINAL")
135 b = os.Getenv("GOOS")
140 if find(goos, okgoos) < 0 {
141 fatalf("unknown $GOOS %s", goos)
144 b = os.Getenv("GOARM")
150 b = os.Getenv("GO386")
156 b = os.Getenv("GOAMD64")
162 b = os.Getenv("GOMIPS")
168 b = os.Getenv("GOMIPS64")
174 b = os.Getenv("GOPPC64")
180 if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
181 fatalf("$GOROOT is not set correctly or not exported\n"+
183 "\t%s does not exist", goroot, p)
186 b = os.Getenv("GOHOSTARCH")
190 if find(gohostarch, okgoarch) < 0 {
191 fatalf("unknown $GOHOSTARCH %s", gohostarch)
194 b = os.Getenv("GOARCH")
199 if find(goarch, okgoarch) < 0 {
200 fatalf("unknown $GOARCH %s", goarch)
203 b = os.Getenv("GO_EXTLINK_ENABLED")
205 if b != "0" && b != "1" {
206 fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
211 goexperiment = os.Getenv("GOEXPERIMENT")
212 // TODO(mdempsky): Validate known experiments?
214 gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
215 goldflags = os.Getenv("BOOT_GO_LDFLAGS")
217 defaultcc = compilerEnv("CC", "")
218 defaultcxx = compilerEnv("CXX", "")
220 b = os.Getenv("PKG_CONFIG")
226 defaultldso = os.Getenv("GO_LDSO")
228 // For tools being invoked but also for os.ExpandEnv.
229 os.Setenv("GO386", go386)
230 os.Setenv("GOAMD64", goamd64)
231 os.Setenv("GOARCH", goarch)
232 os.Setenv("GOARM", goarm)
233 os.Setenv("GOHOSTARCH", gohostarch)
234 os.Setenv("GOHOSTOS", gohostos)
235 os.Setenv("GOOS", goos)
236 os.Setenv("GOMIPS", gomips)
237 os.Setenv("GOMIPS64", gomips64)
238 os.Setenv("GOPPC64", goppc64)
239 os.Setenv("GOROOT", goroot)
240 os.Setenv("GOROOT_FINAL", goroot_final)
242 // Set GOBIN to GOROOT/bin. The meaning of GOBIN has drifted over time
243 // (see https://go.dev/issue/3269, https://go.dev/cl/183058,
244 // https://go.dev/issue/31576). Since we want binaries installed by 'dist' to
245 // always go to GOROOT/bin anyway.
246 os.Setenv("GOBIN", gorootBin)
248 // Make the environment more predictable.
249 os.Setenv("LANG", "C")
250 os.Setenv("LANGUAGE", "en_US.UTF8")
251 os.Unsetenv("GO111MODULE")
252 os.Setenv("GOENV", "off")
253 os.Unsetenv("GOFLAGS")
254 os.Setenv("GOWORK", "off")
257 if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap"), 0666); err != nil {
258 fatalf("cannot write stub go.mod: %s", err)
262 tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
264 goversion := findgoversion()
265 isRelease = strings.HasPrefix(goversion, "release.") || strings.HasPrefix(goversion, "go")
268 // compilerEnv returns a map from "goos/goarch" to the
269 // compiler setting to use for that platform.
270 // The entry for key "" covers any goos/goarch not explicitly set in the map.
271 // For example, compilerEnv("CC", "gcc") returns the C compiler settings
272 // read from $CC, defaulting to gcc.
274 // The result is a map because additional environment variables
275 // can be set to change the compiler based on goos/goarch settings.
276 // The following applies to all envNames but CC is assumed to simplify
279 // If no environment variables are set, we use def for all goos/goarch.
280 // $CC, if set, applies to all goos/goarch but is overridden by the following.
281 // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
282 // but is overridden by the following.
283 // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
284 // $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
285 func compilerEnv(envName, def string) map[string]string {
286 m := map[string]string{"": def}
288 if env := os.Getenv(envName); env != "" {
291 if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
292 if gohostos != goos || gohostarch != goarch {
293 m[gohostos+"/"+gohostarch] = m[""]
298 for _, goos := range okgoos {
299 for _, goarch := range okgoarch {
300 if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
301 m[goos+"/"+goarch] = env
309 // clangos lists the operating systems where we prefer clang to gcc.
310 var clangos = []string{
311 "darwin", "ios", // macOS 10.9 and later require clang
312 "freebsd", // FreeBSD 10 and later do not ship gcc
313 "openbsd", // OpenBSD ships with GCC 4.2, which is now quite old.
316 // compilerEnvLookup returns the compiler settings for goos/goarch in map m.
317 // kind is "CC" or "CXX".
318 func compilerEnvLookup(kind string, m map[string]string, goos, goarch string) string {
322 if cc := m[goos+"/"+goarch]; cc != "" {
325 if cc := m[""]; cc != "" {
328 for _, os := range clangos {
342 // rmworkdir deletes the work directory.
345 errprintf("rm -rf %s\n", workdir)
350 // Remove trailing spaces.
351 func chomp(s string) string {
352 return strings.TrimRight(s, " \t\r\n")
355 // findgoversion determines the Go version to use in the version string.
356 // It also parses any other metadata found in the version file.
357 func findgoversion() string {
358 // The $GOROOT/VERSION file takes priority, for distributions
359 // without the source repo.
360 path := pathf("%s/VERSION", goroot)
362 b := chomp(readfile(path))
364 // Starting in Go 1.21 the VERSION file starts with the
365 // version on a line by itself but then can contain other
366 // metadata about the release, one item per line.
367 if i := strings.Index(b, "\n"); i >= 0 {
370 for _, line := range strings.Split(rest, "\n") {
371 f := strings.Fields(line)
377 fatalf("VERSION: unexpected line: %s", line)
380 fatalf("VERSION: unexpected time line: %s", line)
382 _, err := time.Parse(time.RFC3339, f[1])
384 fatalf("VERSION: bad time: %s", err)
390 // Commands such as "dist version > VERSION" will cause
391 // the shell to create an empty VERSION file and set dist's
392 // stdout to its fd. dist in turn looks at VERSION and uses
393 // its content if available, which is empty at this point.
394 // Only use the VERSION file if it is non-empty.
400 // The $GOROOT/VERSION.cache file is a cache to avoid invoking
401 // git every time we run this command. Unlike VERSION, it gets
402 // deleted by the clean command.
403 path = pathf("%s/VERSION.cache", goroot)
405 return chomp(readfile(path))
408 // Show a nicer error message if this isn't a Git repo.
410 fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
413 // Otherwise, use Git.
415 // Include 1.x base version, hash, and date in the version.
417 // Note that we lightly parse internal/goversion/goversion.go to
418 // obtain the base version. We can't just import the package,
419 // because cmd/dist is built with a bootstrap GOROOT which could
420 // be an entirely different version of Go. We assume
421 // that the file contains "const Version = <Integer>".
422 goversionSource := readfile(pathf("%s/src/internal/goversion/goversion.go", goroot))
423 m := regexp.MustCompile(`(?m)^const Version = (\d+)`).FindStringSubmatch(goversionSource)
425 fatalf("internal/goversion/goversion.go does not contain 'const Version = ...'")
427 version := fmt.Sprintf("devel go1.%s-", m[1])
428 version += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format:%h %cd", "HEAD"))
431 writefile(version, path, 0)
436 // isGitRepo reports whether the working directory is inside a Git repository.
437 func isGitRepo() bool {
438 // NB: simply checking the exit code of `git rev-parse --git-dir` would
439 // suffice here, but that requires deviating from the infrastructure
440 // provided by `run`.
441 gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
442 if !filepath.IsAbs(gitDir) {
443 gitDir = filepath.Join(goroot, gitDir)
449 * Initial tree setup.
452 // The old tools that no longer live in $GOBIN or $GOROOT/bin.
453 var oldtool = []string{
454 "5a", "5c", "5g", "5l",
455 "6a", "6c", "6g", "6l",
456 "8a", "8c", "8g", "8l",
457 "9a", "9c", "9g", "9l",
476 // Unreleased directories (relative to $GOROOT) that should
477 // not be in release branches.
478 var unreleased = []string{
485 // setup sets up the tree for the initial build.
487 // Create bin directory.
488 if p := pathf("%s/bin", goroot); !isdir(p) {
492 // Create package directory.
493 if p := pathf("%s/pkg", goroot); !isdir(p) {
497 goosGoarch := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
499 xremoveall(goosGoarch)
501 xmkdirall(goosGoarch)
503 if files := xreaddir(goosGoarch); len(files) == 0 {
508 if goos != gohostos || goarch != gohostarch {
509 p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
516 // Create object directory.
517 // We used to use it for C objects.
518 // Now we use it for the build cache, to separate dist's cache
519 // from any other cache the user might have, and for the location
520 // to build the bootstrap versions of the standard library.
521 obj := pathf("%s/pkg/obj", goroot)
525 xatexit(func() { xremove(obj) })
527 // Create build cache directory.
528 objGobuild := pathf("%s/pkg/obj/go-build", goroot)
530 xremoveall(objGobuild)
532 xmkdirall(objGobuild)
533 xatexit(func() { xremoveall(objGobuild) })
535 // Create directory for bootstrap versions of standard library .a files.
536 objGoBootstrap := pathf("%s/pkg/obj/go-bootstrap", goroot)
538 xremoveall(objGoBootstrap)
540 xmkdirall(objGoBootstrap)
541 xatexit(func() { xremoveall(objGoBootstrap) })
543 // Create tool directory.
544 // We keep it in pkg/, just like the object directory above.
550 // Remove tool binaries from before the tool/gohostos_gohostarch
551 xremoveall(pathf("%s/bin/tool", goroot))
553 // Remove old pre-tool binaries.
554 for _, old := range oldtool {
555 xremove(pathf("%s/bin/%s", goroot, old))
558 // Special release-specific setup.
560 // Make sure release-excluded things are excluded.
561 for _, dir := range unreleased {
562 if p := pathf("%s/%s", goroot, dir); isdir(p) {
563 fatalf("%s should not exist in release build", p)
573 // mustLinkExternal is a copy of internal/platform.MustLinkExternal,
574 // duplicated here to avoid version skew in the MustLinkExternal function
575 // during bootstrapping.
576 func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
580 "mips", "mipsle", "mips64", "mips64le",
582 // Internally linking cgo is incomplete on some architectures.
583 // https://golang.org/issue/14449
586 if goos == "windows" {
587 // windows/arm64 internal linking is not implemented.
591 // Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
599 // It seems that on Dragonfly thread local storage is
600 // set up by the dynamic linker, so internal cgo linking
601 // doesn't work. Test case is "go test runtime/cgo".
608 if goarch != "arm64" {
612 if goarch == "arm64" {
619 // depsuffix records the allowed suffixes for source files.
620 var depsuffix = []string{
625 // gentab records how to generate some trivial files.
626 // Files listed here should also be listed in ../distpack/pack.go's srcArch.Remove list.
627 var gentab = []struct {
628 pkg string // Relative to $GOROOT/src
630 gen func(dir, file string)
632 {"go/build", "zcgo.go", mkzcgo},
633 {"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc},
634 {"runtime/internal/sys", "zversion.go", mkzversion},
635 {"time/tzdata", "zzipdata.go", mktzdata},
638 // installed maps from a dir name (as given to install) to a chan
639 // closed when the dir's package is installed.
640 var installed = make(map[string]chan struct{})
641 var installedMu sync.Mutex
643 func install(dir string) {
647 func startInstall(dir string) chan struct{} {
651 ch = make(chan struct{})
653 go runInstall(dir, ch)
659 // runInstall installs the library, package, or binary associated with pkg,
660 // which is relative to $GOROOT/src.
661 func runInstall(pkg string, ch chan struct{}) {
662 if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
663 fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
673 if goos != gohostos || goarch != gohostarch {
674 errprintf("%s (%s/%s)\n", pkg, goos, goarch)
676 errprintf("%s\n", pkg)
680 workdir := pathf("%s/%s", workdir, pkg)
685 for _, name := range clean {
690 // dir = full path to pkg.
691 dir := pathf("%s/src/%s", goroot, pkg)
692 name := filepath.Base(dir)
694 // ispkg predicts whether the package should be linked as a binary, based
695 // on the name. There should be no "main" packages in vendor, since
696 // 'go mod vendor' will only copy imported packages there.
697 ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
699 // Start final link command line.
700 // Note: code below knows that link.p[targ] is the target.
707 // Go library (package).
709 link = []string{"pack", packagefile(pkg)}
711 xmkdirall(filepath.Dir(link[targ]))
716 elem = "go_bootstrap"
718 link = []string{pathf("%s/link", tooldir)}
719 if goos == "android" {
720 link = append(link, "-buildmode=pie")
723 link = append(link, goldflags)
725 link = append(link, "-extld="+compilerEnvLookup("CC", defaultcc, goos, goarch))
726 link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch))
727 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
730 ttarg := mtime(link[targ])
732 // Gather files that are sources for this target.
733 // Everything in that directory, and any target-specific
735 files := xreaddir(dir)
737 // Remove files beginning with . or _,
738 // which are likely to be editor temporary files.
739 // This is the same heuristic build.ScanDir uses.
740 // There do exist real C files beginning with _,
741 // so limit that check to just Go files.
742 files = filter(files, func(p string) bool {
743 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
746 // Add generated files for this package.
747 for _, gt := range gentab {
749 files = append(files, gt.file)
754 // Convert to absolute paths.
755 for i, p := range files {
756 if !filepath.IsAbs(p) {
757 files[i] = pathf("%s/%s", dir, p)
761 // Is the target up-to-date?
762 var gofiles, sfiles []string
764 files = filter(files, func(p string) bool {
765 for _, suf := range depsuffix {
766 if strings.HasSuffix(p, suf) {
773 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
776 if strings.HasSuffix(p, ".go") {
777 gofiles = append(gofiles, p)
778 } else if strings.HasSuffix(p, ".s") {
779 sfiles = append(sfiles, p)
787 // If there are no files to compile, we're done.
796 // For package runtime, copy some files into the work space.
797 if pkg == "runtime" {
798 xmkdirall(pathf("%s/pkg/include", goroot))
799 // For use by assembly and C files.
800 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
801 pathf("%s/src/runtime/textflag.h", goroot), 0)
802 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
803 pathf("%s/src/runtime/funcdata.h", goroot), 0)
804 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
805 pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
806 copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot),
807 pathf("%s/src/runtime/asm_amd64.h", goroot), 0)
810 // Generate any missing files; regenerate existing ones.
811 for _, gt := range gentab {
815 p := pathf("%s/%s", dir, gt.file)
817 errprintf("generate %s\n", p)
820 // Do not add generated file to clean list.
821 // In runtime, we want to be able to
822 // build the package with the go tool,
823 // and it assumes these generated files already
824 // exist (it does not know how to build them).
825 // The 'clean' command can remove
826 // the generated files.
829 // Resolve imported packages to actual package paths.
830 // Make sure they're installed.
831 importMap := make(map[string]string)
832 for _, p := range gofiles {
833 for _, imp := range readimports(p) {
835 fatalf("%s imports C", p)
837 importMap[imp] = resolveVendor(imp, dir)
840 sortedImports := make([]string, 0, len(importMap))
841 for imp := range importMap {
842 sortedImports = append(sortedImports, imp)
844 sort.Strings(sortedImports)
846 for _, dep := range importMap {
848 fatalf("%s imports C", pkg)
852 for _, dep := range importMap {
856 if goos != gohostos || goarch != gohostarch {
857 // We've generated the right files; the go command can do the build.
859 errprintf("skip build for cross-compile %s\n", pkg)
865 pathf("%s/asm", tooldir),
867 "-I", pathf("%s/pkg/include", goroot),
868 "-D", "GOOS_" + goos,
869 "-D", "GOARCH_" + goarch,
870 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
873 if goarch == "mips" || goarch == "mipsle" {
874 // Define GOMIPS_value from gomips.
875 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
877 if goarch == "mips64" || goarch == "mips64le" {
878 // Define GOMIPS64_value from gomips64.
879 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
881 if goarch == "ppc64" || goarch == "ppc64le" {
882 // We treat each powerpc version as a superset of functionality.
885 asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
888 asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
890 default: // This should always be power8.
891 asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
894 goasmh := pathf("%s/go_asm.h", workdir)
895 if IsRuntimePackagePath(pkg) {
896 asmArgs = append(asmArgs, "-compiling-runtime")
899 // Collect symabis from assembly code.
902 symabis = pathf("%s/symabis", workdir)
903 var wg sync.WaitGroup
904 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
905 asmabis = append(asmabis, sfiles...)
906 if err := os.WriteFile(goasmh, nil, 0666); err != nil {
907 fatalf("cannot write empty go_asm.h: %s", err)
909 bgrun(&wg, dir, asmabis...)
913 // Build an importcfg file for the compiler.
914 buf := &bytes.Buffer{}
915 for _, imp := range sortedImports {
919 dep := importMap[imp]
921 fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
923 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
925 importcfg := pathf("%s/importcfg", workdir)
926 if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
927 fatalf("cannot write importcfg file: %v", err)
931 // The next loop will compile individual non-Go files.
932 // Hand the Go files to the compiler en masse.
933 // For packages containing assembly, this writes go_asm.h, which
934 // the assembly files will need.
936 if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
939 b := pathf("%s/_go_.a", workdir)
940 clean = append(clean, b)
942 link = append(link, b)
948 compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
950 compile = append(compile, strings.Fields(gogcflags)...)
952 if pkg == "runtime" {
953 compile = append(compile, "-+")
956 compile = append(compile, "-asmhdr", goasmh)
959 compile = append(compile, "-symabis", symabis)
961 if goos == "android" {
962 compile = append(compile, "-shared")
965 compile = append(compile, gofiles...)
966 var wg sync.WaitGroup
967 // We use bgrun and immediately wait for it instead of calling run() synchronously.
968 // This executes all jobs through the bgwork channel and allows the process
969 // to exit cleanly in case an error occurs.
970 bgrun(&wg, dir, compile...)
973 // Compile the files.
974 for _, p := range sfiles {
975 // Assembly file for a Go package.
976 compile := asmArgs[:len(asmArgs):len(asmArgs)]
979 b := pathf("%s/%s", workdir, filepath.Base(p))
981 // Change the last character of the output file (which was c or s).
982 b = b[:len(b)-1] + "o"
983 compile = append(compile, "-o", b, p)
984 bgrun(&wg, dir, compile...)
986 link = append(link, b)
988 clean = append(clean, b)
995 dopack(link[targ], archive, link[targ+1:])
999 // Remove target before writing it.
1001 bgrun(&wg, "", link...)
1005 // packagefile returns the path to a compiled .a file for the given package
1006 // path. Paths may need to be resolved with resolveVendor first.
1007 func packagefile(pkg string) string {
1008 return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg)
1011 // unixOS is the set of GOOS values matched by the "unix" build tag.
1012 // This is the same list as in go/build/syslist.go and
1013 // cmd/go/internal/imports/build.go.
1014 var unixOS = map[string]bool{
1029 // matchtag reports whether the tag matches this build.
1030 func matchtag(tag string) bool {
1032 case "gc", "cmd_go_bootstrap", "go1.1":
1035 return goos == "linux" || goos == "android"
1037 return goos == "solaris" || goos == "illumos"
1039 return goos == "darwin" || goos == "ios"
1049 // shouldbuild reports whether we should build this file.
1050 // It applies the same rules that are used with context tags
1051 // in package go/build, except it's less picky about the order
1052 // of GOOS and GOARCH.
1053 // We also allow the special tag cmd_go_bootstrap.
1054 // See ../go/bootstrap.go and package go/build.
1055 func shouldbuild(file, pkg string) bool {
1056 // Check file name for GOOS or GOARCH.
1057 name := filepath.Base(file)
1058 excluded := func(list []string, ok string) bool {
1059 for _, x := range list {
1060 if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") {
1063 i := strings.Index(name, x)
1064 if i <= 0 || name[i-1] != '_' {
1068 if i == len(name) || name[i] == '.' || name[i] == '_' {
1074 if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1079 if strings.Contains(name, "_test") {
1083 // Check file contents for //go:build lines.
1084 for _, p := range strings.Split(readfile(file), "\n") {
1085 p = strings.TrimSpace(p)
1090 i := strings.Index(code, "//")
1092 code = strings.TrimSpace(code[:i])
1094 if code == "package documentation" {
1097 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
1100 if !strings.HasPrefix(p, "//") {
1103 if strings.HasPrefix(p, "//go:build ") {
1104 matched, err := matchexpr(p[len("//go:build "):])
1106 errprintf("%s: %v", file, err)
1115 // copyfile copies the file src to dst, via memory (so only good for small files).
1116 func copyfile(dst, src string, flag int) {
1118 errprintf("cp %s %s\n", src, dst)
1120 writefile(readfile(src), dst, flag)
1123 // dopack copies the package src to dst,
1124 // appending the files listed in extra.
1125 // The archive format is the traditional Unix ar format.
1126 func dopack(dst, src string, extra []string) {
1127 bdst := bytes.NewBufferString(readfile(src))
1128 for _, file := range extra {
1130 // find last path element for archive member name
1131 i := strings.LastIndex(file, "/") + 1
1132 j := strings.LastIndex(file, `\`) + 1
1136 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1142 writefile(bdst.String(), dst, 0)
1146 generated := []byte(generatedHeader)
1148 // Remove generated source files.
1149 filepath.WalkDir(pathf("%s/src", goroot), func(path string, d fs.DirEntry, err error) error {
1153 case d.IsDir() && (d.Name() == "vendor" || d.Name() == "testdata"):
1154 return filepath.SkipDir
1155 case d.IsDir() && d.Name() != "dist":
1156 // Remove generated binary named for directory, but not dist out from under us.
1157 exe := filepath.Join(path, d.Name())
1158 if info, err := os.Stat(exe); err == nil && !info.IsDir() {
1161 xremove(exe + ".exe")
1162 case !d.IsDir() && strings.HasPrefix(d.Name(), "z"):
1163 // Remove generated file, identified by marker string.
1164 head := make([]byte, 512)
1165 if f, err := os.Open(path); err == nil {
1166 io.ReadFull(f, head)
1169 if bytes.HasPrefix(head, generated) {
1177 // Remove object tree.
1178 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1180 // Remove installed packages and tools.
1181 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1182 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1183 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1184 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1187 // Remove cached version info.
1188 xremove(pathf("%s/VERSION.cache", goroot))
1190 // Remove distribution packages.
1191 xremoveall(pathf("%s/pkg/distpack", goroot))
1196 * command implementations
1199 // The env command prints the default environment.
1201 path := flag.Bool("p", false, "emit updated PATH")
1202 plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax")
1203 windows := flag.Bool("w", gohostos == "windows", "emit windows syntax")
1206 format := "%s=\"%s\";\n" // Include ; to separate variables when 'dist env' output is used with eval.
1209 format = "%s='%s'\n"
1211 format = "set %s=%s\r\n"
1214 xprintf(format, "GO111MODULE", "")
1215 xprintf(format, "GOARCH", goarch)
1216 xprintf(format, "GOBIN", gorootBin)
1217 xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1218 xprintf(format, "GOENV", "off")
1219 xprintf(format, "GOFLAGS", "")
1220 xprintf(format, "GOHOSTARCH", gohostarch)
1221 xprintf(format, "GOHOSTOS", gohostos)
1222 xprintf(format, "GOOS", goos)
1223 xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1224 xprintf(format, "GOROOT", goroot)
1225 xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1226 xprintf(format, "GOTOOLDIR", tooldir)
1227 if goarch == "arm" {
1228 xprintf(format, "GOARM", goarm)
1230 if goarch == "386" {
1231 xprintf(format, "GO386", go386)
1233 if goarch == "amd64" {
1234 xprintf(format, "GOAMD64", goamd64)
1236 if goarch == "mips" || goarch == "mipsle" {
1237 xprintf(format, "GOMIPS", gomips)
1239 if goarch == "mips64" || goarch == "mips64le" {
1240 xprintf(format, "GOMIPS64", gomips64)
1242 if goarch == "ppc64" || goarch == "ppc64le" {
1243 xprintf(format, "GOPPC64", goppc64)
1245 xprintf(format, "GOWORK", "off")
1249 if gohostos == "windows" {
1252 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH")))
1254 // Also include $DIST_UNMODIFIED_PATH with the original $PATH
1255 // for the internal needs of "dist banner", along with export
1256 // so that it reaches the dist process. See its comment below.
1257 var exportFormat string
1258 if !*windows && !*plan9 {
1259 exportFormat = "export " + format
1261 exportFormat = format
1263 xprintf(exportFormat, "DIST_UNMODIFIED_PATH", os.Getenv("PATH"))
1268 timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1269 timeLogMu sync.Mutex
1270 timeLogFile *os.File
1271 timeLogStart time.Time
1274 func timelog(op, name string) {
1275 if !timeLogEnabled {
1279 defer timeLogMu.Unlock()
1280 if timeLogFile == nil {
1281 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1285 buf := make([]byte, 100)
1287 s := string(buf[:n])
1288 if i := strings.Index(s, "\n"); i >= 0 {
1291 i := strings.Index(s, " start")
1293 log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE"))
1295 t, err := time.Parse(time.UnixDate, s[:i])
1297 log.Fatalf("cannot parse time log line %q: %v", s, err)
1303 fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1306 // toolenv returns the environment to use when building commands in cmd.
1308 // This is a function instead of a variable because the exact toolenv depends
1309 // on the GOOS and GOARCH, and (at least for now) those are modified in place
1310 // to switch between the host and target configurations when cross-compiling.
1311 func toolenv() []string {
1313 if !mustLinkExternal(goos, goarch, false) {
1314 // Unless the platform requires external linking,
1315 // we disable cgo to get static binaries for cmd/go and cmd/pprof,
1316 // so that they work on systems without the same dynamic libraries
1317 // as the original build system.
1318 env = append(env, "CGO_ENABLED=0")
1320 if isRelease || os.Getenv("GO_BUILDER_NAME") != "" {
1321 // Add -trimpath for reproducible builds of releases.
1322 // Include builders so that -trimpath is well-tested ahead of releases.
1323 // Do not include local development, so that people working in the
1324 // main branch for day-to-day work on the Go toolchain itself can
1325 // still have full paths for stack traces for compiler crashes and the like.
1326 env = append(env, "GOFLAGS=-trimpath -ldflags=-w -gcflags=cmd/...=-dwarf=false")
1331 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
1333 // The bootstrap command runs a build from scratch,
1334 // stopping at having installed the go_bootstrap command.
1336 // WARNING: This command runs after cmd/dist is built with the Go bootstrap toolchain.
1337 // It rebuilds and installs cmd/dist with the new toolchain, so other
1338 // commands (like "go tool dist test" in run.bash) can rely on bug fixes
1339 // made since the Go bootstrap version, but this function cannot.
1340 func cmdbootstrap() {
1341 timelog("start", "dist bootstrap")
1342 defer timelog("end", "dist bootstrap")
1344 var debug, distpack, force, noBanner, noClean bool
1345 flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1346 flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1347 flag.BoolVar(&distpack, "distpack", distpack, "write distribution files to pkg/distpack")
1348 flag.BoolVar(&force, "force", force, "build even if the port is marked as broken")
1349 flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1350 flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning")
1355 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n")
1358 // Don't build broken ports by default.
1359 if broken[goos+"/"+goarch] && !force {
1360 fatalf("build stopped because the port %s/%s is marked as broken\n\n"+
1361 "Use the -force flag to build anyway.\n", goos, goarch)
1364 // Set GOPATH to an internal directory. We shouldn't actually
1365 // need to store files here, since the toolchain won't
1366 // depend on modules outside of vendor directories, but if
1367 // GOPATH points somewhere else (e.g., to GOROOT), the
1368 // go tool may complain.
1369 os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1371 // Use a build cache separate from the default user one.
1372 // Also one that will be wiped out during startup, so that
1373 // make.bash really does start from a clean slate.
1374 oldgocache = os.Getenv("GOCACHE")
1375 os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
1377 // Disable GOEXPERIMENT when building toolchain1 and
1378 // go_bootstrap. We don't need any experiments for the
1379 // bootstrap toolchain, and this lets us avoid duplicating the
1380 // GOEXPERIMENT-related build logic from cmd/go here. If the
1381 // bootstrap toolchain is < Go 1.17, it will ignore this
1382 // anyway since GOEXPERIMENT is baked in; otherwise it will
1383 // pick it up from the environment we set here. Once we're
1384 // using toolchain1 with dist as the build system, we need to
1385 // override this to keep the experiments assumed by the
1386 // toolchain and by dist consistent. Once go_bootstrap takes
1387 // over the build process, we'll set this back to the original
1389 os.Setenv("GOEXPERIMENT", "none")
1392 // cmd/buildid is used in debug mode.
1393 toolchain = append(toolchain, "cmd/buildid")
1396 if isdir(pathf("%s/src/pkg", goroot)) {
1398 "The Go package sources have moved to $GOROOT/src.\n"+
1399 "*** %s still exists. ***\n"+
1400 "It probably contains stale files that may confuse the build.\n"+
1401 "Please (check what's there and) remove it and try again.\n"+
1402 "See https://golang.org/s/go14nopkg\n",
1403 pathf("%s/src/pkg", goroot))
1412 timelog("build", "toolchain1")
1414 bootstrapBuildTools()
1416 // Remember old content of $GOROOT/bin for comparison below.
1417 oldBinFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1419 fatalf("glob: %v", err)
1422 // For the main bootstrap, building for host os/arch.
1427 os.Setenv("GOHOSTARCH", gohostarch)
1428 os.Setenv("GOHOSTOS", gohostos)
1429 os.Setenv("GOARCH", goarch)
1430 os.Setenv("GOOS", goos)
1432 timelog("build", "go_bootstrap")
1433 xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1434 install("runtime") // dependency not visible in sources; also sets up textflag.h
1435 install("time/tzdata") // no dependency in sources; creates generated file
1441 gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
1443 goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now
1444 goBootstrap := pathf("%s/go_bootstrap", tooldir)
1446 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1447 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1450 // To recap, so far we have built the new toolchain
1451 // (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
1452 // using the Go bootstrap toolchain and go command.
1453 // Then we built the new go command (as go_bootstrap)
1454 // using the new toolchain and our own build logic (above).
1456 // toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go)
1457 // go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
1459 // The toolchain1 we built earlier is built from the new sources,
1460 // but because it was built using cmd/go it has no build IDs.
1461 // The eventually installed toolchain needs build IDs, so we need
1462 // to do another round:
1464 // toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
1466 timelog("build", "toolchain2")
1470 xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1471 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1472 // Now that cmd/go is in charge of the build process, enable GOEXPERIMENT.
1473 os.Setenv("GOEXPERIMENT", goexperiment)
1474 // No need to enable PGO for toolchain2.
1475 goInstall(toolenv(), goBootstrap, append([]string{"-pgo=off"}, toolchain...)...)
1477 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1478 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1481 // Toolchain2 should be semantically equivalent to toolchain1,
1482 // but it was built using the newly built compiler instead of the Go bootstrap compiler,
1483 // so it should at the least run faster. Also, toolchain1 had no build IDs
1484 // in the binaries, while toolchain2 does. In non-release builds, the
1485 // toolchain's build IDs feed into constructing the build IDs of built targets,
1486 // so in non-release builds, everything now looks out-of-date due to
1487 // toolchain2 having build IDs - that is, due to the go command seeing
1488 // that there are new compilers. In release builds, the toolchain's reported
1489 // version is used in place of the build ID, and the go command does not
1490 // see that change from toolchain1 to toolchain2, so in release builds,
1491 // nothing looks out of date.
1492 // To keep the behavior the same in both non-release and release builds,
1493 // we force-install everything here.
1495 // toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
1497 timelog("build", "toolchain3")
1501 xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1502 goInstall(toolenv(), goBootstrap, append([]string{"-a"}, toolchain...)...)
1504 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1505 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1508 // Now that toolchain3 has been built from scratch, its compiler and linker
1509 // should have accurate build IDs suitable for caching.
1510 // Now prime the build cache with the rest of the standard library for
1511 // testing, and so that the user can run 'go install std cmd' to quickly
1512 // iterate on local changes without waiting for a full rebuild.
1513 if _, err := os.Stat(pathf("%s/VERSION", goroot)); err == nil {
1514 // If we have a VERSION file, then we use the Go version
1515 // instead of build IDs as a cache key, and there is no guarantee
1516 // that code hasn't changed since the last time we ran a build
1517 // with this exact VERSION file (especially if someone is working
1518 // on a release branch). We must not fall back to the shared build cache
1519 // in this case. Leave $GOCACHE alone.
1521 os.Setenv("GOCACHE", oldgocache)
1524 if goos == oldgoos && goarch == oldgoarch {
1525 // Common case - not setting up for cross-compilation.
1526 timelog("build", "toolchain")
1530 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1532 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
1533 // Finish GOHOSTOS/GOHOSTARCH installation and then
1534 // run GOOS/GOARCH installation.
1535 timelog("build", "host toolchain")
1539 xprintf("Building commands for host, %s/%s.\n", goos, goarch)
1540 goInstall(toolenv(), goBootstrap, "cmd")
1541 checkNotStale(toolenv(), goBootstrap, "cmd")
1542 checkNotStale(toolenv(), gorootBinGo, "cmd")
1544 timelog("build", "target toolchain")
1550 os.Setenv("GOOS", goos)
1551 os.Setenv("GOARCH", goarch)
1552 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
1553 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1555 goInstall(nil, goBootstrap, "std")
1556 goInstall(toolenv(), goBootstrap, "cmd")
1557 checkNotStale(toolenv(), goBootstrap, toolchain...)
1558 checkNotStale(nil, goBootstrap, "std")
1559 checkNotStale(toolenv(), goBootstrap, "cmd")
1560 checkNotStale(nil, gorootBinGo, "std")
1561 checkNotStale(toolenv(), gorootBinGo, "cmd")
1563 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1564 checkNotStale(toolenv(), goBootstrap, toolchain...)
1565 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1568 // Check that there are no new files in $GOROOT/bin other than
1569 // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
1570 binFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
1572 fatalf("glob: %v", err)
1575 ok := map[string]bool{}
1576 for _, f := range oldBinFiles {
1579 for _, f := range binFiles {
1580 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1581 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1582 fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1586 // Remove go_bootstrap now that we're done.
1587 xremove(pathf("%s/go_bootstrap"+exe, tooldir))
1589 if goos == "android" {
1590 // Make sure the exec wrapper will sync a fresh $GOROOT to the device.
1591 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1594 if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1595 oldcc := os.Getenv("CC")
1596 os.Setenv("GOOS", gohostos)
1597 os.Setenv("GOARCH", gohostarch)
1598 os.Setenv("CC", compilerEnvLookup("CC", defaultcc, gohostos, gohostarch))
1599 goCmd(nil, gorootBinGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
1600 // Restore environment.
1601 // TODO(elias.naur): support environment variables in goCmd?
1602 os.Setenv("GOOS", goos)
1603 os.Setenv("GOARCH", goarch)
1604 os.Setenv("CC", oldcc)
1608 xprintf("Packaging archives for %s/%s.\n", goos, goarch)
1609 run("", ShowOutput|CheckExit, pathf("%s/distpack", tooldir))
1612 // Print trailing banner unless instructed otherwise.
1618 func wrapperPathFor(goos, goarch string) string {
1620 case goos == "android":
1621 if gohostos != "android" {
1622 return pathf("%s/misc/go_android_exec/main.go", goroot)
1625 if gohostos != "ios" {
1626 return pathf("%s/misc/ios/go_ios_exec.go", goroot)
1632 func goInstall(env []string, goBinary string, args ...string) {
1633 goCmd(env, goBinary, "install", args...)
1636 func appendCompilerFlags(args []string) []string {
1637 if gogcflags != "" {
1638 args = append(args, "-gcflags=all="+gogcflags)
1640 if goldflags != "" {
1641 args = append(args, "-ldflags=all="+goldflags)
1646 func goCmd(env []string, goBinary string, cmd string, args ...string) {
1647 goCmd := []string{goBinary, cmd}
1649 goCmd = append(goCmd, "-tags=noopt")
1651 goCmd = appendCompilerFlags(goCmd)
1653 goCmd = append(goCmd, "-v")
1656 // Force only one process at a time on vx32 emulation.
1657 if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1658 goCmd = append(goCmd, "-p=1")
1661 runEnv(workdir, ShowOutput|CheckExit, env, append(goCmd, args...)...)
1664 func checkNotStale(env []string, goBinary string, targets ...string) {
1665 goCmd := []string{goBinary, "list"}
1667 goCmd = append(goCmd, "-tags=noopt")
1669 goCmd = appendCompilerFlags(goCmd)
1670 goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
1672 out := runEnv(workdir, CheckExit, env, append(goCmd, targets...)...)
1673 if strings.Contains(out, "\tSTALE ") {
1674 os.Setenv("GODEBUG", "gocachehash=1")
1675 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
1676 if strings.Contains(out, "STALE "+target) {
1677 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1681 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)
1685 // Cannot use go/build directly because cmd/dist for a new release
1686 // builds against an old release's go/build, which may be out of sync.
1687 // To reduce duplication, we generate the list for go/build from this.
1689 // We list all supported platforms in this list, so that this is the
1690 // single point of truth for supported platforms. This list is used
1691 // by 'go tool dist list'.
1692 var cgoEnabled = map[string]bool{
1694 "darwin/amd64": true,
1695 "darwin/arm64": true,
1696 "dragonfly/amd64": true,
1697 "freebsd/386": true,
1698 "freebsd/amd64": true,
1699 "freebsd/arm": true,
1700 "freebsd/arm64": true,
1701 "freebsd/riscv64": true,
1702 "illumos/amd64": true,
1704 "linux/amd64": true,
1706 "linux/arm64": true,
1707 "linux/loong64": true,
1708 "linux/ppc64": false,
1709 "linux/ppc64le": true,
1711 "linux/mipsle": true,
1712 "linux/mips64": true,
1713 "linux/mips64le": true,
1714 "linux/riscv64": true,
1715 "linux/s390x": true,
1716 "linux/sparc64": true,
1717 "android/386": true,
1718 "android/amd64": true,
1719 "android/arm": true,
1720 "android/arm64": true,
1724 "wasip1/wasm": false,
1726 "netbsd/amd64": true,
1728 "netbsd/arm64": true,
1729 "openbsd/386": true,
1730 "openbsd/amd64": true,
1731 "openbsd/arm": true,
1732 "openbsd/arm64": true,
1733 "openbsd/mips64": true,
1734 "openbsd/ppc64": false,
1736 "plan9/amd64": false,
1738 "solaris/amd64": true,
1739 "windows/386": true,
1740 "windows/amd64": true,
1741 "windows/arm": false,
1742 "windows/arm64": true,
1745 // List of platforms that are marked as broken ports.
1746 // These require -force flag to build, and also
1747 // get filtered out of cgoEnabled for 'dist list'.
1748 // See go.dev/issue/56679.
1749 var broken = map[string]bool{
1750 "linux/sparc64": true, // An incomplete port. See CL 132155.
1751 "openbsd/ppc64": true, // An incomplete port: go.dev/issue/56001.
1752 "openbsd/mips64": true, // Broken: go.dev/issue/58110.
1755 // List of platforms which are first class ports. See go.dev/issue/38874.
1756 var firstClass = map[string]bool{
1757 "darwin/amd64": true,
1758 "darwin/arm64": true,
1760 "linux/amd64": true,
1762 "linux/arm64": true,
1763 "windows/386": true,
1764 "windows/amd64": true,
1767 // We only need CC if cgo is forced on, or if the platform requires external linking.
1768 // Otherwise the go command will automatically disable it.
1769 func needCC() bool {
1770 return os.Getenv("CGO_ENABLED") == "1" || mustLinkExternal(gohostos, gohostarch, false)
1777 cc1 := defaultcc[""]
1780 for _, os := range clangos {
1787 cc, err := quotedSplit(cc1)
1789 fatalf("split CC: %v", err)
1791 var ccHelp = append(cc, "--help")
1793 if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
1795 if len(output) > 0 {
1796 outputHdr = "\nCommand output:\n\n"
1798 fatalf("cannot invoke C compiler %q: %v\n\n"+
1799 "Go needs a system C compiler for use with cgo.\n"+
1800 "To set a C compiler, set CC=the-compiler.\n"+
1801 "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
1805 func defaulttarg() string {
1806 // xgetwd might return a path with symlinks fully resolved, and if
1807 // there happens to be symlinks in goroot, then the hasprefix test
1808 // will never succeed. Instead, we use xrealwd to get a canonical
1809 // goroot/src before the comparison to avoid this problem.
1811 src := pathf("%s/src/", goroot)
1812 real_src := xrealwd(src)
1813 if !strings.HasPrefix(pwd, real_src) {
1814 fatalf("current directory %s is not under %s", pwd, real_src)
1816 pwd = pwd[len(real_src):]
1817 // guard against xrealwd returning the directory without the trailing /
1818 pwd = strings.TrimPrefix(pwd, "/")
1823 // Install installs the list of packages named on the command line.
1827 if flag.NArg() == 0 {
1828 install(defaulttarg())
1831 for _, arg := range flag.Args() {
1836 // Clean deletes temporary objects.
1842 // Banner prints the 'now you've installed Go' banner.
1853 xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1854 xprintf("Installed commands in %s\n", gorootBin)
1856 if !xsamefile(goroot_final, goroot) {
1857 // If the files are to be moved, don't check that gobin
1858 // is on PATH; assume they know what they are doing.
1859 } else if gohostos == "plan9" {
1860 // Check that GOROOT/bin is bound before /bin.
1861 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1862 ns := fmt.Sprintf("/proc/%s/ns", pid)
1863 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
1864 xprintf("*** You need to bind %s before /bin.\n", gorootBin)
1867 // Check that GOROOT/bin appears in $PATH.
1869 if gohostos == "windows" {
1872 path := os.Getenv("PATH")
1873 if p, ok := os.LookupEnv("DIST_UNMODIFIED_PATH"); ok {
1874 // Scripts that modify $PATH and then run dist should also provide
1875 // dist with an unmodified copy of $PATH via $DIST_UNMODIFIED_PATH.
1876 // Use it here when determining if the user still needs to update
1877 // their $PATH. See go.dev/issue/42563.
1880 if !strings.Contains(pathsep+path+pathsep, pathsep+gorootBin+pathsep) {
1881 xprintf("*** You need to add %s to your PATH.\n", gorootBin)
1885 if !xsamefile(goroot_final, goroot) {
1887 "The binaries expect %s to be copied or moved to %s\n",
1888 goroot, goroot_final)
1892 // Version prints the Go version.
1895 xprintf("%s\n", findgoversion())
1898 // cmdlist lists all supported platforms.
1900 jsonFlag := flag.Bool("json", false, "produce JSON output")
1901 brokenFlag := flag.Bool("broken", false, "include broken ports")
1905 for p := range cgoEnabled {
1906 if broken[p] && !*brokenFlag {
1909 plats = append(plats, p)
1914 for _, p := range plats {
1920 type jsonResult struct {
1925 Broken bool `json:",omitempty"`
1927 var results []jsonResult
1928 for _, p := range plats {
1929 fields := strings.Split(p, "/")
1930 results = append(results, jsonResult{
1933 CgoSupported: cgoEnabled[p],
1934 FirstClass: firstClass[p],
1938 out, err := json.MarshalIndent(results, "", "\t")
1940 fatalf("json marshal error: %v", err)
1942 if _, err := os.Stdout.Write(out); err != nil {
1943 fatalf("write failed: %v", err)
1947 // IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
1948 // belongs to the collection of "runtime-related" packages, including
1949 // "runtime" itself, "reflect", "syscall", and the
1950 // "runtime/internal/*" packages.
1952 // Keep in sync with cmd/internal/objabi/path.go:IsRuntimePackagePath.
1953 func IsRuntimePackagePath(pkgpath string) bool {
1962 case "internal/bytealg":
1965 rval = strings.HasPrefix(pkgpath, "runtime/internal")
1971 for _, gcflag := range strings.Split(gogcflags, " ") {
1972 if gcflag == "-N" || gcflag == "-l" {