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