test: add -target flag.

--- test/run.go
+++ test/run.go
@@ -34,19 +34,19 @@ import (
 
 var (
 	verbose        = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
 	keep           = flag.Bool("k", false, "keep. keep temporary directory.")
 	numParallel    = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
 	summary        = flag.Bool("summary", false, "show summary of results")
 	showSkips      = flag.Bool("show_skips", false, "show skipped tests")
 	runSkips       = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)")
-	linkshared     = flag.Bool("linkshared", false, "")
 	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
+	target         = flag.String("target", "", "if non empty, use 'go_target' to compile test files and 'go_target_exec' to run the binaries")
 
 	shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
 	shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
 )
 
 var (
 	goos, goarch string
 
@@ -189,48 +189,49 @@ func goFiles(dir string) []string {
 	}
 	sort.Strings(names)
 	return names
 }
 
 type runCmd func(...string) ([]byte, error)
 
 func compileFile(runcmd runCmd, longname string, flags []string) (out []byte, err error) {
-	cmd := []string{"go", "tool", "compile", "-e"}
+	cmd := []string{findGoCmd(), "tool", "compile", "-e"}
 	cmd = append(cmd, flags...)
-	if *linkshared {
-		cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
-	}
 	cmd = append(cmd, longname)
 	return runcmd(cmd...)
 }
 
 func compileInDir(runcmd runCmd, dir string, flags []string, names ...string) (out []byte, err error) {
-	cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
+	cmd := []string{findGoCmd(), "tool", "compile", "-e", "-D", ".", "-I", "."}
 	cmd = append(cmd, flags...)
-	if *linkshared {
-		cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
-	}
 	for _, name := range names {
 		cmd = append(cmd, filepath.Join(dir, name))
 	}
 	return runcmd(cmd...)
 }
 
 func linkFile(runcmd runCmd, goname string) (err error) {
 	pfile := strings.Replace(goname, ".go", ".o", -1)
-	cmd := []string{"go", "tool", "link", "-w", "-o", "a.exe", "-L", "."}
-	if *linkshared {
-		cmd = append(cmd, "-linkshared", "-installsuffix=dynlink")
-	}
-	cmd = append(cmd, pfile)
-	_, err = runcmd(cmd...)
+	_, err = runcmd(findGoCmd(), "tool", "link", "-w", "-o", "a.exe", "-L", ".", pfile)
 	return
 }
 
+func goRun(runcmd runCmd, flags []string, goname string, args ...string) (out []byte, err error) {
+	cmd := []string{findGoCmd(), "run", goGcflags()}
+	if len(findExecCmd()) > 0 {
+		cmd = append(cmd, "-exec")
+		cmd = append(cmd, findExecCmd()...)
+	}
+	cmd = append(cmd, flags...)
+	cmd = append(cmd, goname)
+	cmd = append(cmd, args...)
+	return runcmd(cmd...)
+}
+
 // skipError describes why a test was skipped.
 type skipError string
 
 func (s skipError) Error() string { return string(s) }
 
 func check(err error) {
 	if err != nil {
 		log.Fatal(err)
@@ -590,18 +591,17 @@ func (t *test) run() {
 
 	long := filepath.Join(cwd, t.goFileName())
 	switch action {
 	default:
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "errorcheck":
 		// TODO(gri) remove need for -C (disable printing of columns in error messages)
-		cmdline := []string{"go", "tool", "compile", "-C", "-e", "-o", "a.o"}
-		// No need to add -dynlink even if linkshared if we're just checking for errors...
+		cmdline := []string{findGoCmd(), "tool", "compile", "-C", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, long)
 		out, err := runcmd(cmdline...)
 		if wantError {
 			if err == nil {
 				t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
 				return
 			}
@@ -704,17 +704,17 @@ func (t *test) run() {
 				}
 				if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
 					t.err = fmt.Errorf("incorrect output\n%s", out)
 				}
 			}
 		}
 
 	case "build":
-		_, err := runcmd("go", "build", goGcflags(), "-o", "a.exe", long)
+		_, err := runcmd(findGoCmd(), "build", goGcflags(), "-o", "a.exe", long)
 		if err != nil {
 			t.err = err
 		}
 
 	case "builddir":
 		// Build an executable from all the .go and .s files in a subdirectory.
 		useTmp = true
 		longdir := filepath.Join(cwd, t.goDirName())
@@ -730,177 +730,132 @@ func (t *test) run() {
 			case ".go":
 				gos = append(gos, file)
 			case ".s":
 				asms = append(asms, file)
 			}
 
 		}
 		var objs []string
-		cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", ".", "-o", "go.o"}
+		cmd := []string{findGoCmd(), "tool", "compile", "-e", "-D", ".", "-I", ".", "-o", "go.o"}
 		if len(asms) > 0 {
 			cmd = append(cmd, "-asmhdr", "go_asm.h")
 		}
 		for _, file := range gos {
 			cmd = append(cmd, filepath.Join(longdir, file.Name()))
 		}
 		_, err := runcmd(cmd...)
 		if err != nil {
 			t.err = err
 			break
 		}
 		objs = append(objs, "go.o")
 		if len(asms) > 0 {
-			cmd = []string{"go", "tool", "asm", "-e", "-I", ".", "-o", "asm.o"}
+			cmd = []string{findGoCmd(), "tool", "asm", "-e", "-I", ".", "-o", "asm.o"}
 			for _, file := range asms {
 				cmd = append(cmd, filepath.Join(longdir, file.Name()))
 			}
 			_, err = runcmd(cmd...)
 			if err != nil {
 				t.err = err
 				break
 			}
 			objs = append(objs, "asm.o")
 		}
-		cmd = []string{"go", "tool", "pack", "c", "all.a"}
+		cmd = []string{findGoCmd(), "tool", "pack", "c", "all.a"}
 		cmd = append(cmd, objs...)
 		_, err = runcmd(cmd...)
 		if err != nil {
 			t.err = err
 			break
 		}
-		cmd = []string{"go", "tool", "link", "all.a"}
+		cmd = []string{findGoCmd(), "tool", "link", "all.a"}
 		_, err = runcmd(cmd...)
 		if err != nil {
 			t.err = err
 			break
 		}
 
 	case "buildrun": // build binary, then run binary, instead of go run. Useful for timeout tests where failure mode is infinite loop.
 		// TODO: not supported on NaCl
 		useTmp = true
-		cmd := []string{"go", "build", goGcflags(), "-o", "a.exe"}
-		if *linkshared {
-			cmd = append(cmd, "-linkshared")
-		}
+		cmd := []string{findGoCmd(), "build", goGcflags(), "-o", "a.exe"}
 		longdirgofile := filepath.Join(filepath.Join(cwd, t.dir), t.gofile)
 		cmd = append(cmd, flags...)
 		cmd = append(cmd, longdirgofile)
 		out, err := runcmd(cmd...)
 		if err != nil {
 			t.err = err
 			return
 		}
-		cmd = []string{"./a.exe"}
+		cmd = []string{}
+		if len(findExecCmd()) > 0 {
+			cmd = append(cmd, findExecCmd()...)
+		}
+		cmd = append(cmd, "./a.exe")
 		out, err = runcmd(append(cmd, args...)...)
 		if err != nil {
 			t.err = err
 			return
 		}
 
 		if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
 			t.err = fmt.Errorf("incorrect output\n%s", out)
 		}
 
 	case "run":
 		useTmp = false
-		var out []byte
-		var err error
-		if len(flags)+len(args) == 0 && goGcflags() == "" && !*linkshared {
-			// If we're not using special go command flags,
-			// skip all the go command machinery.
-			// This avoids any time the go command would
-			// spend checking whether, for example, the installed
-			// package runtime is up to date.
-			// Because we run lots of trivial test programs,
-			// the time adds up.
-			pkg := filepath.Join(t.tempDir, "pkg.a")
-			if _, err := runcmd("go", "tool", "compile", "-o", pkg, t.goFileName()); err != nil {
-				t.err = err
-				return
-			}
-			exe := filepath.Join(t.tempDir, "test.exe")
-			cmd := []string{"go", "tool", "link", "-s", "-w"}
-			cmd = append(cmd, "-o", exe, pkg)
-			if _, err := runcmd(cmd...); err != nil {
-				t.err = err
-				return
-			}
-			out, err = runcmd(append([]string{exe}, args...)...)
-		} else {
-			cmd := []string{"go", "run", goGcflags()}
-			if *linkshared {
-				cmd = append(cmd, "-linkshared")
-			}
-			cmd = append(cmd, flags...)
-			cmd = append(cmd, t.goFileName())
-			out, err = runcmd(append(cmd, args...)...)
-		}
+		out, err := goRun(runcmd, flags, t.goFileName(), args...)
 		if err != nil {
 			t.err = err
 			return
 		}
 		if strings.Replace(string(out), "\r\n", "\n", -1) != t.expectedOutput() {
 			t.err = fmt.Errorf("incorrect output\n%s", out)
 		}
 
 	case "runoutput":
 		rungatec <- true
 		defer func() {
 			<-rungatec
 		}()
 		useTmp = false
-		cmd := []string{"go", "run", goGcflags()}
-		if *linkshared {
-			cmd = append(cmd, "-linkshared")
-		}
-		cmd = append(cmd, t.goFileName())
-		out, err := runcmd(append(cmd, args...)...)
+		out, err := goRun(runcmd, nil, t.goFileName(), args...)
 		if err != nil {
 			t.err = err
 			return
 		}
 		tfile := filepath.Join(t.tempDir, "tmp__.go")
 		if err := ioutil.WriteFile(tfile, out, 0666); err != nil {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmd = []string{"go", "run", goGcflags()}
-		if *linkshared {
-			cmd = append(cmd, "-linkshared")
-		}
-		cmd = append(cmd, tfile)
-		out, err = runcmd(cmd...)
+		out, err = goRun(runcmd, nil, tfile)
 		if err != nil {
 			t.err = err
 			return
 		}
 		if string(out) != t.expectedOutput() {
 			t.err = fmt.Errorf("incorrect output\n%s", out)
 		}
 
 	case "errorcheckoutput":
 		useTmp = false
-		cmd := []string{"go", "run", goGcflags()}
-		if *linkshared {
-			cmd = append(cmd, "-linkshared")
-		}
-		cmd = append(cmd, t.goFileName())
-		out, err := runcmd(append(cmd, args...)...)
+		out, err := goRun(runcmd, nil, t.goFileName(), args...)
 		if err != nil {
 			t.err = err
 			return
 		}
 		tfile := filepath.Join(t.tempDir, "tmp__.go")
 		err = ioutil.WriteFile(tfile, out, 0666)
 		if err != nil {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
+		cmdline := []string{findGoCmd(), "tool", "compile", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, tfile)
 		out, err = runcmd(cmdline...)
 		if wantError {
 			if err == nil {
 				t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
 				return
 			}
@@ -917,26 +872,37 @@ func (t *test) run() {
 
 var execCmd []string
 
 func findExecCmd() []string {
 	if execCmd != nil {
 		return execCmd
 	}
 	execCmd = []string{} // avoid work the second time
+	if *target != "" {
+		execCmd = []string{"go_" + *target + "_exec"}
+		return execCmd
+	}
 	if goos == runtime.GOOS && goarch == runtime.GOARCH {
 		return execCmd
 	}
 	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
 	if err == nil {
 		execCmd = []string{path}
 	}
 	return execCmd
 }
 
+func findGoCmd() string {
+	if *target != "" {
+		return "go_" + *target
+	}
+	return "go"
+}
+
 func (t *test) String() string {
 	return filepath.Join(t.dir, t.gofile)
 }
 
 func (t *test) makeTempDir() {
 	var err error
 	t.tempDir, err = ioutil.TempDir("", "")
 	check(err)