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 if err := checkPkgConfigFlags("", "pkg-config", pcflags); err != nil {
1793 return nil, nil, err
1794 }
1795
1796 var out []byte
1797 out, err = sh.runOut(p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs)
1798 if err != nil {
1799 desc := b.PkgconfigCmd() + " --cflags " + strings.Join(pcflags, " ") + " -- " + strings.Join(pkgs, " ")
1800 return nil, nil, sh.reportCmd(desc, "", out, err)
1801 }
1802 if len(out) > 0 {
1803 cflags, err = splitPkgConfigOutput(bytes.TrimSpace(out))
1804 if err != nil {
1805 return nil, nil, err
1806 }
1807 if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
1808 return nil, nil, err
1809 }
1810 }
1811 out, err = sh.runOut(p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs)
1812 if err != nil {
1813 desc := b.PkgconfigCmd() + " --libs " + strings.Join(pcflags, " ") + " -- " + strings.Join(pkgs, " ")
1814 return nil, nil, sh.reportCmd(desc, "", out, err)
1815 }
1816 if len(out) > 0 {
1817
1818
1819 ldflags, err = splitPkgConfigOutput(bytes.TrimSpace(out))
1820 if err != nil {
1821 return nil, nil, err
1822 }
1823 if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil {
1824 return nil, nil, err
1825 }
1826 }
1827 }
1828
1829 return
1830 }
1831
1832 func (b *Builder) installShlibname(ctx context.Context, a *Action) error {
1833 if err := AllowInstall(a); err != nil {
1834 return err
1835 }
1836
1837 sh := b.Shell(a)
1838 a1 := a.Deps[0]
1839 if !cfg.BuildN {
1840 if err := sh.Mkdir(filepath.Dir(a.Target)); err != nil {
1841 return err
1842 }
1843 }
1844 return sh.writeFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"))
1845 }
1846
1847 func (b *Builder) linkSharedActionID(a *Action) cache.ActionID {
1848 h := cache.NewHash("linkShared")
1849
1850
1851 fmt.Fprintf(h, "linkShared\n")
1852 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)
1853
1854
1855 b.printLinkerConfig(h, nil)
1856
1857
1858 for _, a1 := range a.Deps {
1859 p1 := a1.Package
1860 if a1.built == "" {
1861 continue
1862 }
1863 if p1 != nil {
1864 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built)))
1865 if p1.Shlib != "" {
1866 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib)))
1867 }
1868 }
1869 }
1870
1871 for _, a1 := range a.Deps[0].Deps {
1872 p1 := a1.Package
1873 fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built)))
1874 }
1875
1876 return h.Sum()
1877 }
1878
1879 func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) {
1880 if b.useCache(a, b.linkSharedActionID(a), a.Target, !b.IsCmdList) || b.IsCmdList {
1881 return nil
1882 }
1883 defer b.flushOutput(a)
1884
1885 if err := AllowInstall(a); err != nil {
1886 return err
1887 }
1888
1889 if err := b.Shell(a).Mkdir(a.Objdir); err != nil {
1890 return err
1891 }
1892
1893 importcfg := a.Objdir + "importcfg.link"
1894 if err := b.writeLinkImportcfg(a, importcfg); err != nil {
1895 return err
1896 }
1897
1898
1899
1900 a.built = a.Target
1901 return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps)
1902 }
1903
1904
1905 func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) {
1906 defer func() {
1907 if err != nil {
1908
1909
1910
1911 sep, path := "", ""
1912 if a.Package != nil {
1913 sep, path = " ", a.Package.ImportPath
1914 }
1915 err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err)
1916 }
1917 }()
1918 sh := b.Shell(a)
1919
1920 a1 := a.Deps[0]
1921 a.buildID = a1.buildID
1922 if a.json != nil {
1923 a.json.BuildID = a.buildID
1924 }
1925
1926
1927
1928
1929
1930
1931 if a1.built == a.Target {
1932 a.built = a.Target
1933 if !a.buggyInstall {
1934 b.cleanup(a1)
1935 }
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954 if !a.buggyInstall && !b.IsCmdList {
1955 if cfg.BuildN {
1956 sh.ShowCmd("", "touch %s", a.Target)
1957 } else if err := AllowInstall(a); err == nil {
1958 now := time.Now()
1959 os.Chtimes(a.Target, now, now)
1960 }
1961 }
1962 return nil
1963 }
1964
1965
1966
1967 if b.IsCmdList {
1968 a.built = a1.built
1969 return nil
1970 }
1971 if err := AllowInstall(a); err != nil {
1972 return err
1973 }
1974
1975 if err := sh.Mkdir(a.Objdir); err != nil {
1976 return err
1977 }
1978
1979 perm := fs.FileMode(0666)
1980 if a1.Mode == "link" {
1981 switch cfg.BuildBuildmode {
1982 case "c-archive", "c-shared", "plugin":
1983 default:
1984 perm = 0777
1985 }
1986 }
1987
1988
1989 dir, _ := filepath.Split(a.Target)
1990 if dir != "" {
1991 if err := sh.Mkdir(dir); err != nil {
1992 return err
1993 }
1994 }
1995
1996 if !a.buggyInstall {
1997 defer b.cleanup(a1)
1998 }
1999
2000 return sh.moveOrCopyFile(a.Target, a1.built, perm, false)
2001 }
2002
2003
2004
2005
2006
2007
2008 var AllowInstall = func(*Action) error { return nil }
2009
2010
2011
2012
2013
2014 func (b *Builder) cleanup(a *Action) {
2015 if !cfg.BuildWork {
2016 b.Shell(a).RemoveAll(a.Objdir)
2017 }
2018 }
2019
2020
2021 func (b *Builder) installHeader(ctx context.Context, a *Action) error {
2022 sh := b.Shell(a)
2023
2024 src := a.Objdir + "_cgo_install.h"
2025 if _, err := os.Stat(src); os.IsNotExist(err) {
2026
2027
2028
2029
2030
2031 if cfg.BuildX {
2032 sh.ShowCmd("", "# %s not created", src)
2033 }
2034 return nil
2035 }
2036
2037 if err := AllowInstall(a); err != nil {
2038 return err
2039 }
2040
2041 dir, _ := filepath.Split(a.Target)
2042 if dir != "" {
2043 if err := sh.Mkdir(dir); err != nil {
2044 return err
2045 }
2046 }
2047
2048 return sh.moveOrCopyFile(a.Target, src, 0666, true)
2049 }
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059 func (b *Builder) cover(a *Action, infiles, outfiles []string, varName string, mode string) ([]string, error) {
2060 pkgcfg := a.Objdir + "pkgcfg.txt"
2061 covoutputs := a.Objdir + "coveroutfiles.txt"
2062 odir := filepath.Dir(outfiles[0])
2063 cv := filepath.Join(odir, "covervars.go")
2064 outfiles = append([]string{cv}, outfiles...)
2065 if err := b.writeCoverPkgInputs(a, pkgcfg, covoutputs, outfiles); err != nil {
2066 return nil, err
2067 }
2068 args := []string{base.Tool("cover"),
2069 "-pkgcfg", pkgcfg,
2070 "-mode", mode,
2071 "-var", varName,
2072 "-outfilelist", covoutputs,
2073 }
2074 args = append(args, infiles...)
2075 if err := b.Shell(a).run(a.Objdir, "", nil,
2076 cfg.BuildToolexec, args); err != nil {
2077 return nil, err
2078 }
2079 return outfiles, nil
2080 }
2081
2082 func (b *Builder) writeCoverPkgInputs(a *Action, pconfigfile string, covoutputsfile string, outfiles []string) error {
2083 sh := b.Shell(a)
2084 p := a.Package
2085 p.Internal.Cover.Cfg = a.Objdir + "coveragecfg"
2086 pcfg := covcmd.CoverPkgConfig{
2087 PkgPath: p.ImportPath,
2088 PkgName: p.Name,
2089
2090
2091
2092
2093 Granularity: "perblock",
2094 OutConfig: p.Internal.Cover.Cfg,
2095 Local: p.Internal.Local,
2096 }
2097 if ca, ok := a.Actor.(*coverActor); ok && ca.covMetaFileName != "" {
2098 pcfg.EmitMetaFile = a.Objdir + ca.covMetaFileName
2099 }
2100 if a.Package.Module != nil {
2101 pcfg.ModulePath = a.Package.Module.Path
2102 }
2103 data, err := json.Marshal(pcfg)
2104 if err != nil {
2105 return err
2106 }
2107 data = append(data, '\n')
2108 if err := sh.writeFile(pconfigfile, data); err != nil {
2109 return err
2110 }
2111 var sb strings.Builder
2112 for i := range outfiles {
2113 fmt.Fprintf(&sb, "%s\n", outfiles[i])
2114 }
2115 return sh.writeFile(covoutputsfile, []byte(sb.String()))
2116 }
2117
2118 var objectMagic = [][]byte{
2119 {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'},
2120 {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'},
2121 {'\x7F', 'E', 'L', 'F'},
2122 {0xFE, 0xED, 0xFA, 0xCE},
2123 {0xFE, 0xED, 0xFA, 0xCF},
2124 {0xCE, 0xFA, 0xED, 0xFE},
2125 {0xCF, 0xFA, 0xED, 0xFE},
2126 {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},
2127 {0x4d, 0x5a, 0x78, 0x00, 0x01, 0x00},
2128 {0x00, 0x00, 0x01, 0xEB},
2129 {0x00, 0x00, 0x8a, 0x97},
2130 {0x00, 0x00, 0x06, 0x47},
2131 {0x00, 0x61, 0x73, 0x6D},
2132 {0x01, 0xDF},
2133 {0x01, 0xF7},
2134 }
2135
2136 func isObject(s string) bool {
2137 f, err := os.Open(s)
2138 if err != nil {
2139 return false
2140 }
2141 defer f.Close()
2142 buf := make([]byte, 64)
2143 io.ReadFull(f, buf)
2144 for _, magic := range objectMagic {
2145 if bytes.HasPrefix(buf, magic) {
2146 return true
2147 }
2148 }
2149 return false
2150 }
2151
2152
2153
2154
2155 func (b *Builder) cCompilerEnv() []string {
2156 return []string{"TERM=dumb"}
2157 }
2158
2159
2160
2161
2162
2163
2164 func mkAbs(dir, f string) string {
2165
2166
2167
2168
2169 if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") {
2170 return f
2171 }
2172 return filepath.Join(dir, f)
2173 }
2174
2175 type toolchain interface {
2176
2177
2178 gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, pgoProfile string, gofiles []string) (ofile string, out []byte, err error)
2179
2180
2181 cc(b *Builder, a *Action, ofile, cfile string) error
2182
2183
2184 asm(b *Builder, a *Action, sfiles []string) ([]string, error)
2185
2186
2187 symabis(b *Builder, a *Action, sfiles []string) (string, error)
2188
2189
2190
2191 pack(b *Builder, a *Action, afile string, ofiles []string) error
2192
2193 ld(b *Builder, root *Action, targetPath, importcfg, mainpkg string) error
2194
2195 ldShared(b *Builder, root *Action, toplevelactions []*Action, targetPath, importcfg string, allactions []*Action) error
2196
2197 compiler() string
2198 linker() string
2199 }
2200
2201 type noToolchain struct{}
2202
2203 func noCompiler() error {
2204 log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler)
2205 return nil
2206 }
2207
2208 func (noToolchain) compiler() string {
2209 noCompiler()
2210 return ""
2211 }
2212
2213 func (noToolchain) linker() string {
2214 noCompiler()
2215 return ""
2216 }
2217
2218 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) {
2219 return "", nil, noCompiler()
2220 }
2221
2222 func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
2223 return nil, noCompiler()
2224 }
2225
2226 func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
2227 return "", noCompiler()
2228 }
2229
2230 func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
2231 return noCompiler()
2232 }
2233
2234 func (noToolchain) ld(b *Builder, root *Action, targetPath, importcfg, mainpkg string) error {
2235 return noCompiler()
2236 }
2237
2238 func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, targetPath, importcfg string, allactions []*Action) error {
2239 return noCompiler()
2240 }
2241
2242 func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
2243 return noCompiler()
2244 }
2245
2246
2247 func (b *Builder) gcc(a *Action, workdir, out string, flags []string, cfile string) error {
2248 p := a.Package
2249 return b.ccompile(a, out, flags, cfile, b.GccCmd(p.Dir, workdir))
2250 }
2251
2252
2253 func (b *Builder) gas(a *Action, workdir, out string, flags []string, sfile string) error {
2254 p := a.Package
2255 data, err := os.ReadFile(filepath.Join(p.Dir, sfile))
2256 if err == nil {
2257 if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) ||
2258 bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) ||
2259 bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) {
2260 return fmt.Errorf("package using cgo has Go assembly file %s", sfile)
2261 }
2262 }
2263 return b.ccompile(a, out, flags, sfile, b.GccCmd(p.Dir, workdir))
2264 }
2265
2266
2267 func (b *Builder) gxx(a *Action, workdir, out string, flags []string, cxxfile string) error {
2268 p := a.Package
2269 return b.ccompile(a, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
2270 }
2271
2272
2273 func (b *Builder) gfortran(a *Action, workdir, out string, flags []string, ffile string) error {
2274 p := a.Package
2275 return b.ccompile(a, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
2276 }
2277
2278
2279 func (b *Builder) ccompile(a *Action, outfile string, flags []string, file string, compiler []string) error {
2280 p := a.Package
2281 sh := b.Shell(a)
2282 file = mkAbs(p.Dir, file)
2283 outfile = mkAbs(p.Dir, outfile)
2284
2285 flags = slices.Clip(flags)
2286
2287
2288
2289
2290
2291
2292 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
2293 if cfg.BuildTrimpath || p.Goroot {
2294 prefixMapFlag := "-fdebug-prefix-map"
2295 if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") {
2296 prefixMapFlag = "-ffile-prefix-map"
2297 }
2298
2299
2300
2301 var from, toPath string
2302 if m := p.Module; m == nil {
2303 if p.Root == "" {
2304 from = p.Dir
2305 toPath = p.ImportPath
2306 } else if p.Goroot {
2307 from = p.Root
2308 toPath = "GOROOT"
2309 } else {
2310 from = p.Root
2311 toPath = "GOPATH"
2312 }
2313 } else if m.Dir == "" {
2314
2315
2316 from = b.getVendorDir()
2317 toPath = "vendor"
2318 } else {
2319 from = m.Dir
2320 toPath = m.Path
2321 if m.Version != "" {
2322 toPath += "@" + m.Version
2323 }
2324 }
2325
2326
2327
2328 var to string
2329 if cfg.BuildContext.GOOS == "windows" {
2330 to = filepath.Join(`\\_\_`, toPath)
2331 } else {
2332 to = filepath.Join("/_", toPath)
2333 }
2334 flags = append(slices.Clip(flags), prefixMapFlag+"="+from+"="+to)
2335 }
2336 }
2337
2338
2339
2340 if b.gccSupportsFlag(compiler, "-frandom-seed=1") {
2341 flags = append(flags, "-frandom-seed="+buildid.HashToString(a.actionID))
2342 }
2343
2344 overlayPath := file
2345 if p, ok := a.nonGoOverlay[overlayPath]; ok {
2346 overlayPath = p
2347 }
2348 output, err := sh.runOut(filepath.Dir(overlayPath), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(overlayPath))
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358 if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
2359 newFlags := make([]string, 0, len(flags))
2360 for _, f := range flags {
2361 if !strings.HasPrefix(f, "-g") {
2362 newFlags = append(newFlags, f)
2363 }
2364 }
2365 if len(newFlags) < len(flags) {
2366 return b.ccompile(a, outfile, newFlags, file, compiler)
2367 }
2368 }
2369
2370 if len(output) > 0 && err == nil && os.Getenv("GO_BUILDER_NAME") != "" {
2371 output = append(output, "C compiler warning promoted to error on Go builders\n"...)
2372 err = errors.New("warning promoted to error")
2373 }
2374
2375 return sh.reportCmd("", "", output, err)
2376 }
2377
2378
2379 func (b *Builder) gccld(a *Action, objdir, outfile string, flags []string, objs []string) error {
2380 p := a.Package
2381 sh := b.Shell(a)
2382 var cmd []string
2383 if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
2384 cmd = b.GxxCmd(p.Dir, objdir)
2385 } else {
2386 cmd = b.GccCmd(p.Dir, objdir)
2387 }
2388
2389 cmdargs := []any{cmd, "-o", outfile, objs, flags}
2390 _, err := sh.runOut(base.Cwd(), b.cCompilerEnv(), cmdargs...)
2391
2392
2393
2394 if cfg.BuildN || cfg.BuildX {
2395 saw := "succeeded"
2396 if err != nil {
2397 saw = "failed"
2398 }
2399 sh.ShowCmd("", "%s # test for internal linking errors (%s)", joinUnambiguously(str.StringList(cmdargs...)), saw)
2400 }
2401
2402 return err
2403 }
2404
2405
2406
2407 func (b *Builder) GccCmd(incdir, workdir string) []string {
2408 return b.compilerCmd(b.ccExe(), incdir, workdir)
2409 }
2410
2411
2412
2413 func (b *Builder) GxxCmd(incdir, workdir string) []string {
2414 return b.compilerCmd(b.cxxExe(), incdir, workdir)
2415 }
2416
2417
2418 func (b *Builder) gfortranCmd(incdir, workdir string) []string {
2419 return b.compilerCmd(b.fcExe(), incdir, workdir)
2420 }
2421
2422
2423 func (b *Builder) ccExe() []string {
2424 return envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
2425 }
2426
2427
2428 func (b *Builder) cxxExe() []string {
2429 return envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
2430 }
2431
2432
2433 func (b *Builder) fcExe() []string {
2434 return envList("FC", "gfortran")
2435 }
2436
2437
2438
2439 func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string {
2440 a := append(compiler, "-I", incdir)
2441
2442
2443
2444 if cfg.Goos != "windows" {
2445 a = append(a, "-fPIC")
2446 }
2447 a = append(a, b.gccArchArgs()...)
2448
2449
2450 if cfg.BuildContext.CgoEnabled {
2451 switch cfg.Goos {
2452 case "windows":
2453 a = append(a, "-mthreads")
2454 default:
2455 a = append(a, "-pthread")
2456 }
2457 }
2458
2459 if cfg.Goos == "aix" {
2460
2461 a = append(a, "-mcmodel=large")
2462 }
2463
2464
2465 if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") {
2466 a = append(a, "-fno-caret-diagnostics")
2467 }
2468
2469 if b.gccSupportsFlag(compiler, "-Qunused-arguments") {
2470 a = append(a, "-Qunused-arguments")
2471 }
2472
2473
2474
2475
2476 if b.gccSupportsFlag(compiler, "-Wl,--no-gc-sections") {
2477 a = append(a, "-Wl,--no-gc-sections")
2478 }
2479
2480
2481 a = append(a, "-fmessage-length=0")
2482
2483
2484 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
2485 if workdir == "" {
2486 workdir = b.WorkDir
2487 }
2488 workdir = strings.TrimSuffix(workdir, string(filepath.Separator))
2489 if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") {
2490 a = append(a, "-ffile-prefix-map="+workdir+"=/tmp/go-build")
2491 } else {
2492 a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build")
2493 }
2494 }
2495
2496
2497
2498 if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") {
2499 a = append(a, "-gno-record-gcc-switches")
2500 }
2501
2502
2503
2504
2505 if cfg.Goos == "darwin" || cfg.Goos == "ios" {
2506 a = append(a, "-fno-common")
2507 }
2508
2509 return a
2510 }
2511
2512
2513
2514
2515
2516 func (b *Builder) gccNoPie(linker []string) string {
2517 if b.gccSupportsFlag(linker, "-no-pie") {
2518 return "-no-pie"
2519 }
2520 if b.gccSupportsFlag(linker, "-nopie") {
2521 return "-nopie"
2522 }
2523 return ""
2524 }
2525
2526
2527 func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
2528
2529
2530
2531 sh := b.BackgroundShell()
2532
2533 key := [2]string{compiler[0], flag}
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551 tmp := os.DevNull
2552 if runtime.GOOS == "windows" || runtime.GOOS == "ios" {
2553 f, err := os.CreateTemp(b.WorkDir, "")
2554 if err != nil {
2555 return false
2556 }
2557 f.Close()
2558 tmp = f.Name()
2559 defer os.Remove(tmp)
2560 }
2561
2562 cmdArgs := str.StringList(compiler, flag)
2563 if strings.HasPrefix(flag, "-Wl,") {
2564 ldflags, err := buildFlags("LDFLAGS", DefaultCFlags, nil, checkLinkerFlags)
2565 if err != nil {
2566 return false
2567 }
2568 cmdArgs = append(cmdArgs, ldflags...)
2569 } else {
2570 cflags, err := buildFlags("CFLAGS", DefaultCFlags, nil, checkCompilerFlags)
2571 if err != nil {
2572 return false
2573 }
2574 cmdArgs = append(cmdArgs, cflags...)
2575 cmdArgs = append(cmdArgs, "-c")
2576 }
2577
2578 cmdArgs = append(cmdArgs, "-x", "c", "-", "-o", tmp)
2579
2580 if cfg.BuildN {
2581 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
2582 return false
2583 }
2584
2585
2586 compilerID, cacheOK := b.gccCompilerID(compiler[0])
2587
2588 b.exec.Lock()
2589 defer b.exec.Unlock()
2590 if b, ok := b.flagCache[key]; ok {
2591 return b
2592 }
2593 if b.flagCache == nil {
2594 b.flagCache = make(map[[2]string]bool)
2595 }
2596
2597
2598 var flagID cache.ActionID
2599 if cacheOK {
2600 flagID = cache.Subkey(compilerID, "gccSupportsFlag "+flag)
2601 if data, _, err := cache.GetBytes(cache.Default(), flagID); err == nil {
2602 supported := string(data) == "true"
2603 b.flagCache[key] = supported
2604 return supported
2605 }
2606 }
2607
2608 if cfg.BuildX {
2609 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
2610 }
2611 cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
2612 cmd.Dir = b.WorkDir
2613 cmd.Env = append(cmd.Environ(), "LC_ALL=C")
2614 out, _ := cmd.CombinedOutput()
2615
2616
2617
2618
2619
2620
2621 supported := !bytes.Contains(out, []byte("unrecognized")) &&
2622 !bytes.Contains(out, []byte("unknown")) &&
2623 !bytes.Contains(out, []byte("unrecognised")) &&
2624 !bytes.Contains(out, []byte("is not supported")) &&
2625 !bytes.Contains(out, []byte("not recognized")) &&
2626 !bytes.Contains(out, []byte("unsupported"))
2627
2628 if cacheOK {
2629 s := "false"
2630 if supported {
2631 s = "true"
2632 }
2633 cache.PutBytes(cache.Default(), flagID, []byte(s))
2634 }
2635
2636 b.flagCache[key] = supported
2637 return supported
2638 }
2639
2640
2641 func statString(info os.FileInfo) string {
2642 return fmt.Sprintf("stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
2643 }
2644
2645
2646
2647
2648
2649
2650 func (b *Builder) gccCompilerID(compiler string) (id cache.ActionID, ok bool) {
2651
2652
2653
2654 sh := b.BackgroundShell()
2655
2656 if cfg.BuildN {
2657 sh.ShowCmd(b.WorkDir, "%s || true", joinUnambiguously([]string{compiler, "--version"}))
2658 return cache.ActionID{}, false
2659 }
2660
2661 b.exec.Lock()
2662 defer b.exec.Unlock()
2663
2664 if id, ok := b.gccCompilerIDCache[compiler]; ok {
2665 return id, ok
2666 }
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682 exe, err := pathcache.LookPath(compiler)
2683 if err != nil {
2684 return cache.ActionID{}, false
2685 }
2686
2687 h := cache.NewHash("gccCompilerID")
2688 fmt.Fprintf(h, "gccCompilerID %q", exe)
2689 key := h.Sum()
2690 data, _, err := cache.GetBytes(cache.Default(), key)
2691 if err == nil && len(data) > len(id) {
2692 stats := strings.Split(string(data[:len(data)-len(id)]), "\x00")
2693 if len(stats)%2 != 0 {
2694 goto Miss
2695 }
2696 for i := 0; i+2 <= len(stats); i++ {
2697 info, err := os.Stat(stats[i])
2698 if err != nil || statString(info) != stats[i+1] {
2699 goto Miss
2700 }
2701 }
2702 copy(id[:], data[len(data)-len(id):])
2703 return id, true
2704 Miss:
2705 }
2706
2707
2708
2709
2710
2711
2712 toolID, exe2, err := b.gccToolID(compiler, "c")
2713 if err != nil {
2714 return cache.ActionID{}, false
2715 }
2716
2717 exes := []string{exe, exe2}
2718 str.Uniq(&exes)
2719 fmt.Fprintf(h, "gccCompilerID %q %q\n", exes, toolID)
2720 id = h.Sum()
2721
2722 var buf bytes.Buffer
2723 for _, exe := range exes {
2724 if exe == "" {
2725 continue
2726 }
2727 info, err := os.Stat(exe)
2728 if err != nil {
2729 return cache.ActionID{}, false
2730 }
2731 buf.WriteString(exe)
2732 buf.WriteString("\x00")
2733 buf.WriteString(statString(info))
2734 buf.WriteString("\x00")
2735 }
2736 buf.Write(id[:])
2737
2738 cache.PutBytes(cache.Default(), key, buf.Bytes())
2739 if b.gccCompilerIDCache == nil {
2740 b.gccCompilerIDCache = make(map[string]cache.ActionID)
2741 }
2742 b.gccCompilerIDCache[compiler] = id
2743 return id, true
2744 }
2745
2746
2747 func (b *Builder) gccArchArgs() []string {
2748 switch cfg.Goarch {
2749 case "386":
2750 return []string{"-m32"}
2751 case "amd64":
2752 if cfg.Goos == "darwin" {
2753 return []string{"-arch", "x86_64", "-m64"}
2754 }
2755 return []string{"-m64"}
2756 case "arm64":
2757 if cfg.Goos == "darwin" {
2758 return []string{"-arch", "arm64"}
2759 }
2760 case "arm":
2761 return []string{"-marm"}
2762 case "s390x":
2763
2764 return []string{"-m64", "-march=z13"}
2765 case "mips64", "mips64le":
2766 args := []string{"-mabi=64"}
2767 if cfg.GOMIPS64 == "hardfloat" {
2768 return append(args, "-mhard-float")
2769 } else if cfg.GOMIPS64 == "softfloat" {
2770 return append(args, "-msoft-float")
2771 }
2772 case "mips", "mipsle":
2773 args := []string{"-mabi=32", "-march=mips32"}
2774 if cfg.GOMIPS == "hardfloat" {
2775 return append(args, "-mhard-float", "-mfp32", "-mno-odd-spreg")
2776 } else if cfg.GOMIPS == "softfloat" {
2777 return append(args, "-msoft-float")
2778 }
2779 case "loong64":
2780 return []string{"-mabi=lp64d"}
2781 case "ppc64":
2782 if cfg.Goos == "aix" {
2783 return []string{"-maix64"}
2784 }
2785 }
2786 return nil
2787 }
2788
2789
2790
2791
2792
2793
2794
2795 func envList(key, def string) []string {
2796 v := cfg.Getenv(key)
2797 if v == "" {
2798 v = def
2799 }
2800 args, err := quoted.Split(v)
2801 if err != nil {
2802 panic(fmt.Sprintf("could not parse environment variable %s with value %q: %v", key, v, err))
2803 }
2804 return args
2805 }
2806
2807
2808 func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) {
2809 if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
2810 return
2811 }
2812 if cflags, err = buildFlags("CFLAGS", DefaultCFlags, p.CgoCFLAGS, checkCompilerFlags); err != nil {
2813 return
2814 }
2815 if cxxflags, err = buildFlags("CXXFLAGS", DefaultCFlags, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
2816 return
2817 }
2818 if fflags, err = buildFlags("FFLAGS", DefaultCFlags, p.CgoFFLAGS, checkCompilerFlags); err != nil {
2819 return
2820 }
2821 if ldflags, err = buildFlags("LDFLAGS", DefaultCFlags, p.CgoLDFLAGS, checkLinkerFlags); err != nil {
2822 return
2823 }
2824
2825 return
2826 }
2827
2828 func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) {
2829 if err := check(name, "#cgo "+name, fromPackage); err != nil {
2830 return nil, err
2831 }
2832 return str.StringList(envList("CGO_"+name, defaults), fromPackage), nil
2833 }
2834
2835 var cgoRe = lazyregexp.New(`[/\\:]`)
2836
2837 type runCgoProvider struct {
2838 CFLAGS, CXXFLAGS, FFLAGS, LDFLAGS []string
2839 notCompatibleForInternalLinking bool
2840 nonGoOverlay map[string]string
2841 goFiles []string
2842 }
2843
2844 func (pr *runCgoProvider) cflags() []string {
2845 return pr.CFLAGS
2846 }
2847
2848 func (pr *runCgoProvider) cxxflags() []string {
2849 return pr.CXXFLAGS
2850 }
2851
2852 func (pr *runCgoProvider) fflags() []string {
2853 return pr.CXXFLAGS
2854 }
2855
2856 func (pr *runCgoProvider) ldflags() []string {
2857 return pr.LDFLAGS
2858 }
2859
2860 func mustGetCoverInfo(a *Action) *coverProvider {
2861 for _, dep := range a.Deps {
2862 if dep.Mode == "cover" {
2863 return dep.Provider.(*coverProvider)
2864 }
2865 }
2866 base.Fatalf("internal error: cover provider not found")
2867 panic("unreachable")
2868 }
2869
2870 func (b *Builder) runCgo(ctx context.Context, a *Action) error {
2871 p := a.Package
2872 sh := b.Shell(a)
2873 objdir := a.Objdir
2874
2875 if err := sh.Mkdir(objdir); err != nil {
2876 return err
2877 }
2878
2879 nonGoFileLists := [][]string{p.CFiles, p.SFiles, p.CXXFiles, p.HFiles, p.FFiles}
2880 if err := b.computeNonGoOverlay(a, p, sh, objdir, nonGoFileLists); err != nil {
2881 return err
2882 }
2883
2884 cgofiles := slices.Clip(p.CgoFiles)
2885 if a.Package.Internal.Cover.Mode != "" {
2886 cp := mustGetCoverInfo(a)
2887 cgofiles = cp.cgoSources
2888 }
2889
2890 pcCFLAGS, pcLDFLAGS, err := b.getPkgConfigFlags(a, p)
2891 if err != nil {
2892 return err
2893 }
2894
2895
2896
2897
2898
2899
2900
2901 if p.UsesSwig() {
2902 if err := b.swig(a, objdir, pcCFLAGS); err != nil {
2903 return err
2904 }
2905 outGo, _, _ := b.swigOutputs(p, objdir)
2906 cgofiles = append(cgofiles, outGo...)
2907 }
2908
2909 cgoExe := base.Tool("cgo")
2910 cgofiles = mkAbsFiles(p.Dir, cgofiles)
2911
2912 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p)
2913 if err != nil {
2914 return err
2915 }
2916
2917 cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
2918 cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
2919
2920 if len(p.MFiles) > 0 {
2921 cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
2922 }
2923
2924
2925
2926
2927 if len(p.FFiles) > 0 {
2928 fc := cfg.Getenv("FC")
2929 if fc == "" {
2930 fc = "gfortran"
2931 }
2932 if strings.Contains(fc, "gfortran") {
2933 cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
2934 }
2935 }
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952 flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"}
2953 flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS}
2954 notCompatibleWithInternalLinking := flagsNotCompatibleWithInternalLinking(flagSources, flagLists)
2955
2956 if cfg.BuildMSan {
2957 cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
2958 cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
2959 }
2960 if cfg.BuildASan {
2961 cgoCFLAGS = append([]string{"-fsanitize=address"}, cgoCFLAGS...)
2962 cgoLDFLAGS = append([]string{"-fsanitize=address"}, cgoLDFLAGS...)
2963 }
2964
2965
2966
2967 cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir)
2968
2969
2970
2971 gofiles := []string{objdir + "_cgo_gotypes.go"}
2972 cfiles := []string{objdir + "_cgo_export.c"}
2973 for _, fn := range cgofiles {
2974 f := strings.TrimSuffix(filepath.Base(fn), ".go")
2975 gofiles = append(gofiles, objdir+f+".cgo1.go")
2976 cfiles = append(cfiles, objdir+f+".cgo2.c")
2977 }
2978
2979
2980
2981 cgoflags := []string{}
2982 if p.Standard && p.ImportPath == "runtime/cgo" {
2983 cgoflags = append(cgoflags, "-import_runtime_cgo=false")
2984 }
2985 if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo" || p.ImportPath == "runtime/asan") {
2986 cgoflags = append(cgoflags, "-import_syscall=false")
2987 }
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999 cgoenv := b.cCompilerEnv()
3000 cgoenv = append(cgoenv, cfgChangedEnv...)
3001 var ldflagsOption []string
3002 if len(cgoLDFLAGS) > 0 {
3003 flags := make([]string, len(cgoLDFLAGS))
3004 for i, f := range cgoLDFLAGS {
3005 flags[i] = strconv.Quote(f)
3006 }
3007 ldflagsOption = []string{"-ldflags=" + strings.Join(flags, " ")}
3008
3009
3010 cgoenv = append(cgoenv, "CGO_LDFLAGS=")
3011 }
3012
3013 if cfg.BuildToolchainName == "gccgo" {
3014 if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") {
3015 cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
3016 }
3017 cgoflags = append(cgoflags, "-gccgo")
3018 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
3019 cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
3020 }
3021 if !BuildToolchain.(gccgoToolchain).supportsCgoIncomplete(b, a) {
3022 cgoflags = append(cgoflags, "-gccgo_define_cgoincomplete")
3023 }
3024 }
3025
3026 switch cfg.BuildBuildmode {
3027 case "c-archive", "c-shared":
3028
3029
3030
3031 cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h")
3032 }
3033
3034
3035
3036 var trimpath []string
3037 for i := range cgofiles {
3038 path := mkAbs(p.Dir, cgofiles[i])
3039 if fsys.Replaced(path) {
3040 actual := fsys.Actual(path)
3041 cgofiles[i] = actual
3042 trimpath = append(trimpath, actual+"=>"+path)
3043 }
3044 }
3045 if len(trimpath) > 0 {
3046 cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";"))
3047 }
3048
3049 if err := sh.run(p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, ldflagsOption, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil {
3050 return err
3051 }
3052
3053 a.Provider = &runCgoProvider{
3054 CFLAGS: str.StringList(cgoCPPFLAGS, cgoCFLAGS),
3055 CXXFLAGS: str.StringList(cgoCPPFLAGS, cgoCXXFLAGS),
3056 FFLAGS: str.StringList(cgoCPPFLAGS, cgoFFLAGS),
3057 LDFLAGS: cgoLDFLAGS,
3058 notCompatibleForInternalLinking: notCompatibleWithInternalLinking,
3059 nonGoOverlay: a.nonGoOverlay,
3060 goFiles: gofiles,
3061 }
3062
3063 return nil
3064 }
3065
3066 func (b *Builder) processCgoOutputs(a *Action, runCgoProvider *runCgoProvider, cgoExe, objdir string) (outGo, outObj []string, err error) {
3067 outGo = slices.Clip(runCgoProvider.goFiles)
3068
3069
3070
3071
3072
3073
3074
3075
3076 sh := b.Shell(a)
3077
3078
3079
3080 if runCgoProvider.notCompatibleForInternalLinking {
3081 tokenFile := objdir + "preferlinkext"
3082 if err := sh.writeFile(tokenFile, nil); err != nil {
3083 return nil, nil, err
3084 }
3085 outObj = append(outObj, tokenFile)
3086 }
3087
3088 var collectAction *Action
3089 for _, dep := range a.Deps {
3090 if dep.Mode == "collect cgo" {
3091 collectAction = dep
3092 }
3093 }
3094 if collectAction == nil {
3095 base.Fatalf("internal error: no cgo collect action")
3096 }
3097 for _, dep := range collectAction.Deps {
3098 outObj = append(outObj, dep.Target)
3099 }
3100
3101 switch cfg.BuildToolchainName {
3102 case "gc":
3103 importGo := objdir + "_cgo_import.go"
3104 dynOutGo, dynOutObj, err := b.dynimport(a, objdir, importGo, cgoExe, runCgoProvider.CFLAGS, runCgoProvider.LDFLAGS, outObj)
3105 if err != nil {
3106 return nil, nil, err
3107 }
3108 if dynOutGo != "" {
3109 outGo = append(outGo, dynOutGo)
3110 }
3111 if dynOutObj != "" {
3112 outObj = append(outObj, dynOutObj)
3113 }
3114
3115 case "gccgo":
3116 defunC := objdir + "_cgo_defun.c"
3117 defunObj := objdir + "_cgo_defun.o"
3118 if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil {
3119 return nil, nil, err
3120 }
3121 outObj = append(outObj, defunObj)
3122
3123 default:
3124 noCompiler()
3125 }
3126
3127
3128
3129
3130
3131
3132 if cfg.BuildToolchainName == "gc" && !cfg.BuildN {
3133 var flags []string
3134 for _, f := range outGo {
3135 if !strings.HasPrefix(filepath.Base(f), "_cgo_") {
3136 continue
3137 }
3138
3139 src, err := os.ReadFile(f)
3140 if err != nil {
3141 return nil, nil, err
3142 }
3143
3144 const cgoLdflag = "//go:cgo_ldflag"
3145 idx := bytes.Index(src, []byte(cgoLdflag))
3146 for idx >= 0 {
3147
3148
3149 start := bytes.LastIndex(src[:idx], []byte("\n"))
3150 if start == -1 {
3151 start = 0
3152 }
3153
3154
3155 end := bytes.Index(src[idx:], []byte("\n"))
3156 if end == -1 {
3157 end = len(src)
3158 } else {
3159 end += idx
3160 }
3161
3162
3163
3164
3165
3166 commentStart := bytes.Index(src[start:], []byte("//"))
3167 commentStart += start
3168
3169
3170 if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) {
3171
3172
3173 flag := string(src[idx+len(cgoLdflag) : end])
3174 flag = strings.TrimSpace(flag)
3175 flag = strings.Trim(flag, `"`)
3176 flags = append(flags, flag)
3177 }
3178 src = src[end:]
3179 idx = bytes.Index(src, []byte(cgoLdflag))
3180 }
3181 }
3182
3183
3184 if len(runCgoProvider.LDFLAGS) > 0 {
3185 outer:
3186 for i := range flags {
3187 for j, f := range runCgoProvider.LDFLAGS {
3188 if f != flags[i+j] {
3189 continue outer
3190 }
3191 }
3192 flags = append(flags[:i], flags[i+len(runCgoProvider.LDFLAGS):]...)
3193 break
3194 }
3195 }
3196
3197 if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
3198 return nil, nil, err
3199 }
3200 }
3201
3202 return outGo, outObj, nil
3203 }
3204
3205
3206
3207
3208
3209
3210
3211
3212 func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool {
3213 for i := range sourceList {
3214 sn := sourceList[i]
3215 fll := flagListList[i]
3216 if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil {
3217 return true
3218 }
3219 }
3220 return false
3221 }
3222
3223
3224
3225
3226
3227
3228 func (b *Builder) dynimport(a *Action, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) (dynOutGo, dynOutObj string, err error) {
3229 p := a.Package
3230 sh := b.Shell(a)
3231
3232 cfile := objdir + "_cgo_main.c"
3233 ofile := objdir + "_cgo_main.o"
3234 if err := b.gcc(a, objdir, ofile, cflags, cfile); err != nil {
3235 return "", "", err
3236 }
3237
3238
3239 var syso []string
3240 seen := make(map[*Action]bool)
3241 var gatherSyso func(*Action)
3242 gatherSyso = func(a1 *Action) {
3243 if seen[a1] {
3244 return
3245 }
3246 seen[a1] = true
3247 if p1 := a1.Package; p1 != nil {
3248 syso = append(syso, mkAbsFiles(p1.Dir, p1.SysoFiles)...)
3249 }
3250 for _, a2 := range a1.Deps {
3251 gatherSyso(a2)
3252 }
3253 }
3254 gatherSyso(a)
3255 sort.Strings(syso)
3256 str.Uniq(&syso)
3257 linkobj := str.StringList(ofile, outObj, syso)
3258 dynobj := objdir + "_cgo_.o"
3259
3260 ldflags := cgoLDFLAGS
3261 if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" {
3262 if !slices.Contains(ldflags, "-no-pie") {
3263
3264
3265 ldflags = append(ldflags, "-pie")
3266 }
3267 if slices.Contains(ldflags, "-pie") && slices.Contains(ldflags, "-static") {
3268
3269
3270 n := make([]string, 0, len(ldflags)-1)
3271 for _, flag := range ldflags {
3272 if flag != "-static" {
3273 n = append(n, flag)
3274 }
3275 }
3276 ldflags = n
3277 }
3278 }
3279 if err := b.gccld(a, objdir, dynobj, ldflags, linkobj); err != nil {
3280
3281
3282
3283
3284
3285
3286 fail := objdir + "dynimportfail"
3287 if err := sh.writeFile(fail, nil); err != nil {
3288 return "", "", err
3289 }
3290 return "", fail, nil
3291 }
3292
3293
3294 var cgoflags []string
3295 if p.Standard && p.ImportPath == "runtime/cgo" {
3296 cgoflags = []string{"-dynlinker"}
3297 }
3298 err = sh.run(base.Cwd(), p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
3299 if err != nil {
3300 return "", "", err
3301 }
3302 return importGo, "", nil
3303 }
3304
3305
3306
3307
3308 func (b *Builder) swig(a *Action, objdir string, pcCFLAGS []string) error {
3309 p := a.Package
3310
3311 if err := b.swigVersionCheck(); err != nil {
3312 return err
3313 }
3314
3315 intgosize, err := b.swigIntSize(objdir)
3316 if err != nil {
3317 return err
3318 }
3319
3320 for _, f := range p.SwigFiles {
3321 if err := b.swigOne(a, f, objdir, pcCFLAGS, false, intgosize); err != nil {
3322 return err
3323 }
3324 }
3325 for _, f := range p.SwigCXXFiles {
3326 if b.swigOne(a, f, objdir, pcCFLAGS, true, intgosize); err != nil {
3327 return err
3328 }
3329 }
3330 return nil
3331 }
3332
3333 func (b *Builder) swigOutputs(p *load.Package, objdir string) (outGo, outC, outCXX []string) {
3334 for _, f := range p.SwigFiles {
3335 goFile, cFile := swigOneOutputs(f, objdir, false)
3336 outGo = append(outGo, goFile)
3337 outC = append(outC, cFile)
3338 }
3339 for _, f := range p.SwigCXXFiles {
3340 goFile, cxxFile := swigOneOutputs(f, objdir, true)
3341 outGo = append(outGo, goFile)
3342 outCXX = append(outCXX, cxxFile)
3343 }
3344 return outGo, outC, outCXX
3345 }
3346
3347
3348 var (
3349 swigCheckOnce sync.Once
3350 swigCheck error
3351 )
3352
3353 func (b *Builder) swigDoVersionCheck() error {
3354 sh := b.BackgroundShell()
3355 out, err := sh.runOut(".", nil, "swig", "-version")
3356 if err != nil {
3357 return err
3358 }
3359 re := regexp.MustCompile(`[vV]ersion +(\d+)([.]\d+)?([.]\d+)?`)
3360 matches := re.FindSubmatch(out)
3361 if matches == nil {
3362
3363 return nil
3364 }
3365
3366 major, err := strconv.Atoi(string(matches[1]))
3367 if err != nil {
3368
3369 return nil
3370 }
3371 const errmsg = "must have SWIG version >= 3.0.6"
3372 if major < 3 {
3373 return errors.New(errmsg)
3374 }
3375 if major > 3 {
3376
3377 return nil
3378 }
3379
3380
3381 if len(matches[2]) > 0 {
3382 minor, err := strconv.Atoi(string(matches[2][1:]))
3383 if err != nil {
3384 return nil
3385 }
3386 if minor > 0 {
3387
3388 return nil
3389 }
3390 }
3391
3392
3393 if len(matches[3]) > 0 {
3394 patch, err := strconv.Atoi(string(matches[3][1:]))
3395 if err != nil {
3396 return nil
3397 }
3398 if patch < 6 {
3399
3400 return errors.New(errmsg)
3401 }
3402 }
3403
3404 return nil
3405 }
3406
3407 func (b *Builder) swigVersionCheck() error {
3408 swigCheckOnce.Do(func() {
3409 swigCheck = b.swigDoVersionCheck()
3410 })
3411 return swigCheck
3412 }
3413
3414
3415 var (
3416 swigIntSizeOnce sync.Once
3417 swigIntSize string
3418 swigIntSizeError error
3419 )
3420
3421
3422 const swigIntSizeCode = `
3423 package main
3424 const i int = 1 << 32
3425 `
3426
3427
3428
3429 func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
3430 if cfg.BuildN {
3431 return "$INTBITS", nil
3432 }
3433 src := filepath.Join(b.WorkDir, "swig_intsize.go")
3434 if err = os.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil {
3435 return
3436 }
3437 srcs := []string{src}
3438
3439 p := load.GoFilesPackage(modload.NewState(), context.TODO(), load.PackageOpts{}, srcs)
3440
3441 if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, "", srcs); e != nil {
3442 return "32", nil
3443 }
3444 return "64", nil
3445 }
3446
3447
3448
3449 func (b *Builder) swigIntSize(objdir string) (intsize string, err error) {
3450 swigIntSizeOnce.Do(func() {
3451 swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir)
3452 })
3453 return swigIntSize, swigIntSizeError
3454 }
3455
3456
3457 func (b *Builder) swigOne(a *Action, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) error {
3458 p := a.Package
3459 sh := b.Shell(a)
3460
3461 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p)
3462 if err != nil {
3463 return err
3464 }
3465
3466 var cflags []string
3467 if cxx {
3468 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
3469 } else {
3470 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS)
3471 }
3472
3473 base := swigBase(file, cxx)
3474 newGoFile, outC := swigOneOutputs(file, objdir, cxx)
3475
3476 gccgo := cfg.BuildToolchainName == "gccgo"
3477
3478
3479 args := []string{
3480 "-go",
3481 "-cgo",
3482 "-intgosize", intgosize,
3483 "-module", base,
3484 "-o", outC,
3485 "-outdir", objdir,
3486 }
3487
3488 for _, f := range cflags {
3489 if len(f) > 3 && f[:2] == "-I" {
3490 args = append(args, f)
3491 }
3492 }
3493
3494 if gccgo {
3495 args = append(args, "-gccgo")
3496 if pkgpath := gccgoPkgpath(p); pkgpath != "" {
3497 args = append(args, "-go-pkgpath", pkgpath)
3498 }
3499 }
3500 if cxx {
3501 args = append(args, "-c++")
3502 }
3503
3504 out, err := sh.runOut(p.Dir, nil, "swig", args, file)
3505 if err != nil && (bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo"))) {
3506 return errors.New("must have SWIG version >= 3.0.6")
3507 }
3508 if err := sh.reportCmd("", "", out, err); err != nil {
3509 return err
3510 }
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520 goFile := objdir + base + ".go"
3521 if cfg.BuildX || cfg.BuildN {
3522 sh.ShowCmd("", "mv %s %s", goFile, newGoFile)
3523 }
3524 if !cfg.BuildN {
3525 if err := os.Rename(goFile, newGoFile); err != nil {
3526 return err
3527 }
3528 }
3529
3530 return nil
3531 }
3532
3533 func swigBase(file string, cxx bool) string {
3534 n := 5
3535 if cxx {
3536 n = 8
3537 }
3538 return file[:len(file)-n]
3539 }
3540
3541 func swigOneOutputs(file, objdir string, cxx bool) (outGo, outC string) {
3542 base := swigBase(file, cxx)
3543 gccBase := base + "_wrap."
3544 gccExt := "c"
3545 if cxx {
3546 gccExt = "cxx"
3547 }
3548
3549 newGoFile := objdir + "_" + base + "_swig.go"
3550 cFile := objdir + gccBase + gccExt
3551 return newGoFile, cFile
3552 }
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564 func (b *Builder) disableBuildID(ldflags []string) []string {
3565 switch cfg.Goos {
3566 case "android", "dragonfly", "linux", "netbsd":
3567 ldflags = append(ldflags, "-Wl,--build-id=none")
3568 }
3569 return ldflags
3570 }
3571
3572
3573
3574
3575 func mkAbsFiles(dir string, files []string) []string {
3576 abs := make([]string, len(files))
3577 for i, f := range files {
3578 if !filepath.IsAbs(f) {
3579 f = filepath.Join(dir, f)
3580 }
3581 abs[i] = f
3582 }
3583 return abs
3584 }
3585
3586
3587 func actualFiles(files []string) []string {
3588 a := make([]string, len(files))
3589 for i, f := range files {
3590 a[i] = fsys.Actual(f)
3591 }
3592 return a
3593 }
3594
3595
3596
3597
3598
3599
3600
3601
3602 func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) {
3603 cleanup = func() {}
3604
3605 var argLen int
3606 for _, arg := range cmd.Args {
3607 argLen += len(arg)
3608 }
3609
3610
3611
3612 if !useResponseFile(cmd.Path, argLen) {
3613 return
3614 }
3615
3616 tf, err := os.CreateTemp("", "args")
3617 if err != nil {
3618 log.Fatalf("error writing long arguments to response file: %v", err)
3619 }
3620 cleanup = func() { os.Remove(tf.Name()) }
3621 var buf bytes.Buffer
3622 for _, arg := range cmd.Args[1:] {
3623 fmt.Fprintf(&buf, "%s\n", encodeArg(arg))
3624 }
3625 if _, err := tf.Write(buf.Bytes()); err != nil {
3626 tf.Close()
3627 cleanup()
3628 log.Fatalf("error writing long arguments to response file: %v", err)
3629 }
3630 if err := tf.Close(); err != nil {
3631 cleanup()
3632 log.Fatalf("error writing long arguments to response file: %v", err)
3633 }
3634 cmd.Args = []string{cmd.Args[0], "@" + tf.Name()}
3635 return cleanup
3636 }
3637
3638 func useResponseFile(path string, argLen int) bool {
3639
3640
3641
3642 prog := strings.TrimSuffix(filepath.Base(path), ".exe")
3643 switch prog {
3644 case "compile", "link", "cgo", "asm", "cover":
3645 default:
3646 return false
3647 }
3648
3649 if argLen > sys.ExecArgLengthLimit {
3650 return true
3651 }
3652
3653
3654
3655 isBuilder := os.Getenv("GO_BUILDER_NAME") != ""
3656 if isBuilder && rand.Intn(10) == 0 {
3657 return true
3658 }
3659
3660 return false
3661 }
3662
3663
3664 func encodeArg(arg string) string {
3665
3666 if !strings.ContainsAny(arg, "\\\n") {
3667 return arg
3668 }
3669 var b strings.Builder
3670 for _, r := range arg {
3671 switch r {
3672 case '\\':
3673 b.WriteByte('\\')
3674 b.WriteByte('\\')
3675 case '\n':
3676 b.WriteByte('\\')
3677 b.WriteByte('n')
3678 default:
3679 b.WriteRune(r)
3680 }
3681 }
3682 return b.String()
3683 }
3684
View as plain text