github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/go/run.go (about)

     1  // Copyright 2011 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  	"fmt"
     9  	"os"
    10  	"os/exec"
    11  	"runtime"
    12  	"strings"
    13  )
    14  
    15  var execCmd []string // -exec flag, for run and test
    16  
    17  func findExecCmd() []string {
    18  	if execCmd != nil {
    19  		return execCmd
    20  	}
    21  	execCmd = []string{} // avoid work the second time
    22  	if goos == runtime.GOOS && goarch == runtime.GOARCH {
    23  		return execCmd
    24  	}
    25  	path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
    26  	if err == nil {
    27  		execCmd = []string{path}
    28  	}
    29  	return execCmd
    30  }
    31  
    32  var cmdRun = &Command{
    33  	UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
    34  	Short:     "compile and run Go program",
    35  	Long: `
    36  Run compiles and runs the main package comprising the named Go source files.
    37  A Go source file is defined to be a file ending in a literal ".go" suffix.
    38  
    39  By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
    40  If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
    41  If the -exec flag is not given, GOOS or GOARCH is different from the system
    42  default, and a program named go_$GOOS_$GOARCH_exec can be found
    43  on the current search path, 'go run' invokes the binary using that program,
    44  for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
    45  cross-compiled programs when a simulator or other execution method is
    46  available.
    47  
    48  For more about build flags, see 'go help build'.
    49  
    50  See also: go build.
    51  	`,
    52  }
    53  
    54  func init() {
    55  	cmdRun.Run = runRun // break init loop
    56  
    57  	addBuildFlags(cmdRun)
    58  	cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
    59  }
    60  
    61  func printStderr(args ...interface{}) (int, error) {
    62  	return fmt.Fprint(os.Stderr, args...)
    63  }
    64  
    65  func runRun(cmd *Command, args []string) {
    66  	raceInit()
    67  	var b builder
    68  	b.init()
    69  	b.print = printStderr
    70  	i := 0
    71  	for i < len(args) && strings.HasSuffix(args[i], ".go") {
    72  		i++
    73  	}
    74  	files, cmdArgs := args[:i], args[i:]
    75  	if len(files) == 0 {
    76  		fatalf("go run: no go files listed")
    77  	}
    78  	for _, file := range files {
    79  		if strings.HasSuffix(file, "_test.go") {
    80  			// goFilesPackage is going to assign this to TestGoFiles.
    81  			// Reject since it won't be part of the build.
    82  			fatalf("go run: cannot run *_test.go files (%s)", file)
    83  		}
    84  	}
    85  	p := goFilesPackage(files)
    86  	if p.Error != nil {
    87  		fatalf("%s", p.Error)
    88  	}
    89  	p.omitDWARF = true
    90  	for _, err := range p.DepsErrors {
    91  		errorf("%s", err)
    92  	}
    93  	exitIfErrors()
    94  	if p.Name != "main" {
    95  		fatalf("go run: cannot run non-main package")
    96  	}
    97  	p.target = "" // must build - not up to date
    98  	var src string
    99  	if len(p.GoFiles) > 0 {
   100  		src = p.GoFiles[0]
   101  	} else if len(p.CgoFiles) > 0 {
   102  		src = p.CgoFiles[0]
   103  	} else {
   104  		// this case could only happen if the provided source uses cgo
   105  		// while cgo is disabled.
   106  		hint := ""
   107  		if !buildContext.CgoEnabled {
   108  			hint = " (cgo is disabled)"
   109  		}
   110  		fatalf("go run: no suitable source files%s", hint)
   111  	}
   112  	p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
   113  	a1 := b.action(modeBuild, modeBuild, p)
   114  	a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
   115  	b.do(a)
   116  }
   117  
   118  // runProgram is the action for running a binary that has already
   119  // been compiled.  We ignore exit status.
   120  func (b *builder) runProgram(a *action) error {
   121  	cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
   122  	if buildN || buildX {
   123  		b.showcmd("", "%s", strings.Join(cmdline, " "))
   124  		if buildN {
   125  			return nil
   126  		}
   127  	}
   128  
   129  	runStdin(cmdline)
   130  	return nil
   131  }
   132  
   133  // runStdin is like run, but connects Stdin.
   134  func runStdin(cmdline []string) {
   135  	cmd := exec.Command(cmdline[0], cmdline[1:]...)
   136  	cmd.Stdin = os.Stdin
   137  	cmd.Stdout = os.Stdout
   138  	cmd.Stderr = os.Stderr
   139  	startSigHandlers()
   140  	if err := cmd.Run(); err != nil {
   141  		errorf("%v", err)
   142  	}
   143  }