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