...
Run Format

Source file src/cmd/dist/test.go

Documentation: cmd/dist

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

View as plain text