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