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 exit status of Run is not the exit status of the compiled binary.
57
58 For more about build flags, see 'go help build'.
59 For more about specifying packages, see 'go help packages'.
60
61 See also: go build.
62 `,
63 }
64
65 func init() {
66 CmdRun.Run = runRun
67
68 work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
69 work.AddCoverFlags(CmdRun, nil)
70 CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
71 }
72
73 func runRun(ctx context.Context, cmd *base.Command, args []string) {
74 if shouldUseOutsideModuleMode(args) {
75
76
77
78
79 modload.ForceUseModules = true
80 modload.RootMode = modload.NoRoot
81 modload.AllowMissingModuleImports()
82 modload.Init()
83 } else {
84 modload.InitWorkfile()
85 }
86
87 work.BuildInit()
88 b := work.NewBuilder("")
89 defer func() {
90 if err := b.Close(); err != nil {
91 base.Fatal(err)
92 }
93 }()
94
95 i := 0
96 for i < len(args) && strings.HasSuffix(args[i], ".go") {
97 i++
98 }
99 pkgOpts := load.PackageOpts{MainOnly: true}
100 var p *load.Package
101 if i > 0 {
102 files := args[:i]
103 for _, file := range files {
104 if strings.HasSuffix(file, "_test.go") {
105
106
107 base.Fatalf("go: cannot run *_test.go files (%s)", file)
108 }
109 }
110 p = load.GoFilesPackage(ctx, pkgOpts, files)
111 } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
112 arg := args[0]
113 var pkgs []*load.Package
114 if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
115 var err error
116 pkgs, err = load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args[:1])
117 if err != nil {
118 base.Fatal(err)
119 }
120 } else {
121 pkgs = load.PackagesAndErrors(ctx, pkgOpts, args[:1])
122 }
123
124 if len(pkgs) == 0 {
125 base.Fatalf("go: no packages loaded from %s", arg)
126 }
127 if len(pkgs) > 1 {
128 names := make([]string, 0, len(pkgs))
129 for _, p := range pkgs {
130 names = append(names, p.ImportPath)
131 }
132 base.Fatalf("go: pattern %s matches multiple packages:\n\t%s", arg, strings.Join(names, "\n\t"))
133 }
134 p = pkgs[0]
135 i++
136 } else {
137 base.Fatalf("go: no go files listed")
138 }
139 cmdArgs := args[i:]
140 load.CheckPackageErrors([]*load.Package{p})
141
142 if cfg.BuildCover {
143 load.PrepareForCoverageBuild([]*load.Package{p})
144 }
145
146 p.Internal.OmitDebug = true
147 p.Target = ""
148 if p.Internal.CmdlineFiles {
149
150 var src string
151 if len(p.GoFiles) > 0 {
152 src = p.GoFiles[0]
153 } else if len(p.CgoFiles) > 0 {
154 src = p.CgoFiles[0]
155 } else {
156
157
158 hint := ""
159 if !cfg.BuildContext.CgoEnabled {
160 hint = " (cgo is disabled)"
161 }
162 base.Fatalf("go: no suitable source files%s", hint)
163 }
164 p.Internal.ExeName = src[:len(src)-len(".go")]
165 } else {
166 p.Internal.ExeName = p.DefaultExecName()
167 }
168
169 a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p)
170 a1.CacheExecutable = true
171 a := &work.Action{Mode: "go run", Actor: work.ActorFunc(buildRunProgram), Args: cmdArgs, Deps: []*work.Action{a1}}
172 b.Do(ctx, a)
173 }
174
175
176
177
178
179
180
181
182
183
184
185
186 func shouldUseOutsideModuleMode(args []string) bool {
187
188
189 return len(args) > 0 &&
190 !strings.HasSuffix(args[0], ".go") &&
191 !strings.HasPrefix(args[0], "-") &&
192 strings.Contains(args[0], "@") &&
193 !build.IsLocalImport(args[0]) &&
194 !filepath.IsAbs(args[0])
195 }
196
197
198
199 func buildRunProgram(b *work.Builder, ctx context.Context, a *work.Action) error {
200 cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].BuiltTarget(), a.Args)
201 if cfg.BuildN || cfg.BuildX {
202 b.Shell(a).ShowCmd("", "%s", strings.Join(cmdline, " "))
203 if cfg.BuildN {
204 return nil
205 }
206 }
207
208 base.RunStdin(cmdline)
209 return nil
210 }
211
View as plain text