Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/dist/build.go

Documentation: cmd/dist

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

View as plain text