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