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