Source file src/pkg/cmd/go/internal/work/exec.go
1
2
3
4
5
6
7 package work
8
9 import (
10 "bytes"
11 "cmd/go/internal/base"
12 "cmd/go/internal/cache"
13 "cmd/go/internal/cfg"
14 "cmd/go/internal/load"
15 "cmd/go/internal/str"
16 "encoding/json"
17 "errors"
18 "fmt"
19 "internal/lazyregexp"
20 "io"
21 "io/ioutil"
22 "log"
23 "math/rand"
24 "os"
25 "os/exec"
26 "path/filepath"
27 "regexp"
28 "runtime"
29 "strconv"
30 "strings"
31 "sync"
32 "time"
33 )
34
35
36
37 func actionList(root *Action) []*Action {
38 seen := map[*Action]bool{}
39 all := []*Action{}
40 var walk func(*Action)
41 walk = func(a *Action) {
42 if seen[a] {
43 return
44 }
45 seen[a] = true
46 for _, a1 := range a.Deps {
47 walk(a1)
48 }
49 all = append(all, a)
50 }
51 walk(root)
52 return all
53 }
54
55
56 func (b *Builder) Do(root *Action) {
57 if c := cache.Default(); c != nil && !b.IsCmdList {
58
59 defer c.Trim()
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73 all := actionList(root)
74 for i, a := range all {
75 a.priority = i
76 }
77
78
79 writeActionGraph := func() {
80 if file := cfg.DebugActiongraph; file != "" {
81 if strings.HasSuffix(file, ".go") {
82
83
84 base.Fatalf("go: refusing to write action graph to %v\n", file)
85 }
86 js := actionGraphJSON(root)
87 if err := ioutil.WriteFile(file, []byte(js), 0666); err != nil {
88 fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err)
89 base.SetExitStatus(1)
90 }
91 }
92 }
93 writeActionGraph()
94
95 b.readySema = make(chan bool, len(all))
96
97
98 for _, a := range all {
99 for _, a1 := range a.Deps {
100 a1.triggers = append(a1.triggers, a)
101 }
102 a.pending = len(a.Deps)
103 if a.pending == 0 {
104 b.ready.push(a)
105 b.readySema <- true
106 }
107 }
108
109
110
111 handle := func(a *Action) {
112 if a.json != nil {
113 a.json.TimeStart = time.Now()
114 }
115 var err error
116 if a.Func != nil && (!a.Failed || a.IgnoreFail) {
117 err = a.Func(b, a)
118 }
119 if a.json != nil {
120 a.json.TimeDone = time.Now()
121 }
122
123
124
125 b.exec.Lock()
126 defer b.exec.Unlock()
127
128 if err != nil {
129 if err == errPrintedOutput {
130 base.SetExitStatus(2)
131 } else {
132 base.Errorf("%s", err)
133 }
134 a.Failed = true
135 }
136
137 for _, a0 := range a.triggers {
138 if a.Failed {
139 a0.Failed = true
140 }
141 if a0.pending--; a0.pending == 0 {
142 b.ready.push(a0)
143 b.readySema <- true
144 }
145 }
146
147 if a == root {
148 close(b.readySema)
149 }
150 }
151
152 var wg sync.WaitGroup
153
154
155
156
157
158 par := cfg.BuildP
159 if cfg.BuildN {
160 par = 1
161 }
162 for i := 0; i < par; i++ {
163 wg.Add(1)
164 go func() {
165 defer wg.Done()
166 for {
167 select {
168 case _, ok := <-b.readySema:
169 if !ok {
170 return
171 }
172
173
174 b.exec.Lock()
175 a := b.ready.pop()
176 b.exec.Unlock()
177 handle(a)
178 case <-base.Interrupted:
179 base.SetExitStatus(1)
180 return
181 }
182 }
183 }()
184 }
185
186 wg.Wait()
187
188
189 writeActionGraph()
190 }
191
192
193 func (b *Builder) buildActionID(a *Action) cache.ActionID {
194 p := a.Package
195 h := cache.NewHash("build " + p.ImportPath)
196
197
198
199
200
201
202 fmt.Fprintf(h, "compile\n")
203
204
205
206
207
208 if !p.Goroot && !cfg.BuildTrimpath && !strings.HasPrefix(p.Dir, b.WorkDir) {
209 fmt.Fprintf(h, "dir %s\n", p.Dir)
210 }
211 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
212 fmt.Fprintf(h, "import %q\n", p.ImportPath)
213 fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
214 if cfg.BuildTrimpath {
215 fmt.Fprintln(h, "trimpath")
216 }
217 if p.Internal.ForceLibrary {
218 fmt.Fprintf(h, "forcelibrary\n")
219 }
220 if len(p.CgoFiles)+len(p.SwigFiles) > 0 {
221 fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo"))
222 cppflags, cflags, cxxflags, fflags, ldflags, _ := b.CFlags(p)
223 fmt.Fprintf(h, "CC=%q %q %q %q\n", b.ccExe(), cppflags, cflags, ldflags)
224 if len(p.CXXFiles)+len(p.SwigFiles) > 0 {
225 fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags)
226 }
227 if len(p.FFiles) > 0 {
228 fmt.Fprintf(h, "FC=%q %q\n", b.fcExe(), fflags)
229 }
230
231 }
232 if p.Internal.CoverMode != "" {
233 fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover"))
234 }
235 fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo)
236
237
238 switch cfg.BuildToolchainName {
239 default:
240 base.Fatalf("buildActionID: unknown build toolchain %q", cfg.BuildToolchainName)
241 case "gc":
242 fmt.Fprintf(h, "compile %s %q %q\n", b.toolID("compile"), forcedGcflags, p.Internal.Gcflags)
243 if len(p.SFiles) > 0 {
244 fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
245 }
246
247
248 key, val := cfg.GetArchEnv()
249 fmt.Fprintf(h, "%s=%s\n", key, val)
250
251
252
253
254
255
256 magic := []string{
257 "GOCLOBBERDEADHASH",
258 "GOSSAFUNC",
259 "GO_SSA_PHI_LOC_CUTOFF",
260 "GOSSAHASH",
261 }
262 for _, env := range magic {
263 if x := os.Getenv(env); x != "" {
264 fmt.Fprintf(h, "magic %s=%s\n", env, x)
265 }
266 }
267 if os.Getenv("GOSSAHASH") != "" {
268 for i := 0; ; i++ {
269 env := fmt.Sprintf("GOSSAHASH%d", i)
270 x := os.Getenv(env)
271 if x == "" {
272 break
273 }
274 fmt.Fprintf(h, "magic %s=%s\n", env, x)
275 }
276 }
277 if os.Getenv("GSHS_LOGFILE") != "" {
278
279
280
281
282 fmt.Fprintf(h, "nocache %d\n", time.Now().UnixNano())
283 }
284
285 case "gccgo":
286 id, err := b.gccgoToolID(BuildToolchain.compiler(), "go")
287 if err != nil {
288 base.Fatalf("%v", err)
289 }
290 fmt.Fprintf(h, "compile %s %q %q\n", id, forcedGccgoflags, p.Internal.Gccgoflags)
291 fmt.Fprintf(h, "pkgpath %s\n", gccgoPkgpath(p))
292 fmt.Fprintf(h, "ar %q\n", BuildToolchain.(gccgoToolchain).ar())
293 if len(p.SFiles) > 0 {
294 id, _ = b.gccgoToolID(BuildToolchain.compiler(), "assembler-with-cpp")
295
296
297 fmt.Fprintf(h, "asm %q\n", id)
298 }
299 }
300
301
302 inputFiles := str.StringList(
303 p.GoFiles,
304 p.CgoFiles,
305 p.CFiles,
306 p.CXXFiles,
307 p.FFiles,
308 p.MFiles,
309 p.HFiles,
310 p.SFiles,
311 p.SysoFiles,
312 p.SwigFiles,
313 p.SwigCXXFiles,
314 )
315 for _, file := range inputFiles {
316 fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))
317 }
318 for _, a1 := range a.Deps {
319 p1 := a1.Package
320 if p1 != nil {
321 fmt.Fprintf(h, "import %s %s\n", p1.ImportPath, contentID(a1.buildID))
322 }
323 }
324
325 return h.Sum()
326 }
327
328
329
330 func (b *Builder) needCgoHdr(a *Action) bool {
331
332 if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") {
333 for _, t1 := range a.triggers {
334 if t1.Mode == "install header" {
335 return true
336 }
337 }
338 for _, t1 := range a.triggers {
339 for _, t2 := range t1.triggers {
340 if t2.Mode == "install header" {
341 return true
342 }
343 }
344 }
345 }
346 return false
347 }
348
349
350
351
352 func allowedVersion(v string) bool {
353
354 if v == "" {
355 return true
356 }
357
358 if v == "1.0" {
359 return true
360 }
361
362 for _, tag := range cfg.BuildContext.ReleaseTags {
363 if strings.HasPrefix(tag, "go") && tag[2:] == v {
364 return true
365 }
366 }
367 return false
368 }
369
370 const (
371 needBuild uint32 = 1 << iota
372 needCgoHdr
373 needVet
374 needCompiledGoFiles
375 needStale
376 )
377
378
379
380 func (b *Builder) build(a *Action) (err error) {
381 p := a.Package
382
383 bit := func(x uint32, b bool) uint32 {
384 if b {
385 return x
386 }
387 return 0
388 }
389
390 cachedBuild := false
391 need := bit(needBuild, !b.IsCmdList && a.needBuild || b.NeedExport) |
392 bit(needCgoHdr, b.needCgoHdr(a)) |
393 bit(needVet, a.needVet) |
394 bit(needCompiledGoFiles, b.NeedCompiledGoFiles)
395
396 if !p.BinaryOnly {
397 if b.useCache(a, p, b.buildActionID(a), p.Target) {
398
399
400
401
402
403 cachedBuild = true
404 a.output = []byte{}
405 need &^= needBuild
406 if b.NeedExport {
407 p.Export = a.built
408 }
409 if need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
410 need &^= needCompiledGoFiles
411 }
412 }
413
414
415
416 if !cachedBuild && need&needCompiledGoFiles != 0 && b.loadCachedSrcFiles(a) {
417 need &^= needCompiledGoFiles
418 }
419
420 if need == 0 {
421 return nil
422 }
423 defer b.flushOutput(a)
424 }
425
426 defer func() {
427 if err != nil && err != errPrintedOutput {
428 err = fmt.Errorf("go build %s: %v", a.Package.ImportPath, err)
429 }
430 if err != nil && b.IsCmdList && b.NeedError && p.Error == nil {
431 p.Error = &load.PackageError{Err: err.Error()}
432 }
433 }()
434 if cfg.BuildN {
435
436
437
438
439
440 b.Print("\n#\n# " + a.Package.ImportPath + "\n#\n\n")
441 }
442
443 if cfg.BuildV {
444 b.Print(a.Package.ImportPath + "\n")
445 }
446
447 if a.Package.BinaryOnly {
448 p.Stale = true
449 p.StaleReason = "binary-only packages are no longer supported"
450 if b.IsCmdList {
451 return nil
452 }
453 return errors.New("binary-only packages are no longer supported")
454 }
455
456 if err := b.Mkdir(a.Objdir); err != nil {
457 return err
458 }
459 objdir := a.Objdir
460
461
462 if cachedBuild && need&needCgoHdr != 0 && b.loadCachedCgoHdr(a) {
463 need &^= needCgoHdr
464 }
465
466
467
468
469
470 if need == needVet && b.loadCachedVet(a) {
471 need &^= needVet
472 }
473 if need == 0 {
474 return nil
475 }
476
477
478 dir, _ := filepath.Split(a.Target)
479 if dir != "" {
480 if err := b.Mkdir(dir); err != nil {
481 return err
482 }
483 }
484
485 gofiles := str.StringList(a.Package.GoFiles)
486 cgofiles := str.StringList(a.Package.CgoFiles)
487 cfiles := str.StringList(a.Package.CFiles)
488 sfiles := str.StringList(a.Package.SFiles)
489 cxxfiles := str.StringList(a.Package.CXXFiles)
490 var objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
491
492 if a.Package.UsesCgo() || a.Package.UsesSwig() {
493 if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil {
494 return
495 }
496 }
497
498
499
500
501 if a.Package.UsesSwig() {
502 outGo, outC, outCXX, err := b.swig(a, a.Package, objdir, pcCFLAGS)
503 if err != nil {
504 return err
505 }
506 cgofiles = append(cgofiles, outGo...)
507 cfiles = append(cfiles, outC...)
508 cxxfiles = append(cxxfiles, outCXX...)
509 }
510
511
512 if a.Package.Internal.CoverMode != "" {
513 for i, file := range str.StringList(gofiles, cgofiles) {
514 var sourceFile string
515 var coverFile string
516 var key string
517 if strings.HasSuffix(file, ".cgo1.go") {
518
519 base := filepath.Base(file)
520 sourceFile = file
521 coverFile = objdir + base
522 key = strings.TrimSuffix(base, ".cgo1.go") + ".go"
523 } else {
524 sourceFile = filepath.Join(a.Package.Dir, file)
525 coverFile = objdir + file
526 key = file
527 }
528 coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go"
529 cover := a.Package.Internal.CoverVars[key]
530 if cover == nil || base.IsTestFile(file) {
531
532 continue
533 }
534 if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil {
535 return err
536 }
537 if i < len(gofiles) {
538 gofiles[i] = coverFile
539 } else {
540 cgofiles[i-len(gofiles)] = coverFile
541 }
542 }
543 }
544
545
546 if a.Package.UsesCgo() || a.Package.UsesSwig() {
547
548
549
550
551 var gccfiles []string
552 gccfiles = append(gccfiles, cfiles...)
553 cfiles = nil
554 if a.Package.Standard && a.Package.ImportPath == "runtime/cgo" {
555 filter := func(files, nongcc, gcc []string) ([]string, []string) {
556 for _, f := range files {
557 if strings.HasPrefix(f, "gcc_") {
558 gcc = append(gcc, f)
559 } else {
560 nongcc = append(nongcc, f)
561 }
562 }
563 return nongcc, gcc
564 }
565 sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
566 } else {
567 for _, sfile := range sfiles {
568 data, err := ioutil.ReadFile(filepath.Join(a.Package.Dir, sfile))
569 if err == nil {
570 if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) ||
571 bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) ||
572 bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) {
573 return fmt.Errorf("package using cgo has Go assembly file %s", sfile)
574 }
575 }
576 }
577 gccfiles = append(gccfiles, sfiles...)
578 sfiles = nil
579 }
580
581 outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcLDFLAGS, mkAbsFiles(a.Package.Dir, cgofiles), gccfiles, cxxfiles, a.Package.MFiles, a.Package.FFiles)
582 if err != nil {
583 return err
584 }
585 if cfg.BuildToolchainName == "gccgo" {
586 cgoObjects = append(cgoObjects, a.Objdir+"_cgo_flags")
587 }
588 cgoObjects = append(cgoObjects, outObj...)
589 gofiles = append(gofiles, outGo...)
590
591 switch cfg.BuildBuildmode {
592 case "c-archive", "c-shared":
593 b.cacheCgoHdr(a)
594 }
595 }
596
597 var srcfiles []string
598 srcfiles = append(srcfiles, gofiles...)
599 srcfiles = append(srcfiles, sfiles...)
600 srcfiles = append(srcfiles, cfiles...)
601 srcfiles = append(srcfiles, cxxfiles...)
602 b.cacheSrcFiles(a, srcfiles)
603
604
605 need &^= needCgoHdr
606
607
608 if len(gofiles) == 0 {
609 return &load.NoGoError{Package: a.Package}
610 }
611
612
613 if need&needVet != 0 {
614 buildVetConfig(a, srcfiles)
615 need &^= needVet
616 }
617 if need&needCompiledGoFiles != 0 {
618 if !b.loadCachedSrcFiles(a) {
619 return fmt.Errorf("failed to cache compiled Go files")
620 }
621 need &^= needCompiledGoFiles
622 }
623 if need == 0 {
624
625 return nil
626 }
627
628
629 symabis, err := BuildToolchain.symabis(b, a, sfiles)
630 if err != nil {
631 return err
632 }
633
634
635
636
637
638
639
640 var icfg bytes.Buffer
641 fmt.Fprintf(&icfg, "# import config\n")
642 for i, raw := range a.Package.Internal.RawImports {
643 final := a.Package.Imports[i]
644 if final != raw {
645 fmt.Fprintf(&icfg, "importmap %s=%s\n", raw, final)
646 }
647 }
648 for _, a1 := range a.Deps {
649 p1 := a1.Package
650 if p1 == nil || p1.ImportPath == "" || a1.built == "" {
651 continue
652 }
653 fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
654 }
655
656 if p.Internal.BuildInfo != "" && cfg.ModulesEnabled {
657 if err := b.writeFile(objdir+"_gomod_.go", load.ModInfoProg(p.Internal.BuildInfo)); err != nil {
658 return err
659 }
660 gofiles = append(gofiles, objdir+"_gomod_.go")
661 }
662
663
664 objpkg := objdir + "_pkg_.a"
665 ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), symabis, len(sfiles) > 0, gofiles)
666 if len(out) > 0 {
667 output := b.processOutput(out)
668 if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
669 output += "note: module requires Go " + p.Module.GoVersion + "\n"
670 }
671 b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
672 if err != nil {
673 return errPrintedOutput
674 }
675 }
676 if err != nil {
677 if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
678 b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion)
679 }
680 return err
681 }
682 if ofile != objpkg {
683 objects = append(objects, ofile)
684 }
685
686
687
688
689 _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch
690 _goos := "_" + cfg.Goos
691 _goarch := "_" + cfg.Goarch
692 for _, file := range a.Package.HFiles {
693 name, ext := fileExtSplit(file)
694 switch {
695 case strings.HasSuffix(name, _goos_goarch):
696 targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
697 if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
698 return err
699 }
700 case strings.HasSuffix(name, _goarch):
701 targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
702 if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
703 return err
704 }
705 case strings.HasSuffix(name, _goos):
706 targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
707 if err := b.copyFile(objdir+targ, filepath.Join(a.Package.Dir, file), 0666, true); err != nil {
708 return err
709 }
710 }
711 }
712
713 for _, file := range cfiles {
714 out := file[:len(file)-len(".c")] + ".o"
715 if err := BuildToolchain.cc(b, a, objdir+out, file); err != nil {
716 return err
717 }
718 objects = append(objects, out)
719 }
720
721
722 if len(sfiles) > 0 {
723 ofiles, err := BuildToolchain.asm(b, a, sfiles)
724 if err != nil {
725 return err
726 }
727 objects = append(objects, ofiles...)
728 }
729
730
731
732
733 if a.buildID != "" && cfg.BuildToolchainName == "gccgo" {
734 switch cfg.Goos {
735 case "aix", "android", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris":
736 asmfile, err := b.gccgoBuildIDFile(a)
737 if err != nil {
738 return err
739 }
740 ofiles, err := BuildToolchain.asm(b, a, []string{asmfile})
741 if err != nil {
742 return err
743 }
744 objects = append(objects, ofiles...)
745 }
746 }
747
748
749
750
751
752 objects = append(objects, cgoObjects...)
753
754
755 for _, syso := range a.Package.SysoFiles {
756 objects = append(objects, filepath.Join(a.Package.Dir, syso))
757 }
758
759
760
761
762
763
764 if len(objects) > 0 {
765 if err := BuildToolchain.pack(b, a, objpkg, objects); err != nil {
766 return err
767 }
768 }
769
770 if err := b.updateBuildID(a, objpkg, true); err != nil {
771 return err
772 }
773
774 a.built = objpkg
775 return nil
776 }
777
778 func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error {
779 f, err := os.Open(a.Objdir + name)
780 if err != nil {
781 return err
782 }
783 defer f.Close()
784 _, _, err = c.Put(cache.Subkey(a.actionID, name), f)
785 return err
786 }
787
788 func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) {
789 file, _, err := c.GetFile(cache.Subkey(a.actionID, name))
790 if err != nil {
791 return "", err
792 }
793 return file, nil
794 }
795
796 func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error {
797 cached, err := b.findCachedObjdirFile(a, c, name)
798 if err != nil {
799 return err
800 }
801 return b.copyFile(a.Objdir+name, cached, 0666, true)
802 }
803
804 func (b *Builder) cacheCgoHdr(a *Action) {
805 c := cache.Default()
806 if c == nil {
807 return
808 }
809 b.cacheObjdirFile(a, c, "_cgo_install.h")
810 }
811
812 func (b *Builder) loadCachedCgoHdr(a *Action) bool {
813 c := cache.Default()
814 if c == nil {
815 return false
816 }
817 err := b.loadCachedObjdirFile(a, c, "_cgo_install.h")
818 return err == nil
819 }
820
821 func (b *Builder) cacheSrcFiles(a *Action, srcfiles []string) {
822 c := cache.Default()
823 if c == nil {
824 return
825 }
826 var buf bytes.Buffer
827 for _, file := range srcfiles {
828 if !strings.HasPrefix(file, a.Objdir) {
829
830 buf.WriteString("./")
831 buf.WriteString(file)
832 buf.WriteString("\n")
833 continue
834 }
835 name := file[len(a.Objdir):]
836 buf.WriteString(name)
837 buf.WriteString("\n")
838 if err := b.cacheObjdirFile(a, c, name); err != nil {
839 return
840 }
841 }
842 c.PutBytes(cache.Subkey(a.actionID, "srcfiles"), buf.Bytes())
843 }
844
845 func (b *Builder) loadCachedVet(a *Action) bool {
846 c := cache.Default()
847 if c == nil {
848 return false
849 }
850 list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles"))
851 if err != nil {
852 return false
853 }
854 var srcfiles []string
855 for _, name := range strings.Split(string(list), "\n") {
856 if name == "" {
857 continue
858 }
859 if strings.HasPrefix(name, "./") {
860 srcfiles = append(srcfiles, name[2:])
861 continue
862 }
863 if err := b.loadCachedObjdirFile(a, c, name); err != nil {
864 return false
865 }
866 srcfiles = append(srcfiles, a.Objdir+name)
867 }
868 buildVetConfig(a, srcfiles)
869 return true
870 }
871
872 func (b *Builder) loadCachedSrcFiles(a *Action) bool {
873 c := cache.Default()
874 if c == nil {
875 return false
876 }
877 list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles"))
878 if err != nil {
879 return false
880 }
881 var files []string
882 for _, name := range strings.Split(string(list), "\n") {
883 if name == "" {
884 continue
885 }
886 if strings.HasPrefix(name, "./") {
887 files = append(files, name[len("./"):])
888 continue
889 }
890 file, err := b.findCachedObjdirFile(a, c, name)
891 if err != nil {
892 return false
893 }
894 files = append(files, file)
895 }
896 a.Package.CompiledGoFiles = files
897 return true
898 }
899
900
901 type vetConfig struct {
902 ID string
903 Compiler string
904 Dir string
905 ImportPath string
906 GoFiles []string
907 NonGoFiles []string
908
909 ImportMap map[string]string
910 PackageFile map[string]string
911 Standard map[string]bool
912 PackageVetx map[string]string
913 VetxOnly bool
914 VetxOutput string
915
916 SucceedOnTypecheckFailure bool
917 }
918
919 func buildVetConfig(a *Action, srcfiles []string) {
920
921
922 var gofiles, nongofiles []string
923 for _, name := range srcfiles {
924 if strings.HasSuffix(name, ".go") {
925 gofiles = append(gofiles, name)
926 } else {
927 nongofiles = append(nongofiles, name)
928 }
929 }
930
931
932
933
934
935 vcfg := &vetConfig{
936 ID: a.Package.ImportPath,
937 Compiler: cfg.BuildToolchainName,
938 Dir: a.Package.Dir,
939 GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
940 NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles),
941 ImportPath: a.Package.ImportPath,
942 ImportMap: make(map[string]string),
943 PackageFile: make(map[string]string),
944 Standard: make(map[string]bool),
945 }
946 a.vetCfg = vcfg
947 for i, raw := range a.Package.Internal.RawImports {
948 final := a.Package.Imports[i]
949 vcfg.ImportMap[raw] = final
950 }
951
952
953
954 vcfgMapped := make(map[string]bool)
955 for _, p := range vcfg.ImportMap {
956 vcfgMapped[p] = true
957 }
958
959 for _, a1 := range a.Deps {
960 p1 := a1.Package
961 if p1 == nil || p1.ImportPath == "" {
962 continue
963 }
964
965
966 if !vcfgMapped[p1.ImportPath] {
967 vcfg.ImportMap[p1.ImportPath] = p1.ImportPath
968 }
969 if a1.built != "" {
970 vcfg.PackageFile[p1.ImportPath] = a1.built
971 }
972 if p1.Standard {
973 vcfg.Standard[p1.ImportPath] = true
974 }
975 }
976 }
977
978
979
980 var VetTool string
981
982
983
984 var VetFlags []string
985
986
987 var VetExplicit bool
988
989 func (b *Builder) vet(a *Action) error {
990
991
992
993 a.Failed = false
994
995 if a.Deps[0].Failed {
996
997
998
999 return nil
1000 }
1001
1002 vcfg := a.Deps[0].vetCfg
1003 if vcfg == nil {
1004
1005 return fmt.Errorf("vet config not found")
1006 }
1007
1008 vcfg.VetxOnly = a.VetxOnly
1009 vcfg.VetxOutput = a.Objdir + "vet.out"
1010 vcfg.PackageVetx = make(map[string]string)
1011
1012 h := cache.NewHash("vet " + a.Package.ImportPath)
1013 fmt.Fprintf(h, "vet %q\n", b.toolID("vet"))
1014
1015 vetFlags := VetFlags
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033 if a.Package.Goroot && !VetExplicit && VetTool == "" {
1034
1035
1036
1037
1038
1039
1040
1041
1042 vetFlags = []string{"-unsafeptr=false"}
1043 }
1044
1045
1046
1047
1048
1049
1050 fmt.Fprintf(h, "vetflags %q\n", vetFlags)
1051
1052 fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID)
1053 for _, a1 := range a.Deps {
1054 if a1.Mode == "vet" && a1.built != "" {
1055 fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built))
1056 vcfg.PackageVetx[a1.Package.ImportPath] = a1.built
1057 }
1058 }
1059 key := cache.ActionID(h.Sum())
1060
1061 if vcfg.VetxOnly {
1062 if c := cache.Default(); c != nil && !cfg.BuildA {
1063 if file, _, err := c.GetFile(key); err == nil {
1064 a.built = file
1065 return nil
1066 }
1067 }
1068 }
1069
1070 js, err := json.MarshalIndent(vcfg, "", "\t")
1071 if err != nil {
1072 return fmt.Errorf("internal error marshaling vet config: %v", err)
1073 }
1074 js = append(js, '\n')
1075 if err := b.writeFile(a.Objdir+"vet.cfg", js); err != nil {
1076 return err
1077 }
1078
1079 env := b.cCompilerEnv()
1080 if cfg.BuildToolchainName == "gccgo" {
1081 env = append(env, "GCCGO="+BuildToolchain.compiler())
1082 }
1083
1084 p := a.Package
1085 tool := VetTool
1086 if tool == "" {
1087 tool = base.Tool("vet")
1088 }
1089 runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, vetFlags, a.Objdir+"vet.cfg")
1090
1091
1092 if f, err := os.Open(vcfg.VetxOutput); err == nil {
1093 a.built = vcfg.VetxOutput
1094 if c := cache.Default(); c != nil {
1095 c.Put(key, f)
1096 }
1097 f.Close()
1098 }
1099
1100 return runErr
1101 }
1102
1103
1104 func (b *Builder) linkActionID(a *Action) cache.ActionID {
1105 p := a.Package
1106 h := cache.NewHash("link " + p.ImportPath)
1107
1108
1109 fmt.Fprintf(h, "link\n")
1110 fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch)
1111 fmt.Fprintf(h, "import %q\n", p.ImportPath)
1112 fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
1113 if cfg.BuildTrimpath {
1114 fmt.Fprintln(h, "trimpath")
1115 }
1116
1117
1118 b.printLinkerConfig(h, p)
1119
1120
1121 for _, a1 := range a.Deps {
1122 p1 := a1.Package
1123 if p1 != nil {
1124 if a1.built != "" || a1.buildID != "" {
1125 buildID := a1.buildID
1126 if buildID == "" {
1127 buildID = b.buildID(a1.built)
1128 }
1129 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(buildID))
1130 }
1131
1132
1133 if p1.Name == "main" {
1134 fmt.Fprintf(h, "packagemain %s\n", a1.buildID)
1135 }
1136 if p1.Shlib != "" {
1137 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib)))
1138 }
1139 }
1140 }
1141
1142 return h.Sum()
1143 }
1144
1145
1146
1147 func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
1148 switch cfg.BuildToolchainName {
1149 default:
1150 base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName)
1151
1152 case "gc":
1153 fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode)
1154 if p != nil {
1155 fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags)
1156 }
1157
1158
1159 key, val := cfg.GetArchEnv()
1160 fmt.Fprintf(h, "%s=%s\n", key, val)
1161
1162
1163 fmt.Fprintf(h, "GOROOT=%s\n", cfg.GOROOT_FINAL)
1164
1165
1166 fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED"))
1167
1168
1169
1170
1171 case "gccgo":
1172 id, err := b.gccgoToolID(BuildToolchain.linker(), "go")
1173 if err != nil {
1174 base.Fatalf("%v", err)
1175 }
1176 fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode)
1177
1178 }
1179 }
1180
1181
1182
1183 func (b *Builder) link(a *Action) (err error) {
1184 if b.useCache(a, a.Package, b.linkActionID(a), a.Package.Target) || b.IsCmdList {
1185 return nil
1186 }
1187 defer b.flushOutput(a)
1188
1189 if err := b.Mkdir(a.Objdir); err != nil {
1190 return err
1191 }
1192
1193 importcfg := a.Objdir + "importcfg.link"
1194 if err := b.writeLinkImportcfg(a, importcfg); err != nil {
1195 return err
1196 }
1197
1198
1199 dir, _ := filepath.Split(a.Target)
1200 if dir != "" {
1201 if err := b.Mkdir(dir); err != nil {
1202 return err
1203 }
1204 }
1205
1206 if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil {
1207 return err
1208 }
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 if err := b.updateBuildID(a, a.Target, !a.Package.Internal.OmitDebug); err != nil {
1227 return err
1228 }
1229
1230 a.built = a.Target
1231 return nil
1232 }
1233
1234 func (b *Builder) writeLinkImportcfg(a *Action, file string) error {
1235
1236 var icfg bytes.Buffer
1237 for _, a1 := range a.Deps {
1238 p1 := a1.Package
1239 if p1 == nil {
1240 continue
1241 }
1242 fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
1243 if p1.Shlib != "" {
1244 fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib)
1245 }
1246 }
1247 return b.writeFile(file, icfg.Bytes())
1248 }
1249
1250
1251
1252 func (b *Builder) PkgconfigCmd() string {
1253 return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0]
1254 }
1255
1256
1257
1258 func splitPkgConfigOutput(out []byte) ([]string, error) {
1259 if len(out) == 0 {
1260 return nil, nil
1261 }
1262 var flags []string
1263 flag := make([]byte, 0, len(out))
1264 escaped := false
1265 quote := byte(0)
1266
1267 for _, c := range out {
1268 if escaped {
1269 if quote != 0 {
1270 switch c {
1271 case '$', '`', '"', '\\':
1272 default:
1273 flag = append(flag, '\\')
1274 }
1275 flag = append(flag, c)
1276 } else {
1277 flag = append(flag, c)
1278 }
1279 escaped = false
1280 } else if quote != 0 {
1281 if c == quote {
1282 quote = 0
1283 } else {
1284 switch c {
1285 case '\\':
1286 escaped = true
1287 default:
1288 flag = append(flag, c)
1289 }
1290 }
1291 } else if strings.IndexByte(" \t\n\v\f\r", c) < 0 {
1292 switch c {
1293 case '\\':
1294 escaped = true
1295 case '\'', '"':
1296 quote = c
1297 default:
1298 flag = append(flag, c)
1299 }
1300 } else if len(flag) != 0 {
1301 flags = append(flags, string(flag))
1302 flag = flag[:0]
1303 }
1304 }
1305 if escaped {
1306 return nil, errors.New("broken character escaping in pkgconf output ")
1307 }
1308 if quote != 0 {
1309 return nil, errors.New("unterminated quoted string in pkgconf output ")
1310 } else if len(flag) != 0 {
1311 flags = append(flags, string(flag))
1312 }
1313
1314 return flags, nil
1315 }
1316
1317
1318 func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) {
1319 if pcargs := p.CgoPkgConfig; len(pcargs) > 0 {
1320
1321
1322 var pcflags []string
1323 var pkgs []string
1324 for _, pcarg := range pcargs {
1325 if pcarg == "--" {
1326
1327 } else if strings.HasPrefix(pcarg, "--") {
1328 pcflags = append(pcflags, pcarg)
1329 } else {
1330 pkgs = append(pkgs, pcarg)
1331 }
1332 }
1333 for _, pkg := range pkgs {
1334 if !load.SafeArg(pkg) {
1335 return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
1336 }
1337 }
1338 var out []byte
1339 out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
1340 if err != nil {
1341 b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1342 b.Print(err.Error() + "\n")
1343 return nil, nil, errPrintedOutput
1344 }
1345 if len(out) > 0 {
1346 cflags, err = splitPkgConfigOutput(out)
1347 if err != nil {
1348 return nil, nil, err
1349 }
1350 if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
1351 return nil, nil, err
1352 }
1353 }
1354 out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
1355 if err != nil {
1356 b.showOutput(nil, p.Dir, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out))
1357 b.Print(err.Error() + "\n")
1358 return nil, nil, errPrintedOutput
1359 }
1360 if len(out) > 0 {
1361 ldflags = strings.Fields(string(out))
1362 if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
1363 return nil, nil, err
1364 }
1365 }
1366 }
1367
1368 return
1369 }
1370
1371 func (b *Builder) installShlibname(a *Action) error {
1372
1373 a1 := a.Deps[0]
1374 err := ioutil.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666)
1375 if err != nil {
1376 return err
1377 }
1378 if cfg.BuildX {
1379 b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target)
1380 }
1381 return nil
1382 }
1383
1384 func (b *Builder) linkSharedActionID(a *Action) cache.ActionID {
1385 h := cache.NewHash("linkShared")
1386
1387
1388 fmt.Fprintf(h, "linkShared\n")
1389 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
1390
1391
1392 b.printLinkerConfig(h, nil)
1393
1394
1395 for _, a1 := range a.Deps {
1396 p1 := a1.Package
1397 if a1.built == "" {
1398 continue
1399 }
1400 if p1 != nil {
1401 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built)))
1402 if p1.Shlib != "" {
1403 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib)))
1404 }
1405 }
1406 }
1407
1408 for _, a1 := range a.Deps[0].Deps {
1409 p1 := a1.Package
1410 fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built)))
1411 }
1412
1413 return h.Sum()
1414 }
1415
1416 func (b *Builder) linkShared(a *Action) (err error) {
1417 if b.useCache(a, nil, b.linkSharedActionID(a), a.Target) || b.IsCmdList {
1418 return nil
1419 }
1420 defer b.flushOutput(a)
1421
1422 if err := b.Mkdir(a.Objdir); err != nil {
1423 return err
1424 }
1425
1426 importcfg := a.Objdir + "importcfg.link"
1427 if err := b.writeLinkImportcfg(a, importcfg); err != nil {
1428 return err
1429 }
1430
1431
1432
1433 a.built = a.Target
1434 return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps)
1435 }
1436
1437
1438 func BuildInstallFunc(b *Builder, a *Action) (err error) {
1439 defer func() {
1440 if err != nil && err != errPrintedOutput {
1441
1442
1443
1444 sep, path := "", ""
1445 if a.Package != nil {
1446 sep, path = " ", a.Package.ImportPath
1447 }
1448 err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err)
1449 }
1450 }()
1451
1452 a1 := a.Deps[0]
1453 a.buildID = a1.buildID
1454 if a.json != nil {
1455 a.json.BuildID = a.buildID
1456 }
1457
1458
1459
1460
1461
1462
1463 if a1.built == a.Target {
1464 a.built = a.Target
1465 if !a.buggyInstall {
1466 b.cleanup(a1)
1467 }
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486 if !a.buggyInstall && !b.IsCmdList {
1487 now := time.Now()
1488 os.Chtimes(a.Target, now, now)
1489 }
1490 return nil
1491 }
1492
1493
1494
1495 if b.IsCmdList {
1496 a.built = a1.built
1497 return nil
1498 }
1499
1500 if err := b.Mkdir(a.Objdir); err != nil {
1501 return err
1502 }
1503
1504 perm := os.FileMode(0666)
1505 if a1.Mode == "link" {
1506 switch cfg.BuildBuildmode {
1507 case "c-archive", "c-shared", "plugin":
1508 default:
1509 perm = 0777
1510 }
1511 }
1512
1513
1514 dir, _ := filepath.Split(a.Target)
1515 if dir != "" {
1516 if err := b.Mkdir(dir); err != nil {
1517 return err
1518 }
1519 }
1520
1521 if !a.buggyInstall {
1522 defer b.cleanup(a1)
1523 }
1524
1525 return b.moveOrCopyFile(a.Target, a1.built, perm, false)
1526 }
1527
1528
1529
1530
1531
1532 func (b *Builder) cleanup(a *Action) {
1533 if !cfg.BuildWork {
1534 if cfg.BuildX {
1535
1536
1537 if _, err := os.Stat(a.Objdir); err == nil || cfg.BuildN {
1538 b.Showcmd("", "rm -r %s", a.Objdir)
1539 }
1540 }
1541 os.RemoveAll(a.Objdir)
1542 }
1543 }
1544
1545
1546 func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) error {
1547 if cfg.BuildN {
1548 b.Showcmd("", "mv %s %s", src, dst)
1549 return nil
1550 }
1551
1552
1553
1554
1555
1556 if strings.HasPrefix(src, cache.DefaultDir()) {
1557 return b.copyFile(dst, src, perm, force)
1558 }
1559
1560
1561
1562
1563
1564 if runtime.GOOS == "windows" {
1565 return b.copyFile(dst, src, perm, force)
1566 }
1567
1568
1569
1570
1571 if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
1572 if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 {
1573 return b.copyFile(dst, src, perm, force)
1574 }
1575 }
1576
1577
1578
1579
1580
1581
1582 mode := perm
1583 f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
1584 if err == nil {
1585 fi, err := f.Stat()
1586 if err == nil {
1587 mode = fi.Mode() & 0777
1588 }
1589 name := f.Name()
1590 f.Close()
1591 os.Remove(name)
1592 }
1593
1594 if err := os.Chmod(src, mode); err == nil {
1595 if err := os.Rename(src, dst); err == nil {
1596 if cfg.BuildX {
1597 b.Showcmd("", "mv %s %s", src, dst)
1598 }
1599 return nil
1600 }
1601 }
1602
1603 return b.copyFile(dst, src, perm, force)
1604 }
1605
1606
1607 func (b *Builder) copyFile(dst, src string, perm os.FileMode, force bool) error {
1608 if cfg.BuildN || cfg.BuildX {
1609 b.Showcmd("", "cp %s %s", src, dst)
1610 if cfg.BuildN {
1611 return nil
1612 }
1613 }
1614
1615 sf, err := os.Open(src)
1616 if err != nil {
1617 return err
1618 }
1619 defer sf.Close()
1620
1621
1622
1623
1624 if fi, err := os.Stat(dst); err == nil {
1625 if fi.IsDir() {
1626 return fmt.Errorf("build output %q already exists and is a directory", dst)
1627 }
1628 if !force && fi.Mode().IsRegular() && !isObject(dst) {
1629 return fmt.Errorf("build output %q already exists and is not an object file", dst)
1630 }
1631 }
1632
1633
1634 if base.ToolIsWindows {
1635 if _, err := os.Stat(dst + "~"); err == nil {
1636 os.Remove(dst + "~")
1637 }
1638 }
1639
1640 mayberemovefile(dst)
1641 df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
1642 if err != nil && base.ToolIsWindows {
1643
1644
1645
1646
1647 if err := os.Rename(dst, dst+"~"); err == nil {
1648 os.Remove(dst + "~")
1649 }
1650 df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
1651 }
1652 if err != nil {
1653 return err
1654 }
1655
1656 _, err = io.Copy(df, sf)
1657 df.Close()
1658 if err != nil {
1659 mayberemovefile(dst)
1660 return fmt.Errorf("copying %s to %s: %v", src, dst, err)
1661 }
1662 return nil
1663 }
1664
1665
1666 func (b *Builder) writeFile(file string, text []byte) error {
1667 if cfg.BuildN || cfg.BuildX {
1668 b.Showcmd("", "cat >%s << 'EOF' # internal\n%sEOF", file, text)
1669 }
1670 if cfg.BuildN {
1671 return nil
1672 }
1673 return ioutil.WriteFile(file, text, 0666)
1674 }
1675
1676
1677 func (b *Builder) installHeader(a *Action) error {
1678 src := a.Objdir + "_cgo_install.h"
1679 if _, err := os.Stat(src); os.IsNotExist(err) {
1680
1681
1682
1683
1684
1685 if cfg.BuildX {
1686 b.Showcmd("", "# %s not created", src)
1687 }
1688 return nil
1689 }
1690
1691 dir, _ := filepath.Split(a.Target)
1692 if dir != "" {
1693 if err := b.Mkdir(dir); err != nil {
1694 return err
1695 }
1696 }
1697
1698 return b.moveOrCopyFile(a.Target, src, 0666, true)
1699 }
1700
1701
1702
1703 func (b *Builder) cover(a *Action, dst, src string, varName string) error {
1704 return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil,
1705 cfg.BuildToolexec,
1706 base.Tool("cover"),
1707 "-mode", a.Package.Internal.CoverMode,
1708 "-var", varName,
1709 "-o", dst,
1710 src)
1711 }
1712
1713 var objectMagic = [][]byte{
1714 {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'},
1715 {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'},
1716 {'\x7F', 'E', 'L', 'F'},
1717 {0xFE, 0xED, 0xFA, 0xCE},
1718 {0xFE, 0xED, 0xFA, 0xCF},
1719 {0xCE, 0xFA, 0xED, 0xFE},
1720 {0xCF, 0xFA, 0xED, 0xFE},
1721 {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},
1722 {0x00, 0x00, 0x01, 0xEB},
1723 {0x00, 0x00, 0x8a, 0x97},
1724 {0x00, 0x00, 0x06, 0x47},
1725 {0x00, 0x61, 0x73, 0x6D},
1726 {0x01, 0xDF},
1727 {0x01, 0xF7},
1728 }
1729
1730 func isObject(s string) bool {
1731 f, err := os.Open(s)
1732 if err != nil {
1733 return false
1734 }
1735 defer f.Close()
1736 buf := make([]byte, 64)
1737 io.ReadFull(f, buf)
1738 for _, magic := range objectMagic {
1739 if bytes.HasPrefix(buf, magic) {
1740 return true
1741 }
1742 }
1743 return false
1744 }
1745
1746
1747
1748
1749 func mayberemovefile(s string) {
1750 if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
1751 return
1752 }
1753 os.Remove(s)
1754 }
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768 func (b *Builder) fmtcmd(dir string, format string, args ...interface{}) string {
1769 cmd := fmt.Sprintf(format, args...)
1770 if dir != "" && dir != "/" {
1771 dot := " ."
1772 if dir[len(dir)-1] == filepath.Separator {
1773 dot += string(filepath.Separator)
1774 }
1775 cmd = strings.ReplaceAll(" "+cmd, " "+dir, dot)[1:]
1776 if b.scriptDir != dir {
1777 b.scriptDir = dir
1778 cmd = "cd " + dir + "\n" + cmd
1779 }
1780 }
1781 if b.WorkDir != "" {
1782 cmd = strings.ReplaceAll(cmd, b.WorkDir, "$WORK")
1783 }
1784 return cmd
1785 }
1786
1787
1788
1789 func (b *Builder) Showcmd(dir string, format string, args ...interface{}) {
1790 b.output.Lock()
1791 defer b.output.Unlock()
1792 b.Print(b.fmtcmd(dir, format, args...) + "\n")
1793 }
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820 func (b *Builder) showOutput(a *Action, dir, desc, out string) {
1821 prefix := "# " + desc
1822 suffix := "\n" + out
1823 if reldir := base.ShortPath(dir); reldir != dir {
1824 suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir)
1825 suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir)
1826 }
1827 suffix = strings.ReplaceAll(suffix, " "+b.WorkDir, " $WORK")
1828
1829 if a != nil && a.output != nil {
1830 a.output = append(a.output, prefix...)
1831 a.output = append(a.output, suffix...)
1832 return
1833 }
1834
1835 b.output.Lock()
1836 defer b.output.Unlock()
1837 b.Print(prefix, suffix)
1838 }
1839
1840
1841
1842
1843
1844
1845 var errPrintedOutput = errors.New("already printed output - no need to show error")
1846
1847 var cgoLine = lazyregexp.New(`\[[^\[\]]+\.(cgo1|cover)\.go:[0-9]+(:[0-9]+)?\]`)
1848 var cgoTypeSigRe = lazyregexp.New(`\b_C2?(type|func|var|macro)_\B`)
1849
1850
1851
1852
1853 func (b *Builder) run(a *Action, dir string, desc string, env []string, cmdargs ...interface{}) error {
1854 out, err := b.runOut(a, dir, env, cmdargs...)
1855 if len(out) > 0 {
1856 if desc == "" {
1857 desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " "))
1858 }
1859 b.showOutput(a, dir, desc, b.processOutput(out))
1860 if err != nil {
1861 err = errPrintedOutput
1862 }
1863 }
1864 return err
1865 }
1866
1867
1868 func (b *Builder) processOutput(out []byte) string {
1869 if out[len(out)-1] != '\n' {
1870 out = append(out, '\n')
1871 }
1872 messages := string(out)
1873
1874
1875
1876
1877 if !cfg.BuildX && cgoLine.MatchString(messages) {
1878 messages = cgoLine.ReplaceAllString(messages, "")
1879 messages = cgoTypeSigRe.ReplaceAllString(messages, "C.")
1880 }
1881 return messages
1882 }
1883
1884
1885
1886
1887 func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...interface{}) ([]byte, error) {
1888 cmdline := str.StringList(cmdargs...)
1889
1890 for _, arg := range cmdline {
1891
1892
1893
1894
1895 if strings.HasPrefix(arg, "@") {
1896 return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline))
1897 }
1898 }
1899
1900 if cfg.BuildN || cfg.BuildX {
1901 var envcmdline string
1902 for _, e := range env {
1903 if j := strings.IndexByte(e, '='); j != -1 {
1904 if strings.ContainsRune(e[j+1:], '\'') {
1905 envcmdline += fmt.Sprintf("%s=%q", e[:j], e[j+1:])
1906 } else {
1907 envcmdline += fmt.Sprintf("%s='%s'", e[:j], e[j+1:])
1908 }
1909 envcmdline += " "
1910 }
1911 }
1912 envcmdline += joinUnambiguously(cmdline)
1913 b.Showcmd(dir, "%s", envcmdline)
1914 if cfg.BuildN {
1915 return nil, nil
1916 }
1917 }
1918
1919 var buf bytes.Buffer
1920 cmd := exec.Command(cmdline[0], cmdline[1:]...)
1921 cmd.Stdout = &buf
1922 cmd.Stderr = &buf
1923 cleanup := passLongArgsInResponseFiles(cmd)
1924 defer cleanup()
1925 cmd.Dir = dir
1926 cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
1927 cmd.Env = append(cmd.Env, env...)
1928 start := time.Now()
1929 err := cmd.Run()
1930 if a != nil && a.json != nil {
1931 aj := a.json
1932 aj.Cmd = append(aj.Cmd, joinUnambiguously(cmdline))
1933 aj.CmdReal += time.Since(start)
1934 if ps := cmd.ProcessState; ps != nil {
1935 aj.CmdUser += ps.UserTime()
1936 aj.CmdSys += ps.SystemTime()
1937 }
1938 }
1939
1940
1941
1942
1943
1944
1945 if err != nil {
1946 err = errors.New(cmdline[0] + ": " + err.Error())
1947 }
1948 return buf.Bytes(), err
1949 }
1950
1951
1952
1953
1954 func joinUnambiguously(a []string) string {
1955 var buf bytes.Buffer
1956 for i, s := range a {
1957 if i > 0 {
1958 buf.WriteByte(' ')
1959 }
1960 q := strconv.Quote(s)
1961
1962
1963
1964 if s == "" || strings.ContainsAny(s, " ()>;") || len(q) > len(s)+2 {
1965 buf.WriteString(q)
1966 } else {
1967 buf.WriteString(s)
1968 }
1969 }
1970 return buf.String()
1971 }
1972
1973
1974
1975
1976 func (b *Builder) cCompilerEnv() []string {
1977 return []string{"TERM=dumb"}
1978 }
1979
1980
1981 func (b *Builder) Mkdir(dir string) error {
1982
1983 if dir == "" {
1984 return nil
1985 }
1986
1987 b.exec.Lock()
1988 defer b.exec.Unlock()
1989
1990
1991 if b.mkdirCache[dir] {
1992 return nil
1993 }
1994 b.mkdirCache[dir] = true
1995
1996 if cfg.BuildN || cfg.BuildX {
1997 b.Showcmd("", "mkdir -p %s", dir)
1998 if cfg.BuildN {
1999 return nil
2000 }
2001 }
2002
2003 if err := os.MkdirAll(dir, 0777); err != nil {
2004 return err
2005 }
2006 return nil
2007 }
2008
2009
2010 func (b *Builder) Symlink(oldname, newname string) error {
2011
2012 if link, err := os.Readlink(newname); err == nil && link == oldname {
2013 return nil
2014 }
2015
2016 if cfg.BuildN || cfg.BuildX {
2017 b.Showcmd("", "ln -s %s %s", oldname, newname)
2018 if cfg.BuildN {
2019 return nil
2020 }
2021 }
2022 return os.Symlink(oldname, newname)
2023 }
2024
2025
2026
2027
2028
2029
2030 func mkAbs(dir, f string) string {
2031
2032
2033
2034
2035 if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
2036 return f
2037 }
2038 return filepath.Join(dir, f)
2039 }
2040
2041 type toolchain interface {
2042
2043
2044
2045
2046 gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error)
2047
2048
2049 cc(b *Builder, a *Action, ofile, cfile string) error
2050
2051
2052 asm(b *Builder, a *Action, sfiles []string) ([]string, error)
2053
2054
2055 symabis(b *Builder, a *Action, sfiles []string) (string, error)
2056
2057
2058
2059 pack(b *Builder, a *Action, afile string, ofiles []string) error
2060
2061 ld(b *Builder, root *Action, out, importcfg, mainpkg string) error
2062
2063 ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error
2064
2065 compiler() string
2066 linker() string
2067 }
2068
2069 type noToolchain struct{}
2070
2071 func noCompiler() error {
2072 log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler)
2073 return nil
2074 }
2075
2076 func (noToolchain) compiler() string {
2077 noCompiler()
2078 return ""
2079 }
2080
2081 func (noToolchain) linker() string {
2082 noCompiler()
2083 return ""
2084 }
2085
2086 func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) {
2087 return "", nil, noCompiler()
2088 }
2089
2090 func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
2091 return nil, noCompiler()
2092 }
2093
2094 func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
2095 return "", noCompiler()
2096 }
2097
2098 func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
2099 return noCompiler()
2100 }
2101
2102 func (noToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error {
2103 return noCompiler()
2104 }
2105
2106 func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
2107 return noCompiler()
2108 }
2109
2110 func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
2111 return noCompiler()
2112 }
2113
2114
2115 func (b *Builder) gcc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error {
2116 return b.ccompile(a, p, out, flags, cfile, b.GccCmd(p.Dir, workdir))
2117 }
2118
2119
2120 func (b *Builder) gxx(a *Action, p *load.Package, workdir, out string, flags []string, cxxfile string) error {
2121 return b.ccompile(a, p, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
2122 }
2123
2124
2125 func (b *Builder) gfortran(a *Action, p *load.Package, workdir, out string, flags []string, ffile string) error {
2126 return b.ccompile(a, p, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
2127 }
2128
2129
2130 func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error {
2131 file = mkAbs(p.Dir, file)
2132 desc := p.ImportPath
2133 if !filepath.IsAbs(outfile) {
2134 outfile = filepath.Join(p.Dir, outfile)
2135 }
2136 output, err := b.runOut(a, filepath.Dir(file), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(file))
2137 if len(output) > 0 {
2138
2139
2140
2141
2142
2143
2144
2145
2146 if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
2147 newFlags := make([]string, 0, len(flags))
2148 for _, f := range flags {
2149 if !strings.HasPrefix(f, "-g") {
2150 newFlags = append(newFlags, f)
2151 }
2152 }
2153 if len(newFlags) < len(flags) {
2154 return b.ccompile(a, p, outfile, newFlags, file, compiler)
2155 }
2156 }
2157
2158 b.showOutput(a, p.Dir, desc, b.processOutput(output))
2159 if err != nil {
2160 err = errPrintedOutput
2161 } else if os.Getenv("GO_BUILDER_NAME") != "" {
2162 return errors.New("C compiler warning promoted to error on Go builders")
2163 }
2164 }
2165 return err
2166 }
2167
2168
2169 func (b *Builder) gccld(a *Action, p *load.Package, objdir, outfile string, flags []string, objs []string) error {
2170 var cmd []string
2171 if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
2172 cmd = b.GxxCmd(p.Dir, objdir)
2173 } else {
2174 cmd = b.GccCmd(p.Dir, objdir)
2175 }
2176
2177 cmdargs := []interface{}{cmd, "-o", outfile, objs, flags}
2178 dir := p.Dir
2179 out, err := b.runOut(a, dir, b.cCompilerEnv(), cmdargs...)
2180 if len(out) > 0 {
2181
2182
2183 var save [][]byte
2184 var skipLines int
2185 for _, line := range bytes.SplitAfter(out, []byte("\n")) {
2186
2187 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) {
2188 continue
2189 }
2190
2191 if skipLines > 0 {
2192 skipLines--
2193 continue
2194 }
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205 if p.ImportPath == "runtime/cgo" && bytes.Contains(line, []byte("ld: 0711-224 WARNING: Duplicate symbol: .main")) {
2206 skipLines = 1
2207 continue
2208 }
2209
2210 save = append(save, line)
2211 }
2212 out = bytes.Join(save, nil)
2213 if len(out) > 0 {
2214 b.showOutput(nil, dir, p.ImportPath, b.processOutput(out))
2215 if err != nil {
2216 err = errPrintedOutput
2217 }
2218 }
2219 }
2220 return err
2221 }
2222
2223
2224 var (
2225 origCC = cfg.Getenv("CC")
2226 origCXX = cfg.Getenv("CXX")
2227 )
2228
2229
2230
2231 func (b *Builder) GccCmd(incdir, workdir string) []string {
2232 return b.compilerCmd(b.ccExe(), incdir, workdir)
2233 }
2234
2235
2236
2237 func (b *Builder) GxxCmd(incdir, workdir string) []string {
2238 return b.compilerCmd(b.cxxExe(), incdir, workdir)
2239 }
2240
2241
2242 func (b *Builder) gfortranCmd(incdir, workdir string) []string {
2243 return b.compilerCmd(b.fcExe(), incdir, workdir)
2244 }
2245
2246
2247 func (b *Builder) ccExe() []string {
2248 return b.compilerExe(origCC, cfg.DefaultCC(cfg.Goos, cfg.Goarch))
2249 }
2250
2251
2252 func (b *Builder) cxxExe() []string {
2253 return b.compilerExe(origCXX, cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
2254 }
2255
2256
2257 func (b *Builder) fcExe() []string {
2258 return b.compilerExe(cfg.Getenv("FC"), "gfortran")
2259 }
2260
2261
2262
2263
2264
2265
2266
2267 func (b *Builder) compilerExe(envValue string, def string) []string {
2268 compiler := strings.Fields(envValue)
2269 if len(compiler) == 0 {
2270 compiler = []string{def}
2271 }
2272 return compiler
2273 }
2274
2275
2276
2277 func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string {
2278
2279
2280 a := []string{compiler[0], "-I", incdir}
2281 a = append(a, compiler[1:]...)
2282
2283
2284
2285 if cfg.Goos != "windows" {
2286 a = append(a, "-fPIC")
2287 }
2288 a = append(a, b.gccArchArgs()...)
2289
2290
2291 if cfg.BuildContext.CgoEnabled {
2292 switch cfg.Goos {
2293 case "windows":
2294 a = append(a, "-mthreads")
2295 default:
2296 a = append(a, "-pthread")
2297 }
2298 }
2299
2300 if cfg.Goos == "aix" {
2301
2302 a = append(a, "-mcmodel=large")
2303 }
2304
2305
2306 if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") {
2307 a = append(a, "-fno-caret-diagnostics")
2308 }
2309
2310 if b.gccSupportsFlag(compiler, "-Qunused-arguments") {
2311 a = append(a, "-Qunused-arguments")
2312 }
2313
2314
2315 a = append(a, "-fmessage-length=0")
2316
2317
2318 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
2319 if workdir == "" {
2320 workdir = b.WorkDir
2321 }
2322 workdir = strings.TrimSuffix(workdir, string(filepath.Separator))
2323 a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build")
2324 }
2325
2326
2327
2328 if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") {
2329 a = append(a, "-gno-record-gcc-switches")
2330 }
2331
2332
2333
2334
2335 if cfg.Goos == "darwin" {
2336 a = append(a, "-fno-common")
2337 }
2338
2339 return a
2340 }
2341
2342
2343
2344
2345
2346 func (b *Builder) gccNoPie(linker []string) string {
2347 if b.gccSupportsFlag(linker, "-no-pie") {
2348 return "-no-pie"
2349 }
2350 if b.gccSupportsFlag(linker, "-nopie") {
2351 return "-nopie"
2352 }
2353 return ""
2354 }
2355
2356
2357 func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
2358 key := [2]string{compiler[0], flag}
2359
2360 b.exec.Lock()
2361 defer b.exec.Unlock()
2362 if b, ok := b.flagCache[key]; ok {
2363 return b
2364 }
2365 if b.flagCache == nil {
2366 b.flagCache = make(map[[2]string]bool)
2367 }
2368
2369
2370
2371
2372
2373
2374 cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", os.DevNull)
2375 if cfg.BuildN || cfg.BuildX {
2376 b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
2377 if cfg.BuildN {
2378 return false
2379 }
2380 }
2381 cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
2382 cmd.Dir = b.WorkDir
2383 cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
2384 cmd.Env = append(cmd.Env, "LC_ALL=C")
2385 out, _ := cmd.CombinedOutput()
2386
2387
2388
2389
2390 supported := !bytes.Contains(out, []byte("unrecognized")) &&
2391 !bytes.Contains(out, []byte("unknown")) &&
2392 !bytes.Contains(out, []byte("unrecognised")) &&
2393 !bytes.Contains(out, []byte("is not supported"))
2394 b.flagCache[key] = supported
2395 return supported
2396 }
2397
2398
2399 func (b *Builder) gccArchArgs() []string {
2400 switch cfg.Goarch {
2401 case "386":
2402 return []string{"-m32"}
2403 case "amd64", "amd64p32":
2404 return []string{"-m64"}
2405 case "arm":
2406 return []string{"-marm"}
2407 case "s390x":
2408 return []string{"-m64", "-march=z196"}
2409 case "mips64", "mips64le":
2410 return []string{"-mabi=64"}
2411 case "mips", "mipsle":
2412 return []string{"-mabi=32", "-march=mips32"}
2413 case "ppc64":
2414 if cfg.Goos == "aix" {
2415 return []string{"-maix64"}
2416 }
2417 }
2418 return nil
2419 }
2420
2421
2422
2423 func envList(key, def string) []string {
2424 v := cfg.Getenv(key)
2425 if v == "" {
2426 v = def
2427 }
2428 return strings.Fields(v)
2429 }
2430
2431
2432 func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) {
2433 defaults := "-g -O2"
2434
2435 if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
2436 return
2437 }
2438 if cflags, err = buildFlags("CFLAGS", defaults, p.CgoCFLAGS, checkCompilerFlags); err != nil {
2439 return
2440 }
2441 if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
2442 return
2443 }
2444 if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil {
2445 return
2446 }
2447 if ldflags, err = buildFlags("LDFLAGS", defaults, p.CgoLDFLAGS, checkLinkerFlags); err != nil {
2448 return
2449 }
2450
2451 return
2452 }
2453
2454 func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) {
2455 if err := check(name, "#cgo "+name, fromPackage); err != nil {
2456 return nil, err
2457 }
2458 return str.StringList(envList("CGO_"+name, defaults), fromPackage), nil
2459 }
2460
2461 var cgoRe = lazyregexp.New(`[/\\:]`)
2462
2463 func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
2464 p := a.Package
2465 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p)
2466 if err != nil {
2467 return nil, nil, err
2468 }
2469
2470 cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
2471 cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
2472
2473 if len(mfiles) > 0 {
2474 cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
2475 }
2476
2477
2478
2479
2480 if len(ffiles) > 0 {
2481 fc := cfg.Getenv("FC")
2482 if fc == "" {
2483 fc = "gfortran"
2484 }
2485 if strings.Contains(fc, "gfortran") {
2486 cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
2487 }
2488 }
2489
2490 if cfg.BuildMSan {
2491 cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
2492 cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
2493 }
2494
2495
2496 cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir)
2497
2498
2499
2500 gofiles := []string{objdir + "_cgo_gotypes.go"}
2501 cfiles := []string{"_cgo_export.c"}
2502 for _, fn := range cgofiles {
2503 f := strings.TrimSuffix(filepath.Base(fn), ".go")
2504 gofiles = append(gofiles, objdir+f+".cgo1.go")
2505 cfiles = append(cfiles, f+".cgo2.c")
2506 }
2507
2508
2509
2510 cgoflags := []string{}
2511 if p.Standard && p.ImportPath == "runtime/cgo" {
2512 cgoflags = append(cgoflags, "-import_runtime_cgo=false")
2513 }
2514 if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo") {
2515 cgoflags = append(cgoflags, "-import_syscall=false")
2516 }
2517
2518
2519
2520
2521
2522
2523
2524
2525 cgoenv := b.cCompilerEnv()
2526 if len(cgoLDFLAGS) > 0 {
2527 flags := make([]string, len(cgoLDFLAGS))
2528 for i, f := range cgoLDFLAGS {
2529 flags[i] = strconv.Quote(f)
2530 }
2531 cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
2532 }
2533
2534 if cfg.BuildToolchainName == "gccgo" {
2535 if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") {
2536 cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
2537 }
2538 cgoflags = append(cgoflags, "-gccgo")
2539 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
2540 cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
2541 }
2542 }
2543
2544 switch cfg.BuildBuildmode {
2545 case "c-archive", "c-shared":
2546
2547
2548
2549 cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h")
2550 }
2551
2552 if err := b.run(a, p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
2553 return nil, nil, err
2554 }
2555 outGo = append(outGo, gofiles...)
2556
2557
2558
2559
2560
2561
2562
2563 oseq := 0
2564 nextOfile := func() string {
2565 oseq++
2566 return objdir + fmt.Sprintf("_x%03d.o", oseq)
2567 }
2568
2569
2570 cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS)
2571 for _, cfile := range cfiles {
2572 ofile := nextOfile()
2573 if err := b.gcc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil {
2574 return nil, nil, err
2575 }
2576 outObj = append(outObj, ofile)
2577 }
2578
2579 for _, file := range gccfiles {
2580 ofile := nextOfile()
2581 if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil {
2582 return nil, nil, err
2583 }
2584 outObj = append(outObj, ofile)
2585 }
2586
2587 cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS)
2588 for _, file := range gxxfiles {
2589 ofile := nextOfile()
2590 if err := b.gxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil {
2591 return nil, nil, err
2592 }
2593 outObj = append(outObj, ofile)
2594 }
2595
2596 for _, file := range mfiles {
2597 ofile := nextOfile()
2598 if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil {
2599 return nil, nil, err
2600 }
2601 outObj = append(outObj, ofile)
2602 }
2603
2604 fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS)
2605 for _, file := range ffiles {
2606 ofile := nextOfile()
2607 if err := b.gfortran(a, p, a.Objdir, ofile, fflags, file); err != nil {
2608 return nil, nil, err
2609 }
2610 outObj = append(outObj, ofile)
2611 }
2612
2613 switch cfg.BuildToolchainName {
2614 case "gc":
2615 importGo := objdir + "_cgo_import.go"
2616 if err := b.dynimport(a, p, objdir, importGo, cgoExe, cflags, cgoLDFLAGS, outObj); err != nil {
2617 return nil, nil, err
2618 }
2619 outGo = append(outGo, importGo)
2620
2621 case "gccgo":
2622 defunC := objdir + "_cgo_defun.c"
2623 defunObj := objdir + "_cgo_defun.o"
2624 if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil {
2625 return nil, nil, err
2626 }
2627 outObj = append(outObj, defunObj)
2628
2629 default:
2630 noCompiler()
2631 }
2632
2633 return outGo, outObj, nil
2634 }
2635
2636
2637
2638
2639 func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) error {
2640 cfile := objdir + "_cgo_main.c"
2641 ofile := objdir + "_cgo_main.o"
2642 if err := b.gcc(a, p, objdir, ofile, cflags, cfile); err != nil {
2643 return err
2644 }
2645
2646 linkobj := str.StringList(ofile, outObj, p.SysoFiles)
2647 dynobj := objdir + "_cgo_.o"
2648
2649
2650 ldflags := cgoLDFLAGS
2651 if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
2652
2653
2654 n := make([]string, 0, len(ldflags))
2655 for _, flag := range ldflags {
2656 if flag != "-static" {
2657 n = append(n, flag)
2658 }
2659 }
2660 ldflags = append(n, "-pie")
2661 }
2662 if err := b.gccld(a, p, objdir, dynobj, ldflags, linkobj); err != nil {
2663 return err
2664 }
2665
2666
2667 var cgoflags []string
2668 if p.Standard && p.ImportPath == "runtime/cgo" {
2669 cgoflags = []string{"-dynlinker"}
2670 }
2671 return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
2672 }
2673
2674
2675
2676
2677 func (b *Builder) swig(a *Action, p *load.Package, objdir string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
2678 if err := b.swigVersionCheck(); err != nil {
2679 return nil, nil, nil, err
2680 }
2681
2682 intgosize, err := b.swigIntSize(objdir)
2683 if err != nil {
2684 return nil, nil, nil, err
2685 }
2686
2687 for _, f := range p.SwigFiles {
2688 goFile, cFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, false, intgosize)
2689 if err != nil {
2690 return nil, nil, nil, err
2691 }
2692 if goFile != "" {
2693 outGo = append(outGo, goFile)
2694 }
2695 if cFile != "" {
2696 outC = append(outC, cFile)
2697 }
2698 }
2699 for _, f := range p.SwigCXXFiles {
2700 goFile, cxxFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, true, intgosize)
2701 if err != nil {
2702 return nil, nil, nil, err
2703 }
2704 if goFile != "" {
2705 outGo = append(outGo, goFile)
2706 }
2707 if cxxFile != "" {
2708 outCXX = append(outCXX, cxxFile)
2709 }
2710 }
2711 return outGo, outC, outCXX, nil
2712 }
2713
2714
2715 var (
2716 swigCheckOnce sync.Once
2717 swigCheck error
2718 )
2719
2720 func (b *Builder) swigDoVersionCheck() error {
2721 out, err := b.runOut(nil, "", nil, "swig", "-version")
2722 if err != nil {
2723 return err
2724 }
2725 re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
2726 matches := re.FindSubmatch(out)
2727 if matches == nil {
2728
2729 return nil
2730 }
2731
2732 major, err := strconv.Atoi(string(matches[1]))
2733 if err != nil {
2734
2735 return nil
2736 }
2737 const errmsg = "must have SWIG version >= 3.0.6"
2738 if major < 3 {
2739 return errors.New(errmsg)
2740 }
2741 if major > 3 {
2742
2743 return nil
2744 }
2745
2746
2747 if len(matches[2]) > 0 {
2748 minor, err := strconv.Atoi(string(matches[2][1:]))
2749 if err != nil {
2750 return nil
2751 }
2752 if minor > 0 {
2753
2754 return nil
2755 }
2756 }
2757
2758
2759 if len(matches[3]) > 0 {
2760 patch, err := strconv.Atoi(string(matches[3][1:]))
2761 if err != nil {
2762 return nil
2763 }
2764 if patch < 6 {
2765
2766 return errors.New(errmsg)
2767 }
2768 }
2769
2770 return nil
2771 }
2772
2773 func (b *Builder) swigVersionCheck() error {
2774 swigCheckOnce.Do(func() {
2775 swigCheck = b.swigDoVersionCheck()
2776 })
2777 return swigCheck
2778 }
2779
2780
2781 var (
2782 swigIntSizeOnce sync.Once
2783 swigIntSize string
2784 swigIntSizeError error
2785 )
2786
2787
2788 const swigIntSizeCode = `
2789 package main
2790 const i int = 1 << 32
2791 `
2792
2793
2794
2795 func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
2796 if cfg.BuildN {
2797 return "$INTBITS", nil
2798 }
2799 src := filepath.Join(b.WorkDir, "swig_intsize.go")
2800 if err = ioutil.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
2801 return
2802 }
2803 srcs := []string{src}
2804
2805 p := load.GoFilesPackage(srcs)
2806
2807 if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, "", false, srcs); e != nil {
2808 return "32", nil
2809 }
2810 return "64", nil
2811 }
2812
2813
2814
2815 func (b *Builder) swigIntSize(objdir string) (intsize string, err error) {
2816 swigIntSizeOnce.Do(func() {
2817 swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir)
2818 })
2819 return swigIntSize, swigIntSizeError
2820 }
2821
2822
2823 func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
2824 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p)
2825 if err != nil {
2826 return "", "", err
2827 }
2828
2829 var cflags []string
2830 if cxx {
2831 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
2832 } else {
2833 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
2834 }
2835
2836 n := 5
2837 if cxx {
2838 n = 8
2839 }
2840 base := file[:len(file)-n]
2841 goFile := base + ".go"
2842 gccBase := base + "_wrap."
2843 gccExt := "c"
2844 if cxx {
2845 gccExt = "cxx"
2846 }
2847
2848 gccgo := cfg.BuildToolchainName == "gccgo"
2849
2850
2851 args := []string{
2852 "-go",
2853 "-cgo",
2854 "-intgosize", intgosize,
2855 "-module", base,
2856 "-o", objdir + gccBase + gccExt,
2857 "-outdir", objdir,
2858 }
2859
2860 for _, f := range cflags {
2861 if len(f) > 3 && f[:2] == "-I" {
2862 args = append(args, f)
2863 }
2864 }
2865
2866 if gccgo {
2867 args = append(args, "-gccgo")
2868 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
2869 args = append(args, "-go-pkgpath", pkgpath)
2870 }
2871 }
2872 if cxx {
2873 args = append(args, "-c++")
2874 }
2875
2876 out, err := b.runOut(a, p.Dir, nil, "swig", args, file)
2877 if err != nil {
2878 if len(out) > 0 {
2879 if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
2880 return "", "", errors.New("must have SWIG version >= 3.0.6")
2881 }
2882 b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out))
2883 return "", "", errPrintedOutput
2884 }
2885 return "", "", err
2886 }
2887 if len(out) > 0 {
2888 b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out))
2889 }
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899 goFile = objdir + goFile
2900 newGoFile := objdir + "_" + base + "_swig.go"
2901 if err := os.Rename(goFile, newGoFile); err != nil {
2902 return "", "", err
2903 }
2904 return newGoFile, objdir + gccBase + gccExt, nil
2905 }
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917 func (b *Builder) disableBuildID(ldflags []string) []string {
2918 switch cfg.Goos {
2919 case "android", "dragonfly", "linux", "netbsd":
2920 ldflags = append(ldflags, "-Wl,--build-id=none")
2921 }
2922 return ldflags
2923 }
2924
2925
2926
2927
2928 func mkAbsFiles(dir string, files []string) []string {
2929 abs := make([]string, len(files))
2930 for i, f := range files {
2931 if !filepath.IsAbs(f) {
2932 f = filepath.Join(dir, f)
2933 }
2934 abs[i] = f
2935 }
2936 return abs
2937 }
2938
2939
2940
2941
2942
2943
2944
2945
2946 func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) {
2947 cleanup = func() {}
2948
2949 var argLen int
2950 for _, arg := range cmd.Args {
2951 argLen += len(arg)
2952 }
2953
2954
2955
2956 if !useResponseFile(cmd.Path, argLen) {
2957 return
2958 }
2959
2960 tf, err := ioutil.TempFile("", "args")
2961 if err != nil {
2962 log.Fatalf("error writing long arguments to response file: %v", err)
2963 }
2964 cleanup = func() { os.Remove(tf.Name()) }
2965 var buf bytes.Buffer
2966 for _, arg := range cmd.Args[1:] {
2967 fmt.Fprintf(&buf, "%s\n", arg)
2968 }
2969 if _, err := tf.Write(buf.Bytes()); err != nil {
2970 tf.Close()
2971 cleanup()
2972 log.Fatalf("error writing long arguments to response file: %v", err)
2973 }
2974 if err := tf.Close(); err != nil {
2975 cleanup()
2976 log.Fatalf("error writing long arguments to response file: %v", err)
2977 }
2978 cmd.Args = []string{cmd.Args[0], "@" + tf.Name()}
2979 return cleanup
2980 }
2981
2982 func useResponseFile(path string, argLen int) bool {
2983
2984 if runtime.GOOS != "windows" {
2985 return false
2986 }
2987
2988
2989
2990
2991 prog := strings.TrimSuffix(filepath.Base(path), ".exe")
2992 switch prog {
2993 case "compile", "link":
2994 default:
2995 return false
2996 }
2997
2998
2999
3000 if argLen > (30 << 10) {
3001 return true
3002 }
3003
3004
3005
3006 isBuilder := os.Getenv("GO_BUILDER_NAME") != ""
3007 if isBuilder && rand.Intn(10) == 0 {
3008 return true
3009 }
3010
3011 return false
3012 }
3013
View as plain text