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