github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/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:
    41  	'xprog a.out arguments...'.
    42  If the -exec flag is not given, GOOS or GOARCH is different from the system
    43  default, and a program named go_$GOOS_$GOARCH_exec can be found
    44  on the current search path, 'go run' invokes the binary using that program,
    45  for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
    46  cross-compiled programs when a simulator or other execution method is
    47  available.
    48  
    49  For more about build flags, see 'go help build'.
    50  
    51  See also: go build.
    52  	`,
    53  }
    54  
    55  func init() {
    56  	cmdRun.Run = runRun // break init loop
    57  
    58  	addBuildFlags(cmdRun)
    59  	cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
    60  }
    61  
    62  func printStderr(args ...interface{}) (int, error) {
    63  	return fmt.Fprint(os.Stderr, args...)
    64  }
    65  
    66  func runRun(cmd *Command, args []string) {
    67  	instrumentInit()
    68  	buildModeInit()
    69  	var b builder
    70  	b.init()
    71  	b.print = printStderr
    72  	i := 0
    73  	for i < len(args) && strings.HasSuffix(args[i], ".go") {
    74  		i++
    75  	}
    76  	files, cmdArgs := args[:i], args[i:]
    77  	if len(files) == 0 {
    78  		fatalf("go run: no go files listed")
    79  	}
    80  	for _, file := range files {
    81  		if strings.HasSuffix(file, "_test.go") {
    82  			// goFilesPackage is going to assign this to TestGoFiles.
    83  			// Reject since it won't be part of the build.
    84  			fatalf("go run: cannot run *_test.go files (%s)", file)
    85  		}
    86  	}
    87  	p := goFilesPackage(files)
    88  	if p.Error != nil {
    89  		fatalf("%s", p.Error)
    90  	}
    91  	p.omitDWARF = true
    92  	if len(p.DepsErrors) > 0 {
    93  		// Since these are errors in dependencies,
    94  		// the same error might show up multiple times,
    95  		// once in each package that depends on it.
    96  		// Only print each once.
    97  		printed := map[*PackageError]bool{}
    98  		for _, err := range p.DepsErrors {
    99  			if !printed[err] {
   100  				printed[err] = true
   101  				errorf("%s", err)
   102  			}
   103  		}
   104  	}
   105  	exitIfErrors()
   106  	if p.Name != "main" {
   107  		fatalf("go run: cannot run non-main package")
   108  	}
   109  	p.target = "" // must build - not up to date
   110  	var src string
   111  	if len(p.GoFiles) > 0 {
   112  		src = p.GoFiles[0]
   113  	} else if len(p.CgoFiles) > 0 {
   114  		src = p.CgoFiles[0]
   115  	} else {
   116  		// this case could only happen if the provided source uses cgo
   117  		// while cgo is disabled.
   118  		hint := ""
   119  		if !buildContext.CgoEnabled {
   120  			hint = " (cgo is disabled)"
   121  		}
   122  		fatalf("go run: no suitable source files%s", hint)
   123  	}
   124  	p.exeName = src[:len(src)-len(".go")] // name temporary executable for first go file
   125  	a1 := b.action(modeBuild, modeBuild, p)
   126  	a := &action{f: (*builder).runProgram, args: cmdArgs, deps: []*action{a1}}
   127  	b.do(a)
   128  }
   129  
   130  // runProgram is the action for running a binary that has already
   131  // been compiled. We ignore exit status.
   132  func (b *builder) runProgram(a *action) error {
   133  	cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
   134  	if buildN || buildX {
   135  		b.showcmd("", "%s", strings.Join(cmdline, " "))
   136  		if buildN {
   137  			return nil
   138  		}
   139  	}
   140  
   141  	runStdin(cmdline)
   142  	return nil
   143  }
   144  
   145  // runStdin is like run, but connects Stdin.
   146  func runStdin(cmdline []string) {
   147  	cmd := exec.Command(cmdline[0], cmdline[1:]...)
   148  	cmd.Stdin = os.Stdin
   149  	cmd.Stdout = os.Stdout
   150  	cmd.Stderr = os.Stderr
   151  	cmd.Env = origEnv
   152  	startSigHandlers()
   153  	if err := cmd.Run(); err != nil {
   154  		errorf("%v", err)
   155  	}
   156  }