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 ...interface{}) (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 }
86 work.BuildInit()
87 var b work.Builder
88 b.Init()
89 b.Print = printStderr
90
91 i := 0
92 for i < len(args) && strings.HasSuffix(args[i], ".go") {
93 i++
94 }
95 pkgOpts := load.PackageOpts{MainOnly: true}
96 var p *load.Package
97 if i > 0 {
98 files := args[:i]
99 for _, file := range files {
100 if strings.HasSuffix(file, "_test.go") {
101
102
103 base.Fatalf("go run: cannot run *_test.go files (%s)", file)
104 }
105 }
106 p = load.GoFilesPackage(ctx, pkgOpts, files)
107 } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
108 arg := args[0]
109 var pkgs []*load.Package
110 if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
111 var err error
112 pkgs, err = load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args[:1])
113 if err != nil {
114 base.Fatalf("go run: %v", err)
115 }
116 } else {
117 pkgs = load.PackagesAndErrors(ctx, pkgOpts, args[:1])
118 }
119
120 if len(pkgs) == 0 {
121 base.Fatalf("go run: no packages loaded from %s", arg)
122 }
123 if len(pkgs) > 1 {
124 var names []string
125 for _, p := range pkgs {
126 names = append(names, p.ImportPath)
127 }
128 base.Fatalf("go run: pattern %s matches multiple packages:\n\t%s", arg, strings.Join(names, "\n\t"))
129 }
130 p = pkgs[0]
131 i++
132 } else {
133 base.Fatalf("go run: no go files listed")
134 }
135 cmdArgs := args[i:]
136 load.CheckPackageErrors([]*load.Package{p})
137
138 p.Internal.OmitDebug = true
139 p.Target = ""
140 if p.Internal.CmdlineFiles {
141
142 var src string
143 if len(p.GoFiles) > 0 {
144 src = p.GoFiles[0]
145 } else if len(p.CgoFiles) > 0 {
146 src = p.CgoFiles[0]
147 } else {
148
149
150 hint := ""
151 if !cfg.BuildContext.CgoEnabled {
152 hint = " (cgo is disabled)"
153 }
154 base.Fatalf("go run: no suitable source files%s", hint)
155 }
156 p.Internal.ExeName = src[:len(src)-len(".go")]
157 } else {
158 p.Internal.ExeName = path.Base(p.ImportPath)
159 }
160
161 a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p)
162 a := &work.Action{Mode: "go run", Func: buildRunProgram, Args: cmdArgs, Deps: []*work.Action{a1}}
163 b.Do(ctx, a)
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177 func shouldUseOutsideModuleMode(args []string) bool {
178
179
180 return len(args) > 0 &&
181 !strings.HasSuffix(args[0], ".go") &&
182 !strings.HasPrefix(args[0], "-") &&
183 strings.Contains(args[0], "@") &&
184 !build.IsLocalImport(args[0]) &&
185 !filepath.IsAbs(args[0])
186 }
187
188
189
190 func buildRunProgram(b *work.Builder, ctx context.Context, a *work.Action) error {
191 cmdline := str.StringList(work.FindExecCmd(), a.Deps[0].Target, a.Args)
192 if cfg.BuildN || cfg.BuildX {
193 b.Showcmd("", "%s", strings.Join(cmdline, " "))
194 if cfg.BuildN {
195 return nil
196 }
197 }
198
199 base.RunStdin(cmdline)
200 return nil
201 }
202
View as plain text