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

View as plain text