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