github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/dist/build.go (about)

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