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