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