]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/dist/build.go
c36a12e5e9996ad979f8fdda64c20c21e57ddf12
[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 }
562
563 // depsuffix records the allowed suffixes for source files.
564 var depsuffix = []string{
565         ".s",
566         ".go",
567 }
568
569 // gentab records how to generate some trivial files.
570 var gentab = []struct {
571         nameprefix string
572         gen        func(string, string)
573 }{
574         {"zdefaultcc.go", mkzdefaultcc},
575         {"zosarch.go", mkzosarch},
576         {"zversion.go", mkzversion},
577         {"zcgo.go", mkzcgo},
578
579         // not generated anymore, but delete the file if we see it
580         {"enam.c", nil},
581         {"anames5.c", nil},
582         {"anames6.c", nil},
583         {"anames8.c", nil},
584         {"anames9.c", nil},
585 }
586
587 // installed maps from a dir name (as given to install) to a chan
588 // closed when the dir's package is installed.
589 var installed = make(map[string]chan struct{})
590 var installedMu sync.Mutex
591
592 func install(dir string) {
593         <-startInstall(dir)
594 }
595
596 func startInstall(dir string) chan struct{} {
597         installedMu.Lock()
598         ch := installed[dir]
599         if ch == nil {
600                 ch = make(chan struct{})
601                 installed[dir] = ch
602                 go runInstall(dir, ch)
603         }
604         installedMu.Unlock()
605         return ch
606 }
607
608 // runInstall installs the library, package, or binary associated with dir,
609 // which is relative to $GOROOT/src.
610 func runInstall(pkg string, ch chan struct{}) {
611         if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
612                 fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
613         }
614
615         defer close(ch)
616
617         if pkg == "unsafe" {
618                 return
619         }
620
621         if vflag > 0 {
622                 if goos != gohostos || goarch != gohostarch {
623                         errprintf("%s (%s/%s)\n", pkg, goos, goarch)
624                 } else {
625                         errprintf("%s\n", pkg)
626                 }
627         }
628
629         workdir := pathf("%s/%s", workdir, pkg)
630         xmkdirall(workdir)
631
632         var clean []string
633         defer func() {
634                 for _, name := range clean {
635                         xremove(name)
636                 }
637         }()
638
639         // dir = full path to pkg.
640         dir := pathf("%s/src/%s", goroot, pkg)
641         name := filepath.Base(dir)
642
643         // ispkg predicts whether the package should be linked as a binary, based
644         // on the name. There should be no "main" packages in vendor, since
645         // 'go mod vendor' will only copy imported packages there.
646         ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
647
648         // Start final link command line.
649         // Note: code below knows that link.p[targ] is the target.
650         var (
651                 link      []string
652                 targ      int
653                 ispackcmd bool
654         )
655         if ispkg {
656                 // Go library (package).
657                 ispackcmd = true
658                 link = []string{"pack", packagefile(pkg)}
659                 targ = len(link) - 1
660                 xmkdirall(filepath.Dir(link[targ]))
661         } else {
662                 // Go command.
663                 elem := name
664                 if elem == "go" {
665                         elem = "go_bootstrap"
666                 }
667                 link = []string{pathf("%s/link", tooldir)}
668                 if goos == "android" {
669                         link = append(link, "-buildmode=pie")
670                 }
671                 if goldflags != "" {
672                         link = append(link, goldflags)
673                 }
674                 link = append(link, "-extld="+compilerEnvLookup(defaultcc, goos, goarch))
675                 link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch))
676                 link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
677                 targ = len(link) - 1
678         }
679         ttarg := mtime(link[targ])
680
681         // Gather files that are sources for this target.
682         // Everything in that directory, and any target-specific
683         // additions.
684         files := xreaddir(dir)
685
686         // Remove files beginning with . or _,
687         // which are likely to be editor temporary files.
688         // This is the same heuristic build.ScanDir uses.
689         // There do exist real C files beginning with _,
690         // so limit that check to just Go files.
691         files = filter(files, func(p string) bool {
692                 return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
693         })
694
695         for _, dt := range deptab {
696                 if pkg == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(pkg, dt.prefix) {
697                         for _, p := range dt.dep {
698                                 p = os.ExpandEnv(p)
699                                 files = append(files, p)
700                         }
701                 }
702         }
703         files = uniq(files)
704
705         // Convert to absolute paths.
706         for i, p := range files {
707                 if !filepath.IsAbs(p) {
708                         files[i] = pathf("%s/%s", dir, p)
709                 }
710         }
711
712         // Is the target up-to-date?
713         var gofiles, sfiles, missing []string
714         stale := rebuildall
715         files = filter(files, func(p string) bool {
716                 for _, suf := range depsuffix {
717                         if strings.HasSuffix(p, suf) {
718                                 goto ok
719                         }
720                 }
721                 return false
722         ok:
723                 t := mtime(p)
724                 if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
725                         return false
726                 }
727                 if strings.HasSuffix(p, ".go") {
728                         gofiles = append(gofiles, p)
729                 } else if strings.HasSuffix(p, ".s") {
730                         sfiles = append(sfiles, p)
731                 }
732                 if t.After(ttarg) {
733                         stale = true
734                 }
735                 if t.IsZero() {
736                         missing = append(missing, p)
737                 }
738                 return true
739         })
740
741         // If there are no files to compile, we're done.
742         if len(files) == 0 {
743                 return
744         }
745
746         if !stale {
747                 return
748         }
749
750         // For package runtime, copy some files into the work space.
751         if pkg == "runtime" {
752                 xmkdirall(pathf("%s/pkg/include", goroot))
753                 // For use by assembly and C files.
754                 copyfile(pathf("%s/pkg/include/textflag.h", goroot),
755                         pathf("%s/src/runtime/textflag.h", goroot), 0)
756                 copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
757                         pathf("%s/src/runtime/funcdata.h", goroot), 0)
758                 copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
759                         pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
760                 copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot),
761                         pathf("%s/src/runtime/asm_amd64.h", goroot), 0)
762         }
763
764         // Generate any missing files; regenerate existing ones.
765         for _, p := range files {
766                 elem := filepath.Base(p)
767                 for _, gt := range gentab {
768                         if gt.gen == nil {
769                                 continue
770                         }
771                         if strings.HasPrefix(elem, gt.nameprefix) {
772                                 if vflag > 1 {
773                                         errprintf("generate %s\n", p)
774                                 }
775                                 gt.gen(dir, p)
776                                 // Do not add generated file to clean list.
777                                 // In runtime, we want to be able to
778                                 // build the package with the go tool,
779                                 // and it assumes these generated files already
780                                 // exist (it does not know how to build them).
781                                 // The 'clean' command can remove
782                                 // the generated files.
783                                 goto built
784                         }
785                 }
786                 // Did not rebuild p.
787                 if find(p, missing) >= 0 {
788                         fatalf("missing file %s", p)
789                 }
790         built:
791         }
792
793         // Resolve imported packages to actual package paths.
794         // Make sure they're installed.
795         importMap := make(map[string]string)
796         for _, p := range gofiles {
797                 for _, imp := range readimports(p) {
798                         if imp == "C" {
799                                 fatalf("%s imports C", p)
800                         }
801                         importMap[imp] = resolveVendor(imp, dir)
802                 }
803         }
804         sortedImports := make([]string, 0, len(importMap))
805         for imp := range importMap {
806                 sortedImports = append(sortedImports, imp)
807         }
808         sort.Strings(sortedImports)
809
810         for _, dep := range importMap {
811                 if dep == "C" {
812                         fatalf("%s imports C", pkg)
813                 }
814                 startInstall(dep)
815         }
816         for _, dep := range importMap {
817                 install(dep)
818         }
819
820         if goos != gohostos || goarch != gohostarch {
821                 // We've generated the right files; the go command can do the build.
822                 if vflag > 1 {
823                         errprintf("skip build for cross-compile %s\n", pkg)
824                 }
825                 return
826         }
827
828         asmArgs := []string{
829                 pathf("%s/asm", tooldir),
830                 "-I", workdir,
831                 "-I", pathf("%s/pkg/include", goroot),
832                 "-D", "GOOS_" + goos,
833                 "-D", "GOARCH_" + goarch,
834                 "-D", "GOOS_GOARCH_" + goos + "_" + goarch,
835                 "-p", pkg,
836         }
837         if goarch == "mips" || goarch == "mipsle" {
838                 // Define GOMIPS_value from gomips.
839                 asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
840         }
841         if goarch == "mips64" || goarch == "mips64le" {
842                 // Define GOMIPS64_value from gomips64.
843                 asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
844         }
845         if goarch == "ppc64" || goarch == "ppc64le" {
846                 // We treat each powerpc version as a superset of functionality.
847                 switch goppc64 {
848                 case "power10":
849                         asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
850                         fallthrough
851                 case "power9":
852                         asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
853                         fallthrough
854                 default: // This should always be power8.
855                         asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
856                 }
857         }
858         goasmh := pathf("%s/go_asm.h", workdir)
859         if IsRuntimePackagePath(pkg) {
860                 asmArgs = append(asmArgs, "-compiling-runtime")
861         }
862
863         // Collect symabis from assembly code.
864         var symabis string
865         if len(sfiles) > 0 {
866                 symabis = pathf("%s/symabis", workdir)
867                 var wg sync.WaitGroup
868                 asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
869                 asmabis = append(asmabis, sfiles...)
870                 if err := os.WriteFile(goasmh, nil, 0666); err != nil {
871                         fatalf("cannot write empty go_asm.h: %s", err)
872                 }
873                 bgrun(&wg, dir, asmabis...)
874                 bgwait(&wg)
875         }
876
877         // Build an importcfg file for the compiler.
878         buf := &bytes.Buffer{}
879         for _, imp := range sortedImports {
880                 if imp == "unsafe" {
881                         continue
882                 }
883                 dep := importMap[imp]
884                 if imp != dep {
885                         fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
886                 }
887                 fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
888         }
889         importcfg := pathf("%s/importcfg", workdir)
890         if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
891                 fatalf("cannot write importcfg file: %v", err)
892         }
893
894         var archive string
895         // The next loop will compile individual non-Go files.
896         // Hand the Go files to the compiler en masse.
897         // For packages containing assembly, this writes go_asm.h, which
898         // the assembly files will need.
899         pkgName := pkg
900         if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
901                 pkgName = "main"
902         }
903         b := pathf("%s/_go_.a", workdir)
904         clean = append(clean, b)
905         if !ispackcmd {
906                 link = append(link, b)
907         } else {
908                 archive = b
909         }
910
911         // Compile Go code.
912         compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkgName, "-importcfg", importcfg}
913         if gogcflags != "" {
914                 compile = append(compile, strings.Fields(gogcflags)...)
915         }
916         if pkg == "runtime" {
917                 compile = append(compile, "-+")
918         }
919         if len(sfiles) > 0 {
920                 compile = append(compile, "-asmhdr", goasmh)
921         }
922         if symabis != "" {
923                 compile = append(compile, "-symabis", symabis)
924         }
925         if goos == "android" {
926                 compile = append(compile, "-shared")
927         }
928
929         compile = append(compile, gofiles...)
930         var wg sync.WaitGroup
931         // We use bgrun and immediately wait for it instead of calling run() synchronously.
932         // This executes all jobs through the bgwork channel and allows the process
933         // to exit cleanly in case an error occurs.
934         bgrun(&wg, dir, compile...)
935         bgwait(&wg)
936
937         // Compile the files.
938         for _, p := range sfiles {
939                 // Assembly file for a Go package.
940                 compile := asmArgs[:len(asmArgs):len(asmArgs)]
941
942                 doclean := true
943                 b := pathf("%s/%s", workdir, filepath.Base(p))
944
945                 // Change the last character of the output file (which was c or s).
946                 b = b[:len(b)-1] + "o"
947                 compile = append(compile, "-o", b, p)
948                 bgrun(&wg, dir, compile...)
949
950                 link = append(link, b)
951                 if doclean {
952                         clean = append(clean, b)
953                 }
954         }
955         bgwait(&wg)
956
957         if ispackcmd {
958                 xremove(link[targ])
959                 dopack(link[targ], archive, link[targ+1:])
960                 return
961         }
962
963         // Remove target before writing it.
964         xremove(link[targ])
965         bgrun(&wg, "", link...)
966         bgwait(&wg)
967 }
968
969 // packagefile returns the path to a compiled .a file for the given package
970 // path. Paths may need to be resolved with resolveVendor first.
971 func packagefile(pkg string) string {
972         return pathf("%s/pkg/obj/go-bootstrap/%s_%s/%s.a", goroot, goos, goarch, pkg)
973 }
974
975 // unixOS is the set of GOOS values matched by the "unix" build tag.
976 // This is the same list as in go/build/syslist.go and
977 // cmd/go/internal/imports/build.go.
978 var unixOS = map[string]bool{
979         "aix":       true,
980         "android":   true,
981         "darwin":    true,
982         "dragonfly": true,
983         "freebsd":   true,
984         "hurd":      true,
985         "illumos":   true,
986         "ios":       true,
987         "linux":     true,
988         "netbsd":    true,
989         "openbsd":   true,
990         "solaris":   true,
991 }
992
993 // matchtag reports whether the tag matches this build.
994 func matchtag(tag string) bool {
995         switch tag {
996         case "gc", "cmd_go_bootstrap", "go1.1":
997                 return true
998         case "linux":
999                 return goos == "linux" || goos == "android"
1000         case "solaris":
1001                 return goos == "solaris" || goos == "illumos"
1002         case "darwin":
1003                 return goos == "darwin" || goos == "ios"
1004         case goos, goarch:
1005                 return true
1006         case "unix":
1007                 return unixOS[goos]
1008         default:
1009                 return false
1010         }
1011 }
1012
1013 // shouldbuild reports whether we should build this file.
1014 // It applies the same rules that are used with context tags
1015 // in package go/build, except it's less picky about the order
1016 // of GOOS and GOARCH.
1017 // We also allow the special tag cmd_go_bootstrap.
1018 // See ../go/bootstrap.go and package go/build.
1019 func shouldbuild(file, pkg string) bool {
1020         // Check file name for GOOS or GOARCH.
1021         name := filepath.Base(file)
1022         excluded := func(list []string, ok string) bool {
1023                 for _, x := range list {
1024                         if x == ok || (ok == "android" && x == "linux") || (ok == "illumos" && x == "solaris") || (ok == "ios" && x == "darwin") {
1025                                 continue
1026                         }
1027                         i := strings.Index(name, x)
1028                         if i <= 0 || name[i-1] != '_' {
1029                                 continue
1030                         }
1031                         i += len(x)
1032                         if i == len(name) || name[i] == '.' || name[i] == '_' {
1033                                 return true
1034                         }
1035                 }
1036                 return false
1037         }
1038         if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
1039                 return false
1040         }
1041
1042         // Omit test files.
1043         if strings.Contains(name, "_test") {
1044                 return false
1045         }
1046
1047         // Check file contents for //go:build lines.
1048         for _, p := range strings.Split(readfile(file), "\n") {
1049                 p = strings.TrimSpace(p)
1050                 if p == "" {
1051                         continue
1052                 }
1053                 code := p
1054                 i := strings.Index(code, "//")
1055                 if i > 0 {
1056                         code = strings.TrimSpace(code[:i])
1057                 }
1058                 if code == "package documentation" {
1059                         return false
1060                 }
1061                 if code == "package main" && pkg != "cmd/go" && pkg != "cmd/cgo" {
1062                         return false
1063                 }
1064                 if !strings.HasPrefix(p, "//") {
1065                         break
1066                 }
1067                 if strings.HasPrefix(p, "//go:build ") {
1068                         matched, err := matchexpr(p[len("//go:build "):])
1069                         if err != nil {
1070                                 errprintf("%s: %v", file, err)
1071                         }
1072                         return matched
1073                 }
1074         }
1075
1076         return true
1077 }
1078
1079 // copy copies the file src to dst, via memory (so only good for small files).
1080 func copyfile(dst, src string, flag int) {
1081         if vflag > 1 {
1082                 errprintf("cp %s %s\n", src, dst)
1083         }
1084         writefile(readfile(src), dst, flag)
1085 }
1086
1087 // dopack copies the package src to dst,
1088 // appending the files listed in extra.
1089 // The archive format is the traditional Unix ar format.
1090 func dopack(dst, src string, extra []string) {
1091         bdst := bytes.NewBufferString(readfile(src))
1092         for _, file := range extra {
1093                 b := readfile(file)
1094                 // find last path element for archive member name
1095                 i := strings.LastIndex(file, "/") + 1
1096                 j := strings.LastIndex(file, `\`) + 1
1097                 if i < j {
1098                         i = j
1099                 }
1100                 fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
1101                 bdst.WriteString(b)
1102                 if len(b)&1 != 0 {
1103                         bdst.WriteByte(0)
1104                 }
1105         }
1106         writefile(bdst.String(), dst, 0)
1107 }
1108
1109 var runtimegen = []string{
1110         "zaexperiment.h",
1111         "zversion.go",
1112 }
1113
1114 // cleanlist is a list of packages with generated files and commands.
1115 var cleanlist = []string{
1116         "runtime/internal/sys",
1117         "cmd/cgo",
1118         "cmd/go/internal/cfg",
1119         "go/build",
1120 }
1121
1122 func clean() {
1123         for _, name := range cleanlist {
1124                 path := pathf("%s/src/%s", goroot, name)
1125                 // Remove generated files.
1126                 for _, elem := range xreaddir(path) {
1127                         for _, gt := range gentab {
1128                                 if strings.HasPrefix(elem, gt.nameprefix) {
1129                                         xremove(pathf("%s/%s", path, elem))
1130                                 }
1131                         }
1132                 }
1133                 // Remove generated binary named for directory.
1134                 if strings.HasPrefix(name, "cmd/") {
1135                         xremove(pathf("%s/%s", path, name[4:]))
1136                 }
1137         }
1138
1139         // remove runtimegen files.
1140         path := pathf("%s/src/runtime", goroot)
1141         for _, elem := range runtimegen {
1142                 xremove(pathf("%s/%s", path, elem))
1143         }
1144
1145         if rebuildall {
1146                 // Remove object tree.
1147                 xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
1148
1149                 // Remove installed packages and tools.
1150                 xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
1151                 xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
1152                 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
1153                 xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
1154                 xremoveall(tooldir)
1155
1156                 // Remove cached version info.
1157                 xremove(pathf("%s/VERSION.cache", goroot))
1158         }
1159 }
1160
1161 /*
1162  * command implementations
1163  */
1164
1165 // The env command prints the default environment.
1166 func cmdenv() {
1167         path := flag.Bool("p", false, "emit updated PATH")
1168         plan9 := flag.Bool("9", gohostos == "plan9", "emit plan 9 syntax")
1169         windows := flag.Bool("w", gohostos == "windows", "emit windows syntax")
1170         xflagparse(0)
1171
1172         format := "%s=\"%s\"\n"
1173         switch {
1174         case *plan9:
1175                 format = "%s='%s'\n"
1176         case *windows:
1177                 format = "set %s=%s\r\n"
1178         }
1179
1180         xprintf(format, "GO111MODULE", "")
1181         xprintf(format, "GOARCH", goarch)
1182         xprintf(format, "GOBIN", gorootBin)
1183         xprintf(format, "GOCACHE", os.Getenv("GOCACHE"))
1184         xprintf(format, "GODEBUG", os.Getenv("GODEBUG"))
1185         xprintf(format, "GOENV", "off")
1186         xprintf(format, "GOFLAGS", "")
1187         xprintf(format, "GOHOSTARCH", gohostarch)
1188         xprintf(format, "GOHOSTOS", gohostos)
1189         xprintf(format, "GOOS", goos)
1190         xprintf(format, "GOPROXY", os.Getenv("GOPROXY"))
1191         xprintf(format, "GOROOT", goroot)
1192         xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR"))
1193         xprintf(format, "GOTOOLDIR", tooldir)
1194         if goarch == "arm" {
1195                 xprintf(format, "GOARM", goarm)
1196         }
1197         if goarch == "386" {
1198                 xprintf(format, "GO386", go386)
1199         }
1200         if goarch == "amd64" {
1201                 xprintf(format, "GOAMD64", goamd64)
1202         }
1203         if goarch == "mips" || goarch == "mipsle" {
1204                 xprintf(format, "GOMIPS", gomips)
1205         }
1206         if goarch == "mips64" || goarch == "mips64le" {
1207                 xprintf(format, "GOMIPS64", gomips64)
1208         }
1209         if goarch == "ppc64" || goarch == "ppc64le" {
1210                 xprintf(format, "GOPPC64", goppc64)
1211         }
1212         xprintf(format, "GOWORK", "off")
1213
1214         if *path {
1215                 sep := ":"
1216                 if gohostos == "windows" {
1217                         sep = ";"
1218                 }
1219                 xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gorootBin, sep, os.Getenv("PATH")))
1220         }
1221 }
1222
1223 var (
1224         timeLogEnabled = os.Getenv("GOBUILDTIMELOGFILE") != ""
1225         timeLogMu      sync.Mutex
1226         timeLogFile    *os.File
1227         timeLogStart   time.Time
1228 )
1229
1230 func timelog(op, name string) {
1231         if !timeLogEnabled {
1232                 return
1233         }
1234         timeLogMu.Lock()
1235         defer timeLogMu.Unlock()
1236         if timeLogFile == nil {
1237                 f, err := os.OpenFile(os.Getenv("GOBUILDTIMELOGFILE"), os.O_RDWR|os.O_APPEND, 0666)
1238                 if err != nil {
1239                         log.Fatal(err)
1240                 }
1241                 buf := make([]byte, 100)
1242                 n, _ := f.Read(buf)
1243                 s := string(buf[:n])
1244                 if i := strings.Index(s, "\n"); i >= 0 {
1245                         s = s[:i]
1246                 }
1247                 i := strings.Index(s, " start")
1248                 if i < 0 {
1249                         log.Fatalf("time log %s does not begin with start line", os.Getenv("GOBUILDTIMELOGFILE"))
1250                 }
1251                 t, err := time.Parse(time.UnixDate, s[:i])
1252                 if err != nil {
1253                         log.Fatalf("cannot parse time log line %q: %v", s, err)
1254                 }
1255                 timeLogStart = t
1256                 timeLogFile = f
1257         }
1258         t := time.Now()
1259         fmt.Fprintf(timeLogFile, "%s %+.1fs %s %s\n", t.Format(time.UnixDate), t.Sub(timeLogStart).Seconds(), op, name)
1260 }
1261
1262 var toolchain = []string{"cmd/asm", "cmd/cgo", "cmd/compile", "cmd/link"}
1263
1264 // The bootstrap command runs a build from scratch,
1265 // stopping at having installed the go_bootstrap command.
1266 //
1267 // WARNING: This command runs after cmd/dist is built with the Go bootstrap toolchain.
1268 // It rebuilds and installs cmd/dist with the new toolchain, so other
1269 // commands (like "go tool dist test" in run.bash) can rely on bug fixes
1270 // made since the Go bootstrap version, but this function cannot.
1271 func cmdbootstrap() {
1272         timelog("start", "dist bootstrap")
1273         defer timelog("end", "dist bootstrap")
1274
1275         var noBanner, noClean bool
1276         var debug bool
1277         flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
1278         flag.BoolVar(&debug, "d", debug, "enable debugging of bootstrap process")
1279         flag.BoolVar(&noBanner, "no-banner", noBanner, "do not print banner")
1280         flag.BoolVar(&noClean, "no-clean", noClean, "print deprecation warning")
1281
1282         xflagparse(0)
1283
1284         if noClean {
1285                 xprintf("warning: --no-clean is deprecated and has no effect; use 'go install std cmd' instead\n")
1286         }
1287
1288         // Set GOPATH to an internal directory. We shouldn't actually
1289         // need to store files here, since the toolchain won't
1290         // depend on modules outside of vendor directories, but if
1291         // GOPATH points somewhere else (e.g., to GOROOT), the
1292         // go tool may complain.
1293         os.Setenv("GOPATH", pathf("%s/pkg/obj/gopath", goroot))
1294
1295         // Disable GOEXPERIMENT when building toolchain1 and
1296         // go_bootstrap. We don't need any experiments for the
1297         // bootstrap toolchain, and this lets us avoid duplicating the
1298         // GOEXPERIMENT-related build logic from cmd/go here. If the
1299         // bootstrap toolchain is < Go 1.17, it will ignore this
1300         // anyway since GOEXPERIMENT is baked in; otherwise it will
1301         // pick it up from the environment we set here. Once we're
1302         // using toolchain1 with dist as the build system, we need to
1303         // override this to keep the experiments assumed by the
1304         // toolchain and by dist consistent. Once go_bootstrap takes
1305         // over the build process, we'll set this back to the original
1306         // GOEXPERIMENT.
1307         os.Setenv("GOEXPERIMENT", "none")
1308
1309         if debug {
1310                 // cmd/buildid is used in debug mode.
1311                 toolchain = append(toolchain, "cmd/buildid")
1312         }
1313
1314         if isdir(pathf("%s/src/pkg", goroot)) {
1315                 fatalf("\n\n"+
1316                         "The Go package sources have moved to $GOROOT/src.\n"+
1317                         "*** %s still exists. ***\n"+
1318                         "It probably contains stale files that may confuse the build.\n"+
1319                         "Please (check what's there and) remove it and try again.\n"+
1320                         "See https://golang.org/s/go14nopkg\n",
1321                         pathf("%s/src/pkg", goroot))
1322         }
1323
1324         if rebuildall {
1325                 clean()
1326         }
1327
1328         setup()
1329
1330         timelog("build", "toolchain1")
1331         checkCC()
1332         bootstrapBuildTools()
1333
1334         // Remember old content of $GOROOT/bin for comparison below.
1335         oldBinFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1336
1337         // For the main bootstrap, building for host os/arch.
1338         oldgoos = goos
1339         oldgoarch = goarch
1340         goos = gohostos
1341         goarch = gohostarch
1342         os.Setenv("GOHOSTARCH", gohostarch)
1343         os.Setenv("GOHOSTOS", gohostos)
1344         os.Setenv("GOARCH", goarch)
1345         os.Setenv("GOOS", goos)
1346
1347         timelog("build", "go_bootstrap")
1348         xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
1349         install("runtime") // dependency not visible in sources; also sets up textflag.h
1350         install("cmd/go")
1351         if vflag > 0 {
1352                 xprintf("\n")
1353         }
1354
1355         gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
1356         setNoOpt()
1357         goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now
1358         goBootstrap := pathf("%s/go_bootstrap", tooldir)
1359         cmdGo := pathf("%s/go", gorootBin)
1360         if debug {
1361                 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1362                 copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
1363         }
1364
1365         // To recap, so far we have built the new toolchain
1366         // (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
1367         // using the Go bootstrap toolchain and go command.
1368         // Then we built the new go command (as go_bootstrap)
1369         // using the new toolchain and our own build logic (above).
1370         //
1371         //      toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go)
1372         //      go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
1373         //
1374         // The toolchain1 we built earlier is built from the new sources,
1375         // but because it was built using cmd/go it has no build IDs.
1376         // The eventually installed toolchain needs build IDs, so we need
1377         // to do another round:
1378         //
1379         //      toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
1380         //
1381         timelog("build", "toolchain2")
1382         if vflag > 0 {
1383                 xprintf("\n")
1384         }
1385         xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
1386         os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1387         // Now that cmd/go is in charge of the build process, enable GOEXPERIMENT.
1388         os.Setenv("GOEXPERIMENT", goexperiment)
1389         goInstall(goBootstrap, toolchain...)
1390         if debug {
1391                 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1392                 copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
1393         }
1394
1395         // Toolchain2 should be semantically equivalent to toolchain1,
1396         // but it was built using the newly built compiler instead of the Go bootstrap compiler,
1397         // so it should at the least run faster. Also, toolchain1 had no build IDs
1398         // in the binaries, while toolchain2 does. In non-release builds, the
1399         // toolchain's build IDs feed into constructing the build IDs of built targets,
1400         // so in non-release builds, everything now looks out-of-date due to
1401         // toolchain2 having build IDs - that is, due to the go command seeing
1402         // that there are new compilers. In release builds, the toolchain's reported
1403         // version is used in place of the build ID, and the go command does not
1404         // see that change from toolchain1 to toolchain2, so in release builds,
1405         // nothing looks out of date.
1406         // To keep the behavior the same in both non-release and release builds,
1407         // we force-install everything here.
1408         //
1409         //      toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
1410         //
1411         timelog("build", "toolchain3")
1412         if vflag > 0 {
1413                 xprintf("\n")
1414         }
1415         xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
1416         goInstall(goBootstrap, append([]string{"-a"}, toolchain...)...)
1417         if debug {
1418                 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1419                 copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
1420         }
1421
1422         if goos == oldgoos && goarch == oldgoarch {
1423                 // Common case - not setting up for cross-compilation.
1424                 timelog("build", "toolchain")
1425                 if vflag > 0 {
1426                         xprintf("\n")
1427                 }
1428                 xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
1429         } else {
1430                 // GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
1431                 // Finish GOHOSTOS/GOHOSTARCH installation and then
1432                 // run GOOS/GOARCH installation.
1433                 timelog("build", "host toolchain")
1434                 if vflag > 0 {
1435                         xprintf("\n")
1436                 }
1437                 xprintf("Building packages and commands for host, %s/%s.\n", goos, goarch)
1438                 goInstall(goBootstrap, "std", "cmd")
1439                 checkNotStale(goBootstrap, "std", "cmd")
1440                 checkNotStale(cmdGo, "std", "cmd")
1441
1442                 timelog("build", "target toolchain")
1443                 if vflag > 0 {
1444                         xprintf("\n")
1445                 }
1446                 goos = oldgoos
1447                 goarch = oldgoarch
1448                 os.Setenv("GOOS", goos)
1449                 os.Setenv("GOARCH", goarch)
1450                 os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch))
1451                 xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
1452         }
1453         targets := []string{"std", "cmd"}
1454         goInstall(goBootstrap, targets...)
1455         checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1456         checkNotStale(goBootstrap, targets...)
1457         checkNotStale(cmdGo, targets...)
1458         if debug {
1459                 run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
1460                 checkNotStale(goBootstrap, append(toolchain, "runtime/internal/sys")...)
1461                 copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
1462         }
1463
1464         // Check that there are no new files in $GOROOT/bin other than
1465         // go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
1466         binFiles, _ := filepath.Glob(pathf("%s/bin/*", goroot))
1467         ok := map[string]bool{}
1468         for _, f := range oldBinFiles {
1469                 ok[f] = true
1470         }
1471         for _, f := range binFiles {
1472                 elem := strings.TrimSuffix(filepath.Base(f), ".exe")
1473                 if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
1474                         fatalf("unexpected new file in $GOROOT/bin: %s", elem)
1475                 }
1476         }
1477
1478         // Remove go_bootstrap now that we're done.
1479         xremove(pathf("%s/go_bootstrap", tooldir))
1480
1481         if goos == "android" {
1482                 // Make sure the exec wrapper will sync a fresh $GOROOT to the device.
1483                 xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
1484         }
1485
1486         if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
1487                 oldcc := os.Getenv("CC")
1488                 os.Setenv("GOOS", gohostos)
1489                 os.Setenv("GOARCH", gohostarch)
1490                 os.Setenv("CC", compilerEnvLookup(defaultcc, gohostos, gohostarch))
1491                 goCmd(cmdGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
1492                 // Restore environment.
1493                 // TODO(elias.naur): support environment variables in goCmd?
1494                 os.Setenv("GOOS", goos)
1495                 os.Setenv("GOARCH", goarch)
1496                 os.Setenv("CC", oldcc)
1497         }
1498
1499         // Print trailing banner unless instructed otherwise.
1500         if !noBanner {
1501                 banner()
1502         }
1503 }
1504
1505 func wrapperPathFor(goos, goarch string) string {
1506         switch {
1507         case goos == "android":
1508                 if gohostos != "android" {
1509                         return pathf("%s/misc/android/go_android_exec.go", goroot)
1510                 }
1511         case goos == "ios":
1512                 if gohostos != "ios" {
1513                         return pathf("%s/misc/ios/go_ios_exec.go", goroot)
1514                 }
1515         }
1516         return ""
1517 }
1518
1519 func goInstall(goBinary string, args ...string) {
1520         goCmd(goBinary, "install", args...)
1521 }
1522
1523 func appendCompilerFlags(args []string) []string {
1524         if gogcflags != "" {
1525                 args = append(args, "-gcflags=all="+gogcflags)
1526         }
1527         if goldflags != "" {
1528                 args = append(args, "-ldflags=all="+goldflags)
1529         }
1530         return args
1531 }
1532
1533 func goCmd(goBinary string, cmd string, args ...string) {
1534         goCmd := []string{goBinary, cmd}
1535         if noOpt {
1536                 goCmd = append(goCmd, "-tags=noopt")
1537         }
1538         goCmd = appendCompilerFlags(goCmd)
1539         if vflag > 0 {
1540                 goCmd = append(goCmd, "-v")
1541         }
1542
1543         // Force only one process at a time on vx32 emulation.
1544         if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
1545                 goCmd = append(goCmd, "-p=1")
1546         }
1547
1548         run(workdir, ShowOutput|CheckExit, append(goCmd, args...)...)
1549 }
1550
1551 func checkNotStale(goBinary string, targets ...string) {
1552         goCmd := []string{goBinary, "list"}
1553         if noOpt {
1554                 goCmd = append(goCmd, "-tags=noopt")
1555         }
1556         goCmd = appendCompilerFlags(goCmd)
1557         goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
1558
1559         out := run(workdir, CheckExit, append(goCmd, targets...)...)
1560         if strings.Contains(out, "\tSTALE ") {
1561                 os.Setenv("GODEBUG", "gocachehash=1")
1562                 for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
1563                         if strings.Contains(out, "STALE "+target) {
1564                                 run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
1565                                 break
1566                         }
1567                 }
1568                 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)
1569         }
1570 }
1571
1572 // Cannot use go/build directly because cmd/dist for a new release
1573 // builds against an old release's go/build, which may be out of sync.
1574 // To reduce duplication, we generate the list for go/build from this.
1575 //
1576 // We list all supported platforms in this list, so that this is the
1577 // single point of truth for supported platforms. This list is used
1578 // by 'go tool dist list'.
1579 var cgoEnabled = map[string]bool{
1580         "aix/ppc64":       true,
1581         "darwin/amd64":    true,
1582         "darwin/arm64":    true,
1583         "dragonfly/amd64": true,
1584         "freebsd/386":     true,
1585         "freebsd/amd64":   true,
1586         "freebsd/arm":     true,
1587         "freebsd/arm64":   true,
1588         "freebsd/riscv64": true,
1589         "illumos/amd64":   true,
1590         "linux/386":       true,
1591         "linux/amd64":     true,
1592         "linux/arm":       true,
1593         "linux/arm64":     true,
1594         "linux/loong64":   true,
1595         "linux/ppc64":     false,
1596         "linux/ppc64le":   true,
1597         "linux/mips":      true,
1598         "linux/mipsle":    true,
1599         "linux/mips64":    true,
1600         "linux/mips64le":  true,
1601         "linux/riscv64":   true,
1602         "linux/s390x":     true,
1603         "linux/sparc64":   true,
1604         "android/386":     true,
1605         "android/amd64":   true,
1606         "android/arm":     true,
1607         "android/arm64":   true,
1608         "ios/arm64":       true,
1609         "ios/amd64":       true,
1610         "js/wasm":         false,
1611         "netbsd/386":      true,
1612         "netbsd/amd64":    true,
1613         "netbsd/arm":      true,
1614         "netbsd/arm64":    true,
1615         "openbsd/386":     true,
1616         "openbsd/amd64":   true,
1617         "openbsd/arm":     true,
1618         "openbsd/arm64":   true,
1619         "openbsd/mips64":  true,
1620         "plan9/386":       false,
1621         "plan9/amd64":     false,
1622         "plan9/arm":       false,
1623         "solaris/amd64":   true,
1624         "windows/386":     true,
1625         "windows/amd64":   true,
1626         "windows/arm":     false,
1627         "windows/arm64":   true,
1628 }
1629
1630 // List of platforms which are supported but not complete yet. These get
1631 // filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944
1632 var incomplete = map[string]bool{
1633         "linux/sparc64": true,
1634 }
1635
1636 // List of platforms which are first class ports. See golang.org/issue/38874.
1637 var firstClass = map[string]bool{
1638         "darwin/amd64":  true,
1639         "darwin/arm64":  true,
1640         "linux/386":     true,
1641         "linux/amd64":   true,
1642         "linux/arm":     true,
1643         "linux/arm64":   true,
1644         "windows/386":   true,
1645         "windows/amd64": true,
1646 }
1647
1648 func needCC() bool {
1649         switch os.Getenv("CGO_ENABLED") {
1650         case "1":
1651                 return true
1652         case "0":
1653                 return false
1654         }
1655         return cgoEnabled[gohostos+"/"+gohostarch]
1656 }
1657
1658 func checkCC() {
1659         if !needCC() {
1660                 return
1661         }
1662         cc, err := quotedSplit(defaultcc[""])
1663         if err != nil {
1664                 fatalf("split CC: %v", err)
1665         }
1666         var ccHelp = append(cc, "--help")
1667
1668         if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
1669                 outputHdr := ""
1670                 if len(output) > 0 {
1671                         outputHdr = "\nCommand output:\n\n"
1672                 }
1673                 fatalf("cannot invoke C compiler %q: %v\n\n"+
1674                         "Go needs a system C compiler for use with cgo.\n"+
1675                         "To set a C compiler, set CC=the-compiler.\n"+
1676                         "To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
1677         }
1678 }
1679
1680 func defaulttarg() string {
1681         // xgetwd might return a path with symlinks fully resolved, and if
1682         // there happens to be symlinks in goroot, then the hasprefix test
1683         // will never succeed. Instead, we use xrealwd to get a canonical
1684         // goroot/src before the comparison to avoid this problem.
1685         pwd := xgetwd()
1686         src := pathf("%s/src/", goroot)
1687         real_src := xrealwd(src)
1688         if !strings.HasPrefix(pwd, real_src) {
1689                 fatalf("current directory %s is not under %s", pwd, real_src)
1690         }
1691         pwd = pwd[len(real_src):]
1692         // guard against xrealwd returning the directory without the trailing /
1693         pwd = strings.TrimPrefix(pwd, "/")
1694
1695         return pwd
1696 }
1697
1698 // Install installs the list of packages named on the command line.
1699 func cmdinstall() {
1700         xflagparse(-1)
1701
1702         if flag.NArg() == 0 {
1703                 install(defaulttarg())
1704         }
1705
1706         for _, arg := range flag.Args() {
1707                 install(arg)
1708         }
1709 }
1710
1711 // Clean deletes temporary objects.
1712 func cmdclean() {
1713         xflagparse(0)
1714         clean()
1715 }
1716
1717 // Banner prints the 'now you've installed Go' banner.
1718 func cmdbanner() {
1719         xflagparse(0)
1720         banner()
1721 }
1722
1723 func banner() {
1724         if vflag > 0 {
1725                 xprintf("\n")
1726         }
1727         xprintf("---\n")
1728         xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
1729         xprintf("Installed commands in %s\n", gorootBin)
1730
1731         if !xsamefile(goroot_final, goroot) {
1732                 // If the files are to be moved, don't check that gobin
1733                 // is on PATH; assume they know what they are doing.
1734         } else if gohostos == "plan9" {
1735                 // Check that GOROOT/bin is bound before /bin.
1736                 pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
1737                 ns := fmt.Sprintf("/proc/%s/ns", pid)
1738                 if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
1739                         xprintf("*** You need to bind %s before /bin.\n", gorootBin)
1740                 }
1741         } else {
1742                 // Check that GOROOT/bin appears in $PATH.
1743                 pathsep := ":"
1744                 if gohostos == "windows" {
1745                         pathsep = ";"
1746                 }
1747                 if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gorootBin+pathsep) {
1748                         xprintf("*** You need to add %s to your PATH.\n", gorootBin)
1749                 }
1750         }
1751
1752         if !xsamefile(goroot_final, goroot) {
1753                 xprintf("\n"+
1754                         "The binaries expect %s to be copied or moved to %s\n",
1755                         goroot, goroot_final)
1756         }
1757 }
1758
1759 // Version prints the Go version.
1760 func cmdversion() {
1761         xflagparse(0)
1762         xprintf("%s\n", findgoversion())
1763 }
1764
1765 // cmdlist lists all supported platforms.
1766 func cmdlist() {
1767         jsonFlag := flag.Bool("json", false, "produce JSON output")
1768         xflagparse(0)
1769
1770         var plats []string
1771         for p := range cgoEnabled {
1772                 if incomplete[p] {
1773                         continue
1774                 }
1775                 plats = append(plats, p)
1776         }
1777         sort.Strings(plats)
1778
1779         if !*jsonFlag {
1780                 for _, p := range plats {
1781                         xprintf("%s\n", p)
1782                 }
1783                 return
1784         }
1785
1786         type jsonResult struct {
1787                 GOOS         string
1788                 GOARCH       string
1789                 CgoSupported bool
1790                 FirstClass   bool
1791         }
1792         var results []jsonResult
1793         for _, p := range plats {
1794                 fields := strings.Split(p, "/")
1795                 results = append(results, jsonResult{
1796                         GOOS:         fields[0],
1797                         GOARCH:       fields[1],
1798                         CgoSupported: cgoEnabled[p],
1799                         FirstClass:   firstClass[p]})
1800         }
1801         out, err := json.MarshalIndent(results, "", "\t")
1802         if err != nil {
1803                 fatalf("json marshal error: %v", err)
1804         }
1805         if _, err := os.Stdout.Write(out); err != nil {
1806                 fatalf("write failed: %v", err)
1807         }
1808 }
1809
1810 // IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
1811 // belongs to the collection of "runtime-related" packages, including
1812 // "runtime" itself, "reflect", "syscall", and the
1813 // "runtime/internal/*" packages.
1814 //
1815 // Keep in sync with cmd/internal/objabi/path.go:IsRuntimePackagePath.
1816 func IsRuntimePackagePath(pkgpath string) bool {
1817         rval := false
1818         switch pkgpath {
1819         case "runtime":
1820                 rval = true
1821         case "reflect":
1822                 rval = true
1823         case "syscall":
1824                 rval = true
1825         case "internal/bytealg":
1826                 rval = true
1827         default:
1828                 rval = strings.HasPrefix(pkgpath, "runtime/internal")
1829         }
1830         return rval
1831 }
1832
1833 func setNoOpt() {
1834         for _, gcflag := range strings.Split(gogcflags, " ") {
1835                 if gcflag == "-N" || gcflag == "-l" {
1836                         noOpt = true
1837                         break
1838                 }
1839         }
1840 }