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