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