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

View as plain text