Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/go/internal/run/run.go

Documentation: cmd/go/internal/run

     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  	"path"
    12  	"strings"
    13  
    14  	"cmd/go/internal/base"
    15  	"cmd/go/internal/cfg"
    16  	"cmd/go/internal/load"
    17  	"cmd/go/internal/str"
    18  	"cmd/go/internal/work"
    19  )
    20  
    21  var CmdRun = &base.Command{
    22  	UsageLine: "go run [build flags] [-exec xprog] package [arguments...]",
    23  	Short:     "compile and run Go program",
    24  	Long: `
    25  Run compiles and runs the named main Go package.
    26  Typically the package is specified as a list of .go source files from a single directory,
    27  but it may also be an import path, file system path, or pattern
    28  matching a single known package, as in 'go run .' or 'go run my/cmd'.
    29  
    30  By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
    31  If the -exec flag is given, 'go run' invokes the binary using xprog:
    32  	'xprog a.out arguments...'.
    33  If the -exec flag is not given, GOOS or GOARCH is different from the system
    34  default, and a program named go_$GOOS_$GOARCH_exec can be found
    35  on the current search path, 'go run' invokes the binary using that program,
    36  for example 'go_js_wasm_exec a.out arguments...'. This allows execution of
    37  cross-compiled programs when a simulator or other execution method is
    38  available.
    39  
    40  The exit status of Run is not the exit status of the compiled binary.
    41  
    42  For more about build flags, see 'go help build'.
    43  For more about specifying packages, see 'go help packages'.
    44  
    45  See also: go build.
    46  	`,
    47  }
    48  
    49  func init() {
    50  	CmdRun.Run = runRun // break init loop
    51  
    52  	work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
    53  	CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
    54  }
    55  
    56  func printStderr(args ...interface{}) (int, error) {
    57  	return fmt.Fprint(os.Stderr, args...)
    58  }
    59  
    60  func runRun(cmd *base.Command, args []string) {
    61  	work.BuildInit()
    62  	var b work.Builder
    63  	b.Init()
    64  	b.Print = printStderr
    65  	i := 0
    66  	for i < len(args) && strings.HasSuffix(args[i], ".go") {
    67  		i++
    68  	}
    69  	var p *load.Package
    70  	if i > 0 {
    71  		files := args[:i]
    72  		for _, file := range files {
    73  			if strings.HasSuffix(file, "_test.go") {
    74  				// GoFilesPackage is going to assign this to TestGoFiles.
    75  				// Reject since it won't be part of the build.
    76  				base.Fatalf("go run: cannot run *_test.go files (%s)", file)
    77  			}
    78  		}
    79  		p = load.GoFilesPackage(files)
    80  	} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
    81  		pkgs := load.PackagesAndErrors(args[:1])
    82  		if len(pkgs) == 0 {
    83  			base.Fatalf("go run: no packages loaded from %s", args[0])
    84  		}
    85  		if len(pkgs) > 1 {
    86  			var names []string
    87  			for _, p := range pkgs {
    88  				names = append(names, p.ImportPath)
    89  			}
    90  			base.Fatalf("go run: pattern %s matches multiple packages:\n\t%s", args[0], strings.Join(names, "\n\t"))
    91  		}
    92  		p = pkgs[0]
    93  		i++
    94  	} else {
    95  		base.Fatalf("go run: no go files listed")
    96  	}
    97  	cmdArgs := args[i:]
    98  	if p.Error != nil {
    99  		base.Fatalf("%s", p.Error)
   100  	}
   101  
   102  	p.Internal.OmitDebug = true
   103  	if len(p.DepsErrors) > 0 {
   104  		// Since these are errors in dependencies,
   105  		// the same error might show up multiple times,
   106  		// once in each package that depends on it.
   107  		// Only print each once.
   108  		printed := map[*load.PackageError]bool{}
   109  		for _, err := range p.DepsErrors {
   110  			if !printed[err] {
   111  				printed[err] = true
   112  				base.Errorf("%s", err)
   113  			}
   114  		}
   115  	}
   116  	base.ExitIfErrors()
   117  	if p.Name != "main" {
   118  		base.Fatalf("go run: cannot run non-main package")
   119  	}
   120  	p.Target = "" // must build - not up to date
   121  	if p.Internal.CmdlineFiles {
   122  		//set executable name if go file is given as cmd-argument
   123  		var src string
   124  		if len(p.GoFiles) > 0 {
   125  			src = p.GoFiles[0]
   126  		} else if len(p.CgoFiles) > 0 {
   127  			src = p.CgoFiles[0]
   128  		} else {
   129  			// this case could only happen if the provided source uses cgo
   130  			// while cgo is disabled.
   131  			hint := ""
   132  			if !cfg.BuildContext.CgoEnabled {
   133  				hint = " (cgo is disabled)"
   134  			}
   135  			base.Fatalf("go run: no suitable source files%s", hint)
   136  		}
   137  		p.Internal.ExeName = src[:len(src)-len(".go")]
   138  	} else {
   139  		p.Internal.ExeName = path.Base(p.ImportPath)
   140  	}
   141  	a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p)
   142  	a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
   143  	b.Do(a)
   144  }
   145  
   146  // buildRunProgram is the action for running a binary that has already
   147  // been compiled. We ignore exit status.
   148  func buildRunProgram(b *work.Builder, a *work.Action) error {
   149  	cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
   150  	if cfg.BuildN || cfg.BuildX {
   151  		b.Showcmd("", "%s", strings.Join(cmdline, " "))
   152  		if cfg.BuildN {
   153  			return nil
   154  		}
   155  	}
   156  
   157  	base.RunStdin(cmdline)
   158  	return nil
   159  }
   160  

View as plain text