github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/dist/test.go (about)

     1  // Copyright 2015 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  	"errors"
    10  	"flag"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"log"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"reflect"
    18  	"regexp"
    19  	"runtime"
    20  	"strconv"
    21  	"strings"
    22  	"sync"
    23  	"time"
    24  )
    25  
    26  func cmdtest() {
    27  	gogcflags = os.Getenv("GO_GCFLAGS")
    28  
    29  	var t tester
    30  	var noRebuild bool
    31  	flag.BoolVar(&t.listMode, "list", false, "list available tests")
    32  	flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
    33  	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
    34  	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
    35  	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
    36  	flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them. This is for some builders. Not all dist tests respect this flag, but most do.")
    37  	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
    38  	flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
    39  		"run only those tests matching the regular expression; empty means to run all. "+
    40  			"Special exception: if the string begins with '!', the match is inverted.")
    41  	xflagparse(-1) // any number of args
    42  	if noRebuild {
    43  		t.rebuild = false
    44  	}
    45  	t.run()
    46  }
    47  
    48  // tester executes cmdtest.
    49  type tester struct {
    50  	race        bool
    51  	listMode    bool
    52  	rebuild     bool
    53  	failed      bool
    54  	keepGoing   bool
    55  	compileOnly bool // just try to compile all tests, but no need to run
    56  	runRxStr    string
    57  	runRx       *regexp.Regexp
    58  	runRxWant   bool     // want runRx to match (true) or not match (false)
    59  	runNames    []string // tests to run, exclusive with runRx; empty means all
    60  	banner      string   // prefix, or "" for none
    61  	lastHeading string   // last dir heading printed
    62  
    63  	cgoEnabled bool
    64  	partial    bool
    65  	haveTime   bool // the 'time' binary is available
    66  
    67  	tests        []distTest
    68  	timeoutScale int
    69  
    70  	worklist []*work
    71  }
    72  
    73  type work struct {
    74  	dt    *distTest
    75  	cmd   *exec.Cmd
    76  	start chan bool
    77  	out   []byte
    78  	err   error
    79  	end   chan bool
    80  }
    81  
    82  // A distTest is a test run by dist test.
    83  // Each test has a unique name and belongs to a group (heading)
    84  type distTest struct {
    85  	name    string // unique test name; may be filtered with -run flag
    86  	heading string // group section; this header is printed before the test is run.
    87  	fn      func(*distTest) error
    88  }
    89  
    90  func (t *tester) run() {
    91  	timelog("start", "dist test")
    92  
    93  	var exeSuffix string
    94  	if goos == "windows" {
    95  		exeSuffix = ".exe"
    96  	}
    97  	if _, err := os.Stat(filepath.Join(gobin, "go"+exeSuffix)); err == nil {
    98  		os.Setenv("PATH", fmt.Sprintf("%s%c%s", gobin, os.PathListSeparator, os.Getenv("PATH")))
    99  	}
   100  
   101  	slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
   102  	if err != nil {
   103  		log.Fatalf("Error running go env CGO_ENABLED: %v", err)
   104  	}
   105  	t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
   106  	if flag.NArg() > 0 && t.runRxStr != "" {
   107  		log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
   108  	}
   109  
   110  	t.runNames = flag.Args()
   111  
   112  	if t.hasBash() {
   113  		if _, err := exec.LookPath("time"); err == nil {
   114  			t.haveTime = true
   115  		}
   116  	}
   117  
   118  	if t.rebuild {
   119  		t.out("Building packages and commands.")
   120  		// Force rebuild the whole toolchain.
   121  		goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
   122  	}
   123  
   124  	// Complete rebuild bootstrap, even with -no-rebuild.
   125  	// If everything is up-to-date, this is a no-op.
   126  	// If everything is not up-to-date, the first checkNotStale
   127  	// during the test process will kill the tests, so we might
   128  	// as well install the world.
   129  	// Now that for example "go install cmd/compile" does not
   130  	// also install runtime (you need "go install -i cmd/compile"
   131  	// for that), it's easy for previous workflows like
   132  	// "rebuild the compiler and then run run.bash"
   133  	// to break if we don't automatically refresh things here.
   134  	// Rebuilding is a shortened bootstrap.
   135  	// See cmdbootstrap for a description of the overall process.
   136  	//
   137  	// But don't do this if we're running in the Go build system,
   138  	// where cmd/dist is invoked many times. This just slows that
   139  	// down (Issue 24300).
   140  	if !t.listMode && os.Getenv("GO_BUILDER_NAME") == "" {
   141  		goInstall("go", append([]string{"-i"}, toolchain...)...)
   142  		goInstall("go", append([]string{"-i"}, toolchain...)...)
   143  		goInstall("go", "std", "cmd")
   144  		checkNotStale("go", "std", "cmd")
   145  	}
   146  
   147  	t.timeoutScale = 1
   148  	switch goarch {
   149  	case "arm":
   150  		t.timeoutScale = 2
   151  	case "mips", "mipsle", "mips64", "mips64le":
   152  		t.timeoutScale = 4
   153  	}
   154  	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
   155  		t.timeoutScale, err = strconv.Atoi(s)
   156  		if err != nil {
   157  			log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
   158  		}
   159  	}
   160  
   161  	if t.runRxStr != "" {
   162  		if t.runRxStr[0] == '!' {
   163  			t.runRxWant = false
   164  			t.runRxStr = t.runRxStr[1:]
   165  		} else {
   166  			t.runRxWant = true
   167  		}
   168  		t.runRx = regexp.MustCompile(t.runRxStr)
   169  	}
   170  
   171  	t.registerTests()
   172  	if t.listMode {
   173  		for _, tt := range t.tests {
   174  			fmt.Println(tt.name)
   175  		}
   176  		return
   177  	}
   178  
   179  	// We must unset GOROOT_FINAL before tests, because runtime/debug requires
   180  	// correct access to source code, so if we have GOROOT_FINAL in effect,
   181  	// at least runtime/debug test will fail.
   182  	// If GOROOT_FINAL was set before, then now all the commands will appear stale.
   183  	// Nothing we can do about that other than not checking them below.
   184  	// (We call checkNotStale but only with "std" not "cmd".)
   185  	os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test
   186  	os.Unsetenv("GOROOT_FINAL")
   187  
   188  	for _, name := range t.runNames {
   189  		if !t.isRegisteredTestName(name) {
   190  			log.Fatalf("unknown test %q", name)
   191  		}
   192  	}
   193  
   194  	for _, dt := range t.tests {
   195  		if !t.shouldRunTest(dt.name) {
   196  			t.partial = true
   197  			continue
   198  		}
   199  		dt := dt // dt used in background after this iteration
   200  		if err := dt.fn(&dt); err != nil {
   201  			t.runPending(&dt) // in case that hasn't been done yet
   202  			t.failed = true
   203  			if t.keepGoing {
   204  				log.Printf("Failed: %v", err)
   205  			} else {
   206  				log.Fatalf("Failed: %v", err)
   207  			}
   208  		}
   209  	}
   210  	t.runPending(nil)
   211  	timelog("end", "dist test")
   212  	if t.failed {
   213  		fmt.Println("\nFAILED")
   214  		os.Exit(1)
   215  	} else if incomplete[goos+"/"+goarch] {
   216  		fmt.Println("\nFAILED (incomplete port)")
   217  		os.Exit(1)
   218  	} else if t.partial {
   219  		fmt.Println("\nALL TESTS PASSED (some were excluded)")
   220  	} else {
   221  		fmt.Println("\nALL TESTS PASSED")
   222  	}
   223  }
   224  
   225  func (t *tester) shouldRunTest(name string) bool {
   226  	if t.runRx != nil {
   227  		return t.runRx.MatchString(name) == t.runRxWant
   228  	}
   229  	if len(t.runNames) == 0 {
   230  		return true
   231  	}
   232  	for _, runName := range t.runNames {
   233  		if runName == name {
   234  			return true
   235  		}
   236  	}
   237  	return false
   238  }
   239  
   240  // short returns a -short flag to pass to 'go test'.
   241  // It returns "-short", unless the environment variable
   242  // GO_TEST_SHORT is set to a non-empty, false-ish string.
   243  //
   244  // This environment variable is meant to be an internal
   245  // detail between the Go build system and cmd/dist
   246  // and is not intended for use by users.
   247  func short() string {
   248  	if v := os.Getenv("GO_TEST_SHORT"); v != "" {
   249  		short, err := strconv.ParseBool(v)
   250  		if err != nil {
   251  			log.Fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
   252  		}
   253  		if !short {
   254  			return "-short=false"
   255  		}
   256  	}
   257  	return "-short"
   258  }
   259  
   260  // goTest returns the beginning of the go test command line.
   261  // Callers should use goTest and then pass flags overriding these
   262  // defaults as later arguments in the command line.
   263  func (t *tester) goTest() []string {
   264  	return []string{
   265  		"go", "test", short(), "-count=1", t.tags(), t.runFlag(""),
   266  	}
   267  }
   268  
   269  func (t *tester) tags() string {
   270  	if t.iOS() {
   271  		return "-tags=lldb"
   272  	}
   273  	return "-tags="
   274  }
   275  
   276  func (t *tester) timeout(sec int) string {
   277  	return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale))
   278  }
   279  
   280  // ranGoTest and stdMatches are state closed over by the stdlib
   281  // testing func in registerStdTest below. The tests are run
   282  // sequentially, so there's no need for locks.
   283  //
   284  // ranGoBench and benchMatches are the same, but are only used
   285  // in -race mode.
   286  var (
   287  	ranGoTest  bool
   288  	stdMatches []string
   289  
   290  	ranGoBench   bool
   291  	benchMatches []string
   292  )
   293  
   294  func (t *tester) registerStdTest(pkg string) {
   295  	testName := "go_test:" + pkg
   296  	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
   297  		stdMatches = append(stdMatches, pkg)
   298  	}
   299  	t.tests = append(t.tests, distTest{
   300  		name:    testName,
   301  		heading: "Testing packages.",
   302  		fn: func(dt *distTest) error {
   303  			if ranGoTest {
   304  				return nil
   305  			}
   306  			t.runPending(dt)
   307  			timelog("start", dt.name)
   308  			defer timelog("end", dt.name)
   309  			ranGoTest = true
   310  
   311  			timeoutSec := 180
   312  			for _, pkg := range stdMatches {
   313  				if pkg == "cmd/go" {
   314  					timeoutSec *= 3
   315  					break
   316  				}
   317  			}
   318  			args := []string{
   319  				"test",
   320  				short(),
   321  				t.tags(),
   322  				t.timeout(timeoutSec),
   323  				"-gcflags=all=" + gogcflags,
   324  			}
   325  			if t.race {
   326  				args = append(args, "-race")
   327  			}
   328  			if t.compileOnly {
   329  				args = append(args, "-run=^$")
   330  			} else if goos == "js" && goarch == "wasm" {
   331  				args = append(args, "-run=^Test") // exclude examples; Issue 25913
   332  			}
   333  			args = append(args, stdMatches...)
   334  			cmd := exec.Command("go", args...)
   335  			cmd.Stdout = os.Stdout
   336  			cmd.Stderr = os.Stderr
   337  			return cmd.Run()
   338  		},
   339  	})
   340  }
   341  
   342  func (t *tester) registerRaceBenchTest(pkg string) {
   343  	testName := "go_test_bench:" + pkg
   344  	if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
   345  		benchMatches = append(benchMatches, pkg)
   346  	}
   347  	t.tests = append(t.tests, distTest{
   348  		name:    testName,
   349  		heading: "Running benchmarks briefly.",
   350  		fn: func(dt *distTest) error {
   351  			if ranGoBench {
   352  				return nil
   353  			}
   354  			t.runPending(dt)
   355  			timelog("start", dt.name)
   356  			defer timelog("end", dt.name)
   357  			ranGoBench = true
   358  			args := []string{
   359  				"test",
   360  				short(),
   361  				"-race",
   362  				t.timeout(1200), // longer timeout for race with benchmarks
   363  				"-run=^$",       // nothing. only benchmarks.
   364  				"-benchtime=.1s",
   365  				"-cpu=4",
   366  			}
   367  			if !t.compileOnly {
   368  				args = append(args, "-bench=.*")
   369  			}
   370  			args = append(args, benchMatches...)
   371  			cmd := exec.Command("go", args...)
   372  			cmd.Stdout = os.Stdout
   373  			cmd.Stderr = os.Stderr
   374  			return cmd.Run()
   375  		},
   376  	})
   377  }
   378  
   379  // stdOutErrAreTerminals is defined in test_linux.go, to report
   380  // whether stdout & stderr are terminals.
   381  var stdOutErrAreTerminals func() bool
   382  
   383  func (t *tester) registerTests() {
   384  	if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-vetall") {
   385  		// Run vet over std and cmd and call it quits.
   386  		for k := range cgoEnabled {
   387  			osarch := k
   388  			t.tests = append(t.tests, distTest{
   389  				name:    "vet/" + osarch,
   390  				heading: "cmd/vet/all",
   391  				fn: func(dt *distTest) error {
   392  					t.addCmd(dt, "src/cmd/vet/all", "go", "run", "main.go", "-p="+osarch)
   393  					return nil
   394  				},
   395  			})
   396  		}
   397  		return
   398  	}
   399  
   400  	// Fast path to avoid the ~1 second of `go list std cmd` when
   401  	// the caller lists specific tests to run. (as the continuous
   402  	// build coordinator does).
   403  	if len(t.runNames) > 0 {
   404  		for _, name := range t.runNames {
   405  			if strings.HasPrefix(name, "go_test:") {
   406  				t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
   407  			}
   408  			if strings.HasPrefix(name, "go_test_bench:") {
   409  				t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
   410  			}
   411  		}
   412  	} else {
   413  		// Use a format string to only list packages and commands that have tests.
   414  		const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
   415  		cmd := exec.Command("go", "list", "-f", format)
   416  		if t.race {
   417  			cmd.Args = append(cmd.Args, "-tags=race")
   418  		}
   419  		cmd.Args = append(cmd.Args, "std")
   420  		if !t.race {
   421  			cmd.Args = append(cmd.Args, "cmd")
   422  		}
   423  		all, err := cmd.Output()
   424  		if err != nil {
   425  			log.Fatalf("Error running go list std cmd: %v, %s", err, all)
   426  		}
   427  		pkgs := strings.Fields(string(all))
   428  		for _, pkg := range pkgs {
   429  			t.registerStdTest(pkg)
   430  		}
   431  		if t.race {
   432  			for _, pkg := range pkgs {
   433  				if t.packageHasBenchmarks(pkg) {
   434  					t.registerRaceBenchTest(pkg)
   435  				}
   436  			}
   437  		}
   438  	}
   439  
   440  	// Test the os/user package in the pure-Go mode too.
   441  	if !t.compileOnly {
   442  		t.tests = append(t.tests, distTest{
   443  			name:    "osusergo",
   444  			heading: "os/user with tag osusergo",
   445  			fn: func(dt *distTest) error {
   446  				t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user")
   447  				return nil
   448  			},
   449  		})
   450  	}
   451  
   452  	if t.race {
   453  		return
   454  	}
   455  
   456  	// Runtime CPU tests.
   457  	if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1
   458  		testName := "runtime:cpu124"
   459  		t.tests = append(t.tests, distTest{
   460  			name:    testName,
   461  			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick",
   462  			fn: func(dt *distTest) error {
   463  				cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
   464  				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
   465  				// creation of first goroutines and first garbage collections in the parallel setting.
   466  				cmd.Env = append(os.Environ(), "GOMAXPROCS=2")
   467  				return nil
   468  			},
   469  		})
   470  	}
   471  
   472  	// This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
   473  	// See issue 18153.
   474  	if goos == "linux" {
   475  		t.tests = append(t.tests, distTest{
   476  			name:    "cmd_go_test_terminal",
   477  			heading: "cmd/go terminal test",
   478  			fn: func(dt *distTest) error {
   479  				t.runPending(dt)
   480  				timelog("start", dt.name)
   481  				defer timelog("end", dt.name)
   482  				if !stdOutErrAreTerminals() {
   483  					fmt.Println("skipping terminal test; stdout/stderr not terminals")
   484  					return nil
   485  				}
   486  				cmd := exec.Command("go", "test")
   487  				cmd.Dir = filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153")
   488  				cmd.Stdout = os.Stdout
   489  				cmd.Stderr = os.Stderr
   490  				return cmd.Run()
   491  			},
   492  		})
   493  	}
   494  
   495  	// On the builders only, test that a moved GOROOT still works.
   496  	// Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
   497  	// in the unmoved GOROOT.
   498  	// Fails on Android and js/wasm with an exec format error.
   499  	// Fails on plan9 with "cannot find GOROOT" (issue #21016).
   500  	if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
   501  		t.tests = append(t.tests, distTest{
   502  			name:    "moved_goroot",
   503  			heading: "moved GOROOT",
   504  			fn: func(dt *distTest) error {
   505  				t.runPending(dt)
   506  				timelog("start", dt.name)
   507  				defer timelog("end", dt.name)
   508  				moved := goroot + "-moved"
   509  				if err := os.Rename(goroot, moved); err != nil {
   510  					if goos == "windows" {
   511  						// Fails on Windows (with "Access is denied") if a process
   512  						// or binary is in this directory. For instance, using all.bat
   513  						// when run from c:\workdir\go\src fails here
   514  						// if GO_BUILDER_NAME is set. Our builders invoke tests
   515  						// a different way which happens to work when sharding
   516  						// tests, but we should be tolerant of the non-sharded
   517  						// all.bat case.
   518  						log.Printf("skipping test on Windows")
   519  						return nil
   520  					}
   521  					return err
   522  				}
   523  
   524  				// Run `go test fmt` in the moved GOROOT.
   525  				cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
   526  				cmd.Stdout = os.Stdout
   527  				cmd.Stderr = os.Stderr
   528  				// Don't set GOROOT in the environment.
   529  				for _, e := range os.Environ() {
   530  					if !strings.HasPrefix(e, "GOROOT=") && !strings.HasPrefix(e, "GOCACHE=") {
   531  						cmd.Env = append(cmd.Env, e)
   532  					}
   533  				}
   534  				err := cmd.Run()
   535  
   536  				if rerr := os.Rename(moved, goroot); rerr != nil {
   537  					log.Fatalf("failed to restore GOROOT: %v", rerr)
   538  				}
   539  				return err
   540  			},
   541  		})
   542  	}
   543  
   544  	// Test that internal linking of standard packages does not
   545  	// require libgcc. This ensures that we can install a Go
   546  	// release on a system that does not have a C compiler
   547  	// installed and still build Go programs (that don't use cgo).
   548  	for _, pkg := range cgoPackages {
   549  		if !t.internalLink() {
   550  			break
   551  		}
   552  
   553  		// ARM libgcc may be Thumb, which internal linking does not support.
   554  		if goarch == "arm" {
   555  			break
   556  		}
   557  
   558  		pkg := pkg
   559  		var run string
   560  		if pkg == "net" {
   561  			run = "TestTCPStress"
   562  		}
   563  		t.tests = append(t.tests, distTest{
   564  			name:    "nolibgcc:" + pkg,
   565  			heading: "Testing without libgcc.",
   566  			fn: func(dt *distTest) error {
   567  				t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", pkg, t.runFlag(run))
   568  				return nil
   569  			},
   570  		})
   571  	}
   572  
   573  	// Test internal linking of PIE binaries where it is supported.
   574  	if goos == "linux" && goarch == "amd64" && !isAlpineLinux() {
   575  		// Issue 18243: We don't have a way to set the default
   576  		// dynamic linker used in internal linking mode. So
   577  		// this test is skipped on Alpine.
   578  		t.tests = append(t.tests, distTest{
   579  			name:    "pie_internal",
   580  			heading: "internal linking of -buildmode=pie",
   581  			fn: func(dt *distTest) error {
   582  				t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
   583  				return nil
   584  			},
   585  		})
   586  	}
   587  
   588  	// sync tests
   589  	if goos != "js" { // js doesn't support -cpu=10
   590  		t.tests = append(t.tests, distTest{
   591  			name:    "sync_cpu",
   592  			heading: "sync -cpu=10",
   593  			fn: func(dt *distTest) error {
   594  				t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
   595  				return nil
   596  			},
   597  		})
   598  	}
   599  
   600  	if t.raceDetectorSupported() {
   601  		t.tests = append(t.tests, distTest{
   602  			name:    "race",
   603  			heading: "Testing race detector",
   604  			fn:      t.raceTest,
   605  		})
   606  	}
   607  
   608  	if t.cgoEnabled && !t.iOS() {
   609  		// Disabled on iOS. golang.org/issue/15919
   610  		t.tests = append(t.tests, distTest{
   611  			name:    "cgo_stdio",
   612  			heading: "../misc/cgo/stdio",
   613  			fn: func(dt *distTest) error {
   614  				t.addCmd(dt, "misc/cgo/stdio", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".")
   615  				return nil
   616  			},
   617  		})
   618  		t.tests = append(t.tests, distTest{
   619  			name:    "cgo_life",
   620  			heading: "../misc/cgo/life",
   621  			fn: func(dt *distTest) error {
   622  				t.addCmd(dt, "misc/cgo/life", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".")
   623  				return nil
   624  			},
   625  		})
   626  		fortran := os.Getenv("FC")
   627  		if fortran == "" {
   628  			fortran, _ = exec.LookPath("gfortran")
   629  		}
   630  		if t.hasBash() && fortran != "" {
   631  			t.tests = append(t.tests, distTest{
   632  				name:    "cgo_fortran",
   633  				heading: "../misc/cgo/fortran",
   634  				fn: func(dt *distTest) error {
   635  					t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
   636  					return nil
   637  				},
   638  			})
   639  		}
   640  		if t.hasSwig() && goos != "android" {
   641  			t.tests = append(t.tests, distTest{
   642  				name:    "swig_stdio",
   643  				heading: "../misc/swig/stdio",
   644  				fn: func(dt *distTest) error {
   645  					t.addCmd(dt, "misc/swig/stdio", t.goTest())
   646  					return nil
   647  				},
   648  			})
   649  			if t.hasCxx() {
   650  				t.tests = append(t.tests, distTest{
   651  					name:    "swig_callback",
   652  					heading: "../misc/swig/callback",
   653  					fn: func(dt *distTest) error {
   654  						t.addCmd(dt, "misc/swig/callback", t.goTest())
   655  						return nil
   656  					},
   657  				})
   658  			}
   659  		}
   660  	}
   661  	if t.cgoEnabled {
   662  		t.tests = append(t.tests, distTest{
   663  			name:    "cgo_test",
   664  			heading: "../misc/cgo/test",
   665  			fn:      t.cgoTest,
   666  		})
   667  	}
   668  
   669  	if t.hasBash() && t.cgoEnabled && goos != "android" && goos != "darwin" {
   670  		t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash")
   671  	}
   672  
   673  	// Don't run these tests with $GO_GCFLAGS because most of them
   674  	// assume that they can run "go install" with no -gcflags and not
   675  	// recompile the entire standard library. If make.bash ran with
   676  	// special -gcflags, that's not true.
   677  	if t.cgoEnabled && gogcflags == "" {
   678  		if t.cgoTestSOSupported() {
   679  			t.tests = append(t.tests, distTest{
   680  				name:    "testso",
   681  				heading: "../misc/cgo/testso",
   682  				fn: func(dt *distTest) error {
   683  					return t.cgoTestSO(dt, "misc/cgo/testso")
   684  				},
   685  			})
   686  			t.tests = append(t.tests, distTest{
   687  				name:    "testsovar",
   688  				heading: "../misc/cgo/testsovar",
   689  				fn: func(dt *distTest) error {
   690  					return t.cgoTestSO(dt, "misc/cgo/testsovar")
   691  				},
   692  			})
   693  		}
   694  		if t.supportedBuildmode("c-archive") {
   695  			t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", "carchive_test.go")
   696  		}
   697  		if t.supportedBuildmode("c-shared") {
   698  			t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", "cshared_test.go")
   699  		}
   700  		if t.supportedBuildmode("shared") {
   701  			t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600))
   702  		}
   703  		if t.supportedBuildmode("plugin") {
   704  			t.registerTest("testplugin", "../misc/cgo/testplugin", "./test.bash")
   705  		}
   706  		if gohostos == "linux" && goarch == "amd64" {
   707  			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
   708  		}
   709  		if mSanSupported(goos, goarch) {
   710  			t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
   711  		}
   712  		if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
   713  			t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
   714  		}
   715  		if gohostos == "linux" && t.extLink() {
   716  			t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
   717  		}
   718  	}
   719  
   720  	// Doc tests only run on builders.
   721  	// They find problems approximately never.
   722  	if t.hasBash() && goos != "nacl" && goos != "js" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
   723  		t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
   724  		t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
   725  		t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
   726  	}
   727  
   728  	if goos != "android" && !t.iOS() {
   729  		t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), t.timeout(600))
   730  	}
   731  	if goos != "android" && !t.iOS() {
   732  		// Only start multiple test dir shards on builders,
   733  		// where they get distributed to multiple machines.
   734  		// See issue 20141.
   735  		nShards := 1
   736  		if os.Getenv("GO_BUILDER_NAME") != "" {
   737  			nShards = 10
   738  		}
   739  		for shard := 0; shard < nShards; shard++ {
   740  			shard := shard
   741  			t.tests = append(t.tests, distTest{
   742  				name:    fmt.Sprintf("test:%d_%d", shard, nShards),
   743  				heading: "../test",
   744  				fn:      func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
   745  			})
   746  		}
   747  	}
   748  	if goos != "nacl" && goos != "android" && !t.iOS() && goos != "js" {
   749  		t.tests = append(t.tests, distTest{
   750  			name:    "api",
   751  			heading: "API check",
   752  			fn: func(dt *distTest) error {
   753  				if t.compileOnly {
   754  					t.addCmd(dt, "src", "go", "build", filepath.Join(goroot, "src/cmd/api/run.go"))
   755  					return nil
   756  				}
   757  				t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go"))
   758  				return nil
   759  			},
   760  		})
   761  	}
   762  }
   763  
   764  // isRegisteredTestName reports whether a test named testName has already
   765  // been registered.
   766  func (t *tester) isRegisteredTestName(testName string) bool {
   767  	for _, tt := range t.tests {
   768  		if tt.name == testName {
   769  			return true
   770  		}
   771  	}
   772  	return false
   773  }
   774  
   775  func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) {
   776  	bin, args := flattenCmdline(cmdline)
   777  	if bin == "time" && !t.haveTime {
   778  		bin, args = args[0], args[1:]
   779  	}
   780  	if t.isRegisteredTestName(name) {
   781  		panic("duplicate registered test name " + name)
   782  	}
   783  	t.tests = append(t.tests, distTest{
   784  		name:    name,
   785  		heading: dirBanner,
   786  		fn: func(dt *distTest) error {
   787  			if seq {
   788  				t.runPending(dt)
   789  				timelog("start", name)
   790  				defer timelog("end", name)
   791  				return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run()
   792  			}
   793  			t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args)
   794  			return nil
   795  		},
   796  	})
   797  }
   798  
   799  func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
   800  	t.registerTest1(false, name, dirBanner, cmdline...)
   801  }
   802  
   803  func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
   804  	t.registerTest1(true, name, dirBanner, cmdline...)
   805  }
   806  
   807  func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
   808  	cmd := exec.Command(bin, args...)
   809  	if filepath.IsAbs(dir) {
   810  		cmd.Dir = dir
   811  	} else {
   812  		cmd.Dir = filepath.Join(goroot, dir)
   813  	}
   814  	return cmd
   815  }
   816  
   817  func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd {
   818  	bin, args := flattenCmdline(cmdline)
   819  	cmd := t.bgDirCmd(dir, bin, args...)
   820  	cmd.Stdout = os.Stdout
   821  	cmd.Stderr = os.Stderr
   822  	if vflag > 1 {
   823  		errprintf("%s\n", strings.Join(cmd.Args, " "))
   824  	}
   825  	return cmd
   826  }
   827  
   828  // flattenCmdline flattens a mixture of string and []string as single list
   829  // and then interprets it as a command line: first element is binary, then args.
   830  func flattenCmdline(cmdline []interface{}) (bin string, args []string) {
   831  	var list []string
   832  	for _, x := range cmdline {
   833  		switch x := x.(type) {
   834  		case string:
   835  			list = append(list, x)
   836  		case []string:
   837  			list = append(list, x...)
   838  		default:
   839  			panic("invalid addCmd argument type: " + reflect.TypeOf(x).String())
   840  		}
   841  	}
   842  
   843  	// The go command is too picky about duplicated flags.
   844  	// Drop all but the last of the allowed duplicated flags.
   845  	drop := make([]bool, len(list))
   846  	have := map[string]int{}
   847  	for i := 1; i < len(list); i++ {
   848  		j := strings.Index(list[i], "=")
   849  		if j < 0 {
   850  			continue
   851  		}
   852  		flag := list[i][:j]
   853  		switch flag {
   854  		case "-run", "-tags":
   855  			if have[flag] != 0 {
   856  				drop[have[flag]] = true
   857  			}
   858  			have[flag] = i
   859  		}
   860  	}
   861  	out := list[:0]
   862  	for i, x := range list {
   863  		if !drop[i] {
   864  			out = append(out, x)
   865  		}
   866  	}
   867  	list = out
   868  
   869  	return list[0], list[1:]
   870  }
   871  
   872  func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd {
   873  	bin, args := flattenCmdline(cmdline)
   874  	w := &work{
   875  		dt:  dt,
   876  		cmd: t.bgDirCmd(dir, bin, args...),
   877  	}
   878  	t.worklist = append(t.worklist, w)
   879  	return w.cmd
   880  }
   881  
   882  func (t *tester) iOS() bool {
   883  	return goos == "darwin" && (goarch == "arm" || goarch == "arm64")
   884  }
   885  
   886  func (t *tester) out(v string) {
   887  	if t.banner == "" {
   888  		return
   889  	}
   890  	fmt.Println("\n" + t.banner + v)
   891  }
   892  
   893  func (t *tester) extLink() bool {
   894  	pair := gohostos + "-" + goarch
   895  	switch pair {
   896  	case "android-arm",
   897  		"darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
   898  		"dragonfly-amd64",
   899  		"freebsd-386", "freebsd-amd64", "freebsd-arm",
   900  		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
   901  		"netbsd-386", "netbsd-amd64",
   902  		"openbsd-386", "openbsd-amd64",
   903  		"windows-386", "windows-amd64":
   904  		return true
   905  	}
   906  	return false
   907  }
   908  
   909  func (t *tester) internalLink() bool {
   910  	if gohostos == "dragonfly" {
   911  		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
   912  		return false
   913  	}
   914  	if gohostarch == "ppc64le" {
   915  		// linkmode=internal fails on ppc64le because cmd/link doesn't
   916  		// handle the TOC correctly (issue 15409).
   917  		return false
   918  	}
   919  	if goos == "android" {
   920  		return false
   921  	}
   922  	if goos == "darwin" && (goarch == "arm" || goarch == "arm64") {
   923  		return false
   924  	}
   925  	// Internally linking cgo is incomplete on some architectures.
   926  	// https://golang.org/issue/10373
   927  	// https://golang.org/issue/14449
   928  	if goarch == "arm64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" {
   929  		return false
   930  	}
   931  	if isAlpineLinux() {
   932  		// Issue 18243.
   933  		return false
   934  	}
   935  	return true
   936  }
   937  
   938  func (t *tester) supportedBuildmode(mode string) bool {
   939  	pair := goos + "-" + goarch
   940  	switch mode {
   941  	case "c-archive":
   942  		if !t.extLink() {
   943  			return false
   944  		}
   945  		switch pair {
   946  		case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
   947  			"linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
   948  			"freebsd-amd64",
   949  			"windows-amd64", "windows-386":
   950  			return true
   951  		}
   952  		return false
   953  	case "c-shared":
   954  		switch pair {
   955  		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
   956  			"darwin-amd64", "darwin-386",
   957  			"freebsd-amd64",
   958  			"android-arm", "android-arm64", "android-386",
   959  			"windows-amd64", "windows-386":
   960  			return true
   961  		}
   962  		return false
   963  	case "shared":
   964  		switch pair {
   965  		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
   966  			return true
   967  		}
   968  		return false
   969  	case "plugin":
   970  		// linux-arm64 is missing because it causes the external linker
   971  		// to crash, see https://golang.org/issue/17138
   972  		switch pair {
   973  		case "linux-386", "linux-amd64", "linux-arm", "linux-s390x", "linux-ppc64le":
   974  			return true
   975  		case "darwin-amd64":
   976  			return true
   977  		}
   978  		return false
   979  	case "pie":
   980  		switch pair {
   981  		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
   982  			"android-amd64", "android-arm", "android-arm64", "android-386":
   983  			return true
   984  		case "darwin-amd64":
   985  			return true
   986  		}
   987  		return false
   988  
   989  	default:
   990  		log.Fatalf("internal error: unknown buildmode %s", mode)
   991  		return false
   992  	}
   993  }
   994  
   995  func (t *tester) registerHostTest(name, heading, dir, pkg string) {
   996  	t.tests = append(t.tests, distTest{
   997  		name:    name,
   998  		heading: heading,
   999  		fn: func(dt *distTest) error {
  1000  			t.runPending(dt)
  1001  			timelog("start", name)
  1002  			defer timelog("end", name)
  1003  			return t.runHostTest(dir, pkg)
  1004  		},
  1005  	})
  1006  }
  1007  
  1008  func (t *tester) runHostTest(dir, pkg string) error {
  1009  	defer os.Remove(filepath.Join(goroot, dir, "test.test"))
  1010  	cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", "test.test", pkg)
  1011  	cmd.Env = append(os.Environ(), "GOARCH="+gohostarch, "GOOS="+gohostos)
  1012  	if err := cmd.Run(); err != nil {
  1013  		return err
  1014  	}
  1015  	return t.dirCmd(dir, "./test.test").Run()
  1016  }
  1017  
  1018  func (t *tester) cgoTest(dt *distTest) error {
  1019  	t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=auto")
  1020  
  1021  	if t.internalLink() {
  1022  		t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal", "-ldflags", "-linkmode=internal")
  1023  	}
  1024  
  1025  	pair := gohostos + "-" + goarch
  1026  	switch pair {
  1027  	case "darwin-386", "darwin-amd64",
  1028  		"openbsd-386", "openbsd-amd64",
  1029  		"windows-386", "windows-amd64":
  1030  		// test linkmode=external, but __thread not supported, so skip testtls.
  1031  		if !t.extLink() {
  1032  			break
  1033  		}
  1034  		t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external")
  1035  		t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
  1036  	case "android-arm",
  1037  		"dragonfly-amd64",
  1038  		"freebsd-386", "freebsd-amd64", "freebsd-arm",
  1039  		"linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x",
  1040  		"netbsd-386", "netbsd-amd64":
  1041  
  1042  		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external")
  1043  		// A -g argument in CGO_CFLAGS should not affect how the test runs.
  1044  		cmd.Env = append(os.Environ(), "CGO_CFLAGS=-g0")
  1045  
  1046  		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto")
  1047  		t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external")
  1048  
  1049  		switch pair {
  1050  		case "netbsd-386", "netbsd-amd64":
  1051  			// no static linking
  1052  		case "freebsd-arm":
  1053  			// -fPIC compiled tls code will use __tls_get_addr instead
  1054  			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
  1055  			// is implemented in rtld-elf, so -fPIC isn't compatible with
  1056  			// static linking on FreeBSD/ARM with clang. (cgo depends on
  1057  			// -fPIC fundamentally.)
  1058  		default:
  1059  			cmd := t.dirCmd("misc/cgo/test",
  1060  				compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-")
  1061  			cmd.Stdin = strings.NewReader("int main() {}")
  1062  			if err := cmd.Run(); err != nil {
  1063  				fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
  1064  			} else {
  1065  				if goos != "android" {
  1066  					t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
  1067  				}
  1068  				t.addCmd(dt, "misc/cgo/nocgo", t.goTest())
  1069  				t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`)
  1070  				if goos != "android" {
  1071  					t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
  1072  					t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
  1073  					// -static in CGO_LDFLAGS triggers a different code path
  1074  					// than -static in -extldflags, so test both.
  1075  					// See issue #16651.
  1076  					cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static")
  1077  					cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread")
  1078  				}
  1079  			}
  1080  
  1081  			if t.supportedBuildmode("pie") {
  1082  				t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
  1083  				t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
  1084  				t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")
  1085  			}
  1086  		}
  1087  	}
  1088  
  1089  	return nil
  1090  }
  1091  
  1092  // run pending test commands, in parallel, emitting headers as appropriate.
  1093  // When finished, emit header for nextTest, which is going to run after the
  1094  // pending commands are done (and runPending returns).
  1095  // A test should call runPending if it wants to make sure that it is not
  1096  // running in parallel with earlier tests, or if it has some other reason
  1097  // for needing the earlier tests to be done.
  1098  func (t *tester) runPending(nextTest *distTest) {
  1099  	checkNotStale("go", "std")
  1100  	worklist := t.worklist
  1101  	t.worklist = nil
  1102  	for _, w := range worklist {
  1103  		w.start = make(chan bool)
  1104  		w.end = make(chan bool)
  1105  		go func(w *work) {
  1106  			if !<-w.start {
  1107  				timelog("skip", w.dt.name)
  1108  				w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
  1109  			} else {
  1110  				timelog("start", w.dt.name)
  1111  				w.out, w.err = w.cmd.CombinedOutput()
  1112  			}
  1113  			timelog("end", w.dt.name)
  1114  			w.end <- true
  1115  		}(w)
  1116  	}
  1117  
  1118  	started := 0
  1119  	ended := 0
  1120  	var last *distTest
  1121  	for ended < len(worklist) {
  1122  		for started < len(worklist) && started-ended < maxbg {
  1123  			//println("start", started)
  1124  			w := worklist[started]
  1125  			started++
  1126  			w.start <- !t.failed || t.keepGoing
  1127  		}
  1128  		w := worklist[ended]
  1129  		dt := w.dt
  1130  		if dt.heading != "" && t.lastHeading != dt.heading {
  1131  			t.lastHeading = dt.heading
  1132  			t.out(dt.heading)
  1133  		}
  1134  		if dt != last {
  1135  			// Assumes all the entries for a single dt are in one worklist.
  1136  			last = w.dt
  1137  			if vflag > 0 {
  1138  				fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1139  			}
  1140  		}
  1141  		if vflag > 1 {
  1142  			errprintf("%s\n", strings.Join(w.cmd.Args, " "))
  1143  		}
  1144  		//println("wait", ended)
  1145  		ended++
  1146  		<-w.end
  1147  		os.Stdout.Write(w.out)
  1148  		if w.err != nil {
  1149  			log.Printf("Failed: %v", w.err)
  1150  			t.failed = true
  1151  		}
  1152  		checkNotStale("go", "std")
  1153  	}
  1154  	if t.failed && !t.keepGoing {
  1155  		log.Fatal("FAILED")
  1156  	}
  1157  
  1158  	if dt := nextTest; dt != nil {
  1159  		if dt.heading != "" && t.lastHeading != dt.heading {
  1160  			t.lastHeading = dt.heading
  1161  			t.out(dt.heading)
  1162  		}
  1163  		if vflag > 0 {
  1164  			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1165  		}
  1166  	}
  1167  }
  1168  
  1169  func (t *tester) cgoTestSOSupported() bool {
  1170  	if goos == "android" || t.iOS() {
  1171  		// No exec facility on Android or iOS.
  1172  		return false
  1173  	}
  1174  	if goarch == "ppc64" {
  1175  		// External linking not implemented on ppc64 (issue #8912).
  1176  		return false
  1177  	}
  1178  	if goarch == "mips64le" || goarch == "mips64" {
  1179  		// External linking not implemented on mips64.
  1180  		return false
  1181  	}
  1182  	return true
  1183  }
  1184  
  1185  func (t *tester) cgoTestSO(dt *distTest, testpath string) error {
  1186  	t.runPending(dt)
  1187  
  1188  	timelog("start", dt.name)
  1189  	defer timelog("end", dt.name)
  1190  
  1191  	dir := filepath.Join(goroot, testpath)
  1192  
  1193  	// build shared object
  1194  	output, err := exec.Command("go", "env", "CC").Output()
  1195  	if err != nil {
  1196  		return fmt.Errorf("Error running go env CC: %v", err)
  1197  	}
  1198  	cc := strings.TrimSuffix(string(output), "\n")
  1199  	if cc == "" {
  1200  		return errors.New("CC environment variable (go env CC) cannot be empty")
  1201  	}
  1202  	output, err = exec.Command("go", "env", "GOGCCFLAGS").Output()
  1203  	if err != nil {
  1204  		return fmt.Errorf("Error running go env GOGCCFLAGS: %v", err)
  1205  	}
  1206  	gogccflags := strings.Split(strings.TrimSuffix(string(output), "\n"), " ")
  1207  
  1208  	ext := "so"
  1209  	args := append(gogccflags, "-shared")
  1210  	switch goos {
  1211  	case "darwin":
  1212  		ext = "dylib"
  1213  		args = append(args, "-undefined", "suppress", "-flat_namespace")
  1214  	case "windows":
  1215  		ext = "dll"
  1216  		args = append(args, "-DEXPORT_DLL")
  1217  	}
  1218  	sofname := "libcgosotest." + ext
  1219  	args = append(args, "-o", sofname, "cgoso_c.c")
  1220  
  1221  	if err := t.dirCmd(dir, cc, args).Run(); err != nil {
  1222  		return err
  1223  	}
  1224  	defer os.Remove(filepath.Join(dir, sofname))
  1225  
  1226  	if err := t.dirCmd(dir, "go", "build", "-o", "main.exe", "main.go").Run(); err != nil {
  1227  		return err
  1228  	}
  1229  	defer os.Remove(filepath.Join(dir, "main.exe"))
  1230  
  1231  	cmd := t.dirCmd(dir, "./main.exe")
  1232  	if goos != "windows" {
  1233  		s := "LD_LIBRARY_PATH"
  1234  		if goos == "darwin" {
  1235  			s = "DYLD_LIBRARY_PATH"
  1236  		}
  1237  		cmd.Env = append(os.Environ(), s+"=.")
  1238  
  1239  		// On FreeBSD 64-bit architectures, the 32-bit linker looks for
  1240  		// different environment variables.
  1241  		if goos == "freebsd" && gohostarch == "386" {
  1242  			cmd.Env = append(cmd.Env, "LD_32_LIBRARY_PATH=.")
  1243  		}
  1244  	}
  1245  	return cmd.Run()
  1246  }
  1247  
  1248  func (t *tester) hasBash() bool {
  1249  	switch gohostos {
  1250  	case "windows", "plan9":
  1251  		return false
  1252  	}
  1253  	return true
  1254  }
  1255  
  1256  func (t *tester) hasCxx() bool {
  1257  	cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
  1258  	return cxx != ""
  1259  }
  1260  
  1261  func (t *tester) hasSwig() bool {
  1262  	swig, err := exec.LookPath("swig")
  1263  	if err != nil {
  1264  		return false
  1265  	}
  1266  
  1267  	// Check that swig was installed with Go support by checking
  1268  	// that a go directory exists inside the swiglib directory.
  1269  	// See https://golang.org/issue/23469.
  1270  	output, err := exec.Command(swig, "-go", "-swiglib").Output()
  1271  	if err != nil {
  1272  		return false
  1273  	}
  1274  	swigDir := strings.TrimSpace(string(output))
  1275  
  1276  	_, err = os.Stat(filepath.Join(swigDir, "go"))
  1277  	if err != nil {
  1278  		return false
  1279  	}
  1280  
  1281  	// Check that swig has a new enough version.
  1282  	// See https://golang.org/issue/22858.
  1283  	out, err := exec.Command(swig, "-version").CombinedOutput()
  1284  	if err != nil {
  1285  		return false
  1286  	}
  1287  
  1288  	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
  1289  	matches := re.FindSubmatch(out)
  1290  	if matches == nil {
  1291  		// Can't find version number; hope for the best.
  1292  		return true
  1293  	}
  1294  
  1295  	major, err := strconv.Atoi(string(matches[1]))
  1296  	if err != nil {
  1297  		// Can't find version number; hope for the best.
  1298  		return true
  1299  	}
  1300  	if major < 3 {
  1301  		return false
  1302  	}
  1303  	if major > 3 {
  1304  		// 4.0 or later
  1305  		return true
  1306  	}
  1307  
  1308  	// We have SWIG version 3.x.
  1309  	if len(matches[2]) > 0 {
  1310  		minor, err := strconv.Atoi(string(matches[2][1:]))
  1311  		if err != nil {
  1312  			return true
  1313  		}
  1314  		if minor > 0 {
  1315  			// 3.1 or later
  1316  			return true
  1317  		}
  1318  	}
  1319  
  1320  	// We have SWIG version 3.0.x.
  1321  	if len(matches[3]) > 0 {
  1322  		patch, err := strconv.Atoi(string(matches[3][1:]))
  1323  		if err != nil {
  1324  			return true
  1325  		}
  1326  		if patch < 6 {
  1327  			// Before 3.0.6.
  1328  			return false
  1329  		}
  1330  	}
  1331  
  1332  	return true
  1333  }
  1334  
  1335  func (t *tester) raceDetectorSupported() bool {
  1336  	if gohostos != goos {
  1337  		return false
  1338  	}
  1339  	if !t.cgoEnabled {
  1340  		return false
  1341  	}
  1342  	if !raceDetectorSupported(goos, goarch) {
  1343  		return false
  1344  	}
  1345  	// The race detector doesn't work on Alpine Linux:
  1346  	// golang.org/issue/14481
  1347  	if isAlpineLinux() {
  1348  		return false
  1349  	}
  1350  	// NetBSD support is unfinished.
  1351  	// golang.org/issue/26403
  1352  	if goos == "netbsd" {
  1353  		return false
  1354  	}
  1355  	return true
  1356  }
  1357  
  1358  func isAlpineLinux() bool {
  1359  	if runtime.GOOS != "linux" {
  1360  		return false
  1361  	}
  1362  	fi, err := os.Lstat("/etc/alpine-release")
  1363  	return err == nil && fi.Mode().IsRegular()
  1364  }
  1365  
  1366  func (t *tester) runFlag(rx string) string {
  1367  	if t.compileOnly {
  1368  		return "-run=^$"
  1369  	}
  1370  	if rx == "" && goos == "js" && goarch == "wasm" {
  1371  		return "-run=^Test" // exclude examples; Issue 25913
  1372  	}
  1373  	return "-run=" + rx
  1374  }
  1375  
  1376  func (t *tester) raceTest(dt *distTest) error {
  1377  	t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec")
  1378  	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
  1379  	t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
  1380  	// We don't want the following line, because it
  1381  	// slows down all.bash (by 10 seconds on my laptop).
  1382  	// The race builder should catch any error here, but doesn't.
  1383  	// TODO(iant): Figure out how to catch this.
  1384  	// t.addCmd(dt, "src", t.goTest(),  "-race", "-run=TestParallelTest", "cmd/go")
  1385  	if t.cgoEnabled {
  1386  		cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
  1387  		cmd.Env = append(os.Environ(), "GOTRACEBACK=2")
  1388  	}
  1389  	if t.extLink() {
  1390  		// Test with external linking; see issue 9133.
  1391  		t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
  1392  	}
  1393  	return nil
  1394  }
  1395  
  1396  var runtest struct {
  1397  	sync.Once
  1398  	exe string
  1399  	err error
  1400  }
  1401  
  1402  func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
  1403  	runtest.Do(func() {
  1404  		const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere
  1405  		cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go")
  1406  		cmd.Env = append(os.Environ(), "GOOS="+gohostos, "GOARCH="+gohostarch)
  1407  		runtest.exe = filepath.Join(cmd.Dir, exe)
  1408  		if err := cmd.Run(); err != nil {
  1409  			runtest.err = err
  1410  			return
  1411  		}
  1412  		xatexit(func() {
  1413  			os.Remove(runtest.exe)
  1414  		})
  1415  	})
  1416  	if runtest.err != nil {
  1417  		return runtest.err
  1418  	}
  1419  	if t.compileOnly {
  1420  		return nil
  1421  	}
  1422  	t.addCmd(dt, "test", runtest.exe,
  1423  		fmt.Sprintf("--shard=%d", shard),
  1424  		fmt.Sprintf("--shards=%d", shards),
  1425  	)
  1426  	return nil
  1427  }
  1428  
  1429  // cgoPackages is the standard packages that use cgo.
  1430  var cgoPackages = []string{
  1431  	"crypto/x509",
  1432  	"net",
  1433  	"os/user",
  1434  }
  1435  
  1436  var funcBenchmark = []byte("\nfunc Benchmark")
  1437  
  1438  // packageHasBenchmarks reports whether pkg has benchmarks.
  1439  // On any error, it conservatively returns true.
  1440  //
  1441  // This exists just to eliminate work on the builders, since compiling
  1442  // a test in race mode just to discover it has no benchmarks costs a
  1443  // second or two per package, and this function returns false for
  1444  // about 100 packages.
  1445  func (t *tester) packageHasBenchmarks(pkg string) bool {
  1446  	pkgDir := filepath.Join(goroot, "src", pkg)
  1447  	d, err := os.Open(pkgDir)
  1448  	if err != nil {
  1449  		return true // conservatively
  1450  	}
  1451  	defer d.Close()
  1452  	names, err := d.Readdirnames(-1)
  1453  	if err != nil {
  1454  		return true // conservatively
  1455  	}
  1456  	for _, name := range names {
  1457  		if !strings.HasSuffix(name, "_test.go") {
  1458  			continue
  1459  		}
  1460  		slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
  1461  		if err != nil {
  1462  			return true // conservatively
  1463  		}
  1464  		if bytes.Contains(slurp, funcBenchmark) {
  1465  			return true
  1466  		}
  1467  	}
  1468  	return false
  1469  }
  1470  
  1471  // raceDetectorSupported is a copy of the function
  1472  // cmd/internal/sys.RaceDetectorSupported, which can't be used here
  1473  // because cmd/dist has to be buildable by Go 1.4.
  1474  func raceDetectorSupported(goos, goarch string) bool {
  1475  	switch goos {
  1476  	case "linux":
  1477  		return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64"
  1478  	case "darwin", "freebsd", "netbsd", "windows":
  1479  		return goarch == "amd64"
  1480  	default:
  1481  		return false
  1482  	}
  1483  }
  1484  
  1485  // mSanSupported is a copy of the function cmd/internal/sys.MSanSupported,
  1486  // which can't be used here because cmd/dist has to be buildable by Go 1.4.
  1487  func mSanSupported(goos, goarch string) bool {
  1488  	switch goos {
  1489  	case "linux":
  1490  		return goarch == "amd64" || goarch == "arm64"
  1491  	default:
  1492  		return false
  1493  	}
  1494  }