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