1
2
3
4
5 package work
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "internal/buildcfg"
12 "internal/platform"
13 "io"
14 "log"
15 "os"
16 "path/filepath"
17 "runtime"
18 "strings"
19
20 "cmd/go/internal/base"
21 "cmd/go/internal/cfg"
22 "cmd/go/internal/fips140"
23 "cmd/go/internal/fsys"
24 "cmd/go/internal/gover"
25 "cmd/go/internal/load"
26 "cmd/go/internal/str"
27 "cmd/internal/quoted"
28 "crypto/sha1"
29 )
30
31
32 var ToolchainVersion = runtime.Version()
33
34
35
36 type gcToolchain struct{}
37
38 func (gcToolchain) compiler() string {
39 return base.Tool("compile")
40 }
41
42 func (gcToolchain) linker() string {
43 return base.Tool("link")
44 }
45
46 func pkgPath(a *Action) string {
47 p := a.Package
48 ppath := p.ImportPath
49 if cfg.BuildBuildmode == "plugin" {
50 ppath = pluginPath(a)
51 } else if p.Name == "main" && !p.Internal.ForceLibrary {
52 ppath = "main"
53 }
54 return ppath
55 }
56
57 func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, pgoProfile string, gofiles []string) (ofile string, output []byte, err error) {
58 p := a.Package
59 sh := b.Shell(a)
60 objdir := a.Objdir
61 if archive != "" {
62 ofile = archive
63 } else {
64 out := "_go_.o"
65 ofile = objdir + out
66 }
67
68 pkgpath := pkgPath(a)
69 defaultGcFlags := []string{"-p", pkgpath}
70 vers := gover.Local()
71 if p.Module != nil {
72 v := p.Module.GoVersion
73 if v == "" {
74 v = gover.DefaultGoModVersion
75 }
76
77 if allowedVersion(v) {
78 vers = v
79 }
80 }
81 defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(vers))
82 if p.Standard {
83 defaultGcFlags = append(defaultGcFlags, "-std")
84 }
85
86
87
88
89
90 extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
91 if p.Standard {
92 switch p.ImportPath {
93 case "bytes", "internal/poll", "net", "os":
94 fallthrough
95 case "runtime/metrics", "runtime/pprof", "runtime/trace":
96 fallthrough
97 case "sync", "syscall", "time":
98 extFiles++
99 }
100 }
101 if extFiles == 0 {
102 defaultGcFlags = append(defaultGcFlags, "-complete")
103 }
104 if cfg.BuildContext.InstallSuffix != "" {
105 defaultGcFlags = append(defaultGcFlags, "-installsuffix", cfg.BuildContext.InstallSuffix)
106 }
107 if a.buildID != "" {
108 defaultGcFlags = append(defaultGcFlags, "-buildid", a.buildID)
109 }
110 if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
111 defaultGcFlags = append(defaultGcFlags, "-dwarf=false")
112 }
113 if strings.HasPrefix(ToolchainVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
114 defaultGcFlags = append(defaultGcFlags, "-goversion", ToolchainVersion)
115 }
116 if p.Internal.Cover.Cfg != "" {
117 defaultGcFlags = append(defaultGcFlags, "-coveragecfg="+p.Internal.Cover.Cfg)
118 }
119 if pgoProfile != "" {
120 defaultGcFlags = append(defaultGcFlags, "-pgoprofile="+pgoProfile)
121 }
122 if symabis != "" {
123 defaultGcFlags = append(defaultGcFlags, "-symabis", symabis)
124 }
125
126 gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags)
127 if p.Internal.FuzzInstrument {
128 gcflags = append(gcflags, fuzzInstrumentFlags()...)
129 }
130
131 if c := gcBackendConcurrency(gcflags); c > 1 {
132 defaultGcFlags = append(defaultGcFlags, fmt.Sprintf("-c=%d", c))
133 }
134
135 args := []any{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), defaultGcFlags, gcflags}
136 if p.Internal.LocalPrefix == "" {
137 args = append(args, "-nolocalimports")
138 } else {
139 args = append(args, "-D", p.Internal.LocalPrefix)
140 }
141 if importcfg != nil {
142 if err := sh.writeFile(objdir+"importcfg", importcfg); err != nil {
143 return "", nil, err
144 }
145 args = append(args, "-importcfg", objdir+"importcfg")
146 }
147 if embedcfg != nil {
148 if err := sh.writeFile(objdir+"embedcfg", embedcfg); err != nil {
149 return "", nil, err
150 }
151 args = append(args, "-embedcfg", objdir+"embedcfg")
152 }
153 if ofile == archive {
154 args = append(args, "-pack")
155 }
156 if asmhdr {
157 args = append(args, "-asmhdr", objdir+"go_asm.h")
158 }
159
160 for _, f := range gofiles {
161 f := mkAbs(p.Dir, f)
162
163
164
165
166
167
168
169
170
171
172
173
174
175 args = append(args, fsys.Actual(f))
176 }
177 output, err = sh.runOut(base.Cwd(), cfgChangedEnv, args...)
178 return ofile, output, err
179 }
180
181
182 func gcBackendConcurrency(gcflags []string) int {
183
184 canDashC := concurrentGCBackendCompilationEnabledByDefault
185
186 switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e {
187 case "0":
188 canDashC = false
189 case "1":
190 canDashC = true
191 case "":
192
193 default:
194 log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e)
195 }
196
197
198 if cfg.ExperimentErr != nil || cfg.Experiment.FieldTrack || cfg.Experiment.PreemptibleLoops {
199 canDashC = false
200 }
201
202 if !canDashC {
203 return 1
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229 c := runtime.GOMAXPROCS(0)
230 if cfg.BuildP == 1 {
231
232 return c
233 }
234
235 if c > 4 {
236 c = 4
237 }
238 return c
239 }
240
241
242
243 func (a *Action) trimpath() string {
244
245
246
247
248
249 objdir := strings.TrimSuffix(a.Objdir, string(filepath.Separator))
250 rewrite := ""
251
252 rewriteDir := a.Package.Dir
253 if cfg.BuildTrimpath {
254 importPath := a.Package.Internal.OrigImportPath
255 if m := a.Package.Module; m != nil && m.Version != "" {
256 rewriteDir = m.Path + "@" + m.Version + strings.TrimPrefix(importPath, m.Path)
257 } else {
258 rewriteDir = importPath
259 }
260 rewrite += a.Package.Dir + "=>" + rewriteDir + ";"
261 }
262
263
264
265
266
267 cgoFiles := make(map[string]bool)
268 for _, f := range a.Package.CgoFiles {
269 cgoFiles[f] = true
270 }
271
272
273
274
275
276 var overlayNonGoRewrites string
277 hasCgoOverlay := false
278 if fsys.OverlayFile != "" {
279 for _, filename := range a.Package.AllFiles() {
280 path := filename
281 if !filepath.IsAbs(path) {
282 path = filepath.Join(a.Package.Dir, path)
283 }
284 base := filepath.Base(path)
285 isGo := strings.HasSuffix(filename, ".go") || strings.HasSuffix(filename, ".s")
286 isCgo := cgoFiles[filename] || !isGo
287 if fsys.Replaced(path) {
288 if isCgo {
289 hasCgoOverlay = true
290 } else {
291 rewrite += fsys.Actual(path) + "=>" + filepath.Join(rewriteDir, base) + ";"
292 }
293 } else if isCgo {
294
295 if filepath.Dir(path) == a.Package.Dir {
296
297 overlayNonGoRewrites += filepath.Join(objdir, base) + "=>" + filepath.Join(rewriteDir, base) + ";"
298 }
299 } else {
300
301 }
302 }
303 }
304 if hasCgoOverlay {
305 rewrite += overlayNonGoRewrites
306 }
307 rewrite += objdir + "=>"
308
309 return rewrite
310 }
311
312 func asmArgs(a *Action, p *load.Package) []any {
313
314 inc := filepath.Join(cfg.GOROOT, "pkg", "include")
315 pkgpath := pkgPath(a)
316 args := []any{cfg.BuildToolexec, base.Tool("asm"), "-p", pkgpath, "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
317 if p.ImportPath == "runtime" && cfg.Goarch == "386" {
318 for _, arg := range forcedAsmflags {
319 if arg == "-dynlink" {
320 args = append(args, "-D=GOBUILDMODE_shared=1")
321 }
322 }
323 }
324
325 if cfg.Goarch == "386" {
326
327 args = append(args, "-D", "GO386_"+cfg.GO386)
328 }
329
330 if cfg.Goarch == "amd64" {
331
332 args = append(args, "-D", "GOAMD64_"+cfg.GOAMD64)
333 }
334
335 if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" {
336
337 args = append(args, "-D", "GOMIPS_"+cfg.GOMIPS)
338 }
339
340 if cfg.Goarch == "mips64" || cfg.Goarch == "mips64le" {
341
342 args = append(args, "-D", "GOMIPS64_"+cfg.GOMIPS64)
343 }
344
345 if cfg.Goarch == "ppc64" || cfg.Goarch == "ppc64le" {
346
347
348 switch cfg.GOPPC64 {
349 case "power10":
350 args = append(args, "-D", "GOPPC64_power10")
351 fallthrough
352 case "power9":
353 args = append(args, "-D", "GOPPC64_power9")
354 fallthrough
355 default:
356 args = append(args, "-D", "GOPPC64_power8")
357 }
358 }
359
360 if cfg.Goarch == "riscv64" {
361
362 args = append(args, "-D", "GORISCV64_"+cfg.GORISCV64)
363 }
364
365 if cfg.Goarch == "arm" {
366
367
368 switch {
369 case strings.Contains(cfg.GOARM, "7"):
370 args = append(args, "-D", "GOARM_7")
371 fallthrough
372 case strings.Contains(cfg.GOARM, "6"):
373 args = append(args, "-D", "GOARM_6")
374 fallthrough
375 default:
376 args = append(args, "-D", "GOARM_5")
377 }
378 }
379
380 if cfg.Goarch == "arm64" {
381 g, err := buildcfg.ParseGoarm64(cfg.GOARM64)
382 if err == nil && g.LSE {
383 args = append(args, "-D", "GOARM64_LSE")
384 }
385 }
386
387 return args
388 }
389
390 func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
391 p := a.Package
392 args := asmArgs(a, p)
393
394 var ofiles []string
395 for _, sfile := range sfiles {
396 ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o"
397 ofiles = append(ofiles, ofile)
398 args1 := append(args, "-o", ofile, fsys.Actual(mkAbs(p.Dir, sfile)))
399 if err := b.Shell(a).run(p.Dir, p.ImportPath, cfgChangedEnv, args1...); err != nil {
400 return nil, err
401 }
402 }
403 return ofiles, nil
404 }
405
406 func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
407 sh := b.Shell(a)
408
409 mkSymabis := func(p *load.Package, sfiles []string, path string) error {
410 args := asmArgs(a, p)
411 args = append(args, "-gensymabis", "-o", path)
412 for _, sfile := range sfiles {
413 if p.ImportPath == "runtime/cgo" && strings.HasPrefix(sfile, "gcc_") {
414 continue
415 }
416 args = append(args, fsys.Actual(mkAbs(p.Dir, sfile)))
417 }
418
419
420
421
422 if err := sh.writeFile(a.Objdir+"go_asm.h", nil); err != nil {
423 return err
424 }
425
426 return sh.run(p.Dir, p.ImportPath, cfgChangedEnv, args...)
427 }
428
429 var symabis string
430 p := a.Package
431 if len(sfiles) != 0 {
432 symabis = a.Objdir + "symabis"
433 if err := mkSymabis(p, sfiles, symabis); err != nil {
434 return "", err
435 }
436 }
437
438 return symabis, nil
439 }
440
441
442
443
444 func toolVerify(a *Action, b *Builder, p *load.Package, newTool string, ofile string, args []any) error {
445 newArgs := make([]any, len(args))
446 copy(newArgs, args)
447 newArgs[1] = base.Tool(newTool)
448 newArgs[3] = ofile + ".new"
449 if err := b.Shell(a).run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
450 return err
451 }
452 data1, err := os.ReadFile(ofile)
453 if err != nil {
454 return err
455 }
456 data2, err := os.ReadFile(ofile + ".new")
457 if err != nil {
458 return err
459 }
460 if !bytes.Equal(data1, data2) {
461 return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " "))
462 }
463 os.Remove(ofile + ".new")
464 return nil
465 }
466
467 func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
468 absOfiles := make([]string, 0, len(ofiles))
469 for _, f := range ofiles {
470 absOfiles = append(absOfiles, mkAbs(a.Objdir, f))
471 }
472 absAfile := mkAbs(a.Objdir, afile)
473
474
475
476 if !cfg.BuildN {
477 if _, err := os.Stat(absAfile); err != nil {
478 base.Fatalf("os.Stat of archive file failed: %v", err)
479 }
480 }
481
482 p := a.Package
483 sh := b.Shell(a)
484 if cfg.BuildN || cfg.BuildX {
485 cmdline := str.StringList(base.Tool("pack"), "r", absAfile, absOfiles)
486 sh.ShowCmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
487 }
488 if cfg.BuildN {
489 return nil
490 }
491 if err := packInternal(absAfile, absOfiles); err != nil {
492 return sh.reportCmd("", "", nil, err)
493 }
494 return nil
495 }
496
497 func packInternal(afile string, ofiles []string) error {
498 dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
499 if err != nil {
500 return err
501 }
502 defer dst.Close()
503 w := bufio.NewWriter(dst)
504
505 for _, ofile := range ofiles {
506 src, err := os.Open(ofile)
507 if err != nil {
508 return err
509 }
510 fi, err := src.Stat()
511 if err != nil {
512 src.Close()
513 return err
514 }
515
516
517 name := fi.Name()
518 if len(name) > 16 {
519 name = name[:16]
520 } else {
521 name += strings.Repeat(" ", 16-len(name))
522 }
523 size := fi.Size()
524 fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
525 name, 0, 0, 0, 0644, size)
526 n, err := io.Copy(w, src)
527 src.Close()
528 if err == nil && n < size {
529 err = io.ErrUnexpectedEOF
530 } else if err == nil && n > size {
531 err = fmt.Errorf("file larger than size reported by stat")
532 }
533 if err != nil {
534 return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
535 }
536 if size&1 != 0 {
537 w.WriteByte(0)
538 }
539 }
540
541 if err := w.Flush(); err != nil {
542 return err
543 }
544 return dst.Close()
545 }
546
547
548 func setextld(ldflags []string, compiler []string) ([]string, error) {
549 for _, f := range ldflags {
550 if f == "-extld" || strings.HasPrefix(f, "-extld=") {
551
552 return ldflags, nil
553 }
554 }
555 joined, err := quoted.Join(compiler)
556 if err != nil {
557 return nil, err
558 }
559 return append(ldflags, "-extld="+joined), nil
560 }
561
562
563
564
565
566
567
568
569 func pluginPath(a *Action) string {
570 p := a.Package
571 if p.ImportPath != "command-line-arguments" {
572 return p.ImportPath
573 }
574 h := sha1.New()
575 buildID := a.buildID
576 if a.Mode == "link" {
577
578
579
580
581
582
583
584
585
586 id := strings.Split(buildID, buildIDSeparator)
587 buildID = id[1] + buildIDSeparator + id[1]
588 }
589 fmt.Fprintf(h, "build ID: %s\n", buildID)
590 for _, file := range str.StringList(p.GoFiles, p.CgoFiles, p.SFiles) {
591 data, err := os.ReadFile(filepath.Join(p.Dir, file))
592 if err != nil {
593 base.Fatalf("go: %s", err)
594 }
595 h.Write(data)
596 }
597 return fmt.Sprintf("plugin/unnamed-%x", h.Sum(nil))
598 }
599
600 func (gcToolchain) ld(b *Builder, root *Action, targetPath, importcfg, mainpkg string) error {
601 cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0
602 for _, a := range root.Deps {
603 if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
604 cxx = true
605 }
606 }
607 var ldflags []string
608 if cfg.BuildContext.InstallSuffix != "" {
609 ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
610 }
611 if root.Package.Internal.OmitDebug {
612 ldflags = append(ldflags, "-s", "-w")
613 }
614 if cfg.BuildBuildmode == "plugin" {
615 ldflags = append(ldflags, "-pluginpath", pluginPath(root))
616 }
617 if fips140.Enabled() {
618 ldflags = append(ldflags, "-fipso", filepath.Join(root.Objdir, "fips.o"))
619 }
620
621
622
623 if root.Package.Goroot && strings.HasPrefix(root.Package.ImportPath, "cmd/") {
624
625
626
627
628 if !platform.MustLinkExternal(cfg.Goos, cfg.Goarch, false) {
629 ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID)
630 }
631 }
632
633
634 if root.Package.DefaultGODEBUG != "" {
635 ldflags = append(ldflags, "-X=runtime.godebugDefault="+root.Package.DefaultGODEBUG)
636 }
637
638
639
640
641
642 var compiler []string
643 if cxx {
644 compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
645 } else {
646 compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
647 }
648 ldflags = append(ldflags, "-buildmode="+ldBuildmode)
649 if root.buildID != "" {
650 ldflags = append(ldflags, "-buildid="+root.buildID)
651 }
652 ldflags = append(ldflags, forcedLdflags...)
653 ldflags = append(ldflags, root.Package.Internal.Ldflags...)
654 ldflags, err := setextld(ldflags, compiler)
655 if err != nil {
656 return err
657 }
658
659
660
661
662
663
664
665
666
667
668
669
670 dir := "."
671 if cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" {
672 dir, targetPath = filepath.Split(targetPath)
673 }
674
675 env := cfgChangedEnv
676
677 if cfg.BuildTrimpath {
678 env = append(env, "GOROOT=")
679 } else {
680 env = append(env, "GOROOT="+cfg.GOROOT)
681 }
682 return b.Shell(root).run(dir, root.Package.ImportPath, env, cfg.BuildToolexec, base.Tool("link"), "-o", targetPath, "-importcfg", importcfg, ldflags, mainpkg)
683 }
684
685 func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, targetPath, importcfg string, allactions []*Action) error {
686 ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix}
687 ldflags = append(ldflags, "-buildmode=shared")
688 ldflags = append(ldflags, forcedLdflags...)
689 ldflags = append(ldflags, root.Package.Internal.Ldflags...)
690 cxx := false
691 for _, a := range allactions {
692 if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
693 cxx = true
694 }
695 }
696
697
698
699
700 var compiler []string
701 if cxx {
702 compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
703 } else {
704 compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
705 }
706 ldflags, err := setextld(ldflags, compiler)
707 if err != nil {
708 return err
709 }
710 for _, d := range toplevelactions {
711 if !strings.HasSuffix(d.Target, ".a") {
712 continue
713 }
714 ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target)
715 }
716
717
718
719
720
721
722
723
724
725
726
727
728 dir, targetPath := filepath.Split(targetPath)
729
730 return b.Shell(root).run(dir, targetPath, cfgChangedEnv, cfg.BuildToolexec, base.Tool("link"), "-o", targetPath, "-importcfg", importcfg, ldflags)
731 }
732
733 func (gcToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
734 return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(a.Package.Dir, cfile))
735 }
736
View as plain text