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