github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/work/exec.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Action graph execution. 6 7 package work 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/sha256" 13 "encoding/json" 14 "errors" 15 "fmt" 16 "github.com/bir3/gocompiler/src/internal/coverage" 17 "github.com/bir3/gocompiler/src/internal/lazyregexp" 18 "io" 19 "io/fs" 20 "log" 21 "math/rand" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "regexp" 26 "runtime" 27 "sort" 28 "strconv" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 34 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cache" 35 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 36 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/fsys" 37 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/load" 38 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/modload" 39 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/str" 40 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/trace" 41 "github.com/bir3/gocompiler/src/cmd/internal/quoted" 42 "github.com/bir3/gocompiler/src/cmd/internal/sys" 43 ) 44 45 const defaultCFlags = "-O2 -g" 46 47 // actionList returns the list of actions in the dag rooted at root 48 // as visited in a depth-first post-order traversal. 49 func actionList(root *Action) []*Action { 50 seen := map[*Action]bool{} 51 all := []*Action{} 52 var walk func(*Action) 53 walk = func(a *Action) { 54 if seen[a] { 55 return 56 } 57 seen[a] = true 58 for _, a1 := range a.Deps { 59 walk(a1) 60 } 61 all = append(all, a) 62 } 63 walk(root) 64 return all 65 } 66 67 // do runs the action graph rooted at root. 68 func (b *Builder) Do(ctx context.Context, root *Action) { 69 ctx, span := trace.StartSpan(ctx, "exec.Builder.Do ("+root.Mode+" "+root.Target+")") 70 defer span.Done() 71 72 if !b.IsCmdList { 73 // If we're doing real work, take time at the end to trim the cache. 74 c := cache.Default() 75 defer c.Trim() 76 } 77 78 // Build list of all actions, assigning depth-first post-order priority. 79 // The original implementation here was a true queue 80 // (using a channel) but it had the effect of getting 81 // distracted by low-level leaf actions to the detriment 82 // of completing higher-level actions. The order of 83 // work does not matter much to overall execution time, 84 // but when running "go test std" it is nice to see each test 85 // results as soon as possible. The priorities assigned 86 // ensure that, all else being equal, the execution prefers 87 // to do what it would have done first in a simple depth-first 88 // dependency order traversal. 89 all := actionList(root) 90 for i, a := range all { 91 a.priority = i 92 } 93 94 // Write action graph, without timing information, in case we fail and exit early. 95 writeActionGraph := func() { 96 if file := cfg.DebugActiongraph; file != "" { 97 if strings.HasSuffix(file, ".go") { 98 // Do not overwrite Go source code in: 99 // go build -debug-actiongraph x.go 100 base.Fatalf("go: refusing to write action graph to %v\n", file) 101 } 102 js := actionGraphJSON(root) 103 if err := os.WriteFile(file, []byte(js), 0666); err != nil { 104 fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err) 105 base.SetExitStatus(1) 106 } 107 } 108 } 109 writeActionGraph() 110 111 b.readySema = make(chan bool, len(all)) 112 113 // Initialize per-action execution state. 114 for _, a := range all { 115 for _, a1 := range a.Deps { 116 a1.triggers = append(a1.triggers, a) 117 } 118 a.pending = len(a.Deps) 119 if a.pending == 0 { 120 b.ready.push(a) 121 b.readySema <- true 122 } 123 } 124 125 // Handle runs a single action and takes care of triggering 126 // any actions that are runnable as a result. 127 handle := func(ctx context.Context, a *Action) { 128 if a.json != nil { 129 a.json.TimeStart = time.Now() 130 } 131 var err error 132 if a.Actor != nil && (!a.Failed || a.IgnoreFail) { 133 // TODO(matloob): Better action descriptions 134 desc := "Executing action " 135 if a.Package != nil { 136 desc += "(" + a.Mode + " " + a.Package.Desc() + ")" 137 } 138 ctx, span := trace.StartSpan(ctx, desc) 139 a.traceSpan = span 140 for _, d := range a.Deps { 141 trace.Flow(ctx, d.traceSpan, a.traceSpan) 142 } 143 err = a.Actor.Act(b, ctx, a) 144 span.Done() 145 } 146 if a.json != nil { 147 a.json.TimeDone = time.Now() 148 } 149 150 // The actions run in parallel but all the updates to the 151 // shared work state are serialized through b.exec. 152 b.exec.Lock() 153 defer b.exec.Unlock() 154 155 if err != nil { 156 if b.AllowErrors && a.Package != nil { 157 if a.Package.Error == nil { 158 a.Package.Error = &load.PackageError{Err: err} 159 } 160 } else { 161 var ipe load.ImportPathError 162 if a.Package != nil && (!errors.As(err, &ipe) || ipe.ImportPath() != a.Package.ImportPath) { 163 err = fmt.Errorf("%s: %v", a.Package.ImportPath, err) 164 } 165 base.Errorf("%s", err) 166 } 167 a.Failed = true 168 } 169 170 for _, a0 := range a.triggers { 171 if a.Failed { 172 a0.Failed = true 173 } 174 if a0.pending--; a0.pending == 0 { 175 b.ready.push(a0) 176 b.readySema <- true 177 } 178 } 179 180 if a == root { 181 close(b.readySema) 182 } 183 } 184 185 var wg sync.WaitGroup 186 187 // Kick off goroutines according to parallelism. 188 // If we are using the -n flag (just printing commands) 189 // drop the parallelism to 1, both to make the output 190 // deterministic and because there is no real work anyway. 191 par := cfg.BuildP 192 if cfg.BuildN { 193 par = 1 194 } 195 for i := 0; i < par; i++ { 196 wg.Add(1) 197 go func() { 198 ctx := trace.StartGoroutine(ctx) 199 defer wg.Done() 200 for { 201 select { 202 case _, ok := <-b.readySema: 203 if !ok { 204 return 205 } 206 // Receiving a value from b.readySema entitles 207 // us to take from the ready queue. 208 b.exec.Lock() 209 a := b.ready.pop() 210 b.exec.Unlock() 211 handle(ctx, a) 212 case <-base.Interrupted: 213 base.SetExitStatus(1) 214 return 215 } 216 } 217 }() 218 } 219 220 wg.Wait() 221 222 // Write action graph again, this time with timing information. 223 writeActionGraph() 224 } 225 226 // buildActionID computes the action ID for a build action. 227 func (b *Builder) buildActionID(a *Action) cache.ActionID { 228 p := a.Package 229 h := cache.NewHash("build " + p.ImportPath) 230 231 // Configuration independent of compiler toolchain. 232 // Note: buildmode has already been accounted for in buildGcflags 233 // and should not be inserted explicitly. Most buildmodes use the 234 // same compiler settings and can reuse each other's results. 235 // If not, the reason is already recorded in buildGcflags. 236 fmt.Fprintf(h, "compile\n") 237 238 // Include information about the origin of the package that 239 // may be embedded in the debug info for the object file. 240 if cfg.BuildTrimpath { 241 // When -trimpath is used with a package built from the module cache, 242 // its debug information refers to the module path and version 243 // instead of the directory. 244 if p.Module != nil { 245 fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version) 246 } 247 } else if p.Goroot { 248 // The Go compiler always hides the exact value of $GOROOT 249 // when building things in GOROOT. 250 // 251 // The C compiler does not, but for packages in GOROOT we rewrite the path 252 // as though -trimpath were set, so that we don't invalidate the build cache 253 // (and especially any precompiled C archive files) when changing 254 // GOROOT_FINAL. (See https://go.dev/issue/50183.) 255 // 256 // b.WorkDir is always either trimmed or rewritten to 257 // the literal string "/tmp/go-build". 258 } else if !strings.HasPrefix(p.Dir, b.WorkDir) { 259 // -trimpath is not set and no other rewrite rules apply, 260 // so the object file may refer to the absolute directory 261 // containing the package. 262 fmt.Fprintf(h, "dir %s\n", p.Dir) 263 } 264 265 if p.Module != nil { 266 fmt.Fprintf(h, "go %s\n", p.Module.GoVersion) 267 } 268 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) 269 fmt.Fprintf(h, "import %q\n", p.ImportPath) 270 fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) 271 if cfg.BuildTrimpath { 272 fmt.Fprintln(h, "trimpath") 273 } 274 if p.Internal.ForceLibrary { 275 fmt.Fprintf(h, "forcelibrary\n") 276 } 277 if len(p.CgoFiles)+len(p.SwigFiles)+len(p.SwigCXXFiles) > 0 { 278 fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo")) 279 cppflags, cflags, cxxflags, fflags, ldflags, _ := b.CFlags(p) 280 281 ccExe := b.ccExe() 282 fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags) 283 // Include the C compiler tool ID so that if the C 284 // compiler changes we rebuild the package. 285 if ccID, _, err := b.gccToolID(ccExe[0], "c"); err == nil { 286 fmt.Fprintf(h, "CC ID=%q\n", ccID) 287 } 288 if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { 289 cxxExe := b.cxxExe() 290 fmt.Fprintf(h, "CXX=%q %q\n", cxxExe, cxxflags) 291 if cxxID, _, err := b.gccToolID(cxxExe[0], "c++"); err == nil { 292 fmt.Fprintf(h, "CXX ID=%q\n", cxxID) 293 } 294 } 295 if len(p.FFiles) > 0 { 296 fcExe := b.fcExe() 297 fmt.Fprintf(h, "FC=%q %q\n", fcExe, fflags) 298 if fcID, _, err := b.gccToolID(fcExe[0], "f95"); err == nil { 299 fmt.Fprintf(h, "FC ID=%q\n", fcID) 300 } 301 } 302 // TODO(rsc): Should we include the SWIG version? 303 } 304 if p.Internal.CoverMode != "" { 305 fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover")) 306 } 307 if p.Internal.FuzzInstrument { 308 if fuzzFlags := fuzzInstrumentFlags(); fuzzFlags != nil { 309 fmt.Fprintf(h, "fuzz %q\n", fuzzFlags) 310 } 311 } 312 if p.Internal.BuildInfo != "" { 313 fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo) 314 } 315 316 // Configuration specific to compiler toolchain. 317 switch cfg.BuildToolchainName { 318 default: 319 base.Fatalf("buildActionID: unknown build toolchain %q", cfg.BuildToolchainName) 320 case "gc": 321 fmt.Fprintf(h, "compile %s %q %q\n", b.toolID("compile"), forcedGcflags, p.Internal.Gcflags) 322 if len(p.SFiles) > 0 { 323 fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags) 324 } 325 326 // GOARM, GOMIPS, etc. 327 key, val := cfg.GetArchEnv() 328 fmt.Fprintf(h, "%s=%s\n", key, val) 329 330 if cfg.CleanGOEXPERIMENT != "" { 331 fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT) 332 } 333 334 // TODO(rsc): Convince compiler team not to add more magic environment variables, 335 // or perhaps restrict the environment variables passed to subprocesses. 336 // Because these are clumsy, undocumented special-case hacks 337 // for debugging the compiler, they are not settable using 'go env -w', 338 // and so here we use os.Getenv, not cfg.Getenv. 339 magic := []string{ 340 "GOCLOBBERDEADHASH", 341 "GOSSAFUNC", 342 "GOSSADIR", 343 "GOCOMPILEDEBUG", 344 } 345 for _, env := range magic { 346 if x := os.Getenv(env); x != "" { 347 fmt.Fprintf(h, "magic %s=%s\n", env, x) 348 } 349 } 350 351 case "gccgo": 352 id, _, err := b.gccToolID(BuildToolchain.compiler(), "go") 353 if err != nil { 354 base.Fatalf("%v", err) 355 } 356 fmt.Fprintf(h, "compile %s %q %q\n", id, forcedGccgoflags, p.Internal.Gccgoflags) 357 fmt.Fprintf(h, "pkgpath %s\n", gccgoPkgpath(p)) 358 fmt.Fprintf(h, "ar %q\n", BuildToolchain.(gccgoToolchain).ar()) 359 if len(p.SFiles) > 0 { 360 id, _, _ = b.gccToolID(BuildToolchain.compiler(), "assembler-with-cpp") 361 // Ignore error; different assembler versions 362 // are unlikely to make any difference anyhow. 363 fmt.Fprintf(h, "asm %q\n", id) 364 } 365 } 366 367 // Input files. 368 inputFiles := str.StringList( 369 p.GoFiles, 370 p.CgoFiles, 371 p.CFiles, 372 p.CXXFiles, 373 p.FFiles, 374 p.MFiles, 375 p.HFiles, 376 p.SFiles, 377 p.SysoFiles, 378 p.SwigFiles, 379 p.SwigCXXFiles, 380 p.EmbedFiles, 381 ) 382 for _, file := range inputFiles { 383 fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file))) 384 } 385 if cfg.BuildPGOFile != "" { 386 fmt.Fprintf(h, "pgofile %s\n", b.fileHash(cfg.BuildPGOFile)) 387 } 388 for _, a1 := range a.Deps { 389 p1 := a1.Package 390 if p1 != nil { 391 fmt.Fprintf(h, "import %s %s\n", p1.ImportPath, contentID(a1.buildID)) 392 } 393 } 394 395 return h.Sum() 396 } 397 398 // needCgoHdr reports whether the actions triggered by this one 399 // expect to be able to access the cgo-generated header file. 400 func (b *Builder) needCgoHdr(a *Action) bool { 401 // If this build triggers a header install, run cgo to get the header. 402 if !b.IsCmdList && (a.Package.UsesCgo() || a.Package.UsesSwig()) && (cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared") { 403 for _, t1 := range a.triggers { 404 if t1.Mode == "install header" { 405 return true 406 } 407 } 408 for _, t1 := range a.triggers { 409 for _, t2 := range t1.triggers { 410 if t2.Mode == "install header" { 411 return true 412 } 413 } 414 } 415 } 416 return false 417 } 418 419 // allowedVersion reports whether the version v is an allowed version of go 420 // (one that we can compile). 421 // v is known to be of the form "1.23". 422 func allowedVersion(v string) bool { 423 // Special case: no requirement. 424 if v == "" { 425 return true 426 } 427 // Special case "1.0" means "go1", which is OK. 428 if v == "1.0" { 429 return true 430 } 431 // Otherwise look through release tags of form "go1.23" for one that matches. 432 for _, tag := range cfg.BuildContext.ReleaseTags { 433 if strings.HasPrefix(tag, "go") && tag[2:] == v { 434 return true 435 } 436 } 437 return false 438 } 439 440 const ( 441 needBuild uint32 = 1 << iota 442 needCgoHdr 443 needVet 444 needCompiledGoFiles 445 needStale 446 ) 447 448 // build is the action for building a single package. 449 // Note that any new influence on this logic must be reported in b.buildActionID above as well. 450 func (b *Builder) build(ctx context.Context, a *Action) (err error) { 451 p := a.Package 452 453 bit := func(x uint32, b bool) uint32 { 454 if b { 455 return x 456 } 457 return 0 458 } 459 460 cachedBuild := false 461 need := bit(needBuild, !b.IsCmdList && a.needBuild || b.NeedExport) | 462 bit(needCgoHdr, b.needCgoHdr(a)) | 463 bit(needVet, a.needVet) | 464 bit(needCompiledGoFiles, b.NeedCompiledGoFiles) 465 466 if !p.BinaryOnly { 467 if b.useCache(a, b.buildActionID(a), p.Target, need&needBuild != 0) { 468 // We found the main output in the cache. 469 // If we don't need any other outputs, we can stop. 470 // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr). 471 // Remember that we might have them in cache 472 // and check again after we create a.Objdir. 473 cachedBuild = true 474 a.output = []byte{} // start saving output in case we miss any cache results 475 need &^= needBuild 476 if b.NeedExport { 477 p.Export = a.built 478 p.BuildID = a.buildID 479 } 480 if need&needCompiledGoFiles != 0 { 481 if err := b.loadCachedCompiledGoFiles(a); err == nil { 482 need &^= needCompiledGoFiles 483 } 484 } 485 } 486 487 // Source files might be cached, even if the full action is not 488 // (e.g., go list -compiled -find). 489 if !cachedBuild && need&needCompiledGoFiles != 0 { 490 if err := b.loadCachedCompiledGoFiles(a); err == nil { 491 need &^= needCompiledGoFiles 492 } 493 } 494 495 if need == 0 { 496 return nil 497 } 498 defer b.flushOutput(a) 499 } 500 501 defer func() { 502 if err != nil && b.IsCmdList && b.NeedError && p.Error == nil { 503 p.Error = &load.PackageError{Err: err} 504 } 505 }() 506 if cfg.BuildN { 507 // In -n mode, print a banner between packages. 508 // The banner is five lines so that when changes to 509 // different sections of the bootstrap script have to 510 // be merged, the banners give patch something 511 // to use to find its context. 512 b.Print("\n#\n# " + p.ImportPath + "\n#\n\n") 513 } 514 515 if cfg.BuildV { 516 b.Print(p.ImportPath + "\n") 517 } 518 519 if p.Error != nil { 520 // Don't try to build anything for packages with errors. There may be a 521 // problem with the inputs that makes the package unsafe to build. 522 return p.Error 523 } 524 525 if p.BinaryOnly { 526 p.Stale = true 527 p.StaleReason = "binary-only packages are no longer supported" 528 if b.IsCmdList { 529 return nil 530 } 531 return errors.New("binary-only packages are no longer supported") 532 } 533 534 if err := b.Mkdir(a.Objdir); err != nil { 535 return err 536 } 537 objdir := a.Objdir 538 539 // Load cached cgo header, but only if we're skipping the main build (cachedBuild==true). 540 if cachedBuild && need&needCgoHdr != 0 { 541 if err := b.loadCachedCgoHdr(a); err == nil { 542 need &^= needCgoHdr 543 } 544 } 545 546 // Load cached vet config, but only if that's all we have left 547 // (need == needVet, not testing just the one bit). 548 // If we are going to do a full build anyway, 549 // we're going to regenerate the files below anyway. 550 if need == needVet { 551 if err := b.loadCachedVet(a); err == nil { 552 need &^= needVet 553 } 554 } 555 if need == 0 { 556 return nil 557 } 558 559 if err := AllowInstall(a); err != nil { 560 return err 561 } 562 563 // make target directory 564 dir, _ := filepath.Split(a.Target) 565 if dir != "" { 566 if err := b.Mkdir(dir); err != nil { 567 return err 568 } 569 } 570 571 gofiles := str.StringList(p.GoFiles) 572 cgofiles := str.StringList(p.CgoFiles) 573 cfiles := str.StringList(p.CFiles) 574 sfiles := str.StringList(p.SFiles) 575 cxxfiles := str.StringList(p.CXXFiles) 576 var objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string 577 578 if p.UsesCgo() || p.UsesSwig() { 579 if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(p); err != nil { 580 return 581 } 582 } 583 584 // Compute overlays for .c/.cc/.h/etc. and if there are any overlays 585 // put correct contents of all those files in the objdir, to ensure 586 // the correct headers are included. nonGoOverlay is the overlay that 587 // points from nongo files to the copied files in objdir. 588 nonGoFileLists := [][]string{p.CFiles, p.SFiles, p.CXXFiles, p.HFiles, p.FFiles} 589 OverlayLoop: 590 for _, fs := range nonGoFileLists { 591 for _, f := range fs { 592 if _, ok := fsys.OverlayPath(mkAbs(p.Dir, f)); ok { 593 a.nonGoOverlay = make(map[string]string) 594 break OverlayLoop 595 } 596 } 597 } 598 if a.nonGoOverlay != nil { 599 for _, fs := range nonGoFileLists { 600 for i := range fs { 601 from := mkAbs(p.Dir, fs[i]) 602 opath, _ := fsys.OverlayPath(from) 603 dst := objdir + filepath.Base(fs[i]) 604 if err := b.copyFile(dst, opath, 0666, false); err != nil { 605 return err 606 } 607 a.nonGoOverlay[from] = dst 608 } 609 } 610 } 611 612 // Run SWIG on each .swig and .swigcxx file. 613 // Each run will generate two files, a .go file and a .c or .cxx file. 614 // The .go file will use import "C" and is to be processed by cgo. 615 if p.UsesSwig() { 616 outGo, outC, outCXX, err := b.swig(a, p, objdir, pcCFLAGS) 617 if err != nil { 618 return err 619 } 620 cgofiles = append(cgofiles, outGo...) 621 cfiles = append(cfiles, outC...) 622 cxxfiles = append(cxxfiles, outCXX...) 623 } 624 625 // If we're doing coverage, preprocess the .go files and put them in the work directory 626 if p.Internal.CoverMode != "" { 627 outfiles := []string{} 628 infiles := []string{} 629 for i, file := range str.StringList(gofiles, cgofiles) { 630 if base.IsTestFile(file) { 631 continue // Not covering this file. 632 } 633 634 var sourceFile string 635 var coverFile string 636 var key string 637 if base, found := strings.CutSuffix(file, ".cgo1.go"); found { 638 // cgo files have absolute paths 639 base = filepath.Base(base) 640 sourceFile = file 641 coverFile = objdir + base + ".cgo1.go" 642 key = base + ".go" 643 } else { 644 sourceFile = filepath.Join(p.Dir, file) 645 coverFile = objdir + file 646 key = file 647 } 648 coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go" 649 if cfg.Experiment.CoverageRedesign { 650 infiles = append(infiles, sourceFile) 651 outfiles = append(outfiles, coverFile) 652 } else { 653 cover := p.Internal.CoverVars[key] 654 if cover == nil { 655 continue // Not covering this file. 656 } 657 if err := b.cover(a, coverFile, sourceFile, cover.Var); err != nil { 658 return err 659 } 660 } 661 if i < len(gofiles) { 662 gofiles[i] = coverFile 663 } else { 664 cgofiles[i-len(gofiles)] = coverFile 665 } 666 } 667 668 if cfg.Experiment.CoverageRedesign { 669 if len(infiles) != 0 { 670 // Coverage instrumentation creates new top level 671 // variables in the target package for things like 672 // meta-data containers, counter vars, etc. To avoid 673 // collisions with user variables, suffix the var name 674 // with 12 hex digits from the SHA-256 hash of the 675 // import path. Choice of 12 digits is historical/arbitrary, 676 // we just need enough of the hash to avoid accidents, 677 // as opposed to precluding determined attempts by 678 // users to break things. 679 sum := sha256.Sum256([]byte(a.Package.ImportPath)) 680 coverVar := fmt.Sprintf("goCover_%x_", sum[:6]) 681 mode := a.Package.Internal.CoverMode 682 if mode == "" { 683 panic("covermode should be set at this point") 684 } 685 pkgcfg := a.Objdir + "pkgcfg.txt" 686 covoutfiles := a.Objdir + "coveroutfiles.txt" 687 if err := b.cover2(a, pkgcfg, covoutfiles, infiles, outfiles, coverVar, mode); err != nil { 688 return err 689 } 690 } else { 691 // If there are no input files passed to cmd/cover, 692 // then we don't want to pass -covercfg when building 693 // the package with the compiler, so set covermode to 694 // the empty string so as to signal that we need to do 695 // that. 696 p.Internal.CoverMode = "" 697 } 698 } 699 } 700 701 // Run cgo. 702 if p.UsesCgo() || p.UsesSwig() { 703 // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. 704 // There is one exception: runtime/cgo's job is to bridge the 705 // cgo and non-cgo worlds, so it necessarily has files in both. 706 // In that case gcc only gets the gcc_* files. 707 var gccfiles []string 708 gccfiles = append(gccfiles, cfiles...) 709 cfiles = nil 710 if p.Standard && p.ImportPath == "runtime/cgo" { 711 filter := func(files, nongcc, gcc []string) ([]string, []string) { 712 for _, f := range files { 713 if strings.HasPrefix(f, "gcc_") { 714 gcc = append(gcc, f) 715 } else { 716 nongcc = append(nongcc, f) 717 } 718 } 719 return nongcc, gcc 720 } 721 sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles) 722 } else { 723 for _, sfile := range sfiles { 724 data, err := os.ReadFile(filepath.Join(p.Dir, sfile)) 725 if err == nil { 726 if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) || 727 bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) || 728 bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) { 729 return fmt.Errorf("package using cgo has Go assembly file %s", sfile) 730 } 731 } 732 } 733 gccfiles = append(gccfiles, sfiles...) 734 sfiles = nil 735 } 736 737 outGo, outObj, err := b.cgo(a, base.Tool("cgo"), objdir, pcCFLAGS, pcLDFLAGS, mkAbsFiles(p.Dir, cgofiles), gccfiles, cxxfiles, p.MFiles, p.FFiles) 738 739 // The files in cxxfiles have now been handled by b.cgo. 740 cxxfiles = nil 741 742 if err != nil { 743 return err 744 } 745 if cfg.BuildToolchainName == "gccgo" { 746 cgoObjects = append(cgoObjects, a.Objdir+"_cgo_flags") 747 } 748 cgoObjects = append(cgoObjects, outObj...) 749 gofiles = append(gofiles, outGo...) 750 751 switch cfg.BuildBuildmode { 752 case "c-archive", "c-shared": 753 b.cacheCgoHdr(a) 754 } 755 } 756 757 var srcfiles []string // .go and non-.go 758 srcfiles = append(srcfiles, gofiles...) 759 srcfiles = append(srcfiles, sfiles...) 760 srcfiles = append(srcfiles, cfiles...) 761 srcfiles = append(srcfiles, cxxfiles...) 762 b.cacheSrcFiles(a, srcfiles) 763 764 // Running cgo generated the cgo header. 765 need &^= needCgoHdr 766 767 // Sanity check only, since Package.load already checked as well. 768 if len(gofiles) == 0 { 769 return &load.NoGoError{Package: p} 770 } 771 772 // Prepare Go vet config if needed. 773 if need&needVet != 0 { 774 buildVetConfig(a, srcfiles) 775 need &^= needVet 776 } 777 if need&needCompiledGoFiles != 0 { 778 if err := b.loadCachedCompiledGoFiles(a); err != nil { 779 return fmt.Errorf("loading compiled Go files from cache: %w", err) 780 } 781 need &^= needCompiledGoFiles 782 } 783 if need == 0 { 784 // Nothing left to do. 785 return nil 786 } 787 788 // Collect symbol ABI requirements from assembly. 789 symabis, err := BuildToolchain.symabis(b, a, sfiles) 790 if err != nil { 791 return err 792 } 793 794 // Prepare Go import config. 795 // We start it off with a comment so it can't be empty, so icfg.Bytes() below is never nil. 796 // It should never be empty anyway, but there have been bugs in the past that resulted 797 // in empty configs, which then unfortunately turn into "no config passed to compiler", 798 // and the compiler falls back to looking in pkg itself, which mostly works, 799 // except when it doesn't. 800 var icfg bytes.Buffer 801 fmt.Fprintf(&icfg, "# import config\n") 802 for i, raw := range p.Internal.RawImports { 803 final := p.Imports[i] 804 if final != raw { 805 fmt.Fprintf(&icfg, "importmap %s=%s\n", raw, final) 806 } 807 } 808 for _, a1 := range a.Deps { 809 p1 := a1.Package 810 if p1 == nil || p1.ImportPath == "" || a1.built == "" { 811 continue 812 } 813 fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) 814 } 815 816 // Prepare Go embed config if needed. 817 // Unlike the import config, it's okay for the embed config to be empty. 818 var embedcfg []byte 819 if len(p.Internal.Embed) > 0 { 820 var embed struct { 821 Patterns map[string][]string 822 Files map[string]string 823 } 824 embed.Patterns = p.Internal.Embed 825 embed.Files = make(map[string]string) 826 for _, file := range p.EmbedFiles { 827 embed.Files[file] = filepath.Join(p.Dir, file) 828 } 829 js, err := json.MarshalIndent(&embed, "", "\t") 830 if err != nil { 831 return fmt.Errorf("marshal embedcfg: %v", err) 832 } 833 embedcfg = js 834 } 835 836 if p.Internal.BuildInfo != "" && cfg.ModulesEnabled { 837 prog := modload.ModInfoProg(p.Internal.BuildInfo, cfg.BuildToolchainName == "gccgo") 838 if len(prog) > 0 { 839 if err := b.writeFile(objdir+"_gomod_.go", prog); err != nil { 840 return err 841 } 842 gofiles = append(gofiles, objdir+"_gomod_.go") 843 } 844 } 845 846 // Compile Go. 847 objpkg := objdir + "_pkg_.a" 848 ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), embedcfg, symabis, len(sfiles) > 0, gofiles) 849 if len(out) > 0 { 850 output := b.processOutput(out) 851 if p.Module != nil && !allowedVersion(p.Module.GoVersion) { 852 output += "note: module requires Go " + p.Module.GoVersion + "\n" 853 } 854 855 if err != nil { 856 return formatOutput(b.WorkDir, p.Dir, p.ImportPath, p.Desc(), output) 857 } else { 858 b.showOutput(a, p.Dir, p.Desc(), output) 859 } 860 } 861 if err != nil { 862 if p.Module != nil && !allowedVersion(p.Module.GoVersion) { 863 b.showOutput(a, p.Dir, p.Desc(), "note: module requires Go "+p.Module.GoVersion+"\n") 864 } 865 return err 866 } 867 if ofile != objpkg { 868 objects = append(objects, ofile) 869 } 870 871 // Copy .h files named for goos or goarch or goos_goarch 872 // to names using GOOS and GOARCH. 873 // For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h. 874 _goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch 875 _goos := "_" + cfg.Goos 876 _goarch := "_" + cfg.Goarch 877 for _, file := range p.HFiles { 878 name, ext := fileExtSplit(file) 879 switch { 880 case strings.HasSuffix(name, _goos_goarch): 881 targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext 882 if err := b.copyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil { 883 return err 884 } 885 case strings.HasSuffix(name, _goarch): 886 targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext 887 if err := b.copyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil { 888 return err 889 } 890 case strings.HasSuffix(name, _goos): 891 targ := file[:len(name)-len(_goos)] + "_GOOS." + ext 892 if err := b.copyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil { 893 return err 894 } 895 } 896 } 897 898 for _, file := range cfiles { 899 out := file[:len(file)-len(".c")] + ".o" 900 if err := BuildToolchain.cc(b, a, objdir+out, file); err != nil { 901 return err 902 } 903 objects = append(objects, out) 904 } 905 906 // Assemble .s files. 907 if len(sfiles) > 0 { 908 ofiles, err := BuildToolchain.asm(b, a, sfiles) 909 if err != nil { 910 return err 911 } 912 objects = append(objects, ofiles...) 913 } 914 915 // For gccgo on ELF systems, we write the build ID as an assembler file. 916 // This lets us set the SHF_EXCLUDE flag. 917 // This is read by readGccgoArchive in cmd/internal/buildid/buildid.go. 918 if a.buildID != "" && cfg.BuildToolchainName == "gccgo" { 919 switch cfg.Goos { 920 case "aix", "android", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris": 921 asmfile, err := b.gccgoBuildIDFile(a) 922 if err != nil { 923 return err 924 } 925 ofiles, err := BuildToolchain.asm(b, a, []string{asmfile}) 926 if err != nil { 927 return err 928 } 929 objects = append(objects, ofiles...) 930 } 931 } 932 933 // NOTE(rsc): On Windows, it is critically important that the 934 // gcc-compiled objects (cgoObjects) be listed after the ordinary 935 // objects in the archive. I do not know why this is. 936 // https://golang.org/issue/2601 937 objects = append(objects, cgoObjects...) 938 939 // Add system object files. 940 for _, syso := range p.SysoFiles { 941 objects = append(objects, filepath.Join(p.Dir, syso)) 942 } 943 944 // Pack into archive in objdir directory. 945 // If the Go compiler wrote an archive, we only need to add the 946 // object files for non-Go sources to the archive. 947 // If the Go compiler wrote an archive and the package is entirely 948 // Go sources, there is no pack to execute at all. 949 if len(objects) > 0 { 950 if err := BuildToolchain.pack(b, a, objpkg, objects); err != nil { 951 return err 952 } 953 } 954 955 if err := b.updateBuildID(a, objpkg, true); err != nil { 956 return err 957 } 958 959 a.built = objpkg 960 return nil 961 } 962 963 func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error { 964 f, err := os.Open(a.Objdir + name) 965 if err != nil { 966 return err 967 } 968 defer f.Close() 969 _, _, err = c.Put(cache.Subkey(a.actionID, name), f) 970 return err 971 } 972 973 func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) { 974 file, _, err := c.GetFile(cache.Subkey(a.actionID, name)) 975 if err != nil { 976 return "", fmt.Errorf("loading cached file %s: %w", name, err) 977 } 978 return file, nil 979 } 980 981 func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error { 982 cached, err := b.findCachedObjdirFile(a, c, name) 983 if err != nil { 984 return err 985 } 986 return b.copyFile(a.Objdir+name, cached, 0666, true) 987 } 988 989 func (b *Builder) cacheCgoHdr(a *Action) { 990 c := cache.Default() 991 b.cacheObjdirFile(a, c, "_cgo_install.h") 992 } 993 994 func (b *Builder) loadCachedCgoHdr(a *Action) error { 995 c := cache.Default() 996 return b.loadCachedObjdirFile(a, c, "_cgo_install.h") 997 } 998 999 func (b *Builder) cacheSrcFiles(a *Action, srcfiles []string) { 1000 c := cache.Default() 1001 var buf bytes.Buffer 1002 for _, file := range srcfiles { 1003 if !strings.HasPrefix(file, a.Objdir) { 1004 // not generated 1005 buf.WriteString("./") 1006 buf.WriteString(file) 1007 buf.WriteString("\n") 1008 continue 1009 } 1010 name := file[len(a.Objdir):] 1011 buf.WriteString(name) 1012 buf.WriteString("\n") 1013 if err := b.cacheObjdirFile(a, c, name); err != nil { 1014 return 1015 } 1016 } 1017 c.PutBytes(cache.Subkey(a.actionID, "srcfiles"), buf.Bytes()) 1018 } 1019 1020 func (b *Builder) loadCachedVet(a *Action) error { 1021 c := cache.Default() 1022 list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles")) 1023 if err != nil { 1024 return fmt.Errorf("reading srcfiles list: %w", err) 1025 } 1026 var srcfiles []string 1027 for _, name := range strings.Split(string(list), "\n") { 1028 if name == "" { // end of list 1029 continue 1030 } 1031 if strings.HasPrefix(name, "./") { 1032 srcfiles = append(srcfiles, name[2:]) 1033 continue 1034 } 1035 if err := b.loadCachedObjdirFile(a, c, name); err != nil { 1036 return err 1037 } 1038 srcfiles = append(srcfiles, a.Objdir+name) 1039 } 1040 buildVetConfig(a, srcfiles) 1041 return nil 1042 } 1043 1044 func (b *Builder) loadCachedCompiledGoFiles(a *Action) error { 1045 c := cache.Default() 1046 list, _, err := c.GetBytes(cache.Subkey(a.actionID, "srcfiles")) 1047 if err != nil { 1048 return fmt.Errorf("reading srcfiles list: %w", err) 1049 } 1050 var gofiles []string 1051 for _, name := range strings.Split(string(list), "\n") { 1052 if name == "" { // end of list 1053 continue 1054 } else if !strings.HasSuffix(name, ".go") { 1055 continue 1056 } 1057 if strings.HasPrefix(name, "./") { 1058 gofiles = append(gofiles, name[len("./"):]) 1059 continue 1060 } 1061 file, err := b.findCachedObjdirFile(a, c, name) 1062 if err != nil { 1063 return fmt.Errorf("finding %s: %w", name, err) 1064 } 1065 gofiles = append(gofiles, file) 1066 } 1067 a.Package.CompiledGoFiles = gofiles 1068 return nil 1069 } 1070 1071 // vetConfig is the configuration passed to vet describing a single package. 1072 type vetConfig struct { 1073 ID string // package ID (example: "fmt [fmt.test]") 1074 Compiler string // compiler name (gc, gccgo) 1075 Dir string // directory containing package 1076 ImportPath string // canonical import path ("package path") 1077 GoFiles []string // absolute paths to package source files 1078 NonGoFiles []string // absolute paths to package non-Go files 1079 IgnoredFiles []string // absolute paths to ignored source files 1080 1081 ImportMap map[string]string // map import path in source code to package path 1082 PackageFile map[string]string // map package path to .a file with export data 1083 Standard map[string]bool // map package path to whether it's in the standard library 1084 PackageVetx map[string]string // map package path to vetx data from earlier vet run 1085 VetxOnly bool // only compute vetx data; don't report detected problems 1086 VetxOutput string // write vetx data to this output file 1087 1088 SucceedOnTypecheckFailure bool // awful hack; see #18395 and below 1089 } 1090 1091 func buildVetConfig(a *Action, srcfiles []string) { 1092 // Classify files based on .go extension. 1093 // srcfiles does not include raw cgo files. 1094 var gofiles, nongofiles []string 1095 for _, name := range srcfiles { 1096 if strings.HasSuffix(name, ".go") { 1097 gofiles = append(gofiles, name) 1098 } else { 1099 nongofiles = append(nongofiles, name) 1100 } 1101 } 1102 1103 ignored := str.StringList(a.Package.IgnoredGoFiles, a.Package.IgnoredOtherFiles) 1104 1105 // Pass list of absolute paths to vet, 1106 // so that vet's error messages will use absolute paths, 1107 // so that we can reformat them relative to the directory 1108 // in which the go command is invoked. 1109 vcfg := &vetConfig{ 1110 ID: a.Package.ImportPath, 1111 Compiler: cfg.BuildToolchainName, 1112 Dir: a.Package.Dir, 1113 GoFiles: mkAbsFiles(a.Package.Dir, gofiles), 1114 NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles), 1115 IgnoredFiles: mkAbsFiles(a.Package.Dir, ignored), 1116 ImportPath: a.Package.ImportPath, 1117 ImportMap: make(map[string]string), 1118 PackageFile: make(map[string]string), 1119 Standard: make(map[string]bool), 1120 } 1121 a.vetCfg = vcfg 1122 for i, raw := range a.Package.Internal.RawImports { 1123 final := a.Package.Imports[i] 1124 vcfg.ImportMap[raw] = final 1125 } 1126 1127 // Compute the list of mapped imports in the vet config 1128 // so that we can add any missing mappings below. 1129 vcfgMapped := make(map[string]bool) 1130 for _, p := range vcfg.ImportMap { 1131 vcfgMapped[p] = true 1132 } 1133 1134 for _, a1 := range a.Deps { 1135 p1 := a1.Package 1136 if p1 == nil || p1.ImportPath == "" { 1137 continue 1138 } 1139 // Add import mapping if needed 1140 // (for imports like "runtime/cgo" that appear only in generated code). 1141 if !vcfgMapped[p1.ImportPath] { 1142 vcfg.ImportMap[p1.ImportPath] = p1.ImportPath 1143 } 1144 if a1.built != "" { 1145 vcfg.PackageFile[p1.ImportPath] = a1.built 1146 } 1147 if p1.Standard { 1148 vcfg.Standard[p1.ImportPath] = true 1149 } 1150 } 1151 } 1152 1153 // VetTool is the path to an alternate vet tool binary. 1154 // The caller is expected to set it (if needed) before executing any vet actions. 1155 var VetTool string 1156 1157 // VetFlags are the default flags to pass to vet. 1158 // The caller is expected to set them before executing any vet actions. 1159 var VetFlags []string 1160 1161 // VetExplicit records whether the vet flags were set explicitly on the command line. 1162 var VetExplicit bool 1163 1164 func (b *Builder) vet(ctx context.Context, a *Action) error { 1165 // a.Deps[0] is the build of the package being vetted. 1166 // a.Deps[1] is the build of the "fmt" package. 1167 1168 a.Failed = false // vet of dependency may have failed but we can still succeed 1169 1170 if a.Deps[0].Failed { 1171 // The build of the package has failed. Skip vet check. 1172 // Vet could return export data for non-typecheck errors, 1173 // but we ignore it because the package cannot be compiled. 1174 return nil 1175 } 1176 1177 vcfg := a.Deps[0].vetCfg 1178 if vcfg == nil { 1179 // Vet config should only be missing if the build failed. 1180 return fmt.Errorf("vet config not found") 1181 } 1182 1183 vcfg.VetxOnly = a.VetxOnly 1184 vcfg.VetxOutput = a.Objdir + "vet.out" 1185 vcfg.PackageVetx = make(map[string]string) 1186 1187 h := cache.NewHash("vet " + a.Package.ImportPath) 1188 fmt.Fprintf(h, "vet %q\n", b.toolID("vet")) 1189 1190 vetFlags := VetFlags 1191 1192 // In GOROOT, we enable all the vet tests during 'go test', 1193 // not just the high-confidence subset. This gets us extra 1194 // checking for the standard library (at some compliance cost) 1195 // and helps us gain experience about how well the checks 1196 // work, to help decide which should be turned on by default. 1197 // The command-line still wins. 1198 // 1199 // Note that this flag change applies even when running vet as 1200 // a dependency of vetting a package outside std. 1201 // (Otherwise we'd have to introduce a whole separate 1202 // space of "vet fmt as a dependency of a std top-level vet" 1203 // versus "vet fmt as a dependency of a non-std top-level vet".) 1204 // This is OK as long as the packages that are farther down the 1205 // dependency tree turn on *more* analysis, as here. 1206 // (The unsafeptr check does not write any facts for use by 1207 // later vet runs, nor does unreachable.) 1208 if a.Package.Goroot && !VetExplicit && VetTool == "" { 1209 // Turn off -unsafeptr checks. 1210 // There's too much unsafe.Pointer code 1211 // that vet doesn't like in low-level packages 1212 // like runtime, sync, and reflect. 1213 // Note that $GOROOT/src/buildall.bash 1214 // does the same for the misc-compile trybots 1215 // and should be updated if these flags are 1216 // changed here. 1217 vetFlags = []string{"-unsafeptr=false"} 1218 1219 // Also turn off -unreachable checks during go test. 1220 // During testing it is very common to make changes 1221 // like hard-coded forced returns or panics that make 1222 // code unreachable. It's unreasonable to insist on files 1223 // not having any unreachable code during "go test". 1224 // (buildall.bash still runs with -unreachable enabled 1225 // for the overall whole-tree scan.) 1226 if cfg.CmdName == "test" { 1227 vetFlags = append(vetFlags, "-unreachable=false") 1228 } 1229 } 1230 1231 // Note: We could decide that vet should compute export data for 1232 // all analyses, in which case we don't need to include the flags here. 1233 // But that would mean that if an analysis causes problems like 1234 // unexpected crashes there would be no way to turn it off. 1235 // It seems better to let the flags disable export analysis too. 1236 fmt.Fprintf(h, "vetflags %q\n", vetFlags) 1237 1238 fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID) 1239 for _, a1 := range a.Deps { 1240 if a1.Mode == "vet" && a1.built != "" { 1241 fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built)) 1242 vcfg.PackageVetx[a1.Package.ImportPath] = a1.built 1243 } 1244 } 1245 key := cache.ActionID(h.Sum()) 1246 1247 if vcfg.VetxOnly && !cfg.BuildA { 1248 c := cache.Default() 1249 if file, _, err := c.GetFile(key); err == nil { 1250 a.built = file 1251 return nil 1252 } 1253 } 1254 1255 js, err := json.MarshalIndent(vcfg, "", "\t") 1256 if err != nil { 1257 return fmt.Errorf("internal error marshaling vet config: %v", err) 1258 } 1259 js = append(js, '\n') 1260 if err := b.writeFile(a.Objdir+"vet.cfg", js); err != nil { 1261 return err 1262 } 1263 1264 // TODO(rsc): Why do we pass $GCCGO to go vet? 1265 env := b.cCompilerEnv() 1266 if cfg.BuildToolchainName == "gccgo" { 1267 env = append(env, "GCCGO="+BuildToolchain.compiler()) 1268 } 1269 1270 p := a.Package 1271 tool := VetTool 1272 if tool == "" { 1273 tool = base.Tool("vet") 1274 } 1275 runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, vetFlags, a.Objdir+"vet.cfg") 1276 1277 // If vet wrote export data, save it for input to future vets. 1278 if f, err := os.Open(vcfg.VetxOutput); err == nil { 1279 a.built = vcfg.VetxOutput 1280 cache.Default().Put(key, f) 1281 f.Close() 1282 } 1283 1284 return runErr 1285 } 1286 1287 // linkActionID computes the action ID for a link action. 1288 func (b *Builder) linkActionID(a *Action) cache.ActionID { 1289 p := a.Package 1290 h := cache.NewHash("link " + p.ImportPath) 1291 1292 // Toolchain-independent configuration. 1293 fmt.Fprintf(h, "link\n") 1294 fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) 1295 fmt.Fprintf(h, "import %q\n", p.ImportPath) 1296 fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) 1297 if cfg.BuildTrimpath { 1298 fmt.Fprintln(h, "trimpath") 1299 } 1300 1301 // Toolchain-dependent configuration, shared with b.linkSharedActionID. 1302 b.printLinkerConfig(h, p) 1303 1304 // Input files. 1305 for _, a1 := range a.Deps { 1306 p1 := a1.Package 1307 if p1 != nil { 1308 if a1.built != "" || a1.buildID != "" { 1309 buildID := a1.buildID 1310 if buildID == "" { 1311 buildID = b.buildID(a1.built) 1312 } 1313 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(buildID)) 1314 } 1315 // Because we put package main's full action ID into the binary's build ID, 1316 // we must also put the full action ID into the binary's action ID hash. 1317 if p1.Name == "main" { 1318 fmt.Fprintf(h, "packagemain %s\n", a1.buildID) 1319 } 1320 if p1.Shlib != "" { 1321 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) 1322 } 1323 } 1324 } 1325 1326 return h.Sum() 1327 } 1328 1329 // printLinkerConfig prints the linker config into the hash h, 1330 // as part of the computation of a linker-related action ID. 1331 func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { 1332 switch cfg.BuildToolchainName { 1333 default: 1334 base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName) 1335 1336 case "gc": 1337 fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode) 1338 if p != nil { 1339 fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags) 1340 } 1341 1342 // GOARM, GOMIPS, etc. 1343 key, val := cfg.GetArchEnv() 1344 fmt.Fprintf(h, "%s=%s\n", key, val) 1345 1346 if cfg.CleanGOEXPERIMENT != "" { 1347 fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT) 1348 } 1349 1350 // The linker writes source file paths that say GOROOT_FINAL, but 1351 // only if -trimpath is not specified (see ld() in gc.go). 1352 gorootFinal := cfg.GOROOT_FINAL 1353 if cfg.BuildTrimpath { 1354 gorootFinal = trimPathGoRootFinal 1355 } 1356 fmt.Fprintf(h, "GOROOT=%s\n", gorootFinal) 1357 1358 // GO_EXTLINK_ENABLED controls whether the external linker is used. 1359 fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED")) 1360 1361 // TODO(rsc): Do cgo settings and flags need to be included? 1362 // Or external linker settings and flags? 1363 1364 case "gccgo": 1365 id, _, err := b.gccToolID(BuildToolchain.linker(), "go") 1366 if err != nil { 1367 base.Fatalf("%v", err) 1368 } 1369 fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode) 1370 // TODO(iant): Should probably include cgo flags here. 1371 } 1372 } 1373 1374 // link is the action for linking a single command. 1375 // Note that any new influence on this logic must be reported in b.linkActionID above as well. 1376 func (b *Builder) link(ctx context.Context, a *Action) (err error) { 1377 if b.useCache(a, b.linkActionID(a), a.Package.Target, !b.IsCmdList) || b.IsCmdList { 1378 return nil 1379 } 1380 defer b.flushOutput(a) 1381 1382 if err := b.Mkdir(a.Objdir); err != nil { 1383 return err 1384 } 1385 1386 importcfg := a.Objdir + "importcfg.link" 1387 if err := b.writeLinkImportcfg(a, importcfg); err != nil { 1388 return err 1389 } 1390 1391 if err := AllowInstall(a); err != nil { 1392 return err 1393 } 1394 1395 // make target directory 1396 dir, _ := filepath.Split(a.Target) 1397 if dir != "" { 1398 if err := b.Mkdir(dir); err != nil { 1399 return err 1400 } 1401 } 1402 1403 if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil { 1404 return err 1405 } 1406 1407 // Update the binary with the final build ID. 1408 // But if OmitDebug is set, don't rewrite the binary, because we set OmitDebug 1409 // on binaries that we are going to run and then delete. 1410 // There's no point in doing work on such a binary. 1411 // Worse, opening the binary for write here makes it 1412 // essentially impossible to safely fork+exec due to a fundamental 1413 // incompatibility between ETXTBSY and threads on modern Unix systems. 1414 // See golang.org/issue/22220. 1415 // We still call updateBuildID to update a.buildID, which is important 1416 // for test result caching, but passing rewrite=false (final arg) 1417 // means we don't actually rewrite the binary, nor store the 1418 // result into the cache. That's probably a net win: 1419 // less cache space wasted on large binaries we are not likely to 1420 // need again. (On the other hand it does make repeated go test slower.) 1421 // It also makes repeated go run slower, which is a win in itself: 1422 // we don't want people to treat go run like a scripting environment. 1423 if err := b.updateBuildID(a, a.Target, !a.Package.Internal.OmitDebug); err != nil { 1424 return err 1425 } 1426 1427 a.built = a.Target 1428 return nil 1429 } 1430 1431 func (b *Builder) writeLinkImportcfg(a *Action, file string) error { 1432 // Prepare Go import cfg. 1433 var icfg bytes.Buffer 1434 for _, a1 := range a.Deps { 1435 p1 := a1.Package 1436 if p1 == nil { 1437 continue 1438 } 1439 fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) 1440 if p1.Shlib != "" { 1441 fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib) 1442 } 1443 } 1444 fmt.Fprintf(&icfg, "modinfo %q\n", modload.ModInfoData(a.Package.Internal.BuildInfo)) 1445 return b.writeFile(file, icfg.Bytes()) 1446 } 1447 1448 // PkgconfigCmd returns a pkg-config binary name 1449 // defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist. 1450 func (b *Builder) PkgconfigCmd() string { 1451 return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0] 1452 } 1453 1454 // splitPkgConfigOutput parses the pkg-config output into a slice of 1455 // flags. This implements the algorithm from pkgconf/libpkgconf/argvsplit.c. 1456 func splitPkgConfigOutput(out []byte) ([]string, error) { 1457 if len(out) == 0 { 1458 return nil, nil 1459 } 1460 var flags []string 1461 flag := make([]byte, 0, len(out)) 1462 escaped := false 1463 quote := byte(0) 1464 1465 for _, c := range out { 1466 if escaped { 1467 if quote != 0 { 1468 switch c { 1469 case '$', '`', '"', '\\': 1470 default: 1471 flag = append(flag, '\\') 1472 } 1473 flag = append(flag, c) 1474 } else { 1475 flag = append(flag, c) 1476 } 1477 escaped = false 1478 } else if quote != 0 { 1479 if c == quote { 1480 quote = 0 1481 } else { 1482 switch c { 1483 case '\\': 1484 escaped = true 1485 default: 1486 flag = append(flag, c) 1487 } 1488 } 1489 } else if strings.IndexByte(" \t\n\v\f\r", c) < 0 { 1490 switch c { 1491 case '\\': 1492 escaped = true 1493 case '\'', '"': 1494 quote = c 1495 default: 1496 flag = append(flag, c) 1497 } 1498 } else if len(flag) != 0 { 1499 flags = append(flags, string(flag)) 1500 flag = flag[:0] 1501 } 1502 } 1503 if escaped { 1504 return nil, errors.New("broken character escaping in pkgconf output ") 1505 } 1506 if quote != 0 { 1507 return nil, errors.New("unterminated quoted string in pkgconf output ") 1508 } else if len(flag) != 0 { 1509 flags = append(flags, string(flag)) 1510 } 1511 1512 return flags, nil 1513 } 1514 1515 // Calls pkg-config if needed and returns the cflags/ldflags needed to build the package. 1516 func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, err error) { 1517 if pcargs := p.CgoPkgConfig; len(pcargs) > 0 { 1518 // pkg-config permits arguments to appear anywhere in 1519 // the command line. Move them all to the front, before --. 1520 var pcflags []string 1521 var pkgs []string 1522 for _, pcarg := range pcargs { 1523 if pcarg == "--" { 1524 // We're going to add our own "--" argument. 1525 } else if strings.HasPrefix(pcarg, "--") { 1526 pcflags = append(pcflags, pcarg) 1527 } else { 1528 pkgs = append(pkgs, pcarg) 1529 } 1530 } 1531 for _, pkg := range pkgs { 1532 if !load.SafeArg(pkg) { 1533 return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg) 1534 } 1535 } 1536 var out []byte 1537 out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs) 1538 if err != nil { 1539 err = formatOutput(b.WorkDir, p.Dir, p.ImportPath, b.PkgconfigCmd()+" --cflags "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out)+err.Error()) 1540 return nil, nil, err 1541 } 1542 if len(out) > 0 { 1543 cflags, err = splitPkgConfigOutput(out) 1544 if err != nil { 1545 return nil, nil, err 1546 } 1547 if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil { 1548 return nil, nil, err 1549 } 1550 } 1551 out, err = b.runOut(nil, p.Dir, nil, b.PkgconfigCmd(), "--libs", pcflags, "--", pkgs) 1552 if err != nil { 1553 err = formatOutput(b.WorkDir, p.Dir, p.ImportPath, b.PkgconfigCmd()+" --libs "+strings.Join(pcflags, " ")+" -- "+strings.Join(pkgs, " "), string(out)+err.Error()) 1554 return nil, nil, err 1555 } 1556 if len(out) > 0 { 1557 // NOTE: we don't attempt to parse quotes and unescapes here. pkg-config 1558 // is typically used within shell backticks, which treats quotes literally. 1559 ldflags = strings.Fields(string(out)) 1560 if err := checkLinkerFlags("LDFLAGS", "pkg-config --libs", ldflags); err != nil { 1561 return nil, nil, err 1562 } 1563 } 1564 } 1565 1566 return 1567 } 1568 1569 func (b *Builder) installShlibname(ctx context.Context, a *Action) error { 1570 if err := AllowInstall(a); err != nil { 1571 return err 1572 } 1573 1574 // TODO: BuildN 1575 a1 := a.Deps[0] 1576 if err := b.Mkdir(filepath.Dir(a.Target)); err != nil { 1577 return err 1578 } 1579 err := os.WriteFile(a.Target, []byte(filepath.Base(a1.Target)+"\n"), 0666) 1580 if err != nil { 1581 return err 1582 } 1583 if cfg.BuildX { 1584 b.Showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.Target), a.Target) 1585 } 1586 return nil 1587 } 1588 1589 func (b *Builder) linkSharedActionID(a *Action) cache.ActionID { 1590 h := cache.NewHash("linkShared") 1591 1592 // Toolchain-independent configuration. 1593 fmt.Fprintf(h, "linkShared\n") 1594 fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) 1595 1596 // Toolchain-dependent configuration, shared with b.linkActionID. 1597 b.printLinkerConfig(h, nil) 1598 1599 // Input files. 1600 for _, a1 := range a.Deps { 1601 p1 := a1.Package 1602 if a1.built == "" { 1603 continue 1604 } 1605 if p1 != nil { 1606 fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) 1607 if p1.Shlib != "" { 1608 fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib))) 1609 } 1610 } 1611 } 1612 // Files named on command line are special. 1613 for _, a1 := range a.Deps[0].Deps { 1614 p1 := a1.Package 1615 fmt.Fprintf(h, "top %s=%s\n", p1.ImportPath, contentID(b.buildID(a1.built))) 1616 } 1617 1618 return h.Sum() 1619 } 1620 1621 func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) { 1622 if b.useCache(a, b.linkSharedActionID(a), a.Target, !b.IsCmdList) || b.IsCmdList { 1623 return nil 1624 } 1625 defer b.flushOutput(a) 1626 1627 if err := AllowInstall(a); err != nil { 1628 return err 1629 } 1630 1631 if err := b.Mkdir(a.Objdir); err != nil { 1632 return err 1633 } 1634 1635 importcfg := a.Objdir + "importcfg.link" 1636 if err := b.writeLinkImportcfg(a, importcfg); err != nil { 1637 return err 1638 } 1639 1640 // TODO(rsc): There is a missing updateBuildID here, 1641 // but we have to decide where to store the build ID in these files. 1642 a.built = a.Target 1643 return BuildToolchain.ldShared(b, a, a.Deps[0].Deps, a.Target, importcfg, a.Deps) 1644 } 1645 1646 // BuildInstallFunc is the action for installing a single package or executable. 1647 func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { 1648 defer func() { 1649 if err != nil { 1650 // a.Package == nil is possible for the go install -buildmode=shared 1651 // action that installs libmangledname.so, which corresponds to 1652 // a list of packages, not just one. 1653 sep, path := "", "" 1654 if a.Package != nil { 1655 sep, path = " ", a.Package.ImportPath 1656 } 1657 err = fmt.Errorf("go %s%s%s: %v", cfg.CmdName, sep, path, err) 1658 } 1659 }() 1660 1661 a1 := a.Deps[0] 1662 a.buildID = a1.buildID 1663 if a.json != nil { 1664 a.json.BuildID = a.buildID 1665 } 1666 1667 // If we are using the eventual install target as an up-to-date 1668 // cached copy of the thing we built, then there's no need to 1669 // copy it into itself (and that would probably fail anyway). 1670 // In this case a1.built == a.Target because a1.built == p.Target, 1671 // so the built target is not in the a1.Objdir tree that b.cleanup(a1) removes. 1672 if a1.built == a.Target { 1673 a.built = a.Target 1674 if !a.buggyInstall { 1675 b.cleanup(a1) 1676 } 1677 // Whether we're smart enough to avoid a complete rebuild 1678 // depends on exactly what the staleness and rebuild algorithms 1679 // are, as well as potentially the state of the Go build cache. 1680 // We don't really want users to be able to infer (or worse start depending on) 1681 // those details from whether the modification time changes during 1682 // "go install", so do a best-effort update of the file times to make it 1683 // look like we rewrote a.Target even if we did not. Updating the mtime 1684 // may also help other mtime-based systems that depend on our 1685 // previous mtime updates that happened more often. 1686 // This is still not perfect - we ignore the error result, and if the file was 1687 // unwritable for some reason then pretending to have written it is also 1688 // confusing - but it's probably better than not doing the mtime update. 1689 // 1690 // But don't do that for the special case where building an executable 1691 // with -linkshared implicitly installs all its dependent libraries. 1692 // We want to hide that awful detail as much as possible, so don't 1693 // advertise it by touching the mtimes (usually the libraries are up 1694 // to date). 1695 if !a.buggyInstall && !b.IsCmdList { 1696 if cfg.BuildN { 1697 b.Showcmd("", "touch %s", a.Target) 1698 } else if err := AllowInstall(a); err == nil { 1699 now := time.Now() 1700 os.Chtimes(a.Target, now, now) 1701 } 1702 } 1703 return nil 1704 } 1705 1706 // If we're building for go list -export, 1707 // never install anything; just keep the cache reference. 1708 if b.IsCmdList { 1709 a.built = a1.built 1710 return nil 1711 } 1712 if err := AllowInstall(a); err != nil { 1713 return err 1714 } 1715 1716 if err := b.Mkdir(a.Objdir); err != nil { 1717 return err 1718 } 1719 1720 perm := fs.FileMode(0666) 1721 if a1.Mode == "link" { 1722 switch cfg.BuildBuildmode { 1723 case "c-archive", "c-shared", "plugin": 1724 default: 1725 perm = 0777 1726 } 1727 } 1728 1729 // make target directory 1730 dir, _ := filepath.Split(a.Target) 1731 if dir != "" { 1732 if err := b.Mkdir(dir); err != nil { 1733 return err 1734 } 1735 } 1736 1737 if !a.buggyInstall { 1738 defer b.cleanup(a1) 1739 } 1740 1741 return b.moveOrCopyFile(a.Target, a1.built, perm, false) 1742 } 1743 1744 // AllowInstall returns a non-nil error if this invocation of the go command is 1745 // allowed to install a.Target. 1746 // 1747 // The build of cmd/go running under its own test is forbidden from installing 1748 // to its original GOROOT. The var is exported so it can be set by TestMain. 1749 var AllowInstall = func(*Action) error { return nil } 1750 1751 // cleanup removes a's object dir to keep the amount of 1752 // on-disk garbage down in a large build. On an operating system 1753 // with aggressive buffering, cleaning incrementally like 1754 // this keeps the intermediate objects from hitting the disk. 1755 func (b *Builder) cleanup(a *Action) { 1756 if !cfg.BuildWork { 1757 if cfg.BuildX { 1758 // Don't say we are removing the directory if 1759 // we never created it. 1760 if _, err := os.Stat(a.Objdir); err == nil || cfg.BuildN { 1761 b.Showcmd("", "rm -r %s", a.Objdir) 1762 } 1763 } 1764 os.RemoveAll(a.Objdir) 1765 } 1766 } 1767 1768 // moveOrCopyFile is like 'mv src dst' or 'cp src dst'. 1769 func (b *Builder) moveOrCopyFile(dst, src string, perm fs.FileMode, force bool) error { 1770 if cfg.BuildN { 1771 b.Showcmd("", "mv %s %s", src, dst) 1772 return nil 1773 } 1774 1775 // If we can update the mode and rename to the dst, do it. 1776 // Otherwise fall back to standard copy. 1777 1778 // If the source is in the build cache, we need to copy it. 1779 if strings.HasPrefix(src, cache.DefaultDir()) { 1780 return b.copyFile(dst, src, perm, force) 1781 } 1782 1783 // On Windows, always copy the file, so that we respect the NTFS 1784 // permissions of the parent folder. https://golang.org/issue/22343. 1785 // What matters here is not cfg.Goos (the system we are building 1786 // for) but runtime.GOOS (the system we are building on). 1787 if runtime.GOOS == "windows" { 1788 return b.copyFile(dst, src, perm, force) 1789 } 1790 1791 // If the destination directory has the group sticky bit set, 1792 // we have to copy the file to retain the correct permissions. 1793 // https://golang.org/issue/18878 1794 if fi, err := os.Stat(filepath.Dir(dst)); err == nil { 1795 if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 { 1796 return b.copyFile(dst, src, perm, force) 1797 } 1798 } 1799 1800 // The perm argument is meant to be adjusted according to umask, 1801 // but we don't know what the umask is. 1802 // Create a dummy file to find out. 1803 // This avoids build tags and works even on systems like Plan 9 1804 // where the file mask computation incorporates other information. 1805 mode := perm 1806 f, err := os.OpenFile(filepath.Clean(dst)+"-go-tmp-umask", os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) 1807 if err == nil { 1808 fi, err := f.Stat() 1809 if err == nil { 1810 mode = fi.Mode() & 0777 1811 } 1812 name := f.Name() 1813 f.Close() 1814 os.Remove(name) 1815 } 1816 1817 if err := os.Chmod(src, mode); err == nil { 1818 if err := os.Rename(src, dst); err == nil { 1819 if cfg.BuildX { 1820 b.Showcmd("", "mv %s %s", src, dst) 1821 } 1822 return nil 1823 } 1824 } 1825 1826 return b.copyFile(dst, src, perm, force) 1827 } 1828 1829 // copyFile is like 'cp src dst'. 1830 func (b *Builder) copyFile(dst, src string, perm fs.FileMode, force bool) error { 1831 if cfg.BuildN || cfg.BuildX { 1832 b.Showcmd("", "cp %s %s", src, dst) 1833 if cfg.BuildN { 1834 return nil 1835 } 1836 } 1837 1838 sf, err := os.Open(src) 1839 if err != nil { 1840 return err 1841 } 1842 defer sf.Close() 1843 1844 // Be careful about removing/overwriting dst. 1845 // Do not remove/overwrite if dst exists and is a directory 1846 // or a non-empty non-object file. 1847 if fi, err := os.Stat(dst); err == nil { 1848 if fi.IsDir() { 1849 return fmt.Errorf("build output %q already exists and is a directory", dst) 1850 } 1851 if !force && fi.Mode().IsRegular() && fi.Size() != 0 && !isObject(dst) { 1852 return fmt.Errorf("build output %q already exists and is not an object file", dst) 1853 } 1854 } 1855 1856 // On Windows, remove lingering ~ file from last attempt. 1857 if runtime.GOOS == "windows" { 1858 if _, err := os.Stat(dst + "~"); err == nil { 1859 os.Remove(dst + "~") 1860 } 1861 } 1862 1863 mayberemovefile(dst) 1864 df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 1865 if err != nil && runtime.GOOS == "windows" { 1866 // Windows does not allow deletion of a binary file 1867 // while it is executing. Try to move it out of the way. 1868 // If the move fails, which is likely, we'll try again the 1869 // next time we do an install of this binary. 1870 if err := os.Rename(dst, dst+"~"); err == nil { 1871 os.Remove(dst + "~") 1872 } 1873 df, err = os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) 1874 } 1875 if err != nil { 1876 return fmt.Errorf("copying %s: %w", src, err) // err should already refer to dst 1877 } 1878 1879 _, err = io.Copy(df, sf) 1880 df.Close() 1881 if err != nil { 1882 mayberemovefile(dst) 1883 return fmt.Errorf("copying %s to %s: %v", src, dst, err) 1884 } 1885 return nil 1886 } 1887 1888 // writeFile writes the text to file. 1889 func (b *Builder) writeFile(file string, text []byte) error { 1890 if cfg.BuildN || cfg.BuildX { 1891 b.Showcmd("", "cat >%s << 'EOF' # internal\n%sEOF", file, text) 1892 } 1893 if cfg.BuildN { 1894 return nil 1895 } 1896 return os.WriteFile(file, text, 0666) 1897 } 1898 1899 // Install the cgo export header file, if there is one. 1900 func (b *Builder) installHeader(ctx context.Context, a *Action) error { 1901 src := a.Objdir + "_cgo_install.h" 1902 if _, err := os.Stat(src); os.IsNotExist(err) { 1903 // If the file does not exist, there are no exported 1904 // functions, and we do not install anything. 1905 // TODO(rsc): Once we know that caching is rebuilding 1906 // at the right times (not missing rebuilds), here we should 1907 // probably delete the installed header, if any. 1908 if cfg.BuildX { 1909 b.Showcmd("", "# %s not created", src) 1910 } 1911 return nil 1912 } 1913 1914 if err := AllowInstall(a); err != nil { 1915 return err 1916 } 1917 1918 dir, _ := filepath.Split(a.Target) 1919 if dir != "" { 1920 if err := b.Mkdir(dir); err != nil { 1921 return err 1922 } 1923 } 1924 1925 return b.moveOrCopyFile(a.Target, src, 0666, true) 1926 } 1927 1928 // cover runs, in effect, 1929 // 1930 // go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go 1931 func (b *Builder) cover(a *Action, dst, src string, varName string) error { 1932 return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil, 1933 cfg.BuildToolexec, 1934 base.Tool("cover"), 1935 "-mode", a.Package.Internal.CoverMode, 1936 "-var", varName, 1937 "-o", dst, 1938 src) 1939 } 1940 1941 // cover2 runs, in effect, 1942 // 1943 // go tool cover -pkgcfg=<config file> -mode=b.coverMode -var="varName" -o <outfiles> <infiles> 1944 func (b *Builder) cover2(a *Action, pkgcfg, covoutputs string, infiles, outfiles []string, varName string, mode string) error { 1945 if err := b.writeCoverPkgInputs(a, pkgcfg, covoutputs, outfiles); err != nil { 1946 return err 1947 } 1948 args := []string{base.Tool("cover"), 1949 "-pkgcfg", pkgcfg, 1950 "-mode", mode, 1951 "-var", varName, 1952 "-outfilelist", covoutputs, 1953 } 1954 args = append(args, infiles...) 1955 return b.run(a, a.Objdir, "cover "+a.Package.ImportPath, nil, 1956 cfg.BuildToolexec, args) 1957 } 1958 1959 func (b *Builder) writeCoverPkgInputs(a *Action, pconfigfile string, covoutputsfile string, outfiles []string) error { 1960 p := a.Package 1961 p.Internal.CoverageCfg = a.Objdir + "coveragecfg" 1962 pcfg := coverage.CoverPkgConfig{ 1963 PkgPath: p.ImportPath, 1964 PkgName: p.Name, 1965 // Note: coverage granularity is currently hard-wired to 1966 // 'perblock'; there isn't a way using "go build -cover" or "go 1967 // test -cover" to select it. This may change in the future 1968 // depending on user demand. 1969 Granularity: "perblock", 1970 OutConfig: p.Internal.CoverageCfg, 1971 Local: p.Internal.Local, 1972 } 1973 if a.Package.Module != nil { 1974 pcfg.ModulePath = a.Package.Module.Path 1975 } 1976 data, err := json.Marshal(pcfg) 1977 if err != nil { 1978 return err 1979 } 1980 if err := b.writeFile(pconfigfile, data); err != nil { 1981 return err 1982 } 1983 var sb strings.Builder 1984 for i := range outfiles { 1985 fmt.Fprintf(&sb, "%s\n", outfiles[i]) 1986 } 1987 return b.writeFile(covoutputsfile, []byte(sb.String())) 1988 } 1989 1990 var objectMagic = [][]byte{ 1991 {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive 1992 {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package AIX big archive 1993 {'\x7F', 'E', 'L', 'F'}, // ELF 1994 {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit 1995 {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit 1996 {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit 1997 {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit 1998 {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc 1999 {0x4d, 0x5a, 0x78, 0x00, 0x01, 0x00}, // PE (Windows) as generated by llvm for dll 2000 {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 2001 {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 2002 {0x00, 0x00, 0x06, 0x47}, // Plan 9 arm 2003 {0x00, 0x61, 0x73, 0x6D}, // WASM 2004 {0x01, 0xDF}, // XCOFF 32bit 2005 {0x01, 0xF7}, // XCOFF 64bit 2006 } 2007 2008 func isObject(s string) bool { 2009 f, err := os.Open(s) 2010 if err != nil { 2011 return false 2012 } 2013 defer f.Close() 2014 buf := make([]byte, 64) 2015 io.ReadFull(f, buf) 2016 for _, magic := range objectMagic { 2017 if bytes.HasPrefix(buf, magic) { 2018 return true 2019 } 2020 } 2021 return false 2022 } 2023 2024 // mayberemovefile removes a file only if it is a regular file 2025 // When running as a user with sufficient privileges, we may delete 2026 // even device files, for example, which is not intended. 2027 func mayberemovefile(s string) { 2028 if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() { 2029 return 2030 } 2031 os.Remove(s) 2032 } 2033 2034 // fmtcmd formats a command in the manner of fmt.Sprintf but also: 2035 // 2036 // If dir is non-empty and the script is not in dir right now, 2037 // fmtcmd inserts "cd dir\n" before the command. 2038 // 2039 // fmtcmd replaces the value of b.WorkDir with $WORK. 2040 // fmtcmd replaces the value of goroot with $GOROOT. 2041 // fmtcmd replaces the value of b.gobin with $GOBIN. 2042 // 2043 // fmtcmd replaces the name of the current directory with dot (.) 2044 // but only when it is at the beginning of a space-separated token. 2045 func (b *Builder) fmtcmd(dir string, format string, args ...any) string { 2046 cmd := fmt.Sprintf(format, args...) 2047 if dir != "" && dir != "/" { 2048 dot := " ." 2049 if dir[len(dir)-1] == filepath.Separator { 2050 dot += string(filepath.Separator) 2051 } 2052 cmd = strings.ReplaceAll(" "+cmd, " "+dir, dot)[1:] 2053 if b.scriptDir != dir { 2054 b.scriptDir = dir 2055 cmd = "cd " + dir + "\n" + cmd 2056 } 2057 } 2058 if b.WorkDir != "" && !strings.HasPrefix(cmd, "cat ") { 2059 cmd = strings.ReplaceAll(cmd, b.WorkDir, "$WORK") 2060 escaped := strconv.Quote(b.WorkDir) 2061 escaped = escaped[1 : len(escaped)-1] // strip quote characters 2062 if escaped != b.WorkDir { 2063 cmd = strings.ReplaceAll(cmd, escaped, "$WORK") 2064 } 2065 } 2066 return cmd 2067 } 2068 2069 // showcmd prints the given command to standard output 2070 // for the implementation of -n or -x. 2071 func (b *Builder) Showcmd(dir string, format string, args ...any) { 2072 b.output.Lock() 2073 defer b.output.Unlock() 2074 b.Print(b.fmtcmd(dir, format, args...) + "\n") 2075 } 2076 2077 // showOutput prints "# desc" followed by the given output. 2078 // The output is expected to contain references to 'dir', usually 2079 // the source directory for the package that has failed to build. 2080 // showOutput rewrites mentions of dir with a relative path to dir 2081 // when the relative path is shorter. This is usually more pleasant. 2082 // For example, if fmt doesn't compile and we are in src/html, 2083 // the output is 2084 // 2085 // $ go build 2086 // # fmt 2087 // ../fmt/print.go:1090: undefined: asdf 2088 // $ 2089 // 2090 // instead of 2091 // 2092 // $ go build 2093 // # fmt 2094 // /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf 2095 // $ 2096 // 2097 // showOutput also replaces references to the work directory with $WORK. 2098 // 2099 // If a is not nil and a.output is not nil, showOutput appends to that slice instead of 2100 // printing to b.Print. 2101 func (b *Builder) showOutput(a *Action, dir, desc, out string) { 2102 importPath := "" 2103 if a != nil && a.Package != nil { 2104 importPath = a.Package.ImportPath 2105 } 2106 psErr := formatOutput(b.WorkDir, dir, importPath, desc, out) 2107 if a != nil && a.output != nil { 2108 a.output = append(a.output, psErr.prefix...) 2109 a.output = append(a.output, psErr.suffix...) 2110 return 2111 } 2112 2113 b.output.Lock() 2114 defer b.output.Unlock() 2115 b.Print(psErr.prefix, psErr.suffix) 2116 } 2117 2118 // A prefixSuffixError is an error formatted by formatOutput. 2119 type prefixSuffixError struct { 2120 importPath string 2121 prefix, suffix string 2122 } 2123 2124 func (e *prefixSuffixError) Error() string { 2125 if e.importPath != "" && !strings.HasPrefix(strings.TrimPrefix(e.prefix, "# "), e.importPath) { 2126 return fmt.Sprintf("go build %s:\n%s%s", e.importPath, e.prefix, e.suffix) 2127 } 2128 return e.prefix + e.suffix 2129 } 2130 2131 func (e *prefixSuffixError) ImportPath() string { 2132 return e.importPath 2133 } 2134 2135 // formatOutput prints "# desc" followed by the given output. 2136 // The output is expected to contain references to 'dir', usually 2137 // the source directory for the package that has failed to build. 2138 // formatOutput rewrites mentions of dir with a relative path to dir 2139 // when the relative path is shorter. This is usually more pleasant. 2140 // For example, if fmt doesn't compile and we are in src/html, 2141 // the output is 2142 // 2143 // $ go build 2144 // # fmt 2145 // ../fmt/print.go:1090: undefined: asdf 2146 // $ 2147 // 2148 // instead of 2149 // 2150 // $ go build 2151 // # fmt 2152 // /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf 2153 // $ 2154 // 2155 // formatOutput also replaces references to the work directory with $WORK. 2156 // formatOutput returns the output in a prefix with the description and a 2157 // suffix with the actual output. 2158 func formatOutput(workDir, dir, importPath, desc, out string) *prefixSuffixError { 2159 prefix := "# " + desc 2160 suffix := "\n" + out 2161 if reldir := base.ShortPath(dir); reldir != dir { 2162 suffix = strings.ReplaceAll(suffix, " "+dir, " "+reldir) 2163 suffix = strings.ReplaceAll(suffix, "\n"+dir, "\n"+reldir) 2164 suffix = strings.ReplaceAll(suffix, "\n\t"+dir, "\n\t"+reldir) 2165 } 2166 suffix = strings.ReplaceAll(suffix, " "+workDir, " $WORK") 2167 2168 return &prefixSuffixError{importPath: importPath, prefix: prefix, suffix: suffix} 2169 } 2170 2171 var cgoLine = lazyregexp.New(`\[[^\[\]]+\.(cgo1|cover)\.go:[0-9]+(:[0-9]+)?\]`) 2172 var cgoTypeSigRe = lazyregexp.New(`\b_C2?(type|func|var|macro)_\B`) 2173 2174 // run runs the command given by cmdline in the directory dir. 2175 // If the command fails, run prints information about the failure 2176 // and returns a non-nil error. 2177 func (b *Builder) run(a *Action, dir string, desc string, env []string, cmdargs ...any) error { 2178 out, err := b.runOut(a, dir, env, cmdargs...) 2179 if len(out) > 0 { 2180 if desc == "" { 2181 desc = b.fmtcmd(dir, "%s", strings.Join(str.StringList(cmdargs...), " ")) 2182 } 2183 if err != nil { 2184 err = formatOutput(b.WorkDir, dir, a.Package.ImportPath, desc, b.processOutput(out)) 2185 } else { 2186 b.showOutput(a, dir, desc, b.processOutput(out)) 2187 } 2188 } 2189 return err 2190 } 2191 2192 // processOutput prepares the output of runOut to be output to the console. 2193 func (b *Builder) processOutput(out []byte) string { 2194 if out[len(out)-1] != '\n' { 2195 out = append(out, '\n') 2196 } 2197 messages := string(out) 2198 // Fix up output referring to cgo-generated code to be more readable. 2199 // Replace x.go:19[/tmp/.../x.cgo1.go:18] with x.go:19. 2200 // Replace *[100]_Ctype_foo with *[100]C.foo. 2201 // If we're using -x, assume we're debugging and want the full dump, so disable the rewrite. 2202 if !cfg.BuildX && cgoLine.MatchString(messages) { 2203 messages = cgoLine.ReplaceAllString(messages, "") 2204 messages = cgoTypeSigRe.ReplaceAllString(messages, "C.") 2205 } 2206 return messages 2207 } 2208 2209 // runOut runs the command given by cmdline in the directory dir. 2210 // It returns the command output and any errors that occurred. 2211 // It accumulates execution time in a. 2212 func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...any) ([]byte, error) { 2213 cmdline := str.StringList(cmdargs...) 2214 2215 for _, arg := range cmdline { 2216 // GNU binutils commands, including gcc and gccgo, interpret an argument 2217 // @foo anywhere in the command line (even following --) as meaning 2218 // "read and insert arguments from the file named foo." 2219 // Don't say anything that might be misinterpreted that way. 2220 if strings.HasPrefix(arg, "@") { 2221 return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline)) 2222 } 2223 } 2224 2225 if cfg.BuildN || cfg.BuildX { 2226 var envcmdline string 2227 for _, e := range env { 2228 if j := strings.IndexByte(e, '='); j != -1 { 2229 if strings.ContainsRune(e[j+1:], '\'') { 2230 envcmdline += fmt.Sprintf("%s=%q", e[:j], e[j+1:]) 2231 } else { 2232 envcmdline += fmt.Sprintf("%s='%s'", e[:j], e[j+1:]) 2233 } 2234 envcmdline += " " 2235 } 2236 } 2237 envcmdline += joinUnambiguously(cmdline) 2238 b.Showcmd(dir, "%s", envcmdline) 2239 if cfg.BuildN { 2240 return nil, nil 2241 } 2242 } 2243 2244 var buf bytes.Buffer 2245 cmd := base.ToolCommand(cmdline[0], cmdline[1:]...) 2246 if cmd.Path != "" { 2247 cmd.Args[0] = cmd.Path 2248 } 2249 cmd.Stdout = &buf 2250 cmd.Stderr = &buf 2251 cleanup := passLongArgsInResponseFiles(cmd) 2252 defer cleanup() 2253 if dir != "." { 2254 cmd.Dir = dir 2255 } 2256 cmd.Env = cmd.Environ() // Pre-allocate with correct PWD. 2257 2258 // Add the TOOLEXEC_IMPORTPATH environment variable for -toolexec tools. 2259 // It doesn't really matter if -toolexec isn't being used. 2260 // Note that a.Package.Desc is not really an import path, 2261 // but this is consistent with 'go list -f {{.ImportPath}}'. 2262 // Plus, it is useful to uniquely identify packages in 'go list -json'. 2263 if a != nil && a.Package != nil { 2264 cmd.Env = append(cmd.Env, "TOOLEXEC_IMPORTPATH="+a.Package.Desc()) 2265 } 2266 2267 cmd.Env = append(cmd.Env, env...) 2268 start := time.Now() 2269 err := cmd.Run() 2270 if a != nil && a.json != nil { 2271 aj := a.json 2272 aj.Cmd = append(aj.Cmd, joinUnambiguously(cmdline)) 2273 aj.CmdReal += time.Since(start) 2274 if ps := cmd.ProcessState; ps != nil { 2275 aj.CmdUser += ps.UserTime() 2276 aj.CmdSys += ps.SystemTime() 2277 } 2278 } 2279 2280 // err can be something like 'exit status 1'. 2281 // Add information about what program was running. 2282 // Note that if buf.Bytes() is non-empty, the caller usually 2283 // shows buf.Bytes() and does not print err at all, so the 2284 // prefix here does not make most output any more verbose. 2285 if err != nil { 2286 err = errors.New(cmdline[0] + ": " + err.Error()) 2287 } 2288 return buf.Bytes(), err 2289 } 2290 2291 // joinUnambiguously prints the slice, quoting where necessary to make the 2292 // output unambiguous. 2293 // TODO: See issue 5279. The printing of commands needs a complete redo. 2294 func joinUnambiguously(a []string) string { 2295 var buf strings.Builder 2296 for i, s := range a { 2297 if i > 0 { 2298 buf.WriteByte(' ') 2299 } 2300 q := strconv.Quote(s) 2301 // A gccgo command line can contain -( and -). 2302 // Make sure we quote them since they are special to the shell. 2303 // The trimpath argument can also contain > (part of =>) and ;. Quote those too. 2304 if s == "" || strings.ContainsAny(s, " ()>;") || len(q) > len(s)+2 { 2305 buf.WriteString(q) 2306 } else { 2307 buf.WriteString(s) 2308 } 2309 } 2310 return buf.String() 2311 } 2312 2313 // cCompilerEnv returns environment variables to set when running the 2314 // C compiler. This is needed to disable escape codes in clang error 2315 // messages that confuse tools like cgo. 2316 func (b *Builder) cCompilerEnv() []string { 2317 return []string{"TERM=dumb"} 2318 } 2319 2320 // mkdir makes the named directory. 2321 func (b *Builder) Mkdir(dir string) error { 2322 // Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "". 2323 if dir == "" { 2324 return nil 2325 } 2326 2327 b.exec.Lock() 2328 defer b.exec.Unlock() 2329 // We can be a little aggressive about being 2330 // sure directories exist. Skip repeated calls. 2331 if b.mkdirCache[dir] { 2332 return nil 2333 } 2334 b.mkdirCache[dir] = true 2335 2336 if cfg.BuildN || cfg.BuildX { 2337 b.Showcmd("", "mkdir -p %s", dir) 2338 if cfg.BuildN { 2339 return nil 2340 } 2341 } 2342 2343 if err := os.MkdirAll(dir, 0777); err != nil { 2344 return err 2345 } 2346 return nil 2347 } 2348 2349 // symlink creates a symlink newname -> oldname. 2350 func (b *Builder) Symlink(oldname, newname string) error { 2351 // It's not an error to try to recreate an existing symlink. 2352 if link, err := os.Readlink(newname); err == nil && link == oldname { 2353 return nil 2354 } 2355 2356 if cfg.BuildN || cfg.BuildX { 2357 b.Showcmd("", "ln -s %s %s", oldname, newname) 2358 if cfg.BuildN { 2359 return nil 2360 } 2361 } 2362 return os.Symlink(oldname, newname) 2363 } 2364 2365 // mkAbs returns an absolute path corresponding to 2366 // evaluating f in the directory dir. 2367 // We always pass absolute paths of source files so that 2368 // the error messages will include the full path to a file 2369 // in need of attention. 2370 func mkAbs(dir, f string) string { 2371 // Leave absolute paths alone. 2372 // Also, during -n mode we use the pseudo-directory $WORK 2373 // instead of creating an actual work directory that won't be used. 2374 // Leave paths beginning with $WORK alone too. 2375 if filepath.IsAbs(f) || strings.HasPrefix(f, "$WORK") { 2376 return f 2377 } 2378 return filepath.Join(dir, f) 2379 } 2380 2381 type toolchain interface { 2382 // gc runs the compiler in a specific directory on a set of files 2383 // and returns the name of the generated output file. 2384 gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) 2385 // cc runs the toolchain's C compiler in a directory on a C file 2386 // to produce an output file. 2387 cc(b *Builder, a *Action, ofile, cfile string) error 2388 // asm runs the assembler in a specific directory on specific files 2389 // and returns a list of named output files. 2390 asm(b *Builder, a *Action, sfiles []string) ([]string, error) 2391 // symabis scans the symbol ABIs from sfiles and returns the 2392 // path to the output symbol ABIs file, or "" if none. 2393 symabis(b *Builder, a *Action, sfiles []string) (string, error) 2394 // pack runs the archive packer in a specific directory to create 2395 // an archive from a set of object files. 2396 // typically it is run in the object directory. 2397 pack(b *Builder, a *Action, afile string, ofiles []string) error 2398 // ld runs the linker to create an executable starting at mainpkg. 2399 ld(b *Builder, root *Action, out, importcfg, mainpkg string) error 2400 // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions 2401 ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error 2402 2403 compiler() string 2404 linker() string 2405 } 2406 2407 type noToolchain struct{} 2408 2409 func noCompiler() error { 2410 log.Fatalf("unknown compiler %q", cfg.BuildContext.Compiler) 2411 return nil 2412 } 2413 2414 func (noToolchain) compiler() string { 2415 noCompiler() 2416 return "" 2417 } 2418 2419 func (noToolchain) linker() string { 2420 noCompiler() 2421 return "" 2422 } 2423 2424 func (noToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, out []byte, err error) { 2425 return "", nil, noCompiler() 2426 } 2427 2428 func (noToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) { 2429 return nil, noCompiler() 2430 } 2431 2432 func (noToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) { 2433 return "", noCompiler() 2434 } 2435 2436 func (noToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error { 2437 return noCompiler() 2438 } 2439 2440 func (noToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error { 2441 return noCompiler() 2442 } 2443 2444 func (noToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error { 2445 return noCompiler() 2446 } 2447 2448 func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error { 2449 return noCompiler() 2450 } 2451 2452 // gcc runs the gcc C compiler to create an object from a single C file. 2453 func (b *Builder) gcc(a *Action, p *load.Package, workdir, out string, flags []string, cfile string) error { 2454 return b.ccompile(a, p, out, flags, cfile, b.GccCmd(p.Dir, workdir)) 2455 } 2456 2457 // gxx runs the g++ C++ compiler to create an object from a single C++ file. 2458 func (b *Builder) gxx(a *Action, p *load.Package, workdir, out string, flags []string, cxxfile string) error { 2459 return b.ccompile(a, p, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir)) 2460 } 2461 2462 // gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. 2463 func (b *Builder) gfortran(a *Action, p *load.Package, workdir, out string, flags []string, ffile string) error { 2464 return b.ccompile(a, p, out, flags, ffile, b.gfortranCmd(p.Dir, workdir)) 2465 } 2466 2467 // ccompile runs the given C or C++ compiler and creates an object from a single source file. 2468 func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []string, file string, compiler []string) error { 2469 file = mkAbs(p.Dir, file) 2470 outfile = mkAbs(p.Dir, outfile) 2471 2472 // Elide source directory paths if -trimpath or GOROOT_FINAL is set. 2473 // This is needed for source files (e.g., a .c file in a package directory). 2474 // TODO(golang.org/issue/36072): cgo also generates files with #line 2475 // directives pointing to the source directory. It should not generate those 2476 // when -trimpath is enabled. 2477 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { 2478 if cfg.BuildTrimpath || p.Goroot { 2479 // Keep in sync with Action.trimpath. 2480 // The trimmed paths are a little different, but we need to trim in the 2481 // same situations. 2482 var from, toPath string 2483 if m := p.Module; m != nil { 2484 from = m.Dir 2485 toPath = m.Path + "@" + m.Version 2486 } else { 2487 from = p.Dir 2488 toPath = p.ImportPath 2489 } 2490 // -fdebug-prefix-map requires an absolute "to" path (or it joins the path 2491 // with the working directory). Pick something that makes sense for the 2492 // target platform. 2493 var to string 2494 if cfg.BuildContext.GOOS == "windows" { 2495 to = filepath.Join(`\\_\_`, toPath) 2496 } else { 2497 to = filepath.Join("/_", toPath) 2498 } 2499 flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+from+"="+to) 2500 } 2501 } 2502 2503 overlayPath := file 2504 if p, ok := a.nonGoOverlay[overlayPath]; ok { 2505 overlayPath = p 2506 } 2507 output, err := b.runOut(a, filepath.Dir(overlayPath), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(overlayPath)) 2508 if len(output) > 0 { 2509 // On FreeBSD 11, when we pass -g to clang 3.8 it 2510 // invokes its internal assembler with -dwarf-version=2. 2511 // When it sees .section .note.GNU-stack, it warns 2512 // "DWARF2 only supports one section per compilation unit". 2513 // This warning makes no sense, since the section is empty, 2514 // but it confuses people. 2515 // We work around the problem by detecting the warning 2516 // and dropping -g and trying again. 2517 if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) { 2518 newFlags := make([]string, 0, len(flags)) 2519 for _, f := range flags { 2520 if !strings.HasPrefix(f, "-g") { 2521 newFlags = append(newFlags, f) 2522 } 2523 } 2524 if len(newFlags) < len(flags) { 2525 return b.ccompile(a, p, outfile, newFlags, file, compiler) 2526 } 2527 } 2528 2529 if err != nil || os.Getenv("GO_BUILDER_NAME") != "" { 2530 err = formatOutput(b.WorkDir, p.Dir, p.ImportPath, p.Desc(), b.processOutput(output)) 2531 } else { 2532 b.showOutput(a, p.Dir, p.Desc(), b.processOutput(output)) 2533 } 2534 } 2535 return err 2536 } 2537 2538 // gccld runs the gcc linker to create an executable from a set of object files. 2539 // Any error output is only displayed for BuildN or BuildX. 2540 func (b *Builder) gccld(a *Action, p *load.Package, objdir, outfile string, flags []string, objs []string) error { 2541 var cmd []string 2542 if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { 2543 cmd = b.GxxCmd(p.Dir, objdir) 2544 } else { 2545 cmd = b.GccCmd(p.Dir, objdir) 2546 } 2547 2548 cmdargs := []any{cmd, "-o", outfile, objs, flags} 2549 dir := p.Dir 2550 out, err := b.runOut(a, base.Cwd(), b.cCompilerEnv(), cmdargs...) 2551 2552 if len(out) > 0 { 2553 // Filter out useless linker warnings caused by bugs outside Go. 2554 // See also cmd/link/internal/ld's hostlink method. 2555 var save [][]byte 2556 var skipLines int 2557 for _, line := range bytes.SplitAfter(out, []byte("\n")) { 2558 // golang.org/issue/26073 - Apple Xcode bug 2559 if bytes.Contains(line, []byte("ld: warning: text-based stub file")) { 2560 continue 2561 } 2562 2563 if skipLines > 0 { 2564 skipLines-- 2565 continue 2566 } 2567 2568 // Remove duplicate main symbol with runtime/cgo on AIX. 2569 // With runtime/cgo, two main are available: 2570 // One is generated by cgo tool with {return 0;}. 2571 // The other one is the main calling runtime.rt0_go 2572 // in runtime/cgo. 2573 // The second can't be used by cgo programs because 2574 // runtime.rt0_go is unknown to them. 2575 // Therefore, we let ld remove this main version 2576 // and used the cgo generated one. 2577 if p.ImportPath == "runtime/cgo" && bytes.Contains(line, []byte("ld: 0711-224 WARNING: Duplicate symbol: .main")) { 2578 skipLines = 1 2579 continue 2580 } 2581 2582 save = append(save, line) 2583 } 2584 out = bytes.Join(save, nil) 2585 if len(out) > 0 && (cfg.BuildN || cfg.BuildX) { 2586 b.showOutput(nil, dir, p.ImportPath, b.processOutput(out)) 2587 } 2588 } 2589 return err 2590 } 2591 2592 // gccCmd returns a gcc command line prefix 2593 // defaultCC is defined in zdefaultcc.go, written by cmd/dist. 2594 func (b *Builder) GccCmd(incdir, workdir string) []string { 2595 return b.compilerCmd(b.ccExe(), incdir, workdir) 2596 } 2597 2598 // gxxCmd returns a g++ command line prefix 2599 // defaultCXX is defined in zdefaultcc.go, written by cmd/dist. 2600 func (b *Builder) GxxCmd(incdir, workdir string) []string { 2601 return b.compilerCmd(b.cxxExe(), incdir, workdir) 2602 } 2603 2604 // gfortranCmd returns a gfortran command line prefix. 2605 func (b *Builder) gfortranCmd(incdir, workdir string) []string { 2606 return b.compilerCmd(b.fcExe(), incdir, workdir) 2607 } 2608 2609 // ccExe returns the CC compiler setting without all the extra flags we add implicitly. 2610 func (b *Builder) ccExe() []string { 2611 return envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch)) 2612 } 2613 2614 // cxxExe returns the CXX compiler setting without all the extra flags we add implicitly. 2615 func (b *Builder) cxxExe() []string { 2616 return envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch)) 2617 } 2618 2619 // fcExe returns the FC compiler setting without all the extra flags we add implicitly. 2620 func (b *Builder) fcExe() []string { 2621 return envList("FC", "gfortran") 2622 } 2623 2624 // compilerCmd returns a command line prefix for the given environment 2625 // variable and using the default command when the variable is empty. 2626 func (b *Builder) compilerCmd(compiler []string, incdir, workdir string) []string { 2627 a := append(compiler, "-I", incdir) 2628 2629 // Definitely want -fPIC but on Windows gcc complains 2630 // "-fPIC ignored for target (all code is position independent)" 2631 if cfg.Goos != "windows" { 2632 a = append(a, "-fPIC") 2633 } 2634 a = append(a, b.gccArchArgs()...) 2635 // gcc-4.5 and beyond require explicit "-pthread" flag 2636 // for multithreading with pthread library. 2637 if cfg.BuildContext.CgoEnabled { 2638 switch cfg.Goos { 2639 case "windows": 2640 a = append(a, "-mthreads") 2641 default: 2642 a = append(a, "-pthread") 2643 } 2644 } 2645 2646 if cfg.Goos == "aix" { 2647 // mcmodel=large must always be enabled to allow large TOC. 2648 a = append(a, "-mcmodel=large") 2649 } 2650 2651 // disable ASCII art in clang errors, if possible 2652 if b.gccSupportsFlag(compiler, "-fno-caret-diagnostics") { 2653 a = append(a, "-fno-caret-diagnostics") 2654 } 2655 // clang is too smart about command-line arguments 2656 if b.gccSupportsFlag(compiler, "-Qunused-arguments") { 2657 a = append(a, "-Qunused-arguments") 2658 } 2659 2660 // zig cc passes --gc-sections to the underlying linker, which then causes 2661 // undefined symbol errors when compiling with cgo but without C code. 2662 // https://github.com/golang/go/issues/52690 2663 if b.gccSupportsFlag(compiler, "-Wl,--no-gc-sections") { 2664 a = append(a, "-Wl,--no-gc-sections") 2665 } 2666 2667 // disable word wrapping in error messages 2668 a = append(a, "-fmessage-length=0") 2669 2670 // Tell gcc not to include the work directory in object files. 2671 if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") { 2672 if workdir == "" { 2673 workdir = b.WorkDir 2674 } 2675 workdir = strings.TrimSuffix(workdir, string(filepath.Separator)) 2676 a = append(a, "-fdebug-prefix-map="+workdir+"=/tmp/go-build") 2677 } 2678 2679 // Tell gcc not to include flags in object files, which defeats the 2680 // point of -fdebug-prefix-map above. 2681 if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") { 2682 a = append(a, "-gno-record-gcc-switches") 2683 } 2684 2685 // On OS X, some of the compilers behave as if -fno-common 2686 // is always set, and the Mach-O linker in 6l/8l assumes this. 2687 // See https://golang.org/issue/3253. 2688 if cfg.Goos == "darwin" || cfg.Goos == "ios" { 2689 a = append(a, "-fno-common") 2690 } 2691 2692 return a 2693 } 2694 2695 // gccNoPie returns the flag to use to request non-PIE. On systems 2696 // with PIE (position independent executables) enabled by default, 2697 // -no-pie must be passed when doing a partial link with -Wl,-r. 2698 // But -no-pie is not supported by all compilers, and clang spells it -nopie. 2699 func (b *Builder) gccNoPie(linker []string) string { 2700 if b.gccSupportsFlag(linker, "-no-pie") { 2701 return "-no-pie" 2702 } 2703 if b.gccSupportsFlag(linker, "-nopie") { 2704 return "-nopie" 2705 } 2706 return "" 2707 } 2708 2709 // gccSupportsFlag checks to see if the compiler supports a flag. 2710 func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool { 2711 key := [2]string{compiler[0], flag} 2712 2713 // We used to write an empty C file, but that gets complicated with go 2714 // build -n. We tried using a file that does not exist, but that fails on 2715 // systems with GCC version 4.2.1; that is the last GPLv2 version of GCC, 2716 // so some systems have frozen on it. Now we pass an empty file on stdin, 2717 // which should work at least for GCC and clang. 2718 // 2719 // If the argument is "-Wl,", then it is testing the linker. In that case, 2720 // skip "-c". If it's not "-Wl,", then we are testing the compiler and can 2721 // omit the linking step with "-c". 2722 // 2723 // Using the same CFLAGS/LDFLAGS here and for building the program. 2724 2725 // On the iOS builder the command 2726 // $CC -Wl,--no-gc-sections -x c - -o /dev/null < /dev/null 2727 // is failing with: 2728 // Unable to remove existing file: Invalid argument 2729 tmp := os.DevNull 2730 if runtime.GOOS == "windows" || runtime.GOOS == "ios" { 2731 f, err := os.CreateTemp(b.WorkDir, "") 2732 if err != nil { 2733 return false 2734 } 2735 f.Close() 2736 tmp = f.Name() 2737 defer os.Remove(tmp) 2738 } 2739 2740 cmdArgs := str.StringList(compiler, flag) 2741 if strings.HasPrefix(flag, "-Wl,") /* linker flag */ { 2742 ldflags, err := buildFlags("LDFLAGS", defaultCFlags, nil, checkLinkerFlags) 2743 if err != nil { 2744 return false 2745 } 2746 cmdArgs = append(cmdArgs, ldflags...) 2747 } else { /* compiler flag, add "-c" */ 2748 cflags, err := buildFlags("CFLAGS", defaultCFlags, nil, checkCompilerFlags) 2749 if err != nil { 2750 return false 2751 } 2752 cmdArgs = append(cmdArgs, cflags...) 2753 cmdArgs = append(cmdArgs, "-c") 2754 } 2755 2756 cmdArgs = append(cmdArgs, "-x", "c", "-", "-o", tmp) 2757 2758 if cfg.BuildN { 2759 b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs)) 2760 return false 2761 } 2762 2763 // gccCompilerID acquires b.exec, so do before acquiring lock. 2764 compilerID, cacheOK := b.gccCompilerID(compiler[0]) 2765 2766 b.exec.Lock() 2767 defer b.exec.Unlock() 2768 if b, ok := b.flagCache[key]; ok { 2769 return b 2770 } 2771 if b.flagCache == nil { 2772 b.flagCache = make(map[[2]string]bool) 2773 } 2774 2775 // Look in build cache. 2776 var flagID cache.ActionID 2777 if cacheOK { 2778 flagID = cache.Subkey(compilerID, "gccSupportsFlag "+flag) 2779 if data, _, err := cache.Default().GetBytes(flagID); err == nil { 2780 supported := string(data) == "true" 2781 b.flagCache[key] = supported 2782 return supported 2783 } 2784 } 2785 2786 if cfg.BuildX { 2787 b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs)) 2788 } 2789 cmd := base.ToolCommand(cmdArgs[0], cmdArgs[1:]...) 2790 cmd.Dir = b.WorkDir 2791 cmd.Env = append(cmd.Environ(), "LC_ALL=C") 2792 out, _ := cmd.CombinedOutput() 2793 // GCC says "unrecognized command line option". 2794 // clang says "unknown argument". 2795 // tcc says "unsupported" 2796 // AIX says "not recognized" 2797 // Older versions of GCC say "unrecognised debug output level". 2798 // For -fsplit-stack GCC says "'-fsplit-stack' is not supported". 2799 supported := !bytes.Contains(out, []byte("unrecognized")) && 2800 !bytes.Contains(out, []byte("unknown")) && 2801 !bytes.Contains(out, []byte("unrecognised")) && 2802 !bytes.Contains(out, []byte("is not supported")) && 2803 !bytes.Contains(out, []byte("not recognized")) && 2804 !bytes.Contains(out, []byte("unsupported")) 2805 2806 if cacheOK { 2807 s := "false" 2808 if supported { 2809 s = "true" 2810 } 2811 cache.Default().PutBytes(flagID, []byte(s)) 2812 } 2813 2814 b.flagCache[key] = supported 2815 return supported 2816 } 2817 2818 // statString returns a string form of an os.FileInfo, for serializing and comparison. 2819 func statString(info os.FileInfo) string { 2820 return fmt.Sprintf("stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir()) 2821 } 2822 2823 // gccCompilerID returns a build cache key for the current gcc, 2824 // as identified by running 'compiler'. 2825 // The caller can use subkeys of the key. 2826 // Other parts of cmd/go can use the id as a hash 2827 // of the installed compiler version. 2828 func (b *Builder) gccCompilerID(compiler string) (id cache.ActionID, ok bool) { 2829 if cfg.BuildN { 2830 b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously([]string{compiler, "--version"})) 2831 return cache.ActionID{}, false 2832 } 2833 2834 b.exec.Lock() 2835 defer b.exec.Unlock() 2836 2837 if id, ok := b.gccCompilerIDCache[compiler]; ok { 2838 return id, ok 2839 } 2840 2841 // We hash the compiler's full path to get a cache entry key. 2842 // That cache entry holds a validation description, 2843 // which is of the form: 2844 // 2845 // filename \x00 statinfo \x00 2846 // ... 2847 // compiler id 2848 // 2849 // If os.Stat of each filename matches statinfo, 2850 // then the entry is still valid, and we can use the 2851 // compiler id without any further expense. 2852 // 2853 // Otherwise, we compute a new validation description 2854 // and compiler id (below). 2855 exe, err := exec.LookPath(compiler) 2856 if err != nil { 2857 return cache.ActionID{}, false 2858 } 2859 2860 h := cache.NewHash("gccCompilerID") 2861 fmt.Fprintf(h, "gccCompilerID %q", exe) 2862 key := h.Sum() 2863 data, _, err := cache.Default().GetBytes(key) 2864 if err == nil && len(data) > len(id) { 2865 stats := strings.Split(string(data[:len(data)-len(id)]), "\x00") 2866 if len(stats)%2 != 0 { 2867 goto Miss 2868 } 2869 for i := 0; i+2 <= len(stats); i++ { 2870 info, err := os.Stat(stats[i]) 2871 if err != nil || statString(info) != stats[i+1] { 2872 goto Miss 2873 } 2874 } 2875 copy(id[:], data[len(data)-len(id):]) 2876 return id, true 2877 Miss: 2878 } 2879 2880 // Validation failed. Compute a new description (in buf) and compiler ID (in h). 2881 // For now, there are only at most two filenames in the stat information. 2882 // The first one is the compiler executable we invoke. 2883 // The second is the underlying compiler as reported by -v -### 2884 // (see b.gccToolID implementation in buildid.go). 2885 toolID, exe2, err := b.gccToolID(compiler, "c") 2886 if err != nil { 2887 return cache.ActionID{}, false 2888 } 2889 2890 exes := []string{exe, exe2} 2891 str.Uniq(&exes) 2892 fmt.Fprintf(h, "gccCompilerID %q %q\n", exes, toolID) 2893 id = h.Sum() 2894 2895 var buf bytes.Buffer 2896 for _, exe := range exes { 2897 if exe == "" { 2898 continue 2899 } 2900 info, err := os.Stat(exe) 2901 if err != nil { 2902 return cache.ActionID{}, false 2903 } 2904 buf.WriteString(exe) 2905 buf.WriteString("\x00") 2906 buf.WriteString(statString(info)) 2907 buf.WriteString("\x00") 2908 } 2909 buf.Write(id[:]) 2910 2911 cache.Default().PutBytes(key, buf.Bytes()) 2912 if b.gccCompilerIDCache == nil { 2913 b.gccCompilerIDCache = make(map[string]cache.ActionID) 2914 } 2915 b.gccCompilerIDCache[compiler] = id 2916 return id, true 2917 } 2918 2919 // gccArchArgs returns arguments to pass to gcc based on the architecture. 2920 func (b *Builder) gccArchArgs() []string { 2921 switch cfg.Goarch { 2922 case "386": 2923 return []string{"-m32"} 2924 case "amd64": 2925 if cfg.Goos == "darwin" { 2926 return []string{"-arch", "x86_64", "-m64"} 2927 } 2928 return []string{"-m64"} 2929 case "arm64": 2930 if cfg.Goos == "darwin" { 2931 return []string{"-arch", "arm64"} 2932 } 2933 case "arm": 2934 return []string{"-marm"} // not thumb 2935 case "s390x": 2936 return []string{"-m64", "-march=z196"} 2937 case "mips64", "mips64le": 2938 args := []string{"-mabi=64"} 2939 if cfg.GOMIPS64 == "hardfloat" { 2940 return append(args, "-mhard-float") 2941 } else if cfg.GOMIPS64 == "softfloat" { 2942 return append(args, "-msoft-float") 2943 } 2944 case "mips", "mipsle": 2945 args := []string{"-mabi=32", "-march=mips32"} 2946 if cfg.GOMIPS == "hardfloat" { 2947 return append(args, "-mhard-float", "-mfp32", "-mno-odd-spreg") 2948 } else if cfg.GOMIPS == "softfloat" { 2949 return append(args, "-msoft-float") 2950 } 2951 case "loong64": 2952 return []string{"-mabi=lp64d"} 2953 case "ppc64": 2954 if cfg.Goos == "aix" { 2955 return []string{"-maix64"} 2956 } 2957 } 2958 return nil 2959 } 2960 2961 // envList returns the value of the given environment variable broken 2962 // into fields, using the default value when the variable is empty. 2963 // 2964 // The environment variable must be quoted correctly for 2965 // quoted.Split. This should be done before building 2966 // anything, for example, in BuildInit. 2967 func envList(key, def string) []string { 2968 v := cfg.Getenv(key) 2969 if v == "" { 2970 v = def 2971 } 2972 args, err := quoted.Split(v) 2973 if err != nil { 2974 panic(fmt.Sprintf("could not parse environment variable %s with value %q: %v", key, v, err)) 2975 } 2976 return args 2977 } 2978 2979 // CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo. 2980 func (b *Builder) CFlags(p *load.Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) { 2981 if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil { 2982 return 2983 } 2984 if cflags, err = buildFlags("CFLAGS", defaultCFlags, p.CgoCFLAGS, checkCompilerFlags); err != nil { 2985 return 2986 } 2987 if cxxflags, err = buildFlags("CXXFLAGS", defaultCFlags, p.CgoCXXFLAGS, checkCompilerFlags); err != nil { 2988 return 2989 } 2990 if fflags, err = buildFlags("FFLAGS", defaultCFlags, p.CgoFFLAGS, checkCompilerFlags); err != nil { 2991 return 2992 } 2993 if ldflags, err = buildFlags("LDFLAGS", defaultCFlags, p.CgoLDFLAGS, checkLinkerFlags); err != nil { 2994 return 2995 } 2996 2997 return 2998 } 2999 3000 func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) { 3001 if err := check(name, "#cgo "+name, fromPackage); err != nil { 3002 return nil, err 3003 } 3004 return str.StringList(envList("CGO_"+name, defaults), fromPackage), nil 3005 } 3006 3007 var cgoRe = lazyregexp.New(`[/\\:]`) 3008 3009 func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) { 3010 p := a.Package 3011 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.CFlags(p) 3012 if err != nil { 3013 return nil, nil, err 3014 } 3015 3016 cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) 3017 cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...) 3018 // If we are compiling Objective-C code, then we need to link against libobjc 3019 if len(mfiles) > 0 { 3020 cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc") 3021 } 3022 3023 // Likewise for Fortran, except there are many Fortran compilers. 3024 // Support gfortran out of the box and let others pass the correct link options 3025 // via CGO_LDFLAGS 3026 if len(ffiles) > 0 { 3027 fc := cfg.Getenv("FC") 3028 if fc == "" { 3029 fc = "gfortran" 3030 } 3031 if strings.Contains(fc, "gfortran") { 3032 cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran") 3033 } 3034 } 3035 3036 // Scrutinize CFLAGS and related for flags that might cause 3037 // problems if we are using internal linking (for example, use of 3038 // plugins, LTO, etc) by calling a helper routine that builds on 3039 // the existing CGO flags allow-lists. If we see anything 3040 // suspicious, emit a special token file "preferlinkext" (known to 3041 // the linker) in the object file to signal the that it should not 3042 // try to link internally and should revert to external linking. 3043 // The token we pass is a suggestion, not a mandate; if a user is 3044 // explicitly asking for a specific linkmode via the "-linkmode" 3045 // flag, the token will be ignored. NB: in theory we could ditch 3046 // the token approach and just pass a flag to the linker when we 3047 // eventually invoke it, and the linker flag could then be 3048 // documented (although coming up with a simple explanation of the 3049 // flag might be challenging). For more context see issues #58619, 3050 // #58620, and #58848. 3051 flagSources := []string{"CGO_CFLAGS", "CGO_CXXFLAGS", "CGO_FFLAGS"} 3052 flagLists := [][]string{cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS} 3053 if flagsNotCompatibleWithInternalLinking(flagSources, flagLists) { 3054 tokenFile := objdir + "preferlinkext" 3055 if cfg.BuildN || cfg.BuildX { 3056 b.Showcmd("", "echo > %s", tokenFile) 3057 } 3058 if !cfg.BuildN { 3059 if err := os.WriteFile(tokenFile, nil, 0666); err != nil { 3060 return nil, nil, err 3061 } 3062 } 3063 outObj = append(outObj, tokenFile) 3064 } 3065 3066 if cfg.BuildMSan { 3067 cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...) 3068 cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...) 3069 } 3070 if cfg.BuildASan { 3071 cgoCFLAGS = append([]string{"-fsanitize=address"}, cgoCFLAGS...) 3072 cgoLDFLAGS = append([]string{"-fsanitize=address"}, cgoLDFLAGS...) 3073 } 3074 3075 // Allows including _cgo_export.h, as well as the user's .h files, 3076 // from .[ch] files in the package. 3077 cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", objdir) 3078 3079 // cgo 3080 // TODO: CGO_FLAGS? 3081 gofiles := []string{objdir + "_cgo_gotypes.go"} 3082 cfiles := []string{"_cgo_export.c"} 3083 for _, fn := range cgofiles { 3084 f := strings.TrimSuffix(filepath.Base(fn), ".go") 3085 gofiles = append(gofiles, objdir+f+".cgo1.go") 3086 cfiles = append(cfiles, f+".cgo2.c") 3087 } 3088 3089 // TODO: make cgo not depend on $GOARCH? 3090 3091 cgoflags := []string{} 3092 if p.Standard && p.ImportPath == "runtime/cgo" { 3093 cgoflags = append(cgoflags, "-import_runtime_cgo=false") 3094 } 3095 if p.Standard && (p.ImportPath == "runtime/race" || p.ImportPath == "runtime/msan" || p.ImportPath == "runtime/cgo" || p.ImportPath == "runtime/asan") { 3096 cgoflags = append(cgoflags, "-import_syscall=false") 3097 } 3098 3099 // Update $CGO_LDFLAGS with p.CgoLDFLAGS. 3100 // These flags are recorded in the generated _cgo_gotypes.go file 3101 // using //go:cgo_ldflag directives, the compiler records them in the 3102 // object file for the package, and then the Go linker passes them 3103 // along to the host linker. At this point in the code, cgoLDFLAGS 3104 // consists of the original $CGO_LDFLAGS (unchecked) and all the 3105 // flags put together from source code (checked). 3106 cgoenv := b.cCompilerEnv() 3107 if len(cgoLDFLAGS) > 0 { 3108 flags := make([]string, len(cgoLDFLAGS)) 3109 for i, f := range cgoLDFLAGS { 3110 flags[i] = strconv.Quote(f) 3111 } 3112 cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " ")) 3113 } 3114 3115 if cfg.BuildToolchainName == "gccgo" { 3116 if b.gccSupportsFlag([]string{BuildToolchain.compiler()}, "-fsplit-stack") { 3117 cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") 3118 } 3119 cgoflags = append(cgoflags, "-gccgo") 3120 if pkgpath := gccgoPkgpath(p); pkgpath != "" { 3121 cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath) 3122 } 3123 if !BuildToolchain.(gccgoToolchain).supportsCgoIncomplete(b) { 3124 cgoflags = append(cgoflags, "-gccgo_define_cgoincomplete") 3125 } 3126 } 3127 3128 switch cfg.BuildBuildmode { 3129 case "c-archive", "c-shared": 3130 // Tell cgo that if there are any exported functions 3131 // it should generate a header file that C code can 3132 // #include. 3133 cgoflags = append(cgoflags, "-exportheader="+objdir+"_cgo_install.h") 3134 } 3135 3136 // Rewrite overlaid paths in cgo files. 3137 // cgo adds //line and #line pragmas in generated files with these paths. 3138 var trimpath []string 3139 for i := range cgofiles { 3140 path := mkAbs(p.Dir, cgofiles[i]) 3141 if opath, ok := fsys.OverlayPath(path); ok { 3142 cgofiles[i] = opath 3143 trimpath = append(trimpath, opath+"=>"+path) 3144 } 3145 } 3146 if len(trimpath) > 0 { 3147 cgoflags = append(cgoflags, "-trimpath", strings.Join(trimpath, ";")) 3148 } 3149 3150 if err := b.run(a, p.Dir, p.ImportPath, cgoenv, cfg.BuildToolexec, cgoExe, "-objdir", objdir, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoCFLAGS, cgofiles); err != nil { 3151 return nil, nil, err 3152 } 3153 outGo = append(outGo, gofiles...) 3154 3155 // Use sequential object file names to keep them distinct 3156 // and short enough to fit in the .a header file name slots. 3157 // We no longer collect them all into _all.o, and we'd like 3158 // tools to see both the .o suffix and unique names, so 3159 // we need to make them short enough not to be truncated 3160 // in the final archive. 3161 oseq := 0 3162 nextOfile := func() string { 3163 oseq++ 3164 return objdir + fmt.Sprintf("_x%03d.o", oseq) 3165 } 3166 3167 // gcc 3168 cflags := str.StringList(cgoCPPFLAGS, cgoCFLAGS) 3169 for _, cfile := range cfiles { 3170 ofile := nextOfile() 3171 if err := b.gcc(a, p, a.Objdir, ofile, cflags, objdir+cfile); err != nil { 3172 return nil, nil, err 3173 } 3174 outObj = append(outObj, ofile) 3175 } 3176 3177 for _, file := range gccfiles { 3178 ofile := nextOfile() 3179 if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { 3180 return nil, nil, err 3181 } 3182 outObj = append(outObj, ofile) 3183 } 3184 3185 cxxflags := str.StringList(cgoCPPFLAGS, cgoCXXFLAGS) 3186 for _, file := range gxxfiles { 3187 ofile := nextOfile() 3188 if err := b.gxx(a, p, a.Objdir, ofile, cxxflags, file); err != nil { 3189 return nil, nil, err 3190 } 3191 outObj = append(outObj, ofile) 3192 } 3193 3194 for _, file := range mfiles { 3195 ofile := nextOfile() 3196 if err := b.gcc(a, p, a.Objdir, ofile, cflags, file); err != nil { 3197 return nil, nil, err 3198 } 3199 outObj = append(outObj, ofile) 3200 } 3201 3202 fflags := str.StringList(cgoCPPFLAGS, cgoFFLAGS) 3203 for _, file := range ffiles { 3204 ofile := nextOfile() 3205 if err := b.gfortran(a, p, a.Objdir, ofile, fflags, file); err != nil { 3206 return nil, nil, err 3207 } 3208 outObj = append(outObj, ofile) 3209 } 3210 3211 switch cfg.BuildToolchainName { 3212 case "gc": 3213 importGo := objdir + "_cgo_import.go" 3214 dynOutGo, dynOutObj, err := b.dynimport(a, p, objdir, importGo, cgoExe, cflags, cgoLDFLAGS, outObj) 3215 if err != nil { 3216 return nil, nil, err 3217 } 3218 if dynOutGo != "" { 3219 outGo = append(outGo, dynOutGo) 3220 } 3221 if dynOutObj != "" { 3222 outObj = append(outObj, dynOutObj) 3223 } 3224 3225 case "gccgo": 3226 defunC := objdir + "_cgo_defun.c" 3227 defunObj := objdir + "_cgo_defun.o" 3228 if err := BuildToolchain.cc(b, a, defunObj, defunC); err != nil { 3229 return nil, nil, err 3230 } 3231 outObj = append(outObj, defunObj) 3232 3233 default: 3234 noCompiler() 3235 } 3236 3237 // Double check the //go:cgo_ldflag comments in the generated files. 3238 // The compiler only permits such comments in files whose base name 3239 // starts with "_cgo_". Make sure that the comments in those files 3240 // are safe. This is a backstop against people somehow smuggling 3241 // such a comment into a file generated by cgo. 3242 if cfg.BuildToolchainName == "gc" && !cfg.BuildN { 3243 var flags []string 3244 for _, f := range outGo { 3245 if !strings.HasPrefix(filepath.Base(f), "_cgo_") { 3246 continue 3247 } 3248 3249 src, err := os.ReadFile(f) 3250 if err != nil { 3251 return nil, nil, err 3252 } 3253 3254 const cgoLdflag = "//go:cgo_ldflag" 3255 idx := bytes.Index(src, []byte(cgoLdflag)) 3256 for idx >= 0 { 3257 // We are looking at //go:cgo_ldflag. 3258 // Find start of line. 3259 start := bytes.LastIndex(src[:idx], []byte("\n")) 3260 if start == -1 { 3261 start = 0 3262 } 3263 3264 // Find end of line. 3265 end := bytes.Index(src[idx:], []byte("\n")) 3266 if end == -1 { 3267 end = len(src) 3268 } else { 3269 end += idx 3270 } 3271 3272 // Check for first line comment in line. 3273 // We don't worry about /* */ comments, 3274 // which normally won't appear in files 3275 // generated by cgo. 3276 commentStart := bytes.Index(src[start:], []byte("//")) 3277 commentStart += start 3278 // If that line comment is //go:cgo_ldflag, 3279 // it's a match. 3280 if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) { 3281 // Pull out the flag, and unquote it. 3282 // This is what the compiler does. 3283 flag := string(src[idx+len(cgoLdflag) : end]) 3284 flag = strings.TrimSpace(flag) 3285 flag = strings.Trim(flag, `"`) 3286 flags = append(flags, flag) 3287 } 3288 src = src[end:] 3289 idx = bytes.Index(src, []byte(cgoLdflag)) 3290 } 3291 } 3292 3293 // We expect to find the contents of cgoLDFLAGS in flags. 3294 if len(cgoLDFLAGS) > 0 { 3295 outer: 3296 for i := range flags { 3297 for j, f := range cgoLDFLAGS { 3298 if f != flags[i+j] { 3299 continue outer 3300 } 3301 } 3302 flags = append(flags[:i], flags[i+len(cgoLDFLAGS):]...) 3303 break 3304 } 3305 } 3306 3307 if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil { 3308 return nil, nil, err 3309 } 3310 } 3311 3312 return outGo, outObj, nil 3313 } 3314 3315 // flagsNotCompatibleWithInternalLinking scans the list of cgo 3316 // compiler flags (C/C++/Fortran) looking for flags that might cause 3317 // problems if the build in question uses internal linking. The 3318 // primary culprits are use of plugins or use of LTO, but we err on 3319 // the side of caution, supporting only those flags that are on the 3320 // allow-list for safe flags from security perspective. Return is TRUE 3321 // if a sensitive flag is found, FALSE otherwise. 3322 func flagsNotCompatibleWithInternalLinking(sourceList []string, flagListList [][]string) bool { 3323 for i := range sourceList { 3324 sn := sourceList[i] 3325 fll := flagListList[i] 3326 if err := checkCompilerFlagsForInternalLink(sn, sn, fll); err != nil { 3327 return true 3328 } 3329 } 3330 return false 3331 } 3332 3333 // dynimport creates a Go source file named importGo containing 3334 // //go:cgo_import_dynamic directives for each symbol or library 3335 // dynamically imported by the object files outObj. 3336 // dynOutGo, if not empty, is a new Go file to build as part of the package. 3337 // dynOutObj, if not empty, is a new file to add to the generated archive. 3338 func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe string, cflags, cgoLDFLAGS, outObj []string) (dynOutGo, dynOutObj string, err error) { 3339 cfile := objdir + "_cgo_main.c" 3340 ofile := objdir + "_cgo_main.o" 3341 if err := b.gcc(a, p, objdir, ofile, cflags, cfile); err != nil { 3342 return "", "", err 3343 } 3344 3345 // Gather .syso files from this package and all (transitive) dependencies. 3346 var syso []string 3347 seen := make(map[*Action]bool) 3348 var gatherSyso func(*Action) 3349 gatherSyso = func(a1 *Action) { 3350 if seen[a1] { 3351 return 3352 } 3353 seen[a1] = true 3354 if p1 := a1.Package; p1 != nil { 3355 syso = append(syso, mkAbsFiles(p1.Dir, p1.SysoFiles)...) 3356 } 3357 for _, a2 := range a1.Deps { 3358 gatherSyso(a2) 3359 } 3360 } 3361 gatherSyso(a) 3362 sort.Strings(syso) 3363 str.Uniq(&syso) 3364 linkobj := str.StringList(ofile, outObj, syso) 3365 dynobj := objdir + "_cgo_.o" 3366 3367 ldflags := cgoLDFLAGS 3368 if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" { 3369 if !str.Contains(ldflags, "-no-pie") { 3370 // we need to use -pie for Linux/ARM to get accurate imported sym (added in https://golang.org/cl/5989058) 3371 // this seems to be outdated, but we don't want to break existing builds depending on this (Issue 45940) 3372 ldflags = append(ldflags, "-pie") 3373 } 3374 if str.Contains(ldflags, "-pie") && str.Contains(ldflags, "-static") { 3375 // -static -pie doesn't make sense, and causes link errors. 3376 // Issue 26197. 3377 n := make([]string, 0, len(ldflags)-1) 3378 for _, flag := range ldflags { 3379 if flag != "-static" { 3380 n = append(n, flag) 3381 } 3382 } 3383 ldflags = n 3384 } 3385 } 3386 if err := b.gccld(a, p, objdir, dynobj, ldflags, linkobj); err != nil { 3387 // We only need this information for internal linking. 3388 // If this link fails, mark the object as requiring 3389 // external linking. This link can fail for things like 3390 // syso files that have unexpected dependencies. 3391 // cmd/link explicitly looks for the name "dynimportfail". 3392 // See issue #52863. 3393 fail := objdir + "dynimportfail" 3394 if cfg.BuildN || cfg.BuildX { 3395 b.Showcmd("", "echo > %s", fail) 3396 } 3397 if !cfg.BuildN { 3398 if err := os.WriteFile(fail, nil, 0666); err != nil { 3399 return "", "", err 3400 } 3401 } 3402 return "", fail, nil 3403 } 3404 3405 // cgo -dynimport 3406 var cgoflags []string 3407 if p.Standard && p.ImportPath == "runtime/cgo" { 3408 cgoflags = []string{"-dynlinker"} // record path to dynamic linker 3409 } 3410 err = b.run(a, base.Cwd(), p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) 3411 if err != nil { 3412 return "", "", err 3413 } 3414 return importGo, "", nil 3415 } 3416 3417 // Run SWIG on all SWIG input files. 3418 // TODO: Don't build a shared library, once SWIG emits the necessary 3419 // pragmas for external linking. 3420 func (b *Builder) swig(a *Action, p *load.Package, objdir string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { 3421 if err := b.swigVersionCheck(); err != nil { 3422 return nil, nil, nil, err 3423 } 3424 3425 intgosize, err := b.swigIntSize(objdir) 3426 if err != nil { 3427 return nil, nil, nil, err 3428 } 3429 3430 for _, f := range p.SwigFiles { 3431 goFile, cFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, false, intgosize) 3432 if err != nil { 3433 return nil, nil, nil, err 3434 } 3435 if goFile != "" { 3436 outGo = append(outGo, goFile) 3437 } 3438 if cFile != "" { 3439 outC = append(outC, cFile) 3440 } 3441 } 3442 for _, f := range p.SwigCXXFiles { 3443 goFile, cxxFile, err := b.swigOne(a, p, f, objdir, pcCFLAGS, true, intgosize) 3444 if err != nil { 3445 return nil, nil, nil, err 3446 } 3447 if goFile != "" { 3448 outGo = append(outGo, goFile) 3449 } 3450 if cxxFile != "" { 3451 outCXX = append(outCXX, cxxFile) 3452 } 3453 } 3454 return outGo, outC, outCXX, nil 3455 } 3456 3457 // Make sure SWIG is new enough. 3458 var ( 3459 swigCheckOnce sync.Once 3460 swigCheck error 3461 ) 3462 3463 func (b *Builder) swigDoVersionCheck() error { 3464 out, err := b.runOut(nil, ".", nil, "swig", "-version") 3465 if err != nil { 3466 return err 3467 } 3468 re := regexp.MustCompile(`[vV]ersion +(\d+)([.]\d+)?([.]\d+)?`) 3469 matches := re.FindSubmatch(out) 3470 if matches == nil { 3471 // Can't find version number; hope for the best. 3472 return nil 3473 } 3474 3475 major, err := strconv.Atoi(string(matches[1])) 3476 if err != nil { 3477 // Can't find version number; hope for the best. 3478 return nil 3479 } 3480 const errmsg = "must have SWIG version >= 3.0.6" 3481 if major < 3 { 3482 return errors.New(errmsg) 3483 } 3484 if major > 3 { 3485 // 4.0 or later 3486 return nil 3487 } 3488 3489 // We have SWIG version 3.x. 3490 if len(matches[2]) > 0 { 3491 minor, err := strconv.Atoi(string(matches[2][1:])) 3492 if err != nil { 3493 return nil 3494 } 3495 if minor > 0 { 3496 // 3.1 or later 3497 return nil 3498 } 3499 } 3500 3501 // We have SWIG version 3.0.x. 3502 if len(matches[3]) > 0 { 3503 patch, err := strconv.Atoi(string(matches[3][1:])) 3504 if err != nil { 3505 return nil 3506 } 3507 if patch < 6 { 3508 // Before 3.0.6. 3509 return errors.New(errmsg) 3510 } 3511 } 3512 3513 return nil 3514 } 3515 3516 func (b *Builder) swigVersionCheck() error { 3517 swigCheckOnce.Do(func() { 3518 swigCheck = b.swigDoVersionCheck() 3519 }) 3520 return swigCheck 3521 } 3522 3523 // Find the value to pass for the -intgosize option to swig. 3524 var ( 3525 swigIntSizeOnce sync.Once 3526 swigIntSize string 3527 swigIntSizeError error 3528 ) 3529 3530 // This code fails to build if sizeof(int) <= 32 3531 const swigIntSizeCode = ` 3532 package main 3533 const i int = 1 << 32 3534 ` 3535 3536 // Determine the size of int on the target system for the -intgosize option 3537 // of swig >= 2.0.9. Run only once. 3538 func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) { 3539 if cfg.BuildN { 3540 return "$INTBITS", nil 3541 } 3542 src := filepath.Join(b.WorkDir, "swig_intsize.go") 3543 if err = os.WriteFile(src, []byte(swigIntSizeCode), 0666); err != nil { 3544 return 3545 } 3546 srcs := []string{src} 3547 3548 p := load.GoFilesPackage(context.TODO(), load.PackageOpts{}, srcs) 3549 3550 if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, srcs); e != nil { 3551 return "32", nil 3552 } 3553 return "64", nil 3554 } 3555 3556 // Determine the size of int on the target system for the -intgosize option 3557 // of swig >= 2.0.9. 3558 func (b *Builder) swigIntSize(objdir string) (intsize string, err error) { 3559 swigIntSizeOnce.Do(func() { 3560 swigIntSize, swigIntSizeError = b.swigDoIntSize(objdir) 3561 }) 3562 return swigIntSize, swigIntSizeError 3563 } 3564 3565 // Run SWIG on one SWIG input file. 3566 func (b *Builder) swigOne(a *Action, p *load.Package, file, objdir string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { 3567 cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.CFlags(p) 3568 if err != nil { 3569 return "", "", err 3570 } 3571 3572 var cflags []string 3573 if cxx { 3574 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS) 3575 } else { 3576 cflags = str.StringList(cgoCPPFLAGS, pcCFLAGS, cgoCFLAGS) 3577 } 3578 3579 n := 5 // length of ".swig" 3580 if cxx { 3581 n = 8 // length of ".swigcxx" 3582 } 3583 base := file[:len(file)-n] 3584 goFile := base + ".go" 3585 gccBase := base + "_wrap." 3586 gccExt := "c" 3587 if cxx { 3588 gccExt = "cxx" 3589 } 3590 3591 gccgo := cfg.BuildToolchainName == "gccgo" 3592 3593 // swig 3594 args := []string{ 3595 "-go", 3596 "-cgo", 3597 "-intgosize", intgosize, 3598 "-module", base, 3599 "-o", objdir + gccBase + gccExt, 3600 "-outdir", objdir, 3601 } 3602 3603 for _, f := range cflags { 3604 if len(f) > 3 && f[:2] == "-I" { 3605 args = append(args, f) 3606 } 3607 } 3608 3609 if gccgo { 3610 args = append(args, "-gccgo") 3611 if pkgpath := gccgoPkgpath(p); pkgpath != "" { 3612 args = append(args, "-go-pkgpath", pkgpath) 3613 } 3614 } 3615 if cxx { 3616 args = append(args, "-c++") 3617 } 3618 3619 out, err := b.runOut(a, p.Dir, nil, "swig", args, file) 3620 if err != nil { 3621 if len(out) > 0 { 3622 if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) { 3623 return "", "", errors.New("must have SWIG version >= 3.0.6") 3624 } 3625 // swig error 3626 err = formatOutput(b.WorkDir, p.Dir, p.ImportPath, p.Desc(), b.processOutput(out)) 3627 } 3628 return "", "", err 3629 } 3630 if len(out) > 0 { 3631 b.showOutput(a, p.Dir, p.Desc(), b.processOutput(out)) // swig warning 3632 } 3633 3634 // If the input was x.swig, the output is x.go in the objdir. 3635 // But there might be an x.go in the original dir too, and if it 3636 // uses cgo as well, cgo will be processing both and will 3637 // translate both into x.cgo1.go in the objdir, overwriting one. 3638 // Rename x.go to _x_swig.go to avoid this problem. 3639 // We ignore files in the original dir that begin with underscore 3640 // so _x_swig.go cannot conflict with an original file we were 3641 // going to compile. 3642 goFile = objdir + goFile 3643 newGoFile := objdir + "_" + base + "_swig.go" 3644 if err := os.Rename(goFile, newGoFile); err != nil { 3645 return "", "", err 3646 } 3647 return newGoFile, objdir + gccBase + gccExt, nil 3648 } 3649 3650 // disableBuildID adjusts a linker command line to avoid creating a 3651 // build ID when creating an object file rather than an executable or 3652 // shared library. Some systems, such as Ubuntu, always add 3653 // --build-id to every link, but we don't want a build ID when we are 3654 // producing an object file. On some of those system a plain -r (not 3655 // -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a 3656 // plain -r. I don't know how to turn off --build-id when using clang 3657 // other than passing a trailing --build-id=none. So that is what we 3658 // do, but only on systems likely to support it, which is to say, 3659 // systems that normally use gold or the GNU linker. 3660 func (b *Builder) disableBuildID(ldflags []string) []string { 3661 switch cfg.Goos { 3662 case "android", "dragonfly", "linux", "netbsd": 3663 ldflags = append(ldflags, "-Wl,--build-id=none") 3664 } 3665 return ldflags 3666 } 3667 3668 // mkAbsFiles converts files into a list of absolute files, 3669 // assuming they were originally relative to dir, 3670 // and returns that new list. 3671 func mkAbsFiles(dir string, files []string) []string { 3672 abs := make([]string, len(files)) 3673 for i, f := range files { 3674 if !filepath.IsAbs(f) { 3675 f = filepath.Join(dir, f) 3676 } 3677 abs[i] = f 3678 } 3679 return abs 3680 } 3681 3682 // passLongArgsInResponseFiles modifies cmd such that, for 3683 // certain programs, long arguments are passed in "response files", a 3684 // file on disk with the arguments, with one arg per line. An actual 3685 // argument starting with '@' means that the rest of the argument is 3686 // a filename of arguments to expand. 3687 // 3688 // See issues 18468 (Windows) and 37768 (Darwin). 3689 func passLongArgsInResponseFiles(cmd *exec.Cmd) (cleanup func()) { 3690 cleanup = func() {} // no cleanup by default 3691 3692 var argLen int 3693 for _, arg := range cmd.Args { 3694 argLen += len(arg) 3695 } 3696 3697 // If we're not approaching 32KB of args, just pass args normally. 3698 // (use 30KB instead to be conservative; not sure how accounting is done) 3699 if !useResponseFile(cmd.Path, argLen) { 3700 return 3701 } 3702 3703 tf, err := os.CreateTemp("", "args") 3704 if err != nil { 3705 log.Fatalf("error writing long arguments to response file: %v", err) 3706 } 3707 cleanup = func() { os.Remove(tf.Name()) } 3708 var buf bytes.Buffer 3709 for _, arg := range cmd.Args[1:] { 3710 fmt.Fprintf(&buf, "%s\n", encodeArg(arg)) 3711 } 3712 if _, err := tf.Write(buf.Bytes()); err != nil { 3713 tf.Close() 3714 cleanup() 3715 log.Fatalf("error writing long arguments to response file: %v", err) 3716 } 3717 if err := tf.Close(); err != nil { 3718 cleanup() 3719 log.Fatalf("error writing long arguments to response file: %v", err) 3720 } 3721 cmd.Args = []string{cmd.Args[0], "@" + tf.Name()} 3722 return cleanup 3723 } 3724 3725 func useResponseFile(path string, argLen int) bool { 3726 // Unless the program uses flag_objabi.Flagparse, which understands 3727 // response files, don't use response files. 3728 // TODO: Note that other toolchains like CC are missing here for now. 3729 prog := strings.TrimSuffix(filepath.Base(path), ".exe") 3730 switch prog { 3731 case "compile", "link", "cgo", "asm": 3732 default: 3733 return false 3734 } 3735 3736 if argLen > sys.ExecArgLengthLimit { 3737 return true 3738 } 3739 3740 // On the Go build system, use response files about 10% of the 3741 // time, just to exercise this codepath. 3742 isBuilder := os.Getenv("GO_BUILDER_NAME") != "" 3743 if isBuilder && rand.Intn(10) == 0 { 3744 return true 3745 } 3746 3747 return false 3748 } 3749 3750 // encodeArg encodes an argument for response file writing. 3751 func encodeArg(arg string) string { 3752 // If there aren't any characters we need to reencode, fastpath out. 3753 if !strings.ContainsAny(arg, "\\\n") { 3754 return arg 3755 } 3756 var b strings.Builder 3757 for _, r := range arg { 3758 switch r { 3759 case '\\': 3760 b.WriteByte('\\') 3761 b.WriteByte('\\') 3762 case '\n': 3763 b.WriteByte('\\') 3764 b.WriteByte('n') 3765 default: 3766 b.WriteRune(r) 3767 } 3768 } 3769 return b.String() 3770 }