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