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