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  	// Use a build cache separate from the default user one.
  1398  	// Also one that will be wiped out during startup, so that
  1399  	// make.bash really does start from a clean slate.
  1400  	oldgocache = os.Getenv("GOCACHE")
  1401  	os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
  1402  
  1403  	// Disable GOEXPERIMENT when building toolchain1 and
  1404  	// go_bootstrap. We don't need any experiments for the
  1405  	// bootstrap toolchain, and this lets us avoid duplicating the
  1406  	// GOEXPERIMENT-related build logic from cmd/go here. If the
  1407  	// bootstrap toolchain is < Go 1.17, it will ignore this
  1408  	// anyway since GOEXPERIMENT is baked in; otherwise it will
  1409  	// pick it up from the environment we set here. Once we're
  1410  	// using toolchain1 with dist as the build system, we need to
  1411  	// override this to keep the experiments assumed by the
  1412  	// toolchain and by dist consistent. Once go_bootstrap takes
  1413  	// over the build process, we'll set this back to the original
  1414  	// GOEXPERIMENT.
  1415  	os.Setenv("GOEXPERIMENT", "none")
  1416  
  1417  	if debug {
  1418  		// cmd/buildid is used in debug mode.
  1419  		toolchain = append(toolchain, "cmd/buildid")
  1420  	}
  1421  
  1422  	if isdir(pathf("%s/src/pkg", goroot)) {
  1423  		fatalf("\n\n"+
  1424  			"The Go package sources have moved to $GOROOT/src.\n"+
  1425  			"*** %s still exists. ***\n"+
  1426  			"It probably contains stale files that may confuse the build.\n"+
  1427  			"Please (check what's there and) remove it and try again.\n"+
  1428  			"See https://golang.org/s/go14nopkg\n",
  1429  			pathf("%s/src/pkg", goroot))
  1430  	}
  1431  
  1432  	if rebuildall {
  1433  		clean()
  1434  	}
  1435  
  1436  	setup()
  1437  
  1438  	timelog("build", "toolchain1")
  1439  	checkCC()
  1440  	bootstrapBuildTools()
  1441  
  1442  	// Remember old content of $GOROOT/bin for comparison below.
  1443  	oldBinFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
  1444  	if err != nil {
  1445  		fatalf("glob: %v", err)
  1446  	}
  1447  
  1448  	// For the main bootstrap, building for host os/arch.
  1449  	oldgoos = goos
  1450  	oldgoarch = goarch
  1451  	goos = gohostos
  1452  	goarch = gohostarch
  1453  	os.Setenv("GOHOSTARCH", gohostarch)
  1454  	os.Setenv("GOHOSTOS", gohostos)
  1455  	os.Setenv("GOARCH", goarch)
  1456  	os.Setenv("GOOS", goos)
  1457  
  1458  	timelog("build", "go_bootstrap")
  1459  	xprintf("Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.\n")
  1460  	install("runtime")     // dependency not visible in sources; also sets up textflag.h
  1461  	install("time/tzdata") // no dependency in sources; creates generated file
  1462  	install("cmd/go")
  1463  	if vflag > 0 {
  1464  		xprintf("\n")
  1465  	}
  1466  
  1467  	gogcflags = os.Getenv("GO_GCFLAGS") // we were using $BOOT_GO_GCFLAGS until now
  1468  	setNoOpt()
  1469  	goldflags = os.Getenv("GO_LDFLAGS") // we were using $BOOT_GO_LDFLAGS until now
  1470  	goBootstrap := pathf("%s/go_bootstrap", tooldir)
  1471  	if debug {
  1472  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1473  		copyfile(pathf("%s/compile1", tooldir), pathf("%s/compile", tooldir), writeExec)
  1474  	}
  1475  
  1476  	// To recap, so far we have built the new toolchain
  1477  	// (cmd/asm, cmd/cgo, cmd/compile, cmd/link)
  1478  	// using the Go bootstrap toolchain and go command.
  1479  	// Then we built the new go command (as go_bootstrap)
  1480  	// using the new toolchain and our own build logic (above).
  1481  	//
  1482  	//	toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go)
  1483  	//	go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)
  1484  	//
  1485  	// The toolchain1 we built earlier is built from the new sources,
  1486  	// but because it was built using cmd/go it has no build IDs.
  1487  	// The eventually installed toolchain needs build IDs, so we need
  1488  	// to do another round:
  1489  	//
  1490  	//	toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)
  1491  	//
  1492  	timelog("build", "toolchain2")
  1493  	if vflag > 0 {
  1494  		xprintf("\n")
  1495  	}
  1496  	xprintf("Building Go toolchain2 using go_bootstrap and Go toolchain1.\n")
  1497  	os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
  1498  	// Now that cmd/go is in charge of the build process, enable GOEXPERIMENT.
  1499  	os.Setenv("GOEXPERIMENT", goexperiment)
  1500  	// No need to enable PGO for toolchain2.
  1501  	goInstall(toolenv(), goBootstrap, append([]string{"-pgo=off"}, toolchain...)...)
  1502  	if debug {
  1503  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1504  		copyfile(pathf("%s/compile2", tooldir), pathf("%s/compile", tooldir), writeExec)
  1505  	}
  1506  
  1507  	// Toolchain2 should be semantically equivalent to toolchain1,
  1508  	// but it was built using the newly built compiler instead of the Go bootstrap compiler,
  1509  	// so it should at the least run faster. Also, toolchain1 had no build IDs
  1510  	// in the binaries, while toolchain2 does. In non-release builds, the
  1511  	// toolchain's build IDs feed into constructing the build IDs of built targets,
  1512  	// so in non-release builds, everything now looks out-of-date due to
  1513  	// toolchain2 having build IDs - that is, due to the go command seeing
  1514  	// that there are new compilers. In release builds, the toolchain's reported
  1515  	// version is used in place of the build ID, and the go command does not
  1516  	// see that change from toolchain1 to toolchain2, so in release builds,
  1517  	// nothing looks out of date.
  1518  	// To keep the behavior the same in both non-release and release builds,
  1519  	// we force-install everything here.
  1520  	//
  1521  	//	toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)
  1522  	//
  1523  	timelog("build", "toolchain3")
  1524  	if vflag > 0 {
  1525  		xprintf("\n")
  1526  	}
  1527  	xprintf("Building Go toolchain3 using go_bootstrap and Go toolchain2.\n")
  1528  	goInstall(toolenv(), goBootstrap, append([]string{"-a"}, toolchain...)...)
  1529  	if debug {
  1530  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1531  		copyfile(pathf("%s/compile3", tooldir), pathf("%s/compile", tooldir), writeExec)
  1532  	}
  1533  
  1534  	// Now that toolchain3 has been built from scratch, its compiler and linker
  1535  	// should have accurate build IDs suitable for caching.
  1536  	// Now prime the build cache with the rest of the standard library for
  1537  	// testing, and so that the user can run 'go install std cmd' to quickly
  1538  	// iterate on local changes without waiting for a full rebuild.
  1539  	if _, err := os.Stat(pathf("%s/VERSION", goroot)); err == nil {
  1540  		// If we have a VERSION file, then we use the Go version
  1541  		// instead of build IDs as a cache key, and there is no guarantee
  1542  		// that code hasn't changed since the last time we ran a build
  1543  		// with this exact VERSION file (especially if someone is working
  1544  		// on a release branch). We must not fall back to the shared build cache
  1545  		// in this case. Leave $GOCACHE alone.
  1546  	} else {
  1547  		os.Setenv("GOCACHE", oldgocache)
  1548  	}
  1549  
  1550  	if goos == oldgoos && goarch == oldgoarch {
  1551  		// Common case - not setting up for cross-compilation.
  1552  		timelog("build", "toolchain")
  1553  		if vflag > 0 {
  1554  			xprintf("\n")
  1555  		}
  1556  		xprintf("Building packages and commands for %s/%s.\n", goos, goarch)
  1557  	} else {
  1558  		// GOOS/GOARCH does not match GOHOSTOS/GOHOSTARCH.
  1559  		// Finish GOHOSTOS/GOHOSTARCH installation and then
  1560  		// run GOOS/GOARCH installation.
  1561  		timelog("build", "host toolchain")
  1562  		if vflag > 0 {
  1563  			xprintf("\n")
  1564  		}
  1565  		xprintf("Building commands for host, %s/%s.\n", goos, goarch)
  1566  		goInstall(toolenv(), goBootstrap, "cmd")
  1567  		checkNotStale(toolenv(), goBootstrap, "cmd")
  1568  		checkNotStale(toolenv(), gorootBinGo, "cmd")
  1569  
  1570  		timelog("build", "target toolchain")
  1571  		if vflag > 0 {
  1572  			xprintf("\n")
  1573  		}
  1574  		goos = oldgoos
  1575  		goarch = oldgoarch
  1576  		os.Setenv("GOOS", goos)
  1577  		os.Setenv("GOARCH", goarch)
  1578  		os.Setenv("CC", compilerEnvLookup("CC", defaultcc, goos, goarch))
  1579  		xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch)
  1580  	}
  1581  	goInstall(nil, goBootstrap, "std")
  1582  	goInstall(toolenv(), goBootstrap, "cmd")
  1583  	checkNotStale(toolenv(), goBootstrap, toolchain...)
  1584  	checkNotStale(nil, goBootstrap, "std")
  1585  	checkNotStale(toolenv(), goBootstrap, "cmd")
  1586  	checkNotStale(nil, gorootBinGo, "std")
  1587  	checkNotStale(toolenv(), gorootBinGo, "cmd")
  1588  	if debug {
  1589  		run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full")
  1590  		checkNotStale(toolenv(), goBootstrap, toolchain...)
  1591  		copyfile(pathf("%s/compile4", tooldir), pathf("%s/compile", tooldir), writeExec)
  1592  	}
  1593  
  1594  	// Check that there are no new files in $GOROOT/bin other than
  1595  	// go and gofmt and $GOOS_$GOARCH (target bin when cross-compiling).
  1596  	binFiles, err := filepath.Glob(pathf("%s/bin/*", goroot))
  1597  	if err != nil {
  1598  		fatalf("glob: %v", err)
  1599  	}
  1600  
  1601  	ok := map[string]bool{}
  1602  	for _, f := range oldBinFiles {
  1603  		ok[f] = true
  1604  	}
  1605  	for _, f := range binFiles {
  1606  		if gohostos == "darwin" && filepath.Base(f) == ".DS_Store" {
  1607  			continue // unfortunate but not unexpected
  1608  		}
  1609  		elem := strings.TrimSuffix(filepath.Base(f), ".exe")
  1610  		if !ok[f] && elem != "go" && elem != "gofmt" && elem != goos+"_"+goarch {
  1611  			fatalf("unexpected new file in $GOROOT/bin: %s", elem)
  1612  		}
  1613  	}
  1614  
  1615  	// Remove go_bootstrap now that we're done.
  1616  	xremove(pathf("%s/go_bootstrap"+exe, tooldir))
  1617  
  1618  	if goos == "android" {
  1619  		// Make sure the exec wrapper will sync a fresh $GOROOT to the device.
  1620  		xremove(pathf("%s/go_android_exec-adb-sync-status", os.TempDir()))
  1621  	}
  1622  
  1623  	if wrapperPath := wrapperPathFor(goos, goarch); wrapperPath != "" {
  1624  		oldcc := os.Getenv("CC")
  1625  		os.Setenv("GOOS", gohostos)
  1626  		os.Setenv("GOARCH", gohostarch)
  1627  		os.Setenv("CC", compilerEnvLookup("CC", defaultcc, gohostos, gohostarch))
  1628  		goCmd(nil, gorootBinGo, "build", "-o", pathf("%s/go_%s_%s_exec%s", gorootBin, goos, goarch, exe), wrapperPath)
  1629  		// Restore environment.
  1630  		// TODO(elias.naur): support environment variables in goCmd?
  1631  		os.Setenv("GOOS", goos)
  1632  		os.Setenv("GOARCH", goarch)
  1633  		os.Setenv("CC", oldcc)
  1634  	}
  1635  
  1636  	if distpack {
  1637  		xprintf("Packaging archives for %s/%s.\n", goos, goarch)
  1638  		run("", ShowOutput|CheckExit, pathf("%s/distpack", tooldir))
  1639  	}
  1640  
  1641  	// Print trailing banner unless instructed otherwise.
  1642  	if !noBanner {
  1643  		banner()
  1644  	}
  1645  }
  1646  
  1647  func wrapperPathFor(goos, goarch string) string {
  1648  	switch {
  1649  	case goos == "android":
  1650  		if gohostos != "android" {
  1651  			return pathf("%s/misc/go_android_exec/main.go", goroot)
  1652  		}
  1653  	case goos == "ios":
  1654  		if gohostos != "ios" {
  1655  			return pathf("%s/misc/ios/go_ios_exec.go", goroot)
  1656  		}
  1657  	}
  1658  	return ""
  1659  }
  1660  
  1661  func goInstall(env []string, goBinary string, args ...string) {
  1662  	goCmd(env, goBinary, "install", args...)
  1663  }
  1664  
  1665  func appendCompilerFlags(args []string) []string {
  1666  	if gogcflags != "" {
  1667  		args = append(args, "-gcflags=all="+gogcflags)
  1668  	}
  1669  	if goldflags != "" {
  1670  		args = append(args, "-ldflags=all="+goldflags)
  1671  	}
  1672  	return args
  1673  }
  1674  
  1675  func goCmd(env []string, goBinary string, cmd string, args ...string) {
  1676  	goCmd := []string{goBinary, cmd}
  1677  	if noOpt {
  1678  		goCmd = append(goCmd, "-tags=noopt")
  1679  	}
  1680  	goCmd = appendCompilerFlags(goCmd)
  1681  	if vflag > 0 {
  1682  		goCmd = append(goCmd, "-v")
  1683  	}
  1684  
  1685  	// Force only one process at a time on vx32 emulation.
  1686  	if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
  1687  		goCmd = append(goCmd, "-p=1")
  1688  	}
  1689  
  1690  	runEnv(workdir, ShowOutput|CheckExit, env, append(goCmd, args...)...)
  1691  }
  1692  
  1693  func checkNotStale(env []string, goBinary string, targets ...string) {
  1694  	goCmd := []string{goBinary, "list"}
  1695  	if noOpt {
  1696  		goCmd = append(goCmd, "-tags=noopt")
  1697  	}
  1698  	goCmd = appendCompilerFlags(goCmd)
  1699  	goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}")
  1700  
  1701  	out := runEnv(workdir, CheckExit, env, append(goCmd, targets...)...)
  1702  	if strings.Contains(out, "\tSTALE ") {
  1703  		os.Setenv("GODEBUG", "gocachehash=1")
  1704  		for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
  1705  			if strings.Contains(out, "STALE "+target) {
  1706  				run(workdir, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
  1707  				break
  1708  			}
  1709  		}
  1710  		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)
  1711  	}
  1712  }
  1713  
  1714  // Cannot use go/build directly because cmd/dist for a new release
  1715  // builds against an old release's go/build, which may be out of sync.
  1716  // To reduce duplication, we generate the list for go/build from this.
  1717  //
  1718  // We list all supported platforms in this list, so that this is the
  1719  // single point of truth for supported platforms. This list is used
  1720  // by 'go tool dist list'.
  1721  var cgoEnabled = map[string]bool{
  1722  	"aix/ppc64":       true,
  1723  	"darwin/amd64":    true,
  1724  	"darwin/arm64":    true,
  1725  	"dragonfly/amd64": true,
  1726  	"freebsd/386":     true,
  1727  	"freebsd/amd64":   true,
  1728  	"freebsd/arm":     true,
  1729  	"freebsd/arm64":   true,
  1730  	"freebsd/riscv64": true,
  1731  	"illumos/amd64":   true,
  1732  	"linux/386":       true,
  1733  	"linux/amd64":     true,
  1734  	"linux/arm":       true,
  1735  	"linux/arm64":     true,
  1736  	"linux/loong64":   true,
  1737  	"linux/ppc64":     false,
  1738  	"linux/ppc64le":   true,
  1739  	"linux/mips":      true,
  1740  	"linux/mipsle":    true,
  1741  	"linux/mips64":    true,
  1742  	"linux/mips64le":  true,
  1743  	"linux/riscv64":   true,
  1744  	"linux/s390x":     true,
  1745  	"linux/sparc64":   true,
  1746  	"android/386":     true,
  1747  	"android/amd64":   true,
  1748  	"android/arm":     true,
  1749  	"android/arm64":   true,
  1750  	"ios/arm64":       true,
  1751  	"ios/amd64":       true,
  1752  	"js/wasm":         false,
  1753  	"wasip1/wasm":     false,
  1754  	"netbsd/386":      true,
  1755  	"netbsd/amd64":    true,
  1756  	"netbsd/arm":      true,
  1757  	"netbsd/arm64":    true,
  1758  	"openbsd/386":     true,
  1759  	"openbsd/amd64":   true,
  1760  	"openbsd/arm":     true,
  1761  	"openbsd/arm64":   true,
  1762  	"openbsd/mips64":  true,
  1763  	"openbsd/ppc64":   false,
  1764  	"openbsd/riscv64": true,
  1765  	"plan9/386":       false,
  1766  	"plan9/amd64":     false,
  1767  	"plan9/arm":       false,
  1768  	"solaris/amd64":   true,
  1769  	"windows/386":     true,
  1770  	"windows/amd64":   true,
  1771  	"windows/arm":     false,
  1772  	"windows/arm64":   true,
  1773  }
  1774  
  1775  // List of platforms that are marked as broken ports.
  1776  // These require -force flag to build, and also
  1777  // get filtered out of cgoEnabled for 'dist list'.
  1778  // See go.dev/issue/56679.
  1779  var broken = map[string]bool{
  1780  	"linux/sparc64":  true, // An incomplete port. See CL 132155.
  1781  	"openbsd/mips64": true, // Broken: go.dev/issue/58110.
  1782  }
  1783  
  1784  // List of platforms which are first class ports. See go.dev/issue/38874.
  1785  var firstClass = map[string]bool{
  1786  	"darwin/amd64":  true,
  1787  	"darwin/arm64":  true,
  1788  	"linux/386":     true,
  1789  	"linux/amd64":   true,
  1790  	"linux/arm":     true,
  1791  	"linux/arm64":   true,
  1792  	"windows/386":   true,
  1793  	"windows/amd64": true,
  1794  }
  1795  
  1796  // We only need CC if cgo is forced on, or if the platform requires external linking.
  1797  // Otherwise the go command will automatically disable it.
  1798  func needCC() bool {
  1799  	return os.Getenv("CGO_ENABLED") == "1" || mustLinkExternal(gohostos, gohostarch, false)
  1800  }
  1801  
  1802  func checkCC() {
  1803  	if !needCC() {
  1804  		return
  1805  	}
  1806  	cc1 := defaultcc[""]
  1807  	if cc1 == "" {
  1808  		cc1 = "gcc"
  1809  		for _, os := range clangos {
  1810  			if gohostos == os {
  1811  				cc1 = "clang"
  1812  				break
  1813  			}
  1814  		}
  1815  	}
  1816  	cc, err := quotedSplit(cc1)
  1817  	if err != nil {
  1818  		fatalf("split CC: %v", err)
  1819  	}
  1820  	var ccHelp = append(cc, "--help")
  1821  
  1822  	if output, err := exec.Command(ccHelp[0], ccHelp[1:]...).CombinedOutput(); err != nil {
  1823  		outputHdr := ""
  1824  		if len(output) > 0 {
  1825  			outputHdr = "\nCommand output:\n\n"
  1826  		}
  1827  		fatalf("cannot invoke C compiler %q: %v\n\n"+
  1828  			"Go needs a system C compiler for use with cgo.\n"+
  1829  			"To set a C compiler, set CC=the-compiler.\n"+
  1830  			"To disable cgo, set CGO_ENABLED=0.\n%s%s", cc, err, outputHdr, output)
  1831  	}
  1832  }
  1833  
  1834  func defaulttarg() string {
  1835  	// xgetwd might return a path with symlinks fully resolved, and if
  1836  	// there happens to be symlinks in goroot, then the hasprefix test
  1837  	// will never succeed. Instead, we use xrealwd to get a canonical
  1838  	// goroot/src before the comparison to avoid this problem.
  1839  	pwd := xgetwd()
  1840  	src := pathf("%s/src/", goroot)
  1841  	real_src := xrealwd(src)
  1842  	if !strings.HasPrefix(pwd, real_src) {
  1843  		fatalf("current directory %s is not under %s", pwd, real_src)
  1844  	}
  1845  	pwd = pwd[len(real_src):]
  1846  	// guard against xrealwd returning the directory without the trailing /
  1847  	pwd = strings.TrimPrefix(pwd, "/")
  1848  
  1849  	return pwd
  1850  }
  1851  
  1852  // Install installs the list of packages named on the command line.
  1853  func cmdinstall() {
  1854  	xflagparse(-1)
  1855  
  1856  	if flag.NArg() == 0 {
  1857  		install(defaulttarg())
  1858  	}
  1859  
  1860  	for _, arg := range flag.Args() {
  1861  		install(arg)
  1862  	}
  1863  }
  1864  
  1865  // Clean deletes temporary objects.
  1866  func cmdclean() {
  1867  	xflagparse(0)
  1868  	clean()
  1869  }
  1870  
  1871  // Banner prints the 'now you've installed Go' banner.
  1872  func cmdbanner() {
  1873  	xflagparse(0)
  1874  	banner()
  1875  }
  1876  
  1877  func banner() {
  1878  	if vflag > 0 {
  1879  		xprintf("\n")
  1880  	}
  1881  	xprintf("---\n")
  1882  	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
  1883  	xprintf("Installed commands in %s\n", gorootBin)
  1884  
  1885  	if gohostos == "plan9" {
  1886  		// Check that GOROOT/bin is bound before /bin.
  1887  		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
  1888  		ns := fmt.Sprintf("/proc/%s/ns", pid)
  1889  		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gorootBin)) {
  1890  			xprintf("*** You need to bind %s before /bin.\n", gorootBin)
  1891  		}
  1892  	} else {
  1893  		// Check that GOROOT/bin appears in $PATH.
  1894  		pathsep := ":"
  1895  		if gohostos == "windows" {
  1896  			pathsep = ";"
  1897  		}
  1898  		path := os.Getenv("PATH")
  1899  		if p, ok := os.LookupEnv("DIST_UNMODIFIED_PATH"); ok {
  1900  			// Scripts that modify $PATH and then run dist should also provide
  1901  			// dist with an unmodified copy of $PATH via $DIST_UNMODIFIED_PATH.
  1902  			// Use it here when determining if the user still needs to update
  1903  			// their $PATH. See go.dev/issue/42563.
  1904  			path = p
  1905  		}
  1906  		if !strings.Contains(pathsep+path+pathsep, pathsep+gorootBin+pathsep) {
  1907  			xprintf("*** You need to add %s to your PATH.\n", gorootBin)
  1908  		}
  1909  	}
  1910  }
  1911  
  1912  // Version prints the Go version.
  1913  func cmdversion() {
  1914  	xflagparse(0)
  1915  	xprintf("%s\n", findgoversion())
  1916  }
  1917  
  1918  // cmdlist lists all supported platforms.
  1919  func cmdlist() {
  1920  	jsonFlag := flag.Bool("json", false, "produce JSON output")
  1921  	brokenFlag := flag.Bool("broken", false, "include broken ports")
  1922  	xflagparse(0)
  1923  
  1924  	var plats []string
  1925  	for p := range cgoEnabled {
  1926  		if broken[p] && !*brokenFlag {
  1927  			continue
  1928  		}
  1929  		plats = append(plats, p)
  1930  	}
  1931  	sort.Strings(plats)
  1932  
  1933  	if !*jsonFlag {
  1934  		for _, p := range plats {
  1935  			xprintf("%s\n", p)
  1936  		}
  1937  		return
  1938  	}
  1939  
  1940  	type jsonResult struct {
  1941  		GOOS         string
  1942  		GOARCH       string
  1943  		CgoSupported bool
  1944  		FirstClass   bool
  1945  		Broken       bool `json:",omitempty"`
  1946  	}
  1947  	var results []jsonResult
  1948  	for _, p := range plats {
  1949  		fields := strings.Split(p, "/")
  1950  		results = append(results, jsonResult{
  1951  			GOOS:         fields[0],
  1952  			GOARCH:       fields[1],
  1953  			CgoSupported: cgoEnabled[p],
  1954  			FirstClass:   firstClass[p],
  1955  			Broken:       broken[p],
  1956  		})
  1957  	}
  1958  	out, err := json.MarshalIndent(results, "", "\t")
  1959  	if err != nil {
  1960  		fatalf("json marshal error: %v", err)
  1961  	}
  1962  	if _, err := os.Stdout.Write(out); err != nil {
  1963  		fatalf("write failed: %v", err)
  1964  	}
  1965  }
  1966  
  1967  func setNoOpt() {
  1968  	for _, gcflag := range strings.Split(gogcflags, " ") {
  1969  		if gcflag == "-N" || gcflag == "-l" {
  1970  			noOpt = true
  1971  			break
  1972  		}
  1973  	}
  1974  }
  1975  

View as plain text