github.com/aloncn/graphics-go@v0.0.1/src/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 "log" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "regexp" 17 "strconv" 18 "strings" 19 "sync" 20 "time" 21 ) 22 23 func cmdtest() { 24 var t tester 25 var noRebuild bool 26 flag.BoolVar(&t.listMode, "list", false, "list available tests") 27 flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first") 28 flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)") 29 flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred") 30 flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)") 31 flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners") 32 flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"), 33 "run only those tests matching the regular expression; empty means to run all. "+ 34 "Special exception: if the string begins with '!', the match is inverted.") 35 xflagparse(-1) // any number of args 36 if noRebuild { 37 t.rebuild = false 38 } 39 t.run() 40 } 41 42 // tester executes cmdtest. 43 type tester struct { 44 race bool 45 listMode bool 46 rebuild bool 47 failed bool 48 keepGoing bool 49 runRxStr string 50 runRx *regexp.Regexp 51 runRxWant bool // want runRx to match (true) or not match (false) 52 runNames []string // tests to run, exclusive with runRx; empty means all 53 banner string // prefix, or "" for none 54 lastHeading string // last dir heading printed 55 56 goroot string 57 goarch string 58 gohostarch string 59 goos string 60 gohostos string 61 cgoEnabled bool 62 partial bool 63 haveTime bool // the 'time' binary is available 64 65 tests []distTest 66 timeoutScale int 67 68 worklist []*work 69 } 70 71 type work struct { 72 dt *distTest 73 cmd *exec.Cmd 74 start chan bool 75 out []byte 76 err error 77 end chan bool 78 } 79 80 // A distTest is a test run by dist test. 81 // Each test has a unique name and belongs to a group (heading) 82 type distTest struct { 83 name string // unique test name; may be filtered with -run flag 84 heading string // group section; this header is printed before the test is run. 85 fn func(*distTest) error 86 } 87 88 func mustEnv(k string) string { 89 v := os.Getenv(k) 90 if v == "" { 91 log.Fatalf("Unset environment variable %v", k) 92 } 93 return v 94 } 95 96 func (t *tester) run() { 97 t.goroot = mustEnv("GOROOT") 98 t.goos = mustEnv("GOOS") 99 t.gohostos = mustEnv("GOHOSTOS") 100 t.goarch = mustEnv("GOARCH") 101 t.gohostarch = mustEnv("GOHOSTARCH") 102 slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output() 103 if err != nil { 104 log.Fatalf("Error running go env CGO_ENABLED: %v", err) 105 } 106 t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp))) 107 if flag.NArg() > 0 && t.runRxStr != "" { 108 log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments") 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 cmd := exec.Command("go", "install", "-a", "-v", "std", "cmd") 121 cmd.Stdout = os.Stdout 122 cmd.Stderr = os.Stderr 123 if err := cmd.Run(); err != nil { 124 log.Fatalf("building packages and commands: %v", err) 125 } 126 } 127 128 if t.iOS() { 129 // Install the Mach exception handler used to intercept 130 // EXC_BAD_ACCESS and convert it into a Go panic. This is 131 // necessary for a Go program running under lldb (the way 132 // we run tests). It is disabled by default because iOS 133 // apps are not allowed to access the exc_server symbol. 134 cmd := exec.Command("go", "install", "-a", "-tags", "lldb", "runtime/cgo") 135 cmd.Stdout = os.Stdout 136 cmd.Stderr = os.Stderr 137 if err := cmd.Run(); err != nil { 138 log.Fatalf("building mach exception handler: %v", err) 139 } 140 141 defer func() { 142 cmd := exec.Command("go", "install", "-a", "runtime/cgo") 143 cmd.Stdout = os.Stdout 144 cmd.Stderr = os.Stderr 145 if err := cmd.Run(); err != nil { 146 log.Fatalf("reverting mach exception handler: %v", err) 147 } 148 }() 149 } 150 151 t.timeoutScale = 1 152 if t.goarch == "arm" || t.goos == "windows" { 153 t.timeoutScale = 2 154 } 155 if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { 156 t.timeoutScale, err = strconv.Atoi(s) 157 if err != nil { 158 log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err) 159 } 160 } 161 162 if t.runRxStr != "" { 163 if t.runRxStr[0] == '!' { 164 t.runRxWant = false 165 t.runRxStr = t.runRxStr[1:] 166 } else { 167 t.runRxWant = true 168 } 169 t.runRx = regexp.MustCompile(t.runRxStr) 170 } 171 172 t.registerTests() 173 if t.listMode { 174 for _, tt := range t.tests { 175 fmt.Println(tt.name) 176 } 177 return 178 } 179 180 // we must unset GOROOT_FINAL before tests, because runtime/debug requires 181 // correct access to source code, so if we have GOROOT_FINAL in effect, 182 // at least runtime/debug test will fail. 183 os.Unsetenv("GOROOT_FINAL") 184 185 for _, name := range t.runNames { 186 if !t.isRegisteredTestName(name) { 187 log.Fatalf("unknown test %q", name) 188 } 189 } 190 191 for _, dt := range t.tests { 192 if !t.shouldRunTest(dt.name) { 193 t.partial = true 194 continue 195 } 196 dt := dt // dt used in background after this iteration 197 if err := dt.fn(&dt); err != nil { 198 t.runPending(&dt) // in case that hasn't been done yet 199 t.failed = true 200 if t.keepGoing { 201 log.Printf("Failed: %v", err) 202 } else { 203 log.Fatalf("Failed: %v", err) 204 } 205 } 206 } 207 t.runPending(nil) 208 if t.failed { 209 fmt.Println("\nFAILED") 210 os.Exit(1) 211 } else if t.partial { 212 fmt.Println("\nALL TESTS PASSED (some were excluded)") 213 } else { 214 fmt.Println("\nALL TESTS PASSED") 215 } 216 } 217 218 func (t *tester) shouldRunTest(name string) bool { 219 if t.runRx != nil { 220 return t.runRx.MatchString(name) == t.runRxWant 221 } 222 if len(t.runNames) == 0 { 223 return true 224 } 225 for _, runName := range t.runNames { 226 if runName == name { 227 return true 228 } 229 } 230 return false 231 } 232 233 func (t *tester) tags() string { 234 if t.iOS() { 235 return "-tags=lldb" 236 } 237 return "-tags=" 238 } 239 240 func (t *tester) timeout(sec int) string { 241 return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale)) 242 } 243 244 // ranGoTest and stdMatches are state closed over by the stdlib 245 // testing func in registerStdTest below. The tests are run 246 // sequentially, so there's no need for locks. 247 // 248 // ranGoBench and benchMatches are the same, but are only used 249 // in -race mode. 250 var ( 251 ranGoTest bool 252 stdMatches []string 253 254 ranGoBench bool 255 benchMatches []string 256 ) 257 258 func (t *tester) registerStdTest(pkg string) { 259 testName := "go_test:" + pkg 260 if t.runRx == nil || t.runRx.MatchString(testName) { 261 stdMatches = append(stdMatches, pkg) 262 } 263 t.tests = append(t.tests, distTest{ 264 name: testName, 265 heading: "Testing packages.", 266 fn: func(dt *distTest) error { 267 if ranGoTest { 268 return nil 269 } 270 t.runPending(dt) 271 ranGoTest = true 272 args := []string{ 273 "test", 274 "-short", 275 t.tags(), 276 t.timeout(180), 277 "-gcflags=" + os.Getenv("GO_GCFLAGS"), 278 } 279 if t.race { 280 args = append(args, "-race") 281 } 282 args = append(args, stdMatches...) 283 cmd := exec.Command("go", args...) 284 cmd.Stdout = os.Stdout 285 cmd.Stderr = os.Stderr 286 return cmd.Run() 287 }, 288 }) 289 } 290 291 func (t *tester) registerRaceBenchTest(pkg string) { 292 testName := "go_test_bench:" + pkg 293 if t.runRx == nil || t.runRx.MatchString(testName) { 294 benchMatches = append(benchMatches, pkg) 295 } 296 t.tests = append(t.tests, distTest{ 297 name: testName, 298 heading: "Running benchmarks briefly.", 299 fn: func(dt *distTest) error { 300 if ranGoBench { 301 return nil 302 } 303 t.runPending(dt) 304 ranGoBench = true 305 args := []string{ 306 "test", 307 "-short", 308 "-race", 309 "-run=^$", // nothing. only benchmarks. 310 "-bench=.*", 311 "-benchtime=.1s", 312 "-cpu=4", 313 } 314 args = append(args, benchMatches...) 315 cmd := exec.Command("go", args...) 316 cmd.Stdout = os.Stdout 317 cmd.Stderr = os.Stderr 318 return cmd.Run() 319 }, 320 }) 321 } 322 323 func (t *tester) registerTests() { 324 // Fast path to avoid the ~1 second of `go list std cmd` when 325 // the caller lists specific tests to run. (as the continuous 326 // build coordinator does). 327 if len(t.runNames) > 0 { 328 for _, name := range t.runNames { 329 if strings.HasPrefix(name, "go_test:") { 330 t.registerStdTest(strings.TrimPrefix(name, "go_test:")) 331 } 332 if strings.HasPrefix(name, "go_test_bench:") { 333 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:")) 334 } 335 } 336 } else { 337 // Use a format string to only list packages and commands that have tests. 338 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}" 339 cmd := exec.Command("go", "list", "-f", format) 340 if t.race { 341 cmd.Args = append(cmd.Args, "-tags", "race") 342 } 343 cmd.Args = append(cmd.Args, "std") 344 if !t.race { 345 cmd.Args = append(cmd.Args, "cmd") 346 } 347 all, err := cmd.CombinedOutput() 348 if err != nil { 349 log.Fatalf("Error running go list std cmd: %v, %s", err, all) 350 } 351 pkgs := strings.Fields(string(all)) 352 for _, pkg := range pkgs { 353 t.registerStdTest(pkg) 354 } 355 if t.race { 356 for _, pkg := range pkgs { 357 t.registerRaceBenchTest(pkg) 358 } 359 } 360 } 361 362 if t.race { 363 return 364 } 365 366 // Runtime CPU tests. 367 testName := "runtime:cpu124" 368 t.tests = append(t.tests, distTest{ 369 name: testName, 370 heading: "GOMAXPROCS=2 runtime -cpu=1,2,4", 371 fn: func(dt *distTest) error { 372 cmd := t.addCmd(dt, "src", "go", "test", "-short", t.timeout(300), t.tags(), "runtime", "-cpu=1,2,4") 373 // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code, 374 // creation of first goroutines and first garbage collections in the parallel setting. 375 cmd.Env = mergeEnvLists([]string{"GOMAXPROCS=2"}, os.Environ()) 376 return nil 377 }, 378 }) 379 380 // Test that internal linking of standard packages does not 381 // require libgcc. This ensures that we can install a Go 382 // release on a system that does not have a C compiler 383 // installed and still build Go programs (that don't use cgo). 384 for _, pkg := range cgoPackages { 385 386 // Internal linking is not currently supported on Dragonfly. 387 if t.goos == "dragonfly" { 388 break 389 } 390 391 // ARM libgcc may be Thumb, which internal linking does not support. 392 if t.goarch == "arm" { 393 break 394 } 395 396 // Darwin/Android ARM64 fails with internal linking. 397 if (t.goos == "darwin" || t.goos == "android") && t.goarch == "arm64" { 398 break 399 } 400 401 pkg := pkg 402 var run string 403 if pkg == "net" { 404 run = "TestTCPStress" 405 } 406 t.tests = append(t.tests, distTest{ 407 name: "nolibgcc:" + pkg, 408 heading: "Testing without libgcc.", 409 fn: func(dt *distTest) error { 410 t.addCmd(dt, "src", "go", "test", "-short", "-ldflags=-linkmode=internal -libgcc=none", t.tags(), pkg, "-run="+run) 411 return nil 412 }, 413 }) 414 } 415 416 // sync tests 417 t.tests = append(t.tests, distTest{ 418 name: "sync_cpu", 419 heading: "sync -cpu=10", 420 fn: func(dt *distTest) error { 421 t.addCmd(dt, "src", "go", "test", "sync", "-short", t.timeout(120), t.tags(), "-cpu=10") 422 return nil 423 }, 424 }) 425 426 if t.cgoEnabled && t.goos != "android" && !t.iOS() { 427 // Disabled on android and iOS. golang.org/issue/8345 428 t.tests = append(t.tests, distTest{ 429 name: "cgo_stdio", 430 heading: "../misc/cgo/stdio", 431 fn: func(dt *distTest) error { 432 t.addCmd(dt, "misc/cgo/stdio", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".") 433 return nil 434 }, 435 }) 436 t.tests = append(t.tests, distTest{ 437 name: "cgo_life", 438 heading: "../misc/cgo/life", 439 fn: func(dt *distTest) error { 440 t.addCmd(dt, "misc/cgo/life", "go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".") 441 return nil 442 }, 443 }) 444 } 445 if t.cgoEnabled && t.goos != "android" && !t.iOS() { 446 // TODO(crawshaw): reenable on android and iOS 447 // golang.org/issue/8345 448 // 449 // These tests are not designed to run off the host. 450 t.tests = append(t.tests, distTest{ 451 name: "cgo_test", 452 heading: "../misc/cgo/test", 453 fn: t.cgoTest, 454 }) 455 } 456 457 if t.raceDetectorSupported() { 458 t.tests = append(t.tests, distTest{ 459 name: "race", 460 heading: "Testing race detector", 461 fn: t.raceTest, 462 }) 463 } 464 465 if t.hasBash() && t.cgoEnabled && t.goos != "android" && t.goos != "darwin" { 466 t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash") 467 } 468 if t.cgoEnabled { 469 if t.cgoTestSOSupported() { 470 t.tests = append(t.tests, distTest{ 471 name: "testso", 472 heading: "../misc/cgo/testso", 473 fn: func(dt *distTest) error { 474 return t.cgoTestSO(dt, "misc/cgo/testso") 475 }, 476 }) 477 t.tests = append(t.tests, distTest{ 478 name: "testsovar", 479 heading: "../misc/cgo/testsovar", 480 fn: func(dt *distTest) error { 481 return t.cgoTestSO(dt, "misc/cgo/testsovar") 482 }, 483 }) 484 } 485 if t.supportedBuildmode("c-archive") { 486 t.registerTest("testcarchive", "../misc/cgo/testcarchive", "./test.bash") 487 } 488 if t.supportedBuildmode("c-shared") { 489 t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash") 490 } 491 if t.supportedBuildmode("shared") { 492 t.registerTest("testshared", "../misc/cgo/testshared", "go", "test") 493 } 494 if t.gohostos == "linux" && t.goarch == "amd64" { 495 t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") 496 } 497 if t.gohostos == "linux" && t.goarch == "amd64" { 498 t.registerTest("testsanitizers", "../misc/cgo/testsanitizers", "./test.bash") 499 } 500 if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" { 501 t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash") 502 } 503 if t.gohostos == "linux" && t.extLink() { 504 t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go") 505 } 506 } 507 508 // Doc tests only run on builders. 509 // They find problems approximately never. 510 if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" { 511 t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go") 512 t.registerTest("wiki", "../doc/articles/wiki", "./test.bash") 513 t.registerTest("codewalk", "../doc/codewalk", "time", "./run") 514 } 515 516 if t.goos != "android" && !t.iOS() { 517 t.registerTest("bench_go1", "../test/bench/go1", "go", "test", t.timeout(600)) 518 } 519 if t.goos != "android" && !t.iOS() { 520 const nShards = 5 521 for shard := 0; shard < nShards; shard++ { 522 shard := shard 523 t.tests = append(t.tests, distTest{ 524 name: fmt.Sprintf("test:%d_%d", shard, nShards), 525 heading: "../test", 526 fn: func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) }, 527 }) 528 } 529 } 530 if t.goos != "nacl" && t.goos != "android" && !t.iOS() { 531 t.tests = append(t.tests, distTest{ 532 name: "api", 533 heading: "API check", 534 fn: func(dt *distTest) error { 535 t.addCmd(dt, "src", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go")) 536 return nil 537 }, 538 }) 539 } 540 } 541 542 // isRegisteredTestName reports whether a test named testName has already 543 // been registered. 544 func (t *tester) isRegisteredTestName(testName string) bool { 545 for _, tt := range t.tests { 546 if tt.name == testName { 547 return true 548 } 549 } 550 return false 551 } 552 553 func (t *tester) registerTest1(seq bool, name, dirBanner, bin string, args ...string) { 554 if bin == "time" && !t.haveTime { 555 bin, args = args[0], args[1:] 556 } 557 if t.isRegisteredTestName(name) { 558 panic("duplicate registered test name " + name) 559 } 560 t.tests = append(t.tests, distTest{ 561 name: name, 562 heading: dirBanner, 563 fn: func(dt *distTest) error { 564 if seq { 565 t.runPending(dt) 566 return t.dirCmd(filepath.Join(t.goroot, "src", dirBanner), bin, args...).Run() 567 } 568 t.addCmd(dt, filepath.Join(t.goroot, "src", dirBanner), bin, args...) 569 return nil 570 }, 571 }) 572 } 573 574 func (t *tester) registerTest(name, dirBanner, bin string, args ...string) { 575 t.registerTest1(false, name, dirBanner, bin, args...) 576 } 577 578 func (t *tester) registerSeqTest(name, dirBanner, bin string, args ...string) { 579 t.registerTest1(true, name, dirBanner, bin, args...) 580 } 581 582 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd { 583 cmd := exec.Command(bin, args...) 584 if filepath.IsAbs(dir) { 585 cmd.Dir = dir 586 } else { 587 cmd.Dir = filepath.Join(t.goroot, dir) 588 } 589 return cmd 590 } 591 592 func (t *tester) dirCmd(dir, bin string, args ...string) *exec.Cmd { 593 cmd := t.bgDirCmd(dir, bin, args...) 594 cmd.Stdout = os.Stdout 595 cmd.Stderr = os.Stderr 596 if vflag > 1 { 597 errprintf("%s\n", strings.Join(cmd.Args, " ")) 598 } 599 return cmd 600 } 601 602 func (t *tester) addCmd(dt *distTest, dir, bin string, args ...string) *exec.Cmd { 603 w := &work{ 604 dt: dt, 605 cmd: t.bgDirCmd(dir, bin, args...), 606 } 607 t.worklist = append(t.worklist, w) 608 return w.cmd 609 } 610 611 func (t *tester) iOS() bool { 612 return t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64") 613 } 614 615 func (t *tester) out(v string) { 616 if t.banner == "" { 617 return 618 } 619 fmt.Println("\n" + t.banner + v) 620 } 621 622 func (t *tester) extLink() bool { 623 pair := t.gohostos + "-" + t.goarch 624 switch pair { 625 case "android-arm", 626 "darwin-arm", "darwin-arm64", 627 "dragonfly-386", "dragonfly-amd64", 628 "freebsd-386", "freebsd-amd64", "freebsd-arm", 629 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", 630 "netbsd-386", "netbsd-amd64", 631 "openbsd-386", "openbsd-amd64", 632 "windows-386", "windows-amd64": 633 return true 634 case "darwin-386", "darwin-amd64": 635 // linkmode=external fails on OS X 10.6 and earlier == Darwin 636 // 10.8 and earlier. 637 unameR, err := exec.Command("uname", "-r").Output() 638 if err != nil { 639 log.Fatalf("uname -r: %v", err) 640 } 641 major, _ := strconv.Atoi(string(unameR[:bytes.IndexByte(unameR, '.')])) 642 return major > 10 643 } 644 return false 645 } 646 647 func (t *tester) supportedBuildmode(mode string) bool { 648 pair := t.goos + "-" + t.goarch 649 switch mode { 650 case "c-archive": 651 if !t.extLink() { 652 return false 653 } 654 switch pair { 655 case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64", 656 "linux-amd64", "linux-386": 657 return true 658 } 659 return false 660 case "c-shared": 661 switch pair { 662 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", 663 "darwin-amd64", "darwin-386", 664 "android-arm", "android-arm64", "android-386": 665 return true 666 } 667 return false 668 case "shared": 669 switch pair { 670 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le": 671 return true 672 } 673 return false 674 default: 675 log.Fatal("internal error: unknown buildmode %s", mode) 676 return false 677 } 678 } 679 680 func (t *tester) cgoTest(dt *distTest) error { 681 env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ()) 682 683 if t.goos == "android" || t.iOS() { 684 cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags()) 685 cmd.Env = env 686 return cmd.Run() 687 } 688 689 cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto") 690 cmd.Env = env 691 692 if t.gohostos != "dragonfly" { 693 // linkmode=internal fails on dragonfly since errno is a TLS relocation. 694 cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal") 695 cmd.Env = env 696 } 697 698 pair := t.gohostos + "-" + t.goarch 699 switch pair { 700 case "darwin-386", "darwin-amd64", 701 "openbsd-386", "openbsd-amd64", 702 "windows-386", "windows-amd64": 703 // test linkmode=external, but __thread not supported, so skip testtls. 704 if !t.extLink() { 705 break 706 } 707 cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external") 708 cmd.Env = env 709 cmd = t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external -s") 710 cmd.Env = env 711 case "android-arm", 712 "dragonfly-386", "dragonfly-amd64", 713 "freebsd-386", "freebsd-amd64", "freebsd-arm", 714 "linux-386", "linux-amd64", "linux-arm", 715 "netbsd-386", "netbsd-amd64": 716 717 cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external") 718 cmd.Env = env 719 720 cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=auto") 721 cmd.Env = env 722 723 cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=external") 724 cmd.Env = env 725 726 switch pair { 727 case "netbsd-386", "netbsd-amd64": 728 // no static linking 729 case "freebsd-arm": 730 // -fPIC compiled tls code will use __tls_get_addr instead 731 // of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr 732 // is implemented in rtld-elf, so -fPIC isn't compatible with 733 // static linking on FreeBSD/ARM with clang. (cgo depends on 734 // -fPIC fundamentally.) 735 default: 736 cc := mustEnv("CC") 737 cmd := t.dirCmd("misc/cgo/test", 738 cc, "-xc", "-o", "/dev/null", "-static", "-") 739 cmd.Env = env 740 cmd.Stdin = strings.NewReader("int main() {}") 741 if err := cmd.Run(); err != nil { 742 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.") 743 } else { 744 cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 745 cmd.Env = env 746 747 cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test") 748 cmd.Env = env 749 750 cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`) 751 cmd.Env = env 752 753 cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) 754 cmd.Env = env 755 } 756 757 if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test 758 cmd := t.dirCmd("misc/cgo/test", 759 cc, "-xc", "-o", "/dev/null", "-pie", "-") 760 cmd.Env = env 761 cmd.Stdin = strings.NewReader("int main() {}") 762 if err := cmd.Run(); err != nil { 763 fmt.Println("No support for -pie found, skip cgo PIE test.") 764 } else { 765 cmd = t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`) 766 cmd.Env = env 767 768 cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`) 769 cmd.Env = env 770 771 cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`) 772 cmd.Env = env 773 774 } 775 } 776 } 777 } 778 779 return nil 780 } 781 782 // run pending test commands, in parallel, emitting headers as appropriate. 783 // When finished, emit header for nextTest, which is going to run after the 784 // pending commands are done (and runPending returns). 785 // A test should call runPending if it wants to make sure that it is not 786 // running in parallel with earlier tests, or if it has some other reason 787 // for needing the earlier tests to be done. 788 func (t *tester) runPending(nextTest *distTest) { 789 worklist := t.worklist 790 t.worklist = nil 791 for _, w := range worklist { 792 w.start = make(chan bool) 793 w.end = make(chan bool) 794 go func(w *work) { 795 if !<-w.start { 796 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n")) 797 } else { 798 w.out, w.err = w.cmd.CombinedOutput() 799 } 800 w.end <- true 801 }(w) 802 } 803 804 started := 0 805 ended := 0 806 var last *distTest 807 for ended < len(worklist) { 808 for started < len(worklist) && started-ended < maxbg { 809 //println("start", started) 810 w := worklist[started] 811 started++ 812 w.start <- !t.failed || t.keepGoing 813 } 814 w := worklist[ended] 815 dt := w.dt 816 if dt.heading != "" && t.lastHeading != dt.heading { 817 t.lastHeading = dt.heading 818 t.out(dt.heading) 819 } 820 if dt != last { 821 // Assumes all the entries for a single dt are in one worklist. 822 last = w.dt 823 if vflag > 0 { 824 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 825 } 826 } 827 if vflag > 1 { 828 errprintf("%s\n", strings.Join(w.cmd.Args, " ")) 829 } 830 //println("wait", ended) 831 ended++ 832 <-w.end 833 os.Stdout.Write(w.out) 834 if w.err != nil { 835 log.Printf("Failed: %v", w.err) 836 t.failed = true 837 } 838 } 839 if t.failed && !t.keepGoing { 840 log.Fatal("FAILED") 841 } 842 843 if dt := nextTest; dt != nil { 844 if dt.heading != "" && t.lastHeading != dt.heading { 845 t.lastHeading = dt.heading 846 t.out(dt.heading) 847 } 848 if vflag > 0 { 849 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name) 850 } 851 } 852 } 853 854 func (t *tester) cgoTestSOSupported() bool { 855 if t.goos == "android" || t.iOS() { 856 // No exec facility on Android or iOS. 857 return false 858 } 859 if t.goarch == "ppc64" { 860 // External linking not implemented on ppc64 (issue #8912). 861 return false 862 } 863 if t.goarch == "mips64le" || t.goarch == "mips64" { 864 // External linking not implemented on mips64. 865 return false 866 } 867 return true 868 } 869 870 func (t *tester) cgoTestSO(dt *distTest, testpath string) error { 871 t.runPending(dt) 872 873 dir := filepath.Join(t.goroot, testpath) 874 875 // build shared object 876 output, err := exec.Command("go", "env", "CC").Output() 877 if err != nil { 878 return fmt.Errorf("Error running go env CC: %v", err) 879 } 880 cc := strings.TrimSuffix(string(output), "\n") 881 if cc == "" { 882 return errors.New("CC environment variable (go env CC) cannot be empty") 883 } 884 output, err = exec.Command("go", "env", "GOGCCFLAGS").Output() 885 if err != nil { 886 return fmt.Errorf("Error running go env GOGCCFLAGS: %v", err) 887 } 888 gogccflags := strings.Split(strings.TrimSuffix(string(output), "\n"), " ") 889 890 ext := "so" 891 args := append(gogccflags, "-shared") 892 switch t.goos { 893 case "darwin": 894 ext = "dylib" 895 args = append(args, "-undefined", "suppress", "-flat_namespace") 896 case "windows": 897 ext = "dll" 898 args = append(args, "-DEXPORT_DLL") 899 } 900 sofname := "libcgosotest." + ext 901 args = append(args, "-o", sofname, "cgoso_c.c") 902 903 if err := t.dirCmd(dir, cc, args...).Run(); err != nil { 904 return err 905 } 906 defer os.Remove(filepath.Join(dir, sofname)) 907 908 if err := t.dirCmd(dir, "go", "build", "-o", "main.exe", "main.go").Run(); err != nil { 909 return err 910 } 911 defer os.Remove(filepath.Join(dir, "main.exe")) 912 913 cmd := t.dirCmd(dir, "./main.exe") 914 if t.goos != "windows" { 915 s := "LD_LIBRARY_PATH" 916 if t.goos == "darwin" { 917 s = "DYLD_LIBRARY_PATH" 918 } 919 cmd.Env = mergeEnvLists([]string{s + "=."}, os.Environ()) 920 921 // On FreeBSD 64-bit architectures, the 32-bit linker looks for 922 // different environment variables. 923 if t.goos == "freebsd" && t.gohostarch == "386" { 924 cmd.Env = mergeEnvLists([]string{"LD_32_LIBRARY_PATH=."}, cmd.Env) 925 } 926 } 927 return cmd.Run() 928 } 929 930 func (t *tester) hasBash() bool { 931 switch t.gohostos { 932 case "windows", "plan9": 933 return false 934 } 935 return true 936 } 937 938 func (t *tester) raceDetectorSupported() bool { 939 switch t.gohostos { 940 case "linux", "darwin", "freebsd", "windows": 941 return t.cgoEnabled && t.goarch == "amd64" && t.gohostos == t.goos 942 } 943 return false 944 } 945 946 func (t *tester) raceTest(dt *distTest) error { 947 t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec") 948 t.addCmd(dt, "src", "go", "test", "-race", "-run=Output", "runtime/race") 949 t.addCmd(dt, "src", "go", "test", "-race", "-short", "-run=TestParse|TestEcho", "flag", "os/exec") 950 // We don't want the following line, because it 951 // slows down all.bash (by 10 seconds on my laptop). 952 // The race builder should catch any error here, but doesn't. 953 // TODO(iant): Figure out how to catch this. 954 // t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go") 955 if t.cgoEnabled { 956 env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ()) 957 cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short") 958 cmd.Env = env 959 } 960 if t.extLink() { 961 // Test with external linking; see issue 9133. 962 t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "-run=TestParse|TestEcho", "flag", "os/exec") 963 } 964 return nil 965 } 966 967 var runtest struct { 968 sync.Once 969 exe string 970 err error 971 } 972 973 func (t *tester) testDirTest(dt *distTest, shard, shards int) error { 974 runtest.Do(func() { 975 const exe = "runtest.exe" // named exe for Windows, but harmless elsewhere 976 cmd := t.dirCmd("test", "go", "build", "-o", exe, "run.go") 977 cmd.Env = mergeEnvLists([]string{"GOOS=" + t.gohostos, "GOARCH=" + t.gohostarch, "GOMAXPROCS="}, os.Environ()) 978 runtest.exe = filepath.Join(cmd.Dir, exe) 979 if err := cmd.Run(); err != nil { 980 runtest.err = err 981 return 982 } 983 xatexit(func() { 984 os.Remove(runtest.exe) 985 }) 986 }) 987 if runtest.err != nil { 988 return runtest.err 989 } 990 991 t.addCmd(dt, "test", runtest.exe, 992 fmt.Sprintf("--shard=%d", shard), 993 fmt.Sprintf("--shards=%d", shards), 994 ) 995 return nil 996 } 997 998 // mergeEnvLists merges the two environment lists such that 999 // variables with the same name in "in" replace those in "out". 1000 // out may be mutated. 1001 func mergeEnvLists(in, out []string) []string { 1002 NextVar: 1003 for _, inkv := range in { 1004 k := strings.SplitAfterN(inkv, "=", 2)[0] 1005 for i, outkv := range out { 1006 if strings.HasPrefix(outkv, k) { 1007 out[i] = inkv 1008 continue NextVar 1009 } 1010 } 1011 out = append(out, inkv) 1012 } 1013 return out 1014 } 1015 1016 // cgoPackages is the standard packages that use cgo. 1017 var cgoPackages = []string{ 1018 "crypto/x509", 1019 "net", 1020 "os/user", 1021 }