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