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