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