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