github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/dist/utils.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  	"flag"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"sort"
    17  	"strconv"
    18  	"strings"
    19  	"sync"
    20  	"time"
    21  
    22  	"github.com/zxy12/go_duplicate_112_new/src/zdebug"
    23  )
    24  
    25  // pathf is fmt.Sprintf for generating paths
    26  // (on windows it turns / into \ after the printf).
    27  func pathf(format string, args ...interface{}) string {
    28  	return filepath.Clean(fmt.Sprintf(format, args...))
    29  }
    30  
    31  // filter returns a slice containing the elements x from list for which f(x) == true.
    32  func filter(list []string, f func(string) bool) []string {
    33  	var out []string
    34  	for _, x := range list {
    35  		if f(x) {
    36  			out = append(out, x)
    37  		}
    38  	}
    39  	return out
    40  }
    41  
    42  // uniq returns a sorted slice containing the unique elements of list.
    43  func uniq(list []string) []string {
    44  	out := make([]string, len(list))
    45  	copy(out, list)
    46  	sort.Strings(out)
    47  	keep := out[:0]
    48  	for _, x := range out {
    49  		if len(keep) == 0 || keep[len(keep)-1] != x {
    50  			keep = append(keep, x)
    51  		}
    52  	}
    53  	return keep
    54  }
    55  
    56  const (
    57  	CheckExit = 1 << iota
    58  	ShowOutput
    59  	Background
    60  )
    61  
    62  var outputLock sync.Mutex
    63  
    64  // run runs the command line cmd in dir.
    65  // If mode has ShowOutput set and Background unset, run passes cmd's output to
    66  // stdout/stderr directly. Otherwise, run returns cmd's output as a string.
    67  // If mode has CheckExit set and the command fails, run calls fatalf.
    68  // If mode has Background set, this command is being run as a
    69  // Background job. Only bgrun should use the Background mode,
    70  // not other callers.
    71  func run(dir string, mode int, cmd ...string) string {
    72  	if vflag > 1 {
    73  		errprintf("run: %s\n", strings.Join(cmd, " "))
    74  	}
    75  
    76  	zdebug.T("%v,dir=%v,mode=%v", cmd, dir, mode)
    77  	xcmd := exec.Command(cmd[0], cmd[1:]...)
    78  	xcmd.Dir = dir
    79  	var data []byte
    80  	var err error
    81  
    82  	// If we want to show command output and this is not
    83  	// a background command, assume it's the only thing
    84  	// running, so we can just let it write directly stdout/stderr
    85  	// as it runs without fear of mixing the output with some
    86  	// other command's output. Not buffering lets the output
    87  	// appear as it is printed instead of once the command exits.
    88  	// This is most important for the invocation of 'go1.4 build -v bootstrap/...'.
    89  	if mode&(Background|ShowOutput) == ShowOutput {
    90  		xcmd.Stdout = os.Stdout
    91  		xcmd.Stderr = os.Stderr
    92  		err = xcmd.Run()
    93  	} else {
    94  		data, err = xcmd.CombinedOutput()
    95  	}
    96  	if err != nil && mode&CheckExit != 0 {
    97  		outputLock.Lock()
    98  		if len(data) > 0 {
    99  			xprintf("%s\n", data)
   100  		}
   101  		outputLock.Unlock()
   102  		if mode&Background != 0 {
   103  			// Prevent fatalf from waiting on our own goroutine's
   104  			// bghelper to exit:
   105  			bghelpers.Done()
   106  		}
   107  		fatalf("FAILED: %v: %v", strings.Join(cmd, " "), err)
   108  	}
   109  	if mode&ShowOutput != 0 {
   110  		outputLock.Lock()
   111  		os.Stdout.Write(data)
   112  		outputLock.Unlock()
   113  	}
   114  	if vflag > 2 {
   115  		errprintf("run: %s DONE\n", strings.Join(cmd, " "))
   116  	}
   117  	return string(data)
   118  }
   119  
   120  var maxbg = 4 /* maximum number of jobs to run at once */
   121  
   122  var (
   123  	bgwork = make(chan func(), 1e5)
   124  
   125  	bghelpers sync.WaitGroup
   126  
   127  	dieOnce sync.Once // guards close of dying
   128  	dying   = make(chan struct{})
   129  )
   130  
   131  func bginit() {
   132  	bghelpers.Add(maxbg)
   133  	for i := 0; i < maxbg; i++ {
   134  		go bghelper()
   135  	}
   136  }
   137  
   138  func bghelper() {
   139  	defer bghelpers.Done()
   140  	for {
   141  		select {
   142  		case <-dying:
   143  			return
   144  		case w := <-bgwork:
   145  			// Dying takes precedence over doing more work.
   146  			select {
   147  			case <-dying:
   148  				return
   149  			default:
   150  				w()
   151  			}
   152  		}
   153  	}
   154  }
   155  
   156  // bgrun is like run but runs the command in the background.
   157  // CheckExit|ShowOutput mode is implied (since output cannot be returned).
   158  // bgrun adds 1 to wg immediately, and calls Done when the work completes.
   159  func bgrun(wg *sync.WaitGroup, dir string, cmd ...string) {
   160  	wg.Add(1)
   161  	bgwork <- func() {
   162  		defer wg.Done()
   163  		zdebug.T("bgrun[%v]", cmd)
   164  		run(dir, CheckExit|ShowOutput|Background, cmd...)
   165  	}
   166  }
   167  
   168  // bgwait waits for pending bgruns to finish.
   169  // bgwait must be called from only a single goroutine at a time.
   170  func bgwait(wg *sync.WaitGroup) {
   171  	done := make(chan struct{})
   172  	go func() {
   173  		wg.Wait()
   174  		close(done)
   175  	}()
   176  	select {
   177  	case <-done:
   178  	case <-dying:
   179  	}
   180  }
   181  
   182  // xgetwd returns the current directory.
   183  func xgetwd() string {
   184  	wd, err := os.Getwd()
   185  	if err != nil {
   186  		fatalf("%s", err)
   187  	}
   188  	return wd
   189  }
   190  
   191  // xrealwd returns the 'real' name for the given path.
   192  // real is defined as what xgetwd returns in that directory.
   193  func xrealwd(path string) string {
   194  	old := xgetwd()
   195  	if err := os.Chdir(path); err != nil {
   196  		fatalf("chdir %s: %v", path, err)
   197  	}
   198  	real := xgetwd()
   199  	if err := os.Chdir(old); err != nil {
   200  		fatalf("chdir %s: %v", old, err)
   201  	}
   202  	return real
   203  }
   204  
   205  // isdir reports whether p names an existing directory.
   206  func isdir(p string) bool {
   207  	fi, err := os.Stat(p)
   208  	return err == nil && fi.IsDir()
   209  }
   210  
   211  // isfile reports whether p names an existing file.
   212  func isfile(p string) bool {
   213  	fi, err := os.Stat(p)
   214  	return err == nil && fi.Mode().IsRegular()
   215  }
   216  
   217  // mtime returns the modification time of the file p.
   218  func mtime(p string) time.Time {
   219  	fi, err := os.Stat(p)
   220  	if err != nil {
   221  		return time.Time{}
   222  	}
   223  	return fi.ModTime()
   224  }
   225  
   226  // readfile returns the content of the named file.
   227  func readfile(file string) string {
   228  	data, err := ioutil.ReadFile(file)
   229  	if err != nil {
   230  		fatalf("%v", err)
   231  	}
   232  	return string(data)
   233  }
   234  
   235  const (
   236  	writeExec = 1 << iota
   237  	writeSkipSame
   238  )
   239  
   240  // writefile writes text to the named file, creating it if needed.
   241  // if exec is non-zero, marks the file as executable.
   242  // If the file already exists and has the expected content,
   243  // it is not rewritten, to avoid changing the time stamp.
   244  func writefile(text, file string, flag int) {
   245  	new := []byte(text)
   246  	if flag&writeSkipSame != 0 {
   247  		old, err := ioutil.ReadFile(file)
   248  		if err == nil && bytes.Equal(old, new) {
   249  			return
   250  		}
   251  	}
   252  	mode := os.FileMode(0666)
   253  	if flag&writeExec != 0 {
   254  		mode = 0777
   255  	}
   256  	err := ioutil.WriteFile(file, new, mode)
   257  	if err != nil {
   258  		fatalf("%v", err)
   259  	}
   260  }
   261  
   262  // xmkdir creates the directory p.
   263  func xmkdir(p string) {
   264  	err := os.Mkdir(p, 0777)
   265  	if err != nil {
   266  		fatalf("%v", err)
   267  	}
   268  }
   269  
   270  // xmkdirall creates the directory p and its parents, as needed.
   271  func xmkdirall(p string) {
   272  	err := os.MkdirAll(p, 0777)
   273  	if err != nil {
   274  		fatalf("%v", err)
   275  	}
   276  }
   277  
   278  // xremove removes the file p.
   279  func xremove(p string) {
   280  	if vflag > 2 {
   281  		errprintf("rm %s\n", p)
   282  	}
   283  	os.Remove(p)
   284  }
   285  
   286  // xremoveall removes the file or directory tree rooted at p.
   287  func xremoveall(p string, nolog ...int) {
   288  	if nolog == nil {
   289  
   290  	}
   291  
   292  	if vflag > 2 {
   293  		errprintf("rm -r %s\n", p)
   294  	}
   295  	os.RemoveAll(p)
   296  }
   297  
   298  // xreaddir replaces dst with a list of the names of the files and subdirectories in dir.
   299  // The names are relative to dir; they are not full paths.
   300  func xreaddir(dir string) []string {
   301  	f, err := os.Open(dir)
   302  	if err != nil {
   303  		fatalf("%v", err)
   304  	}
   305  	defer f.Close()
   306  	names, err := f.Readdirnames(-1)
   307  	if err != nil {
   308  		fatalf("reading %s: %v", dir, err)
   309  	}
   310  	return names
   311  }
   312  
   313  // xreaddir replaces dst with a list of the names of the files in dir.
   314  // The names are relative to dir; they are not full paths.
   315  func xreaddirfiles(dir string) []string {
   316  	f, err := os.Open(dir)
   317  	if err != nil {
   318  		fatalf("%v", err)
   319  	}
   320  	defer f.Close()
   321  	infos, err := f.Readdir(-1)
   322  	if err != nil {
   323  		fatalf("reading %s: %v", dir, err)
   324  	}
   325  	var names []string
   326  	for _, fi := range infos {
   327  		if !fi.IsDir() {
   328  			names = append(names, fi.Name())
   329  		}
   330  	}
   331  	// xprintf("bootstrapDir:%v,names%+v\n", dir, names)
   332  	return names
   333  }
   334  
   335  // xworkdir creates a new temporary directory to hold object files
   336  // and returns the name of that directory.
   337  func xworkdir() string {
   338  	name, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-tool-dist-")
   339  	if err != nil {
   340  		fatalf("%v", err)
   341  	}
   342  	return name
   343  }
   344  
   345  // fatalf prints an error message to standard error and exits.
   346  func fatalf(format string, args ...interface{}) {
   347  	fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
   348  
   349  	dieOnce.Do(func() { close(dying) })
   350  
   351  	// Wait for background goroutines to finish,
   352  	// so that exit handler that removes the work directory
   353  	// is not fighting with active writes or open files.
   354  	bghelpers.Wait()
   355  
   356  	xexit(2)
   357  }
   358  
   359  var atexits []func()
   360  
   361  // xexit exits the process with return code n.
   362  func xexit(n int) {
   363  	for i := len(atexits) - 1; i >= 0; i-- {
   364  		atexits[i]()
   365  	}
   366  	os.Exit(n)
   367  }
   368  
   369  // xatexit schedules the exit-handler f to be run when the program exits.
   370  func xatexit(f func()) {
   371  	atexits = append(atexits, f)
   372  }
   373  
   374  // xprintf prints a message to standard output.
   375  func xprintf(format string, args ...interface{}) {
   376  	fmt.Printf(format, args...)
   377  }
   378  
   379  // errprintf prints a message to standard output.
   380  func errprintf(format string, args ...interface{}) {
   381  	fmt.Fprintf(os.Stderr, format, args...)
   382  }
   383  
   384  // xsamefile reports whether f1 and f2 are the same file (or dir)
   385  func xsamefile(f1, f2 string) bool {
   386  	fi1, err1 := os.Stat(f1)
   387  	fi2, err2 := os.Stat(f2)
   388  	if err1 != nil || err2 != nil {
   389  		return f1 == f2
   390  	}
   391  	return os.SameFile(fi1, fi2)
   392  }
   393  
   394  func xgetgoarm() string {
   395  	if goos == "nacl" {
   396  		// NaCl guarantees VFPv3 and is always cross-compiled.
   397  		return "7"
   398  	}
   399  	if goos == "darwin" || goos == "android" {
   400  		// Assume all darwin/arm and android devices have VFPv3.
   401  		// These ports are also mostly cross-compiled, so it makes little
   402  		// sense to auto-detect the setting.
   403  		return "7"
   404  	}
   405  	if gohostarch != "arm" || goos != gohostos {
   406  		// Conservative default for cross-compilation.
   407  		return "5"
   408  	}
   409  	if goos == "freebsd" {
   410  		// FreeBSD has broken VFP support.
   411  		return "5"
   412  	}
   413  
   414  	// Try to exec ourselves in a mode to detect VFP support.
   415  	// Seeing how far it gets determines which instructions failed.
   416  	// The test is OS-agnostic.
   417  	out := run("", 0, os.Args[0], "-check-goarm")
   418  	v1ok := strings.Contains(out, "VFPv1 OK.")
   419  	v3ok := strings.Contains(out, "VFPv3 OK.")
   420  
   421  	if v1ok && v3ok {
   422  		return "7"
   423  	}
   424  	if v1ok {
   425  		return "6"
   426  	}
   427  	return "5"
   428  }
   429  
   430  func min(a, b int) int {
   431  	if a < b {
   432  		return a
   433  	}
   434  	return b
   435  }
   436  
   437  // elfIsLittleEndian detects if the ELF file is little endian.
   438  func elfIsLittleEndian(fn string) bool {
   439  	// read the ELF file header to determine the endianness without using the
   440  	// debug/elf package.
   441  	file, err := os.Open(fn)
   442  	if err != nil {
   443  		fatalf("failed to open file to determine endianness: %v", err)
   444  	}
   445  	defer file.Close()
   446  	var hdr [16]byte
   447  	if _, err := io.ReadFull(file, hdr[:]); err != nil {
   448  		fatalf("failed to read ELF header to determine endianness: %v", err)
   449  	}
   450  	// hdr[5] is EI_DATA byte, 1 is ELFDATA2LSB and 2 is ELFDATA2MSB
   451  	switch hdr[5] {
   452  	default:
   453  		fatalf("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
   454  	case 1:
   455  		return true
   456  	case 2:
   457  		return false
   458  	}
   459  	panic("unreachable")
   460  }
   461  
   462  // count is a flag.Value that is like a flag.Bool and a flag.Int.
   463  // If used as -name, it increments the count, but -name=x sets the count.
   464  // Used for verbose flag -v.
   465  type count int
   466  
   467  func (c *count) String() string {
   468  	return fmt.Sprint(int(*c))
   469  }
   470  
   471  func (c *count) Set(s string) error {
   472  	switch s {
   473  	case "true":
   474  		*c++
   475  	case "false":
   476  		*c = 0
   477  	default:
   478  		n, err := strconv.Atoi(s)
   479  		if err != nil {
   480  			return fmt.Errorf("invalid count %q", s)
   481  		}
   482  		*c = count(n)
   483  	}
   484  	return nil
   485  }
   486  
   487  func (c *count) IsBoolFlag() bool {
   488  	return true
   489  }
   490  
   491  func xflagparse(maxargs int) {
   492  	flag.Var((*count)(&vflag), "v", "verbosity")
   493  	flag.Parse()
   494  	if maxargs >= 0 && flag.NArg() > maxargs {
   495  		flag.Usage()
   496  	}
   497  }
   498  
   499  // Remove trailing spaces.
   500  func chomp(s string) string {
   501  	return strings.TrimRight(s, " \t\r\n")
   502  }
   503  
   504  // find reports the first index of p in l[0:n], or else -1.
   505  func find(p string, l []string) int {
   506  	for i, s := range l {
   507  		if p == s {
   508  			return i
   509  		}
   510  	}
   511  	return -1
   512  }
   513  
   514  // rmworkdir deletes the work directory.
   515  func rmworkdir() {
   516  	if vflag > 1 {
   517  		errprintf("rm -rf %s\n", workdir)
   518  	}
   519  	xremoveall(workdir, 1)
   520  }
   521  
   522  // compilerEnv returns a map from "goos/goarch" to the
   523  // compiler setting to use for that platform.
   524  // The entry for key "" covers any goos/goarch not explicitly set in the map.
   525  // For example, compilerEnv("CC", "gcc") returns the C compiler settings
   526  // read from $CC, defaulting to gcc.
   527  //
   528  // The result is a map because additional environment variables
   529  // can be set to change the compiler based on goos/goarch settings.
   530  // The following applies to all envNames but CC is assumed to simplify
   531  // the presentation.
   532  //
   533  // If no environment variables are set, we use def for all goos/goarch.
   534  // $CC, if set, applies to all goos/goarch but is overridden by the following.
   535  // $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
   536  // but is overridden by the following.
   537  // If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
   538  // $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
   539  func compilerEnv(envName, def string) map[string]string {
   540  	m := map[string]string{"": def}
   541  
   542  	if env := os.Getenv(envName); env != "" {
   543  		m[""] = env
   544  	}
   545  	if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
   546  		if gohostos != goos || gohostarch != goarch {
   547  			m[gohostos+"/"+gohostarch] = m[""]
   548  		}
   549  		m[""] = env
   550  	}
   551  
   552  	for _, goos := range okgoos {
   553  		for _, goarch := range okgoarch {
   554  			if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
   555  				m[goos+"/"+goarch] = env
   556  			}
   557  		}
   558  	}
   559  
   560  	return m
   561  }
   562  
   563  // xinit handles initialization of the various global state, like goroot and goarch.
   564  func xinit() {
   565  	b := os.Getenv("GOROOT")
   566  	if b == "" {
   567  		fatalf("$GOROOT must be set")
   568  	}
   569  	goroot = filepath.Clean(b)
   570  
   571  	b = os.Getenv("GOROOT_FINAL")
   572  	if b == "" {
   573  		b = goroot
   574  	}
   575  	goroot_final = b
   576  
   577  	b = os.Getenv("GOBIN")
   578  	if b == "" {
   579  		b = pathf("%s/bin", goroot)
   580  	}
   581  	gobin = b
   582  
   583  	b = os.Getenv("GOOS")
   584  	if b == "" {
   585  		b = gohostos
   586  	}
   587  	goos = b
   588  	if find(goos, okgoos) < 0 {
   589  		fatalf("unknown $GOOS %s", goos)
   590  	}
   591  
   592  	b = os.Getenv("GOARM")
   593  	if b == "" {
   594  		b = xgetgoarm()
   595  	}
   596  	goarm = b
   597  
   598  	b = os.Getenv("GO386")
   599  	if b == "" {
   600  		if cansse2() {
   601  			b = "sse2"
   602  		} else {
   603  			b = "387"
   604  		}
   605  	}
   606  	go386 = b
   607  
   608  	b = os.Getenv("GOMIPS")
   609  	if b == "" {
   610  		b = "hardfloat"
   611  	}
   612  	gomips = b
   613  
   614  	b = os.Getenv("GOMIPS64")
   615  	if b == "" {
   616  		b = "hardfloat"
   617  	}
   618  	gomips64 = b
   619  
   620  	if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
   621  		fatalf("$GOROOT is not set correctly or not exported\n"+
   622  			"\tGOROOT=%s\n"+
   623  			"\t%s does not exist", goroot, p)
   624  	}
   625  
   626  	b = os.Getenv("GOHOSTARCH")
   627  	if b != "" {
   628  		gohostarch = b
   629  	}
   630  	if find(gohostarch, okgoarch) < 0 {
   631  		fatalf("unknown $GOHOSTARCH %s", gohostarch)
   632  	}
   633  
   634  	b = os.Getenv("GOARCH")
   635  	if b == "" {
   636  		b = gohostarch
   637  	}
   638  	goarch = b
   639  	if find(goarch, okgoarch) < 0 {
   640  		fatalf("unknown $GOARCH %s", goarch)
   641  	}
   642  
   643  	b = os.Getenv("GO_EXTLINK_ENABLED")
   644  	if b != "" {
   645  		if b != "0" && b != "1" {
   646  			fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
   647  		}
   648  		goextlinkenabled = b
   649  	}
   650  
   651  	gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
   652  
   653  	cc, cxx := "gcc", "g++"
   654  	if defaultclang {
   655  		cc, cxx = "clang", "clang++"
   656  	}
   657  	defaultcc = compilerEnv("CC", cc)
   658  	defaultcxx = compilerEnv("CXX", cxx)
   659  
   660  	defaultcflags = os.Getenv("CFLAGS")
   661  	defaultldflags = os.Getenv("LDFLAGS")
   662  
   663  	b = os.Getenv("PKG_CONFIG")
   664  	if b == "" {
   665  		b = "pkg-config"
   666  	}
   667  	defaultpkgconfig = b
   668  
   669  	// For tools being invoked but also for os.ExpandEnv.
   670  	os.Setenv("GO386", go386)
   671  	os.Setenv("GOARCH", goarch)
   672  	os.Setenv("GOARM", goarm)
   673  	os.Setenv("GOHOSTARCH", gohostarch)
   674  	os.Setenv("GOHOSTOS", gohostos)
   675  	os.Setenv("GOOS", goos)
   676  	os.Setenv("GOMIPS", gomips)
   677  	os.Setenv("GOMIPS64", gomips64)
   678  	os.Setenv("GOROOT", goroot)
   679  	os.Setenv("GOROOT_FINAL", goroot_final)
   680  
   681  	// Use a build cache separate from the default user one.
   682  	// Also one that will be wiped out during startup, so that
   683  	// make.bash really does start from a clean slate.
   684  	os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot))
   685  
   686  	// Make the environment more predictable.
   687  	os.Setenv("LANG", "C")
   688  	os.Setenv("LANGUAGE", "en_US.UTF8")
   689  
   690  	workdir = xworkdir()
   691  	xatexit(rmworkdir)
   692  
   693  	tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
   694  }
   695  
   696  func goInstall(goBinary string, args ...string) {
   697  	installCmd := []string{goBinary, "install", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags}
   698  	if vflag > 0 {
   699  		installCmd = append(installCmd, "-v")
   700  	}
   701  
   702  	// Force only one process at a time on vx32 emulation.
   703  	if gohostos == "plan9" && os.Getenv("sysname") == "vx32" {
   704  		installCmd = append(installCmd, "-p=1")
   705  	}
   706  
   707  	run(goroot, ShowOutput|CheckExit, append(installCmd, args...)...)
   708  }
   709  
   710  func checkNotStale(goBinary string, targets ...string) {
   711  	out := run(goroot, CheckExit,
   712  		append([]string{
   713  			goBinary,
   714  			"list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags,
   715  			"-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}",
   716  		}, targets...)...)
   717  	if strings.Contains(out, "\tSTALE ") {
   718  		os.Setenv("GODEBUG", "gocachehash=1")
   719  		for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} {
   720  			if strings.Contains(out, "STALE "+target) {
   721  				run(goroot, ShowOutput|CheckExit, goBinary, "list", "-f={{.ImportPath}} {{.Stale}}", target)
   722  				break
   723  			}
   724  		}
   725  		fatalf("unexpected stale targets reported by %s list -gcflags=\"%s\" -ldflags=\"%s\" for %v:\n%s", goBinary, gogcflags, goldflags, targets, out)
   726  	}
   727  }
   728  
   729  // compilerEnvLookup returns the compiler settings for goos/goarch in map m.
   730  func compilerEnvLookup(m map[string]string, goos, goarch string) string {
   731  	if cc := m[goos+"/"+goarch]; cc != "" {
   732  		return cc
   733  	}
   734  	return m[""]
   735  }
   736  
   737  // copy copies the file src to dst, via memory (so only good for small files).
   738  func copyfile(dst, src string, flag int) {
   739  
   740  	if vflag > 1 {
   741  		errprintf("cp %s %s\n", src, dst)
   742  	}
   743  	writefile(readfile(src), dst, flag)
   744  }
   745  
   746  // shouldbuild reports whether we should build this file.
   747  // It applies the same rules that are used with context tags
   748  // in package go/build, except it's less picky about the order
   749  // of GOOS and GOARCH.
   750  // We also allow the special tag cmd_go_bootstrap.
   751  // See ../go/bootstrap.go and package go/build.
   752  func shouldbuild(file, dir string) bool {
   753  	// Check file name for GOOS or GOARCH.
   754  	name := filepath.Base(file)
   755  	excluded := func(list []string, ok string) bool {
   756  		for _, x := range list {
   757  			if x == ok || ok == "android" && x == "linux" {
   758  				continue
   759  			}
   760  			i := strings.Index(name, x)
   761  			if i <= 0 || name[i-1] != '_' {
   762  				continue
   763  			}
   764  			i += len(x)
   765  			if i == len(name) || name[i] == '.' || name[i] == '_' {
   766  				return true
   767  			}
   768  		}
   769  		return false
   770  	}
   771  	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
   772  		return false
   773  	}
   774  
   775  	// Omit test files.
   776  	if strings.Contains(name, "_test") {
   777  		return false
   778  	}
   779  
   780  	// Check file contents for // +build lines.
   781  	for _, p := range strings.Split(readfile(file), "\n") {
   782  		p = strings.TrimSpace(p)
   783  		if p == "" {
   784  			continue
   785  		}
   786  		code := p
   787  		i := strings.Index(code, "//")
   788  		if i > 0 {
   789  			code = strings.TrimSpace(code[:i])
   790  		}
   791  		if code == "package documentation" {
   792  			return false
   793  		}
   794  		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
   795  			return false
   796  		}
   797  		if !strings.HasPrefix(p, "//") {
   798  			break
   799  		}
   800  		if !strings.Contains(p, "+build") {
   801  			continue
   802  		}
   803  		fields := strings.Fields(p[2:])
   804  		if len(fields) < 1 || fields[0] != "+build" {
   805  			continue
   806  		}
   807  		for _, p := range fields[1:] {
   808  			if matchfield(p) {
   809  				goto fieldmatch
   810  			}
   811  		}
   812  		return false
   813  	fieldmatch:
   814  	}
   815  
   816  	return true
   817  }
   818  
   819  // dopack copies the package src to dst,
   820  // appending the files listed in extra.
   821  // The archive format is the traditional Unix ar format.
   822  func dopack(dst, src string, extra []string) {
   823  	bdst := bytes.NewBufferString(readfile(src))
   824  	for _, file := range extra {
   825  		b := readfile(file)
   826  		// find last path element for archive member name
   827  		i := strings.LastIndex(file, "/") + 1
   828  		j := strings.LastIndex(file, `\`) + 1
   829  		if i < j {
   830  			i = j
   831  		}
   832  		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
   833  		bdst.WriteString(b)
   834  		if len(b)&1 != 0 {
   835  			bdst.WriteByte(0)
   836  		}
   837  	}
   838  	writefile(bdst.String(), dst, 0)
   839  }
   840  
   841  // matchfield reports whether the field (x,y,z) matches this build.
   842  // all the elements in the field must be satisfied.
   843  func matchfield(f string) bool {
   844  	for _, tag := range strings.Split(f, ",") {
   845  		if !matchtag(tag) {
   846  			return false
   847  		}
   848  	}
   849  	return true
   850  }
   851  
   852  // matchtag reports whether the tag (x or !x) matches this build.
   853  func matchtag(tag string) bool {
   854  	if tag == "" {
   855  		return false
   856  	}
   857  	if tag[0] == '!' {
   858  		if len(tag) == 1 || tag[1] == '!' {
   859  			return false
   860  		}
   861  		return !matchtag(tag[1:])
   862  	}
   863  	return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
   864  }