1
2
3
4
5
6 package run
7
8 import (
9 "context"
10 "go/build"
11 "path/filepath"
12 "strings"
13
14 "cmd/go/internal/base"
15 "cmd/go/internal/cfg"
16 "cmd/go/internal/load"
17 "cmd/go/internal/modload"
18 "cmd/go/internal/str"
19 "cmd/go/internal/work"
20 )
21
22 var CmdRun = &base.Command{
23 UsageLine: "go run [build flags] [-exec xprog] package [arguments...]",
24 Short: "compile and run Go program",
25 Long: `
26 Run compiles and runs the named main Go package.
27 Typically the package is specified as a list of .go source files from a single
28 directory, but it may also be an import path, file system path, or pattern
29 matching a single known package, as in 'go run .' or 'go run my/cmd'.
30
31 If the package argument has a version suffix (like @latest or @v1.0.0),
32 "go run" builds the program in module-aware mode, ignoring the go.mod file in
33 the current directory or any parent directory, if there is one. This is useful
34 for running programs without affecting the dependencies of the main module.
35
36 If the package argument doesn't have a version suffix, "go run" may run in
37 module-aware mode or GOPATH mode, depending on the GO111MODULE environment
38 variable and the presence of a go.mod file. See 'go help modules' for details.
39 If module-aware mode is enabled, "go run" runs in the context of the main
40 module.
41
42 By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
43 If the -exec flag is given, 'go run' invokes the binary using xprog:
44 'xprog a.out arguments...'.
45 If the -exec flag is not given, GOOS or GOARCH is different from the system
46 default, and a program named go_$GOOS_$GOARCH_exec can be found
47 on the current search path, 'go run' invokes the binary using that program,
48 for example 'go_js_wasm_exec a.out arguments...'. This allows execution of
49 cross-compiled programs when a simulator or other execution method is
50 available.
51
52 By default, 'go run' compiles the binary without generating the information
53 used by debuggers, to reduce build time. To include debugger information in
54 the binary, use 'go build'.
55
56 The go command places $GOROOT/bin at the beginning of $PATH in the
57 subprocess environment, so that subprocesses that execute 'go' commands
58 use the same 'go' as their parent.
59
60 The exit status of Run is not the exit status of the compiled binary.
61
62 For more about build flags, see 'go help build'.
63 For more about specifying packages, see 'go help packages'.
64
65 See also: go build.
66 `,
67 }
68
69 func init() {
70 CmdRun.Run = runRun
71
72 work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
73 work.AddCoverFlags(CmdRun, nil)
74 CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
75 }
76
77 func runRun(ctx context.Context, cmd *base.Command, args []string) {
78 moduleLoaderState := modload.NewState()
79 if shouldUseOutsideModuleMode(args) {
80
81
82
83
84 moduleLoaderState.ForceUseModules = true
85 moduleLoaderState.RootMode = modload.NoRoot
86 moduleLoaderState.AllowMissingModuleImports()
87 modload.Init(moduleLoaderState)
88 } else {
89 moduleLoaderState.InitWorkfile()
90 }
91
92 work.BuildInit(moduleLoaderState)
93 b := work.NewBuilder("", moduleLoaderState.VendorDirOrEmpty)
94 defer func() {
95 if err := b.Close(); err != nil {
96 base.Fatal(err)
97 }
98 }()
99
100 i := 0
101 for i < len(args) && strings.HasSuffix(args[i], ".go") {
102 i++
103 }
104 pkgOpts := load.PackageOpts{MainOnly: true}
105 var p *load.Package
106 if i > 0 {
107 files := args[:i]
108 for _, file := range files {
109 if strings.HasSuffix(file, "_test.go") {
110
111
112 base.Fatalf("go: cannot run *_test.go files (%s)", file)
113 }
114 }
115 p = load.GoFilesPackage(moduleLoaderState, ctx, pkgOpts, files)
116 } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
117 arg := args[0]
118 var pkgs []*load.Package
119 if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
120 var err error
121 pkgs, err = load.PackagesAndErrorsOutsideModule(moduleLoaderState, ctx, pkgOpts, args[:1])
122 if err != nil {
123 base.Fatal(err)
124 }
125 } else {
126 pkgs = load.PackagesAndErrors(moduleLoaderState, ctx, pkgOpts, args[:1])
127 }
128
129 if len(pkgs) == 0 {
130 base.Fatalf("go: no packages loaded from %s", arg)
131 }
132 if len(pkgs) > 1 {
133 names := make([]string, 0, len(pkgs))
134 for _, p := range pkgs {
135 names = append(names, p.ImportPath)
136 }
137 base.Fatalf("go: pattern %s matches multiple packages:\n\t%s", arg, strings.Join(names, "\n\t"))
138 }
139 p = pkgs[0]
140 i++
141 } else {
142 base.Fatalf("go: no go files listed")
143 }
144 cmdArgs := args[i:]
145 load.CheckPackageErrors([]*load.Package{p})
146
147 if cfg.BuildCover {
148 load.PrepareForCoverageBuild(moduleLoaderState, []*load.Package{p})
149 }
150
151 p.Internal.OmitDebug = true
152 p.Target = ""
153 if p.Internal.CmdlineFiles {
154
155 var src string
156 if len(p.GoFiles) > 0 {
157 src = p.GoFiles[0]
158 } else if len(p.CgoFiles) > 0 {
159 src = p.CgoFiles[0]
160 } else {
161
162
163 hint := ""
164 if !cfg.BuildContext.CgoEnabled {
165 hint = " (cgo is disabled)"
166 }
167 base.Fatalf("go: no suitable source files%s", hint)
168 }
169 p.Internal.ExeName = src[:len(src)-len(".go")]
170 } else {
171 p.Internal.ExeName = p.DefaultExecName()
172 }
173
174 a1 := b.LinkAction(moduleLoaderState, work.ModeBuild, work.ModeBuild, p)
175 a1.CacheExecutable = true
176 a := &work.Action{Mode: "go run", Actor: work.ActorFunc(buildRunProgram), Args: cmdArgs, Deps: []*work.Action{a1}}
177 b.Do(ctx, a)
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191 func shouldUseOutsideModuleMode(args []string) bool {
192
193
194 return len(args) > 0 &&
195 !strings.HasSuffix(args[0], ".go") &&
196 !strings.HasPrefix(args[0], "-") &&
197 strings.Contains(args[0], "@") &&
198 !build.IsLocalImport(args[0]) &&
199 !filepath.IsAbs(args[0])
200 }
201
202
203
204 func buildRunProgram(b *work.Builder, ctx context.Context, a *work.Action) error {
205 cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].BuiltTarget(), a.Args)
206 if cfg.BuildN || cfg.BuildX {
207 b.Shell(a).ShowCmd("", "%s", strings.Join(cmdline, " "))
208 if cfg.BuildN {
209 return nil
210 }
211 }
212
213 base.RunStdin(cmdline)
214 return nil
215 }
216
View as plain text