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