github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/go/internal/run/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 run implements the ``go run'' command.
     6  package run
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"strings"
    12  
    13  	"cmd/go/internal/base"
    14  	"cmd/go/internal/cfg"
    15  	"cmd/go/internal/load"
    16  	"cmd/go/internal/str"
    17  	"cmd/go/internal/work"
    18  )
    19  
    20  var CmdRun = &base.Command{
    21  	UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
    22  	Short:     "compile and run Go program",
    23  	Long: `
    24  Run compiles and runs the main package comprising the named Go source files.
    25  A Go source file is defined to be a file ending in a literal ".go" suffix.
    26  
    27  By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
    28  If the -exec flag is given, 'go run' invokes the binary using xprog:
    29  	'xprog a.out arguments...'.
    30  If the -exec flag is not given, GOOS or GOARCH is different from the system
    31  default, and a program named go_$GOOS_$GOARCH_exec can be found
    32  on the current search path, 'go run' invokes the binary using that program,
    33  for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
    34  cross-compiled programs when a simulator or other execution method is
    35  available.
    36  
    37  For more about build flags, see 'go help build'.
    38  
    39  See also: go build.
    40  	`,
    41  }
    42  
    43  func init() {
    44  	CmdRun.Run = runRun // break init loop
    45  
    46  	work.AddBuildFlags(CmdRun)
    47  	CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
    48  }
    49  
    50  func printStderr(args ...interface{}) (int, error) {
    51  	return fmt.Fprint(os.Stderr, args...)
    52  }
    53  
    54  func runRun(cmd *base.Command, args []string) {
    55  	work.InstrumentInit()
    56  	work.BuildModeInit()
    57  	var b work.Builder
    58  	b.Init()
    59  	b.Print = printStderr
    60  	i := 0
    61  	for i < len(args) && strings.HasSuffix(args[i], ".go") {
    62  		i++
    63  	}
    64  	files, cmdArgs := args[:i], args[i:]
    65  	if len(files) == 0 {
    66  		base.Fatalf("go run: no go files listed")
    67  	}
    68  	for _, file := range files {
    69  		if strings.HasSuffix(file, "_test.go") {
    70  			// GoFilesPackage is going to assign this to TestGoFiles.
    71  			// Reject since it won't be part of the build.
    72  			base.Fatalf("go run: cannot run *_test.go files (%s)", file)
    73  		}
    74  	}
    75  	p := load.GoFilesPackage(files)
    76  	if p.Error != nil {
    77  		base.Fatalf("%s", p.Error)
    78  	}
    79  	p.Internal.OmitDWARF = true
    80  	if len(p.DepsErrors) > 0 {
    81  		// Since these are errors in dependencies,
    82  		// the same error might show up multiple times,
    83  		// once in each package that depends on it.
    84  		// Only print each once.
    85  		printed := map[*load.PackageError]bool{}
    86  		for _, err := range p.DepsErrors {
    87  			if !printed[err] {
    88  				printed[err] = true
    89  				base.Errorf("%s", err)
    90  			}
    91  		}
    92  	}
    93  	base.ExitIfErrors()
    94  	if p.Name != "main" {
    95  		base.Fatalf("go run: cannot run non-main package")
    96  	}
    97  	p.Internal.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 !cfg.BuildContext.CgoEnabled {
   108  			hint = " (cgo is disabled)"
   109  		}
   110  		base.Fatalf("go run: no suitable source files%s", hint)
   111  	}
   112  	p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
   113  	a1 := b.Action(work.ModeBuild, work.ModeBuild, p)
   114  	a := &work.Action{Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
   115  	b.Do(a)
   116  }
   117  
   118  // buildRunProgram is the action for running a binary that has already
   119  // been compiled. We ignore exit status.
   120  func buildRunProgram(b *work.Builder, a *work.Action) error {
   121  	cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
   122  	if cfg.BuildN || cfg.BuildX {
   123  		b.Showcmd("", "%s", strings.Join(cmdline, " "))
   124  		if cfg.BuildN {
   125  			return nil
   126  		}
   127  	}
   128  
   129  	base.RunStdin(cmdline)
   130  	return nil
   131  }