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

View as plain text