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 if cfg.CmdName != "test" {
1745 vetFlags = append(vetFlags, VetFlags...)
1746 }
1747
1748
1749
1750
1751
1752
1753
1754
1755 if cfg.CmdName == "test" {
1756 vetFlags = append(vetFlags, "-unreachable=false")
1757 }
1758 }
1759
1760
1761
1762
1763
1764
1765 fmt.Fprintf(h, "vetflags %q\n", vetFlags)
1766
1767 fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID)
1768 for _, a1 := range a.Deps {
1769 if a1.Mode == "vet" && a1.built != "" {
1770 fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built))
1771 vcfg.PackageVetx[a1.Package.ImportPath] = a1.built
1772 }
1773 }
1774 var (
1775 id = cache.ActionID(h.Sum())
1776 stdoutKey = cache.Subkey(id, "stdout")
1777 fixArchiveKey = cache.Subkey(id, "fix.zip")
1778 )
1779
1780
1781 if !cfg.BuildA {
1782 c := cache.Default()
1783
1784
1785
1786
1787 var (
1788 vetxFile string
1789 fixArchive string
1790 stdout io.Reader = bytes.NewReader(nil)
1791 )
1792
1793
1794 vetxFile, _, err := cache.GetFile(c, id)
1795 if err != nil {
1796 goto cachemiss
1797 }
1798
1799
1800 if a.needFix {
1801 file, _, err := cache.GetFile(c, fixArchiveKey)
1802 if err != nil {
1803 goto cachemiss
1804 }
1805 fixArchive = file
1806 }
1807
1808
1809 if file, _, err := cache.GetFile(c, stdoutKey); err == nil {
1810 f, err := os.Open(file)
1811 if err != nil {
1812 goto cachemiss
1813 }
1814 defer f.Close()
1815 stdout = f
1816 }
1817
1818
1819 a.built = vetxFile
1820 a.FixArchive = fixArchive
1821 if err := VetHandleStdout(stdout); err != nil {
1822 return err
1823 }
1824
1825 return nil
1826 }
1827 cachemiss:
1828
1829 js, err := json.Marshal(vcfg)
1830 if err != nil {
1831 return fmt.Errorf("internal error marshaling vet config: %v", err)
1832 }
1833 if err := sh.writeFile(a.Objdir+"vet.cfg", js); err != nil {
1834 return err
1835 }
1836
1837
1838 env := b.cCompilerEnv()
1839 if cfg.BuildToolchainName == "gccgo" {
1840 env = append(env, "GCCGO="+BuildToolchain.compiler())
1841 }
1842
1843 p := a.Package
1844 tool := VetTool
1845 if tool == "" {
1846 panic("VetTool unset")
1847 }
1848
1849 runErr := sh.run(p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, vetFlags, a.Objdir+"vet.cfg")
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864 if f, err := os.Open(vcfg.VetxOutput); err == nil {
1865 defer f.Close()
1866 a.built = vcfg.VetxOutput
1867 if runErr == nil {
1868 cache.Default().Put(id, f)
1869 }
1870 }
1871
1872 if runErr != nil {
1873 return runErr
1874 }
1875
1876
1877 if a.needFix {
1878 if f, err := os.Open(vcfg.FixArchive); err == nil {
1879 defer f.Close()
1880 a.FixArchive = vcfg.FixArchive
1881 cache.Default().Put(fixArchiveKey, f)
1882 }
1883 }
1884
1885
1886 if f, err := os.Open(vcfg.Stdout); err == nil {
1887 defer f.Close()
1888 if err := VetHandleStdout(f); err != nil {
1889 return err
1890 }
1891 f.Seek(0, io.SeekStart)
1892 cache.Default().Put(stdoutKey, f)
1893 }
1894
1895 return nil
1896 }
1897
1898 func (b *Builder) export(ctx context.Context, a *Action) error {
1899
1900 ecfg := b.buildExportConfig(a)
1901 aid := b.exportActionID(a, ecfg)
1902 if b.useCache(a, aid, a.Target, !b.IsCmdList) {
1903 e, err := cache.Default().Get(aid)
1904 if err != nil {
1905 return err
1906 }
1907 a.Package.BuildID = a.buildID
1908 a.Package.Export = cache.Default().OutputFile(e.OutputID)
1909 return nil
1910 }
1911
1912 defer b.flushOutput(a)
1913 sh := b.Shell(a)
1914 if err := sh.Mkdir(a.Objdir); err != nil {
1915 return err
1916 }
1917
1918 js, err := json.Marshal(ecfg)
1919 if err != nil {
1920 return err
1921 }
1922 in := a.Objdir + "export.cfg"
1923 if err := sh.writeFile(in, js); err != nil {
1924 return err
1925 }
1926 tool := base.Tool("export")
1927
1928 if err := sh.run(b.WorkDir, a.Package.ImportPath, nil, cfg.BuildToolexec, tool, in); err != nil {
1929 return err
1930 }
1931
1932 if err := b.updateBuildID(a, a.Target); err != nil {
1933 return err
1934 }
1935 a.built = a.Target
1936
1937 f, err := os.Open(a.built)
1938 if err != nil {
1939 return err
1940 }
1941 defer f.Close()
1942 oid, _, err := cache.Default().Put(aid, f)
1943 if err != nil {
1944 return err
1945 }
1946 a.Package.BuildID = a.buildID
1947 a.Package.Export = cache.Default().OutputFile(oid)
1948 return nil
1949 }
1950
1951 func (b *Builder) buildExportConfig(a *Action) *exportConfig {
1952 v := gover.Local()
1953 if a.Package.Module != nil {
1954 v = cmp.Or(a.Package.Module.GoVersion, gover.DefaultGoModVersion)
1955 }
1956
1957
1958
1959 srcs := actualFiles(mkAbsFiles(a.Package.Dir, a.Package.GoFiles))
1960
1961 if a.Package.UsesCgo() {
1962 for _, dep := range a.Deps {
1963 if cgo, ok := dep.Provider.(*runCgoProvider); ok {
1964 srcs = append(srcs, cgo.goFiles...)
1965 }
1966 }
1967 }
1968
1969 ecfg := &exportConfig{
1970 ImportPath: a.Package.ImportPath,
1971 GoVersion: "go" + v,
1972 GoFiles: srcs,
1973 ImportMap: make(map[string]string),
1974 PackageFile: make(map[string]string),
1975 Output: a.Target,
1976 }
1977 for i, s := range a.Package.Internal.RawImports {
1978 if s != "C" {
1979 ecfg.ImportMap[s] = a.Package.Imports[i]
1980 }
1981 }
1982
1983 for _, s := range a.Package.Internal.CompiledImports {
1984 ecfg.ImportMap[s] = s
1985 }
1986 for _, dep := range a.Deps {
1987
1988
1989 if dep.Mode == "export" {
1990 ecfg.PackageFile[dep.Package.ImportPath] = dep.built
1991 }
1992 }
1993 return ecfg
1994 }
1995
1996 func (b *Builder) exportActionID(a *Action, ecfg *exportConfig) cache.ActionID {
1997 h := cache.NewHash("export " + a.Package.ImportPath)
1998
1999 fmt.Fprintf(h, "export %s\n", b.toolID("export"))
2000
2001 fmt.Fprintf(h, "importPath %s\n", ecfg.ImportPath)
2002 fmt.Fprintf(h, "goVersion %s\n", ecfg.GoVersion)
2003
2004 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
2005
2006 for _, file := range ecfg.GoFiles {
2007 fmt.Fprintf(h, "goFile %s %s\n", file, b.fileHash(file))
2008 }
2009
2010 for _, dep := range a.Deps {
2011 if dep.Mode == "export" {
2012 fmt.Fprintf(h, "packageFile %s=%s\n", dep.Package.ImportPath, buildExportID(dep.buildID))
2013 }
2014 }
2015 return cache.ActionID(h.Sum())
2016 }
2017
2018 var stdoutMu sync.Mutex
2019
2020
2021 func copyToStdout(r io.Reader) error {
2022 stdoutMu.Lock()
2023 defer stdoutMu.Unlock()
2024 if _, err := io.Copy(os.Stdout, r); err != nil {
2025 return fmt.Errorf("copying vet tool stdout: %w", err)
2026 }
2027 return nil
2028 }
2029
2030
2031 func (b *Builder) linkActionID(a *Action) cache.ActionID {
2032 p := a.Package
2033 h := cache.NewHash("link " + p.ImportPath)
2034
2035
2036 fmt.Fprintf(h, "link\n")
2037
2038
2039
2040 fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", ldBuildmode, cfg.Goos, cfg.Goarch)
2041 fmt.Fprintf(h, "import %q\n", p.ImportPath)
2042 fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)
2043 fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG)
2044 if cfg.BuildTrimpath {
2045 fmt.Fprintln(h, "trimpath")
2046 }
2047
2048
2049 b.printLinkerConfig(h, p)
2050
2051
2052 for _, a1 := range a.Deps {
2053 p1 := a1.Package
2054 if p1 != nil {
2055 if a1.built != "" || a1.buildID != "" {
2056 buildID := a1.buildID
2057 if buildID == "" {
2058 buildID = b.buildID(a1.built)
2059 }
2060 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, buildObjectID(buildID))
2061 }
2062
2063
2064
2065
2066 if p1.Name == "main" {
2067 fmt.Fprintf(h, "packagemain %s\n", buildActionID(a1.buildID)+buildIDSeparator+buildObjectID(a1.buildID))
2068 }
2069 if p1.Shlib != "" {
2070 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, buildObjectID(b.buildID(p1.Shlib)))
2071 }
2072 }
2073 }
2074
2075 return h.Sum()
2076 }
2077
2078
2079
2080 func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
2081 switch cfg.BuildToolchainName {
2082 default:
2083 base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName)
2084
2085 case "gc":
2086 fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode)
2087 if p != nil {
2088 fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags)
2089 }
2090
2091
2092 key, val, _ := cfg.GetArchEnv()
2093 fmt.Fprintf(h, "%s=%s\n", key, val)
2094
2095 if cfg.CleanGOEXPERIMENT != "" {
2096 fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)
2097 }
2098
2099
2100
2101 gorootFinal := cfg.GOROOT
2102 if cfg.BuildTrimpath {
2103 gorootFinal = ""
2104 }
2105 fmt.Fprintf(h, "GOROOT=%s\n", gorootFinal)
2106
2107
2108 fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED"))
2109
2110
2111
2112
2113 case "gccgo":
2114 id, _, err := b.gccgoToolID(BuildToolchain.linker(), "go")
2115 if err != nil {
2116 base.Fatalf("%v", err)
2117 }
2118 fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode)
2119
2120 }
2121 }
2122
2123
2124
2125 func (b *Builder) link(ctx context.Context, a *Action) (err error) {
2126 if b.useCache(a, b.linkActionID(a), a.Package.Target, !b.IsCmdList) || b.IsCmdList {
2127 return nil
2128 }
2129 defer b.flushOutput(a)
2130
2131 sh := b.Shell(a)
2132 if err := sh.Mkdir(a.Objdir); err != nil {
2133 return err
2134 }
2135
2136 importcfg := a.Objdir + "importcfg.link"
2137 if err := b.writeLinkImportcfg(a, importcfg); err != nil {
2138 return err
2139 }
2140
2141 if err := AllowInstall(a); err != nil {
2142 return err
2143 }
2144
2145
2146 dir, _ := filepath.Split(a.Target)
2147 if dir != "" {
2148 if err := sh.Mkdir(dir); err != nil {
2149 return err
2150 }
2151 }
2152
2153 if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil {
2154 return err
2155 }
2156
2157
2158 if err := b.updateBuildID(a, a.Target); err != nil {
2159 return err
2160 }
2161
2162 a.built = a.Target
2163 return nil
2164 }
2165
2166 func (b *Builder) writeLinkImportcfg(a *Action, file string) error {
2167
2168 var icfg bytes.Buffer
2169 for _, a1 := range a.Deps {
2170 p1 := a1.Package
2171 if p1 == nil {
2172 continue
2173 }
2174 fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
2175 if p1.Shlib != "" {
2176 fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib)
2177 }
2178 }
2179 info := ""
2180 if a.Package.Internal.BuildInfo != nil {
2181 info = a.Package.Internal.BuildInfo.String()
2182 }
2183 fmt.Fprintf(&icfg, "modinfo %q\n", modload.ModInfoData(info))
2184 return b.Shell(a).writeFile(file, icfg.Bytes())
2185 }
2186
2187
2188
2189 func (b *Builder) PkgconfigCmd() string {
2190 return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0]
2191 }
2192
2193
2194
2195
2196
2197
2198
2199 func splitPkgConfigOutput(out []byte) ([]string, error) {
2200 if len(out) == 0 {
2201 return nil, nil
2202 }
2203 var flags []string
2204 flag := make([]byte, 0, len(out))
2205 didQuote := false
2206 escaped := false
2207 quote := byte(0)
2208
2209 for _, c := range out {
2210 if escaped {
2211 if quote == '"' {
2212
2213
2214
2215 switch c {
2216 case '$', '`', '"', '\\', '\n':
2217
2218 default:
2219
2220 flag = append(flag, '\\', c)
2221 escaped = false
2222 continue
2223 }
2224 }
2225
2226 if c == '\n' {
2227
2228
2229 } else {
2230 flag = append(flag, c)
2231 }
2232 escaped = false
2233 continue
2234 }
2235
2236 if quote != 0 && c == quote {
2237 quote = 0
2238 continue
2239 }
2240 switch quote {
2241 case '\'':
2242
2243 flag = append(flag, c)
2244 continue
2245 case '"':
2246
2247
2248 switch c {
2249 case '`', '$', '\\':
2250 default:
2251 flag = append(flag, c)
2252 continue
2253 }
2254 }
2255
2256
2257
2258 switch c {
2259 case '|', '&', ';', '<', '>', '(', ')', '$', '`':
2260 return nil, fmt.Errorf("unexpected shell character %q in pkgconf output", c)
2261
2262 case '\\':
2263
2264
2265 escaped = true
2266 continue
2267
2268 case '"', '\'':
2269 quote = c
2270 didQuote = true
2271 continue
2272
2273 case ' ', '\t', '\n':
2274 if len(flag) > 0 || didQuote {
2275 flags = append(flags, string(flag))
2276 }
2277 flag, didQuote = flag[:0], false
2278 continue
2279 }
2280
2281 flag = append(flag, c)
2282 }
2283
2284
2285
2286
2287 if quote != 0 {
2288 return nil, errors.New("unterminated quoted string in pkgconf output")
2289 }
2290 if escaped {
2291 return nil, errors.New("broken character escaping in pkgconf output")
2292 }
2293
2294 if len(flag) > 0 || didQuote {
2295 flags = append(flags, string(flag))
2296 }
2297 return flags, nil
2298 }
2299
2300
2301 func (b *Builder) getPkgConfigFlags(a *Action, p *load.Package) (cflags, ldflags []string, err error) {
2302 sh := b.Shell(a)
2303 if pcargs := p.CgoPkgConfig; len(pcargs) > 0 {
2304
2305
2306 var pcflags []string
2307 var pkgs []string
2308 for _, pcarg := range pcargs {
2309 if pcarg == "--" {
2310
2311 } else if strings.HasPrefix(pcarg, "--") {
2312 pcflags = append(pcflags, pcarg)
2313 } else {
2314 pkgs = append(pkgs, pcarg)
2315 }
2316 }
2317 for _, pkg := range pkgs {
2318 if !load.SafeArg(pkg) {
2319 return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
2320 }
2321 }
2322
2323 if err := checkPkgConfigFlags("", "pkg-config", pcflags); err != nil {
2324 return nil, nil, err
2325 }
2326
2327 var out []byte
2328 out, err = sh.runOut(p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
2329 if err != nil {
2330 desc := b.PkgconfigCmd() + " --cflags " + strings.Join(pcflags, " ") + " -- " + strings.Join(pkgs, " ")
2331 return nil, nil, sh.reportCmd(desc, "", out, err)
2332 }
2333 if len(out) > 0 {
2334 cflags, err = splitPkgConfigOutput(bytes.TrimSpace(out))
2335 if err != nil {
2336 return nil, nil, err
2337 }
2338 if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
2339 return nil, nil, err
2340 }
2341 }
2342 out, err = sh.runOut(p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
2343 if err != nil {
2344 desc := b.PkgconfigCmd() + " --libs " + strings.Join(pcflags, " ") + " -- " + strings.Join(pkgs, " ")
2345 return nil, nil, sh.reportCmd(desc, "", out, err)
2346 }
2347 if len(out) > 0 {
2348
2349
2350 ldflags, err = splitPkgConfigOutput(bytes.TrimSpace(out))
2351 if err != nil {
2352 return nil, nil, err
2353 }
2354 if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
2355 return nil, nil, err
2356 }
2357 }
2358 }
2359
2360 return
2361 }
2362
2363 func (b *Builder) installShlibname(ctx context.Context, a *Action) error {
2364 if err := AllowInstall(a); err != nil {
2365 return err
2366 }
2367
2368 sh := b.Shell(a)
2369 a1 := a.Deps[0]
2370 if !cfg.BuildN {
2371 if err := sh.Mkdir(filepath.Dir(a.Target)); err != nil {
2372 return err
2373 }
2374 }
2375 return sh.writeFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"))
2376 }
2377
2378 func (b *Builder) linkSharedActionID(a *Action) cache.ActionID {
2379 h := cache.NewHash("linkShared")
2380
2381
2382 fmt.Fprintf(h, "linkShared\n")
2383 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
2384
2385
2386 b.printLinkerConfig(h, nil)
2387
2388
2389 for _, a1 := range a.Deps {
2390 p1 := a1.Package
2391 if a1.built == "" {
2392 continue
2393 }
2394 if p1 != nil {
2395 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, buildObjectID(b.buildID(a1.built)))
2396 if p1.Shlib != "" {
2397 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, buildObjectID(b.buildID(p1.Shlib)))
2398 }
2399 }
2400 }
2401
2402 for _, a1 := range a.Deps[0].Deps {
2403 p1 := a1.Package
2404 fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, buildObjectID(b.buildID(a1.built)))
2405 }
2406
2407 return h.Sum()
2408 }
2409
2410 func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) {
2411 if b.useCache(a, b.linkSharedActionID(a), a.Target, !b.IsCmdList) || b.IsCmdList {
2412 return nil
2413 }
2414 defer b.flushOutput(a)
2415
2416 if err := AllowInstall(a); err != nil {
2417 return err
2418 }
2419
2420 if err := b.Shell(a).Mkdir(a.Objdir); err != nil {
2421 return err
2422 }
2423
2424 importcfg := a.Objdir + "importcfg.link"
2425 if err := b.writeLinkImportcfg(a, importcfg); err != nil {
2426 return err
2427 }
2428
2429
2430
2431 a.built = a.Target
2432 return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps)
2433 }
2434
2435
2436 func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) {
2437 defer func() {
2438 if err != nil {
2439
2440
2441
2442 sep, path := "", ""
2443 if a.Package != nil {
2444 sep, path = " ", a.Package.ImportPath
2445 }
2446 err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err)
2447 }
2448 }()
2449 sh := b.Shell(a)
2450
2451 a1 := a.Deps[0]
2452 a.buildID = a1.buildID
2453 if a.json != nil {
2454 a.json.BuildID = a.buildID
2455 }
2456
2457
2458
2459
2460
2461
2462 if a1.built == a.Target {
2463 a.built = a.Target
2464 if !a.buggyInstall {
2465 b.cleanup(a1)
2466 }
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485 if !a.buggyInstall && !b.IsCmdList {
2486 if cfg.BuildN {
2487 sh.ShowCmd("", "touch %s", a.Target)
2488 } else if err := AllowInstall(a); err == nil {
2489 now := time.Now()
2490 os.Chtimes(a.Target, now, now)
2491 }
2492 }
2493 return nil
2494 }
2495
2496
2497
2498 if b.IsCmdList {
2499 a.built = a1.built
2500 return nil
2501 }
2502 if err := AllowInstall(a); err != nil {
2503 return err
2504 }
2505
2506 if err := sh.Mkdir(a.Objdir); err != nil {
2507 return err
2508 }
2509
2510 perm := fs.FileMode(0666)
2511 if a1.Mode == "link" {
2512 switch cfg.BuildBuildmode {
2513 case "c-archive", "c-shared", "plugin":
2514 default:
2515 perm = 0777
2516 }
2517 }
2518
2519
2520 dir, _ := filepath.Split(a.Target)
2521 if dir != "" {
2522 if err := sh.Mkdir(dir); err != nil {
2523 return err
2524 }
2525 }
2526
2527 if !a.buggyInstall {
2528 defer b.cleanup(a1)
2529 }
2530
2531 if err := sh.moveOrCopyFile(a.Target, a1.built, perm, false); err != nil {
2532 return err
2533 }
2534
2535
2536
2537 if a1.Mode == "link" && cfg.CmdName != "install" && a.Target != os.DevNull {
2538 dsym := filepath.Join(a1.built+".dSYM", "Contents", "Resources", "DWARF", filepath.Base(a1.built))
2539 if _, err := os.Stat(dsym); err == nil {
2540 hdr := filepath.Join(a.Target+".dSYM", "Contents", "Resources", "DWARF")
2541 if err := sh.Mkdir(hdr); err != nil {
2542 return err
2543 }
2544 if err := sh.moveOrCopyFile(filepath.Join(hdr, filepath.Base(a.Target)), dsym, 0666, false); err != nil {
2545 return err
2546 }
2547 } else if !cfg.BuildN {
2548
2549 if err := sh.RemoveAll(a.Target + ".dSYM"); err != nil {
2550 return err
2551 }
2552 }
2553 }
2554
2555 return nil
2556 }
2557
2558
2559
2560
2561
2562
2563 var AllowInstall = func(*Action) error { return nil }
2564
2565
2566
2567
2568
2569 func (b *Builder) cleanup(a *Action) {
2570 if !cfg.BuildWork {
2571 b.Shell(a).RemoveAll(a.Objdir)
2572 }
2573 }
2574
2575
2576 func (b *Builder) installHeader(ctx context.Context, a *Action) error {
2577 sh := b.Shell(a)
2578
2579 src := a.Objdir + "_cgo_install.h"
2580 if _, err := os.Stat(src); os.IsNotExist(err) {
2581
2582
2583
2584
2585
2586 if cfg.BuildX {
2587 sh.ShowCmd("", "# %s not created", src)
2588 }
2589 return nil
2590 }
2591
2592 if err := AllowInstall(a); err != nil {
2593 return err
2594 }
2595
2596 dir, _ := filepath.Split(a.Target)
2597 if dir != "" {
2598 if err := sh.Mkdir(dir); err != nil {
2599 return err
2600 }
2601 }
2602
2603 return sh.moveOrCopyFile(a.Target, src, 0666, true)
2604 }
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614 func (b *Builder) cover(a *Action, infiles, outfiles []string, varName, mode, covMetaFileName, coverCfg string) ([]string, error) {
2615 pkgcfg := a.Objdir + "pkgcfg.txt"
2616 covoutputs := a.Objdir + "coveroutfiles.txt"
2617 odir := filepath.Dir(outfiles[0])
2618 cv := filepath.Join(odir, "covervars.go")
2619 outfiles = append([]string{cv}, outfiles...)
2620 if err := b.writeCoverPkgInputs(a, pkgcfg, covMetaFileName, coverCfg, covoutputs, outfiles); err != nil {
2621 return nil, err
2622 }
2623 args := []string{base.Tool("cover"),
2624 "-pkgcfg", pkgcfg,
2625 "-mode", mode,
2626 "-var", varName,
2627 "-outfilelist", covoutputs,
2628 }
2629 args = append(args, infiles...)
2630 if err := b.Shell(a).run(a.Objdir, "", nil,
2631 cfg.BuildToolexec, args); err != nil {
2632 return nil, err
2633 }
2634 return outfiles, nil
2635 }
2636
2637 func coverConfig(p *load.Package, covMetaFileName, outConfig string) covcmd.CoverPkgConfig {
2638 pcfg := covcmd.CoverPkgConfig{
2639 PkgPath: p.ImportPath,
2640 PkgName: p.Name,
2641
2642
2643
2644
2645 Granularity: "perblock",
2646 OutConfig: outConfig,
2647 Local: p.Internal.Local,
2648 EmitMetaFile: covMetaFileName,
2649 }
2650 if p.Module != nil {
2651 pcfg.ModulePath = p.Module.Path
2652 }
2653 return pcfg
2654 }
2655
2656 func (b *Builder) writeCoverPkgInputs(a *Action, pconfigfile, covMetaFileName, coverCfg, covoutputsfile string, outfiles []string) error {
2657 sh := b.Shell(a)
2658 p := a.Package
2659 pcfg := coverConfig(p, covMetaFileName, coverCfg)
2660 data, err := json.Marshal(pcfg)
2661 if err != nil {
2662 return err
2663 }
2664 if err := sh.writeFile(pconfigfile, data); err != nil {
2665 return err
2666 }
2667 var sb strings.Builder
2668 for i := range outfiles {
2669 fmt.Fprintf(&sb, "%s\n", outfiles[i])
2670 }
2671 return sh.writeFile(covoutputsfile, []byte(sb.String()))
2672 }
2673
2674 var objectMagic = [][]byte{
2675 {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'},
2676 {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'},
2677 {'\x7F', 'E', 'L', 'F'},
2678 {0xFE, 0xED, 0xFA, 0xCE},
2679 {0xFE, 0xED, 0xFA, 0xCF},
2680 {0xCE, 0xFA, 0xED, 0xFE},
2681 {0xCF, 0xFA, 0xED, 0xFE},
2682 {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},
2683 {0x4d, 0x5a, 0x78, 0x00, 0x01, 0x00},
2684 {0x00, 0x00, 0x01, 0xEB},
2685 {0x00, 0x00, 0x8a, 0x97},
2686 {0x00, 0x00, 0x06, 0x47},
2687 {0x00, 0x61, 0x73, 0x6D},
2688 {0x01, 0xDF},
2689 {0x01, 0xF7},
2690 }
2691
2692 func isObject(s string) bool {
2693 f, err := os.Open(s)
2694 if err != nil {
2695 return false
2696 }
2697 defer f.Close()
2698 buf := make([]byte, 64)
2699 io.ReadFull(f, buf)
2700 for _, magic := range objectMagic {
2701 if bytes.HasPrefix(buf, magic) {
2702 return true
2703 }
2704 }
2705 return false
2706 }
2707
2708
2709
2710
2711 func (b *Builder) cCompilerEnv() []string {
2712 return []string{"TERM=dumb"}
2713 }
2714
2715
2716
2717
2718
2719
2720 func mkAbs(dir, f string) string {
2721
2722
2723
2724
2725 if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
2726 return f
2727 }
2728 return filepath.Join(dir, f)
2729 }
2730
2731 type toolchain interface {
2732
2733
2734 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)
2735
2736
2737 cc(b *Builder, a *Action, ofile, cfile string) error
2738
2739
2740 asm(b *Builder, a *Action, sfiles []string) ([]string, error)
2741
2742
2743 symabis(b *Builder, a *Action, sfiles []string) (string, error)
2744
2745
2746
2747 pack(b *Builder, a *Action, afile string, ofiles []string) error
2748
2749 ld(b *Builder, root *Action, targetPath, importcfg, mainpkg string) error
2750
2751 ldShared(b *Builder, root *Action, toplevelactions []*Action, targetPath, importcfg string, allactions []*Action) error
2752
2753 compiler() string
2754 linker() string
2755 }
2756
2757 type noToolchain struct{}
2758
2759 func noCompiler() error {
2760 log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler)
2761 return nil
2762 }
2763
2764 func (noToolchain) compiler() string {
2765 noCompiler()
2766 return ""
2767 }
2768
2769 func (noToolchain) linker() string {
2770 noCompiler()
2771 return ""
2772 }
2773
2774 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) {
2775 return "", nil, nil, noCompiler()
2776 }
2777
2778 func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
2779 return nil, noCompiler()
2780 }
2781
2782 func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
2783 return "", noCompiler()
2784 }
2785
2786 func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
2787 return noCompiler()
2788 }
2789
2790 func (noToolchain) ld(b *Builder, root *Action, targetPath, importcfg, mainpkg string) error {
2791 return noCompiler()
2792 }
2793
2794 func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, targetPath, importcfg string, allactions []*Action) error {
2795 return noCompiler()
2796 }
2797
2798 func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
2799 return noCompiler()
2800 }
2801
2802
2803 func (b *Builder) gcc(a *Action, workdir, out string, flags []string, cfile string) error {
2804 p := a.Package
2805 return b.ccompile(a, out, flags, cfile, b.GccCmd(p.Dir, workdir))
2806 }
2807
2808
2809 func (b *Builder) gas(a *Action, workdir, out string, flags []string, sfile string) error {
2810 p := a.Package
2811 data, err := os.ReadFile(sfile)
2812 if err == nil {
2813 if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) ||
2814 bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) ||
2815 bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) {
2816 return fmt.Errorf("package using cgo has Go assembly file %s", sfile)
2817 }
2818 }
2819 return b.ccompile(a, out, flags, sfile, b.GccCmd(p.Dir, workdir))
2820 }
2821
2822
2823 func (b *Builder) gxx(a *Action, workdir, out string, flags []string, cxxfile string) error {
2824 p := a.Package
2825 return b.ccompile(a, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
2826 }
2827
2828
2829 func (b *Builder) gfortran(a *Action, workdir, out string, flags []string, ffile string) error {
2830 p := a.Package
2831 return b.ccompile(a, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
2832 }
2833
2834
2835 func (b *Builder) ccompile(a *Action, outfile string, flags []string, file string, compiler []string) error {
2836 p := a.Package
2837 sh := b.Shell(a)
2838 file = mkAbs(p.Dir, file)
2839 outfile = mkAbs(p.Dir, outfile)
2840
2841 flags = slices.Clip(flags)
2842
2843
2844
2845
2846
2847
2848 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
2849 if cfg.BuildTrimpath || p.Goroot {
2850 prefixMapFlag := "-fdebug-prefix-map"
2851 if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") {
2852 prefixMapFlag = "-ffile-prefix-map"
2853 }
2854
2855
2856
2857 var from, toPath string
2858 if m := p.Module; m == nil {
2859 if p.Root == "" {
2860 from = p.Dir
2861 toPath = p.ImportPath
2862 } else if p.Goroot {
2863 from = p.Root
2864 toPath = "GOROOT"
2865 } else {
2866 from = p.Root
2867 toPath = "GOPATH"
2868 }
2869 } else if m.Dir == "" {
2870
2871
2872 from = b.getVendorDir()
2873 toPath = "vendor"
2874 } else {
2875 from = m.Dir
2876 toPath = m.Path
2877 if m.Version != "" {
2878 toPath += "@" + m.Version
2879 }
2880 }
2881
2882
2883
2884 var to string
2885 if cfg.BuildContext.GOOS == "windows" {
2886 to = filepath.Join(`\\_\_`, toPath)
2887 } else {
2888 to = filepath.Join("/_", toPath)
2889 }
2890 flags = append(slices.Clip(flags), prefixMapFlag+"="+from+"="+to)
2891 }
2892 }
2893
2894
2895
2896 if b.gccSupportsFlag(compiler, "-frandom-seed=1") {
2897 flags = append(flags, "-frandom-seed="+buildid.HashToString(a.actionID))
2898 }
2899
2900 overlayPath := file
2901 if p, ok := a.nonGoOverlay[overlayPath]; ok {
2902 overlayPath = p
2903 }
2904 output, err := sh.runOut(filepath.Dir(overlayPath), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(overlayPath))
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914 if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
2915 newFlags := make([]string, 0, len(flags))
2916 for _, f := range flags {
2917 if !strings.HasPrefix(f, "-g") {
2918 newFlags = append(newFlags, f)
2919 }
2920 }
2921 if len(newFlags) < len(flags) {
2922 return b.ccompile(a, outfile, newFlags, file, compiler)
2923 }
2924 }
2925
2926 if len(output) > 0 && err == nil && os.Getenv("GO_BUILDER_NAME") != "" {
2927 output = append(output, "C compiler warning promoted to error on Go builders\n"...)
2928 err = errors.New("warning promoted to error")
2929 }
2930
2931 return sh.reportCmd("", "", output, err)
2932 }
2933
2934
2935 func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs []string) error {
2936 p := a.Package
2937 sh := b.Shell(a)
2938 var cmd []string
2939 if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
2940 cmd = b.GxxCmd(p.Dir, objdir)
2941 } else {
2942 cmd = b.GccCmd(p.Dir, objdir)
2943 }
2944
2945 cmdargs := []any{cmd, "-o", outfile, objs, flags}
2946 _, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...)
2947
2948
2949
2950 if cfg.BuildN || cfg.BuildX {
2951 saw := "succeeded"
2952 if err != nil {
2953 saw = "failed"
2954 }
2955 sh.ShowCmd("", "%s # test for internal linking errors (%s)", joinUnambiguously(str.StringList(cmdargs...)), saw)
2956 }
2957
2958 return err
2959 }
2960
2961
2962
2963 func (b *Builder) GccCmd(incdir, workdir string) []string {
2964 return b.compilerCmd(b.ccExe(), incdir, workdir)
2965 }
2966
2967
2968
2969 func (b *Builder) GxxCmd(incdir, workdir string) []string {
2970 return b.compilerCmd(b.cxxExe(), incdir, workdir)
2971 }
2972
2973
2974 func (b *Builder) gfortranCmd(incdir, workdir string) []string {
2975 return b.compilerCmd(b.fcExe(), incdir, workdir)
2976 }
2977
2978
2979 func (b *Builder) ccExe() []string {
2980 return envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
2981 }
2982
2983
2984 func (b *Builder) cxxExe() []string {
2985 return envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
2986 }
2987
2988
2989 func (b *Builder) fcExe() []string {
2990 return envList("FC", "gfortran")
2991 }
2992
2993
2994
2995 func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string {
2996 a := append(compiler, "-I", incdir)
2997
2998
2999
3000 if cfg.Goos != "windows" {
3001 a = append(a, "-fPIC")
3002 }
3003 a = append(a, b.gccArchArgs()...)
3004
3005
3006 if cfg.BuildContext.CgoEnabled {
3007 a = append(a, "-pthread")
3008 }
3009
3010 if cfg.Goos == "aix" {
3011
3012 a = append(a, "-mcmodel=large")
3013 }
3014
3015
3016 if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") {
3017 a = append(a, "-fno-caret-diagnostics")
3018 }
3019
3020 if b.gccSupportsFlag(compiler, "-Qunused-arguments") {
3021 a = append(a, "-Qunused-arguments")
3022 }
3023
3024
3025
3026
3027 if b.gccSupportsFlag(compiler, "-Wl,--no-gc-sections") {
3028 a = append(a, "-Wl,--no-gc-sections")
3029 }
3030
3031
3032 a = append(a, "-fmessage-length=0")
3033
3034
3035 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
3036 if workdir == "" {
3037 workdir = b.WorkDir
3038 }
3039 workdir = strings.TrimSuffix(workdir, string(filepath.Separator))
3040 if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") {
3041 a = append(a, "-ffile-prefix-map="+workdir+"=/tmp/go-build")
3042 } else {
3043 a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build")
3044 }
3045 }
3046
3047
3048
3049 if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") {
3050 a = append(a, "-gno-record-gcc-switches")
3051 }
3052
3053
3054
3055
3056 if cfg.Goos == "darwin" || cfg.Goos == "ios" {
3057 a = append(a, "-fno-common")
3058 }
3059
3060 return a
3061 }
3062
3063
3064
3065
3066
3067 func (b *Builder) gccNoPie(linker []string) string {
3068 if b.gccSupportsFlag(linker, "-no-pie") {
3069 return "-no-pie"
3070 }
3071 if b.gccSupportsFlag(linker, "-nopie") {
3072 return "-nopie"
3073 }
3074 return ""
3075 }
3076
3077
3078 func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
3079
3080
3081
3082 sh := b.BackgroundShell()
3083
3084 key := [2]string{compiler[0], flag}
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102 tmp := os.DevNull
3103 if runtime.GOOS == "windows" || runtime.GOOS == "ios" {
3104 f, err := os.CreateTemp(b.WorkDir, "")
3105 if err != nil {
3106 return false
3107 }
3108 f.Close()
3109 tmp = f.Name()
3110 defer os.Remove(tmp)
3111 }
3112
3113 cmdArgs := str.StringList(compiler, flag)
3114 if strings.HasPrefix(flag, "-Wl,") {
3115 ldflags, err := buildFlags("LDFLAGS", DefaultCFlags, nil, checkLinkerFlags)
3116 if err != nil {
3117 return false
3118 }
3119 cmdArgs = append(cmdArgs, ldflags...)
3120 } else {
3121 cflags, err := buildFlags("CFLAGS", DefaultCFlags, nil, checkCompilerFlags)
3122 if err != nil {
3123 return false
3124 }
3125 cmdArgs = append(cmdArgs, cflags...)
3126 cmdArgs = append(cmdArgs, "-c")
3127 }
3128
3129 cmdArgs = append(cmdArgs, "-x", "c", "-", "-o", tmp)
3130
3131 if cfg.BuildN {
3132 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
3133 return false
3134 }
3135
3136
3137 compilerID, cacheOK := b.gccCompilerID(compiler[0])
3138
3139 b.exec.Lock()
3140 defer b.exec.Unlock()
3141 if b, ok := b.flagCache[key]; ok {
3142 return b
3143 }
3144 if b.flagCache == nil {
3145 b.flagCache = make(map[[2]string]bool)
3146 }
3147
3148
3149 var flagID cache.ActionID
3150 if cacheOK {
3151 flagID = cache.Subkey(compilerID, "gccSupportsFlag "+flag)
3152 if data, _, err := cache.GetBytes(cache.Default(), flagID); err == nil {
3153 supported := string(data) == "true"
3154 b.flagCache[key] = supported
3155 return supported
3156 }
3157 }
3158
3159 if cfg.BuildX {
3160 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
3161 }
3162 cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
3163 cmd.Dir = b.WorkDir
3164 cmd.Env = append(cmd.Environ(), "LC_ALL=C")
3165 out, _ := cmd.CombinedOutput()
3166
3167
3168
3169
3170
3171
3172 supported := !bytes.Contains(out, []byte("unrecognized")) &&
3173 !bytes.Contains(out, []byte("unknown")) &&
3174 !bytes.Contains(out, []byte("unrecognised")) &&
3175 !bytes.Contains(out, []byte("is not supported")) &&
3176 !bytes.Contains(out, []byte("not recognized")) &&
3177 !bytes.Contains(out, []byte("unsupported"))
3178
3179 if cacheOK {
3180 s := "false"
3181 if supported {
3182 s = "true"
3183 }
3184 cache.PutBytes(cache.Default(), flagID, []byte(s))
3185 }
3186
3187 b.flagCache[key] = supported
3188 return supported
3189 }
3190
3191
3192 func statString(info os.FileInfo) string {
3193 return fmt.Sprintf("stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
3194 }
3195
3196
3197
3198
3199
3200
3201 func (b *Builder) gccCompilerID(compiler string) (id cache.ActionID, ok bool) {
3202
3203
3204
3205 sh := b.BackgroundShell()
3206
3207 if cfg.BuildN {
3208 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously([]string{compiler, "--version"}))
3209 return cache.ActionID{}, false
3210 }
3211
3212 b.exec.Lock()
3213 defer b.exec.Unlock()
3214
3215 if id, ok := b.gccCompilerIDCache[compiler]; ok {
3216 return id, ok
3217 }
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233 exe, err := pathcache.LookPath(compiler)
3234 if err != nil {
3235 return cache.ActionID{}, false
3236 }
3237
3238 h := cache.NewHash("gccCompilerID")
3239 fmt.Fprintf(h, "gccCompilerID %q", exe)
3240 key := h.Sum()
3241 data, _, err := cache.GetBytes(cache.Default(), key)
3242 if err == nil && len(data) > len(id) {
3243 stats := strings.Split(string(data[:len(data)-len(id)]), "\x00")
3244 if len(stats)%2 != 0 {
3245 goto Miss
3246 }
3247 for i := 0; i+2 <= len(stats); i++ {
3248 info, err := os.Stat(stats[i])
3249 if err != nil || statString(info) != stats[i+1] {
3250 goto Miss
3251 }
3252 }
3253 copy(id[:], data[len(data)-len(id):])
3254 return id, true
3255 Miss:
3256 }
3257
3258
3259
3260
3261
3262
3263 toolID, exe2, err := b.gccToolID(compiler, "c")
3264 if err != nil {
3265 return cache.ActionID{}, false
3266 }
3267
3268 exes := []string{exe, exe2}
3269 str.Uniq(&exes)
3270 fmt.Fprintf(h, "gccCompilerID %q %q\n", exes, toolID)
3271 id = h.Sum()
3272
3273 var buf bytes.Buffer
3274 for _, exe := range exes {
3275 if exe == "" {
3276 continue
3277 }
3278 info, err := os.Stat(exe)
3279 if err != nil {
3280 return cache.ActionID{}, false
3281 }
3282 buf.WriteString(exe)
3283 buf.WriteString("\x00")
3284 buf.WriteString(statString(info))
3285 buf.WriteString("\x00")
3286 }
3287 buf.Write(id[:])
3288
3289 cache.PutBytes(cache.Default(), key, buf.Bytes())
3290 if b.gccCompilerIDCache == nil {
3291 b.gccCompilerIDCache = make(map[string]cache.ActionID)
3292 }
3293 b.gccCompilerIDCache[compiler] = id
3294 return id, true
3295 }
3296
3297
3298 func (b *Builder) gccArchArgs() []string {
3299 switch cfg.Goarch {
3300 case "386":
3301 return []string{"-m32"}
3302 case "amd64":
3303 if cfg.Goos == "darwin" {
3304 return []string{"-arch", "x86_64", "-m64"}
3305 }
3306 return []string{"-m64"}
3307 case "arm64":
3308 if cfg.Goos == "darwin" {
3309 return []string{"-arch", "arm64"}
3310 }
3311 case "arm":
3312 return []string{"-marm"}
3313 case "s390x":
3314
3315 return []string{"-m64", "-march=z13"}
3316 case "mips64", "mips64le":
3317 args := []string{"-mabi=64"}
3318 if cfg.GOMIPS64 == "hardfloat" {
3319 return append(args, "-mhard-float")
3320 } else if cfg.GOMIPS64 == "softfloat" {
3321 return append(args, "-msoft-float")
3322 }
3323 case "mips", "mipsle":
3324 args := []string{"-mabi=32", "-march=mips32"}
3325 if cfg.GOMIPS == "hardfloat" {
3326 return append(args, "-mhard-float", "-mfp32", "-mno-odd-spreg")
3327 } else if cfg.GOMIPS == "softfloat" {
3328 return append(args, "-msoft-float")
3329 }
3330 case "loong64":
3331
3332
3333
3334
3335
3336 return []string{"-mabi=lp64d", "-mno-relax"}
3337 case "ppc64":
3338 if cfg.Goos == "aix" {
3339 return []string{"-maix64"}
3340 }
3341 }
3342 return nil
3343 }
3344
3345
3346
3347
3348
3349
3350
3351 func envList(key, def string) []string {
3352 v := cfg.Getenv(key)
3353 if v == "" {
3354 v = def
3355 }
3356 args, err := quoted.Split(v)
3357 if err != nil {
3358 panic(fmt.Sprintf("could not parse environment variable %s with value %q: %v", key, v, err))
3359 }
3360 return args
3361 }
3362
3363
3364 func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) {
3365 if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
3366 return
3367 }
3368 if cflags, err = buildFlags("CFLAGS", DefaultCFlags, p.CgoCFLAGS, checkCompilerFlags); err != nil {
3369 return
3370 }
3371 if cxxflags, err = buildFlags("CXXFLAGS", DefaultCFlags, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
3372 return
3373 }
3374 if fflags, err = buildFlags("FFLAGS", DefaultCFlags, p.CgoFFLAGS, checkCompilerFlags); err != nil {
3375 return
3376 }
3377 if ldflags, err = buildFlags("LDFLAGS", DefaultCFlags, p.CgoLDFLAGS, checkLinkerFlags); err != nil {
3378 return
3379 }
3380
3381 return
3382 }
3383
3384 func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) {
3385 if err := check(name, "#cgo "+name, fromPackage); err != nil {
3386 return nil, err
3387 }
3388 return slices.Concat(envList("CGO_"+name, defaults), fromPackage), nil
3389 }
3390
3391 var cgoRe = lazyregexp.New(`[/\\:]`)
3392
3393 type runCgoProvider struct {
3394 CFLAGS, CXXFLAGS, FFLAGS, LDFLAGS []string
3395 notCompatibleForInternalLinking bool
3396 nonGoOverlay map[string]string
3397 goFiles []string
3398 }
3399
3400 func (pr *runCgoProvider) cflags() []string {
3401 return pr.CFLAGS
3402 }
3403
3404 func (pr *runCgoProvider) cxxflags() []string {
3405 return pr.CXXFLAGS
3406 }
3407
3408 func (pr *runCgoProvider) fflags() []string {
3409 return pr.FFLAGS
3410 }
3411
3412 func (pr *runCgoProvider) ldflags() []string {
3413 return pr.LDFLAGS
3414 }
3415
3416 func mustGetCoverInfo(a *Action) *coverProvider {
3417 for _, dep := range a.Deps {
3418 if dep.Mode == "cover" {
3419 return dep.Provider.(*coverProvider)
3420 }
3421 }
3422 base.Fatalf("internal error: cover provider not found")
3423 panic("unreachable")
3424 }
3425
3426 func (b *Builder) runCgo(_ context.Context, a *Action) error {
3427 p := a.Package
3428 sh := b.Shell(a)
3429 objdir := a.Objdir
3430
3431 if err := sh.Mkdir(objdir); err != nil {
3432 return err
3433 }
3434
3435 nonGoFileLists := [][]string{p.CFiles, p.SFiles, p.CXXFiles, p.HFiles, p.FFiles}
3436 if err := b.computeNonGoOverlay(a, p, sh, objdir, nonGoFileLists); err != nil {
3437 return err
3438 }
3439
3440 a.actionID = b.cgoRunActionID(a)
3441 if pr, err := b.loadCachedRunCgoOutputs(a); err == nil {
3442 pr.nonGoOverlay = a.nonGoOverlay
3443 a.Provider = pr
3444 return nil
3445 }
3446
3447 cgofiles := slices.Clip(p.CgoFiles)
3448 if a.Package.Internal.Cover.Mode != "" {
3449 cp := mustGetCoverInfo(a)
3450 cgofiles = cp.cgoSources
3451 }
3452
3453 pcCFLAGS, pcLDFLAGS, err := b.getPkgConfigFlags(a, p)
3454 if err != nil {
3455 return err
3456 }
3457
3458
3459
3460
3461
3462
3463
3464 if p.UsesSwig() {
3465 if err := b.swig(a, objdir, pcCFLAGS); err != nil {
3466 return err
3467 }
3468 outGo, _, _ := b.swigOutputs(p, objdir)
3469 cgofiles = append(cgofiles, outGo...)
3470 }
3471
3472 cgoExe := base.Tool("cgo")
3473 cgofiles = mkAbsFiles(p.Dir, cgofiles)
3474
3475 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p)
3476 if err != nil {
3477 return err
3478 }
3479
3480 cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
3481 cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
3482
3483 if len(p.MFiles) > 0 {
3484 cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
3485 }
3486
3487
3488
3489
3490 if len(p.FFiles) > 0 {
3491 fc := cfg.Getenv("FC")
3492 if fc == "" {
3493 fc = "gfortran"
3494 }
3495 if strings.Contains(fc, "gfortran") {
3496 cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
3497 }
3498 }
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515 flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"}
3516 flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS}
3517 notCompatibleWithInternalLinking := flagsNotCompatibleWithInternalLinking(flagSources, flagLists)
3518 if !notCompatibleWithInternalLinking {
3519 if err := checkLinkerFlagsForInternalLink("CGO_LDFLAGS", "CGO_LDFLAGS", cgoLDFLAGS); err != nil {
3520 notCompatibleWithInternalLinking = true
3521 }
3522 }
3523
3524 if cfg.BuildMSan {
3525 cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
3526 cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
3527 }
3528 if cfg.BuildASan {
3529 cgoCFLAGS = append([]string{"-fsanitize=address"}, cgoCFLAGS...)
3530 cgoLDFLAGS = append([]string{"-fsanitize=address"}, cgoLDFLAGS...)
3531 }
3532
3533
3534
3535 cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir)
3536
3537
3538
3539 gofiles := []string{objdir + "_cgo_gotypes.go"}
3540 cfiles := []string{objdir + "_cgo_export.c"}
3541 for _, fn := range cgofiles {
3542 f := strings.TrimSuffix(filepath.Base(fn), ".go")
3543 gofiles = append(gofiles, objdir+f+".cgo1.go")
3544 cfiles = append(cfiles, objdir+f+".cgo2.c")
3545 }
3546
3547
3548
3549 cgoflags := []string{}
3550 if p.Standard && p.ImportPath == "runtime/cgo" {
3551 cgoflags = append(cgoflags, "-import_runtime_cgo=false")
3552 }
3553 if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo" || p.ImportPath == "runtime/asan") {
3554 cgoflags = append(cgoflags, "-import_syscall=false")
3555 }
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567 cgoenv := b.cCompilerEnv()
3568 cgoenv = append(cgoenv, cfgChangedEnv...)
3569 var ldflagsOption []string
3570 if len(cgoLDFLAGS) > 0 {
3571 flags := make([]string, len(cgoLDFLAGS))
3572 for i, f := range cgoLDFLAGS {
3573 flags[i] = strconv.Quote(f)
3574 }
3575 ldflagsOption = []string{"-ldflags=" + strings.Join(flags, " ")}
3576
3577
3578 cgoenv = append(cgoenv, "CGO_LDFLAGS=")
3579 }
3580
3581 if cfg.BuildToolchainName == "gccgo" {
3582 if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") {
3583 cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
3584 }
3585 cgoflags = append(cgoflags, "-gccgo")
3586 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
3587 cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
3588 }
3589 if !BuildToolchain.(gccgoToolchain).supportsCgoIncomplete(b, a) {
3590 cgoflags = append(cgoflags, "-gccgo_define_cgoincomplete")
3591 }
3592 }
3593
3594 switch cfg.BuildBuildmode {
3595 case "c-archive", "c-shared":
3596
3597
3598
3599 cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h")
3600 }
3601
3602
3603
3604 var trimpath []string
3605 for i := range cgofiles {
3606 path := mkAbs(p.Dir, cgofiles[i])
3607 if fsys.Replaced(path) {
3608 actual := fsys.Actual(path)
3609 cgofiles[i] = actual
3610 trimpath = append(trimpath, actual+"=>"+path)
3611 }
3612 }
3613 if len(trimpath) > 0 {
3614 cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";"))
3615 }
3616
3617 if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, ldflagsOption, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
3618 return err
3619 }
3620
3621 a.Provider = &runCgoProvider{
3622 CFLAGS: slices.Concat(cgoCPPFLAGS, cgoCFLAGS),
3623 CXXFLAGS: slices.Concat(cgoCPPFLAGS, cgoCXXFLAGS),
3624 FFLAGS: slices.Concat(cgoCPPFLAGS, cgoFFLAGS),
3625 LDFLAGS: cgoLDFLAGS,
3626 notCompatibleForInternalLinking: notCompatibleWithInternalLinking,
3627 nonGoOverlay: a.nonGoOverlay,
3628 goFiles: gofiles,
3629 }
3630
3631 if !cfg.BuildN {
3632 pr := a.Provider.(*runCgoProvider)
3633 if err := b.cacheRunCgoOutputs(a, pr); err != nil {
3634 return err
3635 }
3636 }
3637
3638 return nil
3639 }
3640
3641 func (b *Builder) processCgoOutputs(a *Action, runCgoProvider *runCgoProvider, cgoExe, objdir string) (outGo, outObj []string, err error) {
3642 outGo = slices.Clip(runCgoProvider.goFiles)
3643
3644
3645
3646
3647
3648
3649
3650
3651 sh := b.Shell(a)
3652
3653
3654
3655 if runCgoProvider.notCompatibleForInternalLinking {
3656 tokenFile := objdir + "preferlinkext"
3657 if err := sh.writeFile(tokenFile, nil); err != nil {
3658 return nil, nil, err
3659 }
3660 outObj = append(outObj, tokenFile)
3661 }
3662
3663 var collectAction *Action
3664 for _, dep := range a.Deps {
3665 if dep.Mode == "collect cgo" {
3666 collectAction = dep
3667 }
3668 }
3669 if collectAction == nil {
3670 base.Fatalf("internal error: no cgo collect action")
3671 }
3672 for _, dep := range collectAction.Deps {
3673 outObj = append(outObj, dep.Target)
3674 }
3675
3676 switch cfg.BuildToolchainName {
3677 case "gc":
3678 importGo := objdir + "_cgo_import.go"
3679 dynOutGo, dynOutObj, err := b.dynimport(a, objdir, importGo, cgoExe, runCgoProvider.CFLAGS, runCgoProvider.LDFLAGS, outObj)
3680 if err != nil {
3681 return nil, nil, err
3682 }
3683 if dynOutGo != "" {
3684 outGo = append(outGo, dynOutGo)
3685 }
3686 if dynOutObj != "" {
3687 outObj = append(outObj, dynOutObj)
3688 }
3689
3690 case "gccgo":
3691 defunC := objdir + "_cgo_defun.c"
3692 defunObj := objdir + "_cgo_defun.o"
3693 if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil {
3694 return nil, nil, err
3695 }
3696 outObj = append(outObj, defunObj)
3697
3698 default:
3699 noCompiler()
3700 }
3701
3702
3703
3704
3705
3706
3707 if cfg.BuildToolchainName == "gc" && !cfg.BuildN {
3708 var flags []string
3709 for _, f := range outGo {
3710 if !strings.HasPrefix(filepath.Base(f), "_cgo_") {
3711 continue
3712 }
3713
3714 src, err := os.ReadFile(f)
3715 if err != nil {
3716 return nil, nil, err
3717 }
3718
3719 const cgoLdflag = "//go:cgo_ldflag"
3720 idx := bytes.Index(src, []byte(cgoLdflag))
3721 for idx >= 0 {
3722
3723
3724 start := bytes.LastIndex(src[:idx], []byte("\n"))
3725 if start == -1 {
3726 start = 0
3727 }
3728
3729
3730 end := bytes.Index(src[idx:], []byte("\n"))
3731 if end == -1 {
3732 end = len(src)
3733 } else {
3734 end += idx
3735 }
3736
3737
3738
3739
3740
3741 commentStart := bytes.Index(src[start:], []byte("//"))
3742 commentStart += start
3743
3744
3745 if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) {
3746
3747
3748 flag := string(src[idx+len(cgoLdflag) : end])
3749 flag = strings.TrimSpace(flag)
3750 flag = strings.Trim(flag, `"`)
3751 flags = append(flags, flag)
3752 }
3753 src = src[end:]
3754 idx = bytes.Index(src, []byte(cgoLdflag))
3755 }
3756 }
3757
3758
3759 if len(runCgoProvider.LDFLAGS) > 0 {
3760 outer:
3761 for i := range flags {
3762 for j, f := range runCgoProvider.LDFLAGS {
3763 if f != flags[i+j] {
3764 continue outer
3765 }
3766 }
3767 flags = append(flags[:i], flags[i+len(runCgoProvider.LDFLAGS):]...)
3768 break
3769 }
3770 }
3771
3772 if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
3773 return nil, nil, err
3774 }
3775 }
3776
3777 return outGo, outObj, nil
3778 }
3779
3780
3781
3782
3783
3784
3785
3786
3787 func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool {
3788 for i := range sourceList {
3789 sn := sourceList[i]
3790 fll := flagListList[i]
3791 if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil {
3792 return true
3793 }
3794 }
3795 return false
3796 }
3797
3798
3799
3800
3801
3802
3803 func (b *Builder) dynimport(a *Action, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) (dynOutGo, dynOutObj string, err error) {
3804 p := a.Package
3805 sh := b.Shell(a)
3806
3807 cfile := objdir + "_cgo_main.c"
3808 ofile := objdir + "_cgo_main.o"
3809 if err := b.gcc(a, objdir, ofile, cflags, cfile); err != nil {
3810 return "", "", err
3811 }
3812
3813
3814 var syso []string
3815 seen := make(map[*Action]bool)
3816 var gatherSyso func(*Action)
3817 gatherSyso = func(a1 *Action) {
3818 if seen[a1] {
3819 return
3820 }
3821 seen[a1] = true
3822 if p1 := a1.Package; p1 != nil {
3823 syso = append(syso, mkAbsFiles(p1.Dir, p1.SysoFiles)...)
3824 }
3825 for _, a2 := range a1.Deps {
3826 gatherSyso(a2)
3827 }
3828 }
3829 gatherSyso(a)
3830 sort.Strings(syso)
3831 str.Uniq(&syso)
3832 linkobj := str.StringList(ofile, outObj, syso)
3833 dynobj := objdir + "_cgo_.o"
3834
3835 ldflags := cgoLDFLAGS
3836 if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
3837 if !slices.Contains(ldflags, "-no-pie") {
3838
3839
3840 ldflags = append(ldflags, "-pie")
3841 }
3842 if slices.Contains(ldflags, "-pie") && slices.Contains(ldflags, "-static") {
3843
3844
3845 n := make([]string, 0, len(ldflags)-1)
3846 for _, flag := range ldflags {
3847 if flag != "-static" {
3848 n = append(n, flag)
3849 }
3850 }
3851 ldflags = n
3852 }
3853 }
3854 if err := b.gccld(a, objdir, dynobj, ldflags, linkobj); err != nil {
3855
3856
3857
3858
3859
3860
3861 fail := objdir + "dynimportfail"
3862 if err := sh.writeFile(fail, nil); err != nil {
3863 return "", "", err
3864 }
3865 return "", fail, nil
3866 }
3867
3868
3869 var cgoflags []string
3870 if p.Standard && p.ImportPath == "runtime/cgo" {
3871 cgoflags = []string{"-dynlinker"}
3872 }
3873 err = sh.run(base.Cwd(), p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
3874 if err != nil {
3875 return "", "", err
3876 }
3877 return importGo, "", nil
3878 }
3879
3880
3881
3882
3883 func (b *Builder) swig(a *Action, objdir string, pcCFLAGS []string) error {
3884 p := a.Package
3885
3886 if err := b.swigVersionCheck(); err != nil {
3887 return err
3888 }
3889
3890 intgosize, err := b.swigIntSize(objdir)
3891 if err != nil {
3892 return err
3893 }
3894
3895 for _, f := range p.SwigFiles {
3896 if err := b.swigOne(a, f, objdir, pcCFLAGS, false, intgosize); err != nil {
3897 return err
3898 }
3899 }
3900 for _, f := range p.SwigCXXFiles {
3901 if err := b.swigOne(a, f, objdir, pcCFLAGS, true, intgosize); err != nil {
3902 return err
3903 }
3904 }
3905 return nil
3906 }
3907
3908 func (b *Builder) swigOutputs(p *load.Package, objdir string) (outGo, outC, outCXX []string) {
3909 for _, f := range p.SwigFiles {
3910 goFile, cFile := swigOneOutputs(f, objdir, false)
3911 outGo = append(outGo, goFile)
3912 outC = append(outC, cFile)
3913 }
3914 for _, f := range p.SwigCXXFiles {
3915 goFile, cxxFile := swigOneOutputs(f, objdir, true)
3916 outGo = append(outGo, goFile)
3917 outCXX = append(outCXX, cxxFile)
3918 }
3919 return outGo, outC, outCXX
3920 }
3921
3922
3923 var (
3924 swigCheckOnce sync.Once
3925 swigCheck error
3926 )
3927
3928 func (b *Builder) swigDoVersionCheck() error {
3929 sh := b.BackgroundShell()
3930 out, err := sh.runOut(".", nil, "swig", "-version")
3931 if err != nil {
3932 return err
3933 }
3934 re := regexp.MustCompile(`[vV]ersion +(\d+)([.]\d+)?([.]\d+)?`)
3935 matches := re.FindSubmatch(out)
3936 if matches == nil {
3937
3938 return nil
3939 }
3940
3941 major, err := strconv.Atoi(string(matches[1]))
3942 if err != nil {
3943
3944 return nil
3945 }
3946 const errmsg = "must have SWIG version >= 3.0.6"
3947 if major < 3 {
3948 return errors.New(errmsg)
3949 }
3950 if major > 3 {
3951
3952 return nil
3953 }
3954
3955
3956 if len(matches[2]) > 0 {
3957 minor, err := strconv.Atoi(string(matches[2][1:]))
3958 if err != nil {
3959 return nil
3960 }
3961 if minor > 0 {
3962
3963 return nil
3964 }
3965 }
3966
3967
3968 if len(matches[3]) > 0 {
3969 patch, err := strconv.Atoi(string(matches[3][1:]))
3970 if err != nil {
3971 return nil
3972 }
3973 if patch < 6 {
3974
3975 return errors.New(errmsg)
3976 }
3977 }
3978
3979 return nil
3980 }
3981
3982 func (b *Builder) swigVersionCheck() error {
3983 swigCheckOnce.Do(func() {
3984 swigCheck = b.swigDoVersionCheck()
3985 })
3986 return swigCheck
3987 }
3988
3989
3990 var (
3991 swigIntSizeOnce sync.Once
3992 swigIntSize string
3993 swigIntSizeError error
3994 )
3995
3996
3997 const swigIntSizeCode = `
3998 package main
3999 const i int = 1 << 32
4000 `
4001
4002
4003
4004 func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
4005 if cfg.BuildN {
4006 return "$INTBITS", nil
4007 }
4008 src := filepath.Join(b.WorkDir, "swig_intsize.go")
4009 if err = os.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
4010 return
4011 }
4012 srcs := []string{src}
4013
4014 p := load.GoFilesPackage(modload.NewLoader(), context.TODO(), load.PackageOpts{}, srcs)
4015
4016 if _, _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, "", "", srcs); e != nil {
4017 return "32", nil
4018 }
4019 return "64", nil
4020 }
4021
4022
4023
4024 func (b *Builder) swigIntSize(objdir string) (intsize string, err error) {
4025 swigIntSizeOnce.Do(func() {
4026 swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir)
4027 })
4028 return swigIntSize, swigIntSizeError
4029 }
4030
4031
4032 func (b *Builder) swigOne(a *Action, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) error {
4033 if strings.HasPrefix(file, "cgo") {
4034 return errors.New("SWIG file must not use prefix 'cgo'")
4035 }
4036
4037 p := a.Package
4038 sh := b.Shell(a)
4039
4040 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p)
4041 if err != nil {
4042 return err
4043 }
4044
4045 var cflags []string
4046 if cxx {
4047 cflags = slices.Concat(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
4048 } else {
4049 cflags = slices.Concat(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
4050 }
4051
4052 base := swigBase(file, cxx)
4053 newGoFile, outC := swigOneOutputs(file, objdir, cxx)
4054
4055 gccgo := cfg.BuildToolchainName == "gccgo"
4056
4057
4058 args := []string{
4059 "-go",
4060 "-cgo",
4061 "-intgosize", intgosize,
4062 "-module", base,
4063 "-o", outC,
4064 "-outdir", objdir,
4065 }
4066
4067 for _, f := range cflags {
4068 if len(f) > 3 && f[:2] == "-I" {
4069 args = append(args, f)
4070 }
4071 }
4072
4073 if gccgo {
4074 args = append(args, "-gccgo")
4075 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
4076 args = append(args, "-go-pkgpath", pkgpath)
4077 }
4078 }
4079 if cxx {
4080 args = append(args, "-c++")
4081 }
4082
4083 out, err := sh.runOut(p.Dir, nil, "swig", args, file)
4084 if err != nil && (bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo"))) {
4085 return errors.New("must have SWIG version >= 3.0.6")
4086 }
4087 if err := sh.reportCmd("", "", out, err); err != nil {
4088 return err
4089 }
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099 goFile := objdir + base + ".go"
4100 if cfg.BuildX || cfg.BuildN {
4101 sh.ShowCmd("", "mv %s %s", goFile, newGoFile)
4102 }
4103 if !cfg.BuildN {
4104 if err := os.Rename(goFile, newGoFile); err != nil {
4105 return err
4106 }
4107 }
4108
4109 return nil
4110 }
4111
4112 func swigBase(file string, cxx bool) string {
4113 n := 5
4114 if cxx {
4115 n = 8
4116 }
4117 return file[:len(file)-n]
4118 }
4119
4120 func swigOneOutputs(file, objdir string, cxx bool) (outGo, outC string) {
4121 base := swigBase(file, cxx)
4122 gccBase := base + "_wrap."
4123 gccExt := "c"
4124 if cxx {
4125 gccExt = "cxx"
4126 }
4127
4128 newGoFile := objdir + "_" + base + "_swig.go"
4129 cFile := objdir + gccBase + gccExt
4130 return newGoFile, cFile
4131 }
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143 func (b *Builder) disableBuildID(ldflags []string) []string {
4144 switch cfg.Goos {
4145 case "android", "dragonfly", "linux", "netbsd":
4146 ldflags = append(ldflags, "-Wl,--build-id=none")
4147 }
4148 return ldflags
4149 }
4150
4151
4152
4153
4154 func mkAbsFiles(dir string, files []string) []string {
4155 abs := make([]string, len(files))
4156 for i, f := range files {
4157 if !filepath.IsAbs(f) {
4158 f = filepath.Join(dir, f)
4159 }
4160 abs[i] = f
4161 }
4162 return abs
4163 }
4164
4165
4166 func actualFiles(files []string) []string {
4167 a := make([]string, len(files))
4168 for i, f := range files {
4169 a[i] = fsys.Actual(f)
4170 }
4171 return a
4172 }
4173
4174
4175
4176
4177
4178
4179
4180
4181 func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) {
4182 cleanup = func() {}
4183
4184 var argLen int
4185 for _, arg := range cmd.Args {
4186 argLen += len(arg)
4187 }
4188
4189
4190
4191 if !useResponseFile(cmd.Path, argLen) {
4192 return
4193 }
4194
4195 tf, err := os.CreateTemp("", "args")
4196 if err != nil {
4197 log.Fatalf("error writing long arguments to response file: %v", err)
4198 }
4199 cleanup = func() { os.Remove(tf.Name()) }
4200 var buf bytes.Buffer
4201 for _, arg := range cmd.Args[1:] {
4202 fmt.Fprintf(&buf, "%s\n", encodeArg(arg))
4203 }
4204 if _, err := tf.Write(buf.Bytes()); err != nil {
4205 tf.Close()
4206 cleanup()
4207 log.Fatalf("error writing long arguments to response file: %v", err)
4208 }
4209 if err := tf.Close(); err != nil {
4210 cleanup()
4211 log.Fatalf("error writing long arguments to response file: %v", err)
4212 }
4213 cmd.Args = []string{cmd.Args[0], "@" + tf.Name()}
4214 return cleanup
4215 }
4216
4217 func useResponseFile(path string, argLen int) bool {
4218
4219
4220
4221 prog := strings.TrimSuffix(filepath.Base(path), ".exe")
4222 switch prog {
4223 case "compile", "link", "cgo", "asm", "cover", "pack":
4224 default:
4225 return false
4226 }
4227
4228 if argLen > sys.ExecArgLengthLimit {
4229 return true
4230 }
4231
4232
4233
4234 isBuilder := os.Getenv("GO_BUILDER_NAME") != ""
4235 if isBuilder && rand.Intn(10) == 0 {
4236 return true
4237 }
4238
4239 return false
4240 }
4241
4242
4243
4244 func encodeArg(arg string) string {
4245
4246 if arg == "" {
4247 return `""`
4248 }
4249
4250 if !strings.ContainsAny(arg, " \t\n\r'\"\\$`") {
4251 return arg
4252 }
4253
4254
4255 var b strings.Builder
4256 b.WriteByte('"')
4257 for _, r := range arg {
4258 switch r {
4259 case '\\':
4260 b.WriteString(`\\`)
4261 case '"':
4262 b.WriteString(`\"`)
4263 case '$':
4264 b.WriteString(`\$`)
4265 case '`':
4266 b.WriteString("\\`")
4267 default:
4268 b.WriteRune(r)
4269 }
4270 }
4271 b.WriteByte('"')
4272 return b.String()
4273 }
4274
View as plain text