github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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.BuildInit()
    56  	var b work.Builder
    57  	b.Init()
    58  	b.Print = printStderr
    59  	i := 0
    60  	for i < len(args) && strings.HasSuffix(args[i], ".go") {
    61  		i++
    62  	}
    63  	files, cmdArgs := args[:i], args[i:]
    64  	if len(files) == 0 {
    65  		base.Fatalf("go run: no go files listed")
    66  	}
    67  	for _, file := range files {
    68  		if strings.HasSuffix(file, "_test.go") {
    69  			// GoFilesPackage is going to assign this to TestGoFiles.
    70  			// Reject since it won't be part of the build.
    71  			base.Fatalf("go run: cannot run *_test.go files (%s)", file)
    72  		}
    73  	}
    74  	p := load.GoFilesPackage(files)
    75  	if p.Error != nil {
    76  		base.Fatalf("%s", p.Error)
    77  	}
    78  	p.Internal.OmitDebug = true
    79  	if len(p.DepsErrors) > 0 {
    80  		// Since these are errors in dependencies,
    81  		// the same error might show up multiple times,
    82  		// once in each package that depends on it.
    83  		// Only print each once.
    84  		printed := map[*load.PackageError]bool{}
    85  		for _, err := range p.DepsErrors {
    86  			if !printed[err] {
    87  				printed[err] = true
    88  				base.Errorf("%s", err)
    89  			}
    90  		}
    91  	}
    92  	base.ExitIfErrors()
    93  	if p.Name != "main" {
    94  		base.Fatalf("go run: cannot run non-main package")
    95  	}
    96  	p.Target = "" // must build - not up to date
    97  	var src string
    98  	if len(p.GoFiles) > 0 {
    99  		src = p.GoFiles[0]
   100  	} else if len(p.CgoFiles) > 0 {
   101  		src = p.CgoFiles[0]
   102  	} else {
   103  		// this case could only happen if the provided source uses cgo
   104  		// while cgo is disabled.
   105  		hint := ""
   106  		if !cfg.BuildContext.CgoEnabled {
   107  			hint = " (cgo is disabled)"
   108  		}
   109  		base.Fatalf("go run: no suitable source files%s", hint)
   110  	}
   111  	p.Internal.ExeName = src[:len(src)-len(".go")] // name temporary executable for first go file
   112  	a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p)
   113  	a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
   114  	b.Do(a)
   115  }
   116  
   117  // buildRunProgram is the action for running a binary that has already
   118  // been compiled. We ignore exit status.
   119  func buildRunProgram(b *work.Builder, a *work.Action) error {
   120  	cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
   121  	if cfg.BuildN || cfg.BuildX {
   122  		b.Showcmd("", "%s", strings.Join(cmdline, " "))
   123  		if cfg.BuildN {
   124  			return nil
   125  		}
   126  	}
   127  
   128  	base.RunStdin(cmdline)
   129  	return nil
   130  }