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