...

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

     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_nacl_386_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)
    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