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