1
2
3
4
5
6
7 package work
8
9 import (
10 "bytes"
11 "cmd/go/internal/base"
12 "cmd/go/internal/cfg"
13 "cmd/go/internal/fsys"
14 "cmd/go/internal/modload"
15 "cmd/internal/quoted"
16 "fmt"
17 "internal/platform"
18 "os"
19 "os/exec"
20 "path/filepath"
21 "regexp"
22 "runtime"
23 "strconv"
24 "sync"
25 )
26
27 var buildInitStarted = false
28
29 func BuildInit() {
30 if buildInitStarted {
31 base.Fatalf("go: internal error: work.BuildInit called more than once")
32 }
33 buildInitStarted = true
34 base.AtExit(closeBuilders)
35
36 modload.Init()
37 instrumentInit()
38 buildModeInit()
39 if err := fsys.Init(base.Cwd()); err != nil {
40 base.Fatal(err)
41 }
42
43
44
45 if cfg.BuildPkgdir != "" && !filepath.IsAbs(cfg.BuildPkgdir) {
46 p, err := filepath.Abs(cfg.BuildPkgdir)
47 if err != nil {
48 fmt.Fprintf(os.Stderr, "go: evaluating -pkgdir: %v\n", err)
49 base.SetExitStatus(2)
50 base.Exit()
51 }
52 cfg.BuildPkgdir = p
53 }
54
55 if cfg.BuildP <= 0 {
56 base.Fatalf("go: -p must be a positive integer: %v\n", cfg.BuildP)
57 }
58
59
60 for _, key := range []string{"CC", "CXX", "FC"} {
61 value := cfg.Getenv(key)
62 args, err := quoted.Split(value)
63 if err != nil {
64 base.Fatalf("go: %s environment variable could not be parsed: %v", key, err)
65 }
66 if len(args) == 0 {
67 continue
68 }
69 path := args[0]
70 if !filepath.IsAbs(path) && path != filepath.Base(path) {
71 base.Fatalf("go: %s environment variable is relative; must be absolute path: %s\n", key, path)
72 }
73 }
74
75
76
77 if cfg.BuildCoverMode == "" {
78 cfg.BuildCoverMode = "set"
79 if cfg.BuildRace {
80
81 cfg.BuildCoverMode = "atomic"
82 }
83 }
84 if cfg.BuildRace && cfg.BuildCoverMode != "atomic" {
85 base.Fatalf(`-covermode must be "atomic", not %q, when -race is enabled`, cfg.BuildCoverMode)
86 }
87 }
88
89
90
91
92
93
94
95 func fuzzInstrumentFlags() []string {
96 if !platform.FuzzInstrumented(cfg.Goos, cfg.Goarch) {
97 return nil
98 }
99 return []string{"-d=libfuzzer"}
100 }
101
102 func instrumentInit() {
103 if !cfg.BuildRace && !cfg.BuildMSan && !cfg.BuildASan {
104 return
105 }
106 if cfg.BuildRace && cfg.BuildMSan {
107 fmt.Fprintf(os.Stderr, "go: may not use -race and -msan simultaneously\n")
108 base.SetExitStatus(2)
109 base.Exit()
110 }
111 if cfg.BuildRace && cfg.BuildASan {
112 fmt.Fprintf(os.Stderr, "go: may not use -race and -asan simultaneously\n")
113 base.SetExitStatus(2)
114 base.Exit()
115 }
116 if cfg.BuildMSan && cfg.BuildASan {
117 fmt.Fprintf(os.Stderr, "go: may not use -msan and -asan simultaneously\n")
118 base.SetExitStatus(2)
119 base.Exit()
120 }
121 if cfg.BuildMSan && !platform.MSanSupported(cfg.Goos, cfg.Goarch) {
122 fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
123 base.SetExitStatus(2)
124 base.Exit()
125 }
126 if cfg.BuildRace && !platform.RaceDetectorSupported(cfg.Goos, cfg.Goarch) {
127 fmt.Fprintf(os.Stderr, "-race is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
128 base.SetExitStatus(2)
129 base.Exit()
130 }
131 if cfg.BuildASan && !platform.ASanSupported(cfg.Goos, cfg.Goarch) {
132 fmt.Fprintf(os.Stderr, "-asan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
133 base.SetExitStatus(2)
134 base.Exit()
135 }
136
137
138
139
140
141 if cfg.BuildASan {
142 if err := compilerRequiredAsanVersion(); err != nil {
143 fmt.Fprintf(os.Stderr, "%v\n", err)
144 base.SetExitStatus(2)
145 base.Exit()
146 }
147 }
148
149 mode := "race"
150 if cfg.BuildMSan {
151 mode = "msan"
152
153
154 if cfg.BuildBuildmode == "default" && (cfg.Goos != "linux" || cfg.Goarch != "amd64") {
155 cfg.BuildBuildmode = "pie"
156 }
157 }
158 if cfg.BuildASan {
159 mode = "asan"
160 }
161 modeFlag := "-" + mode
162
163
164
165 if !cfg.BuildContext.CgoEnabled && (cfg.Goos != "darwin" || cfg.BuildASan || cfg.BuildMSan) {
166 if runtime.GOOS != cfg.Goos || runtime.GOARCH != cfg.Goarch {
167 fmt.Fprintf(os.Stderr, "go: %s requires cgo\n", modeFlag)
168 } else {
169 fmt.Fprintf(os.Stderr, "go: %s requires cgo; enable cgo by setting CGO_ENABLED=1\n", modeFlag)
170 }
171
172 base.SetExitStatus(2)
173 base.Exit()
174 }
175 forcedGcflags = append(forcedGcflags, modeFlag)
176 forcedLdflags = append(forcedLdflags, modeFlag)
177
178 if cfg.BuildContext.InstallSuffix != "" {
179 cfg.BuildContext.InstallSuffix += "_"
180 }
181 cfg.BuildContext.InstallSuffix += mode
182 cfg.BuildContext.ToolTags = append(cfg.BuildContext.ToolTags, mode)
183 }
184
185 func buildModeInit() {
186 gccgo := cfg.BuildToolchainName == "gccgo"
187 var codegenArg string
188
189
190
191
192
193 switch cfg.BuildBuildmode {
194 case "archive":
195 pkgsFilter = pkgsNotMain
196 case "c-archive":
197 pkgsFilter = oneMainPkg
198 if gccgo {
199 codegenArg = "-fPIC"
200 } else {
201 switch cfg.Goos {
202 case "darwin", "ios":
203 switch cfg.Goarch {
204 case "arm64":
205 codegenArg = "-shared"
206 }
207
208 case "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris":
209
210
211
212 codegenArg = "-shared"
213 }
214 }
215 cfg.ExeSuffix = ".a"
216 ldBuildmode = "c-archive"
217 case "c-shared":
218 pkgsFilter = oneMainPkg
219 if gccgo {
220 codegenArg = "-fPIC"
221 } else {
222 switch cfg.Goos {
223 case "linux", "android", "freebsd":
224 codegenArg = "-shared"
225 case "windows":
226
227 cfg.ExeSuffix = ""
228 }
229 }
230 ldBuildmode = "c-shared"
231 case "default":
232 ldBuildmode = "exe"
233 if platform.DefaultPIE(cfg.Goos, cfg.Goarch, cfg.BuildRace) {
234 ldBuildmode = "pie"
235 if cfg.Goos != "windows" && !gccgo {
236 codegenArg = "-shared"
237 }
238 }
239 case "exe":
240 pkgsFilter = pkgsMain
241 ldBuildmode = "exe"
242
243
244
245 if cfg.BuildO != "" {
246 pkgsFilter = oneMainPkg
247 }
248 case "pie":
249 if cfg.BuildRace && !platform.DefaultPIE(cfg.Goos, cfg.Goarch, cfg.BuildRace) {
250 base.Fatalf("-buildmode=pie not supported when -race is enabled on %s/%s", cfg.Goos, cfg.Goarch)
251 }
252 if gccgo {
253 codegenArg = "-fPIE"
254 } else {
255 switch cfg.Goos {
256 case "aix", "windows":
257 default:
258 codegenArg = "-shared"
259 }
260 }
261 ldBuildmode = "pie"
262 case "shared":
263 pkgsFilter = pkgsNotMain
264 if gccgo {
265 codegenArg = "-fPIC"
266 } else {
267 codegenArg = "-dynlink"
268 }
269 if cfg.BuildO != "" {
270 base.Fatalf("-buildmode=shared and -o not supported together")
271 }
272 ldBuildmode = "shared"
273 case "plugin":
274 pkgsFilter = oneMainPkg
275 if gccgo {
276 codegenArg = "-fPIC"
277 } else {
278 codegenArg = "-dynlink"
279 }
280 cfg.ExeSuffix = ".so"
281 ldBuildmode = "plugin"
282 default:
283 base.Fatalf("buildmode=%s not supported", cfg.BuildBuildmode)
284 }
285
286 if cfg.BuildBuildmode != "default" && !platform.BuildModeSupported(cfg.BuildToolchainName, cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) {
287 base.Fatalf("-buildmode=%s not supported on %s/%s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
288 }
289
290 if cfg.BuildLinkshared {
291 if !platform.BuildModeSupported(cfg.BuildToolchainName, "shared", cfg.Goos, cfg.Goarch) {
292 base.Fatalf("-linkshared not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
293 }
294 if gccgo {
295 codegenArg = "-fPIC"
296 } else {
297 forcedAsmflags = append(forcedAsmflags, "-D=GOBUILDMODE_shared=1",
298 "-linkshared")
299 codegenArg = "-dynlink"
300 forcedGcflags = append(forcedGcflags, "-linkshared")
301
302 forcedLdflags = append(forcedLdflags, "-linkshared", "-w")
303 }
304 }
305 if codegenArg != "" {
306 if gccgo {
307 forcedGccgoflags = append([]string{codegenArg}, forcedGccgoflags...)
308 } else {
309 forcedAsmflags = append([]string{codegenArg}, forcedAsmflags...)
310 forcedGcflags = append([]string{codegenArg}, forcedGcflags...)
311 }
312
313 if cfg.BuildBuildmode != "default" || cfg.BuildLinkshared {
314 if cfg.BuildContext.InstallSuffix != "" {
315 cfg.BuildContext.InstallSuffix += "_"
316 }
317 cfg.BuildContext.InstallSuffix += codegenArg[1:]
318 }
319 }
320
321 switch cfg.BuildMod {
322 case "":
323
324 case "readonly", "vendor", "mod":
325 if !cfg.ModulesEnabled && !base.InGOFLAGS("-mod") {
326 base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod)
327 }
328 default:
329 base.Fatalf("-mod=%s not supported (can be '', 'mod', 'readonly', or 'vendor')", cfg.BuildMod)
330 }
331 if !cfg.ModulesEnabled {
332 if cfg.ModCacheRW && !base.InGOFLAGS("-modcacherw") {
333 base.Fatalf("build flag -modcacherw only valid when using modules")
334 }
335 if cfg.ModFile != "" && !base.InGOFLAGS("-mod") {
336 base.Fatalf("build flag -modfile only valid when using modules")
337 }
338 }
339 }
340
341 type version struct {
342 name string
343 major, minor int
344 }
345
346 var compiler struct {
347 sync.Once
348 version
349 err error
350 }
351
352
353
354
355 func compilerVersion() (version, error) {
356 compiler.Once.Do(func() {
357 compiler.err = func() error {
358 compiler.name = "unknown"
359 cc := os.Getenv("CC")
360 out, err := exec.Command(cc, "--version").Output()
361 if err != nil {
362
363 return err
364 }
365
366 var match [][]byte
367 if bytes.HasPrefix(out, []byte("gcc")) {
368 compiler.name = "gcc"
369 out, err := exec.Command(cc, "-v").CombinedOutput()
370 if err != nil {
371
372 return err
373 }
374 gccRE := regexp.MustCompile(`gcc version (\d+)\.(\d+)`)
375 match = gccRE.FindSubmatch(out)
376 } else {
377 clangRE := regexp.MustCompile(`clang version (\d+)\.(\d+)`)
378 if match = clangRE.FindSubmatch(out); len(match) > 0 {
379 compiler.name = "clang"
380 }
381 }
382
383 if len(match) < 3 {
384 return nil
385 }
386 if compiler.major, err = strconv.Atoi(string(match[1])); err != nil {
387 return err
388 }
389 if compiler.minor, err = strconv.Atoi(string(match[2])); err != nil {
390 return err
391 }
392 return nil
393 }()
394 })
395 return compiler.version, compiler.err
396 }
397
398
399
400
401
402 func compilerRequiredAsanVersion() error {
403 compiler, err := compilerVersion()
404 if err != nil {
405 return fmt.Errorf("-asan: the version of $(go env CC) could not be parsed")
406 }
407
408 switch compiler.name {
409 case "gcc":
410 if runtime.GOARCH == "ppc64le" && compiler.major < 9 {
411 return fmt.Errorf("-asan is not supported with %s compiler %d.%d\n", compiler.name, compiler.major, compiler.minor)
412 }
413 if compiler.major < 7 {
414 return fmt.Errorf("-asan is not supported with %s compiler %d.%d\n", compiler.name, compiler.major, compiler.minor)
415 }
416 case "clang":
417 if compiler.major < 9 {
418 return fmt.Errorf("-asan is not supported with %s compiler %d.%d\n", compiler.name, compiler.major, compiler.minor)
419 }
420 default:
421 return fmt.Errorf("-asan: C compiler is not gcc or clang")
422 }
423 return nil
424 }
425
View as plain text