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