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