github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/go/internal/work/buildid.go (about) 1 // Copyright 2017 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 package work 6 7 import ( 8 "bytes" 9 "fmt" 10 "io/ioutil" 11 "os" 12 "os/exec" 13 "strings" 14 15 "cmd/go/internal/base" 16 "cmd/go/internal/cache" 17 "cmd/go/internal/cfg" 18 "cmd/go/internal/load" 19 "cmd/go/internal/str" 20 "cmd/internal/buildid" 21 "cmd/internal/objabi" 22 ) 23 24 // Build IDs 25 // 26 // Go packages and binaries are stamped with build IDs that record both 27 // the action ID, which is a hash of the inputs to the action that produced 28 // the packages or binary, and the content ID, which is a hash of the action 29 // output, namely the archive or binary itself. The hash is the same one 30 // used by the build artifact cache (see cmd/go/internal/cache), but 31 // truncated when stored in packages and binaries, as the full length is not 32 // needed and is a bit unwieldy. The precise form is 33 // 34 // actionID/[.../]contentID 35 // 36 // where the actionID and contentID are prepared by hashToString below. 37 // and are found by looking for the first or last slash. 38 // Usually the buildID is simply actionID/contentID, but see below for an 39 // exception. 40 // 41 // The build ID serves two primary purposes. 42 // 43 // 1. The action ID half allows installed packages and binaries to serve as 44 // one-element cache entries. If we intend to build math.a with a given 45 // set of inputs summarized in the action ID, and the installed math.a already 46 // has that action ID, we can reuse the installed math.a instead of rebuilding it. 47 // 48 // 2. The content ID half allows the easy preparation of action IDs for steps 49 // that consume a particular package or binary. The content hash of every 50 // input file for a given action must be included in the action ID hash. 51 // Storing the content ID in the build ID lets us read it from the file with 52 // minimal I/O, instead of reading and hashing the entire file. 53 // This is especially effective since packages and binaries are typically 54 // the largest inputs to an action. 55 // 56 // Separating action ID from content ID is important for reproducible builds. 57 // The compiler is compiled with itself. If an output were represented by its 58 // own action ID (instead of content ID) when computing the action ID of 59 // the next step in the build process, then the compiler could never have its 60 // own input action ID as its output action ID (short of a miraculous hash collision). 61 // Instead we use the content IDs to compute the next action ID, and because 62 // the content IDs converge, so too do the action IDs and therefore the 63 // build IDs and the overall compiler binary. See cmd/dist's cmdbootstrap 64 // for the actual convergence sequence. 65 // 66 // The “one-element cache” purpose is a bit more complex for installed 67 // binaries. For a binary, like cmd/gofmt, there are two steps: compile 68 // cmd/gofmt/*.go into main.a, and then link main.a into the gofmt binary. 69 // We do not install gofmt's main.a, only the gofmt binary. Being able to 70 // decide that the gofmt binary is up-to-date means computing the action ID 71 // for the final link of the gofmt binary and comparing it against the 72 // already-installed gofmt binary. But computing the action ID for the link 73 // means knowing the content ID of main.a, which we did not keep. 74 // To sidestep this problem, each binary actually stores an expanded build ID: 75 // 76 // actionID(binary)/actionID(main.a)/contentID(main.a)/contentID(binary) 77 // 78 // (Note that this can be viewed equivalently as: 79 // 80 // actionID(binary)/buildID(main.a)/contentID(binary) 81 // 82 // Storing the buildID(main.a) in the middle lets the computations that care 83 // about the prefix or suffix halves ignore the middle and preserves the 84 // original build ID as a contiguous string.) 85 // 86 // During the build, when it's time to build main.a, the gofmt binary has the 87 // information needed to decide whether the eventual link would produce 88 // the same binary: if the action ID for main.a's inputs matches and then 89 // the action ID for the link step matches when assuming the given main.a 90 // content ID, then the binary as a whole is up-to-date and need not be rebuilt. 91 // 92 // This is all a bit complex and may be simplified once we can rely on the 93 // main cache, but at least at the start we will be using the content-based 94 // staleness determination without a cache beyond the usual installed 95 // package and binary locations. 96 97 const buildIDSeparator = "/" 98 99 // actionID returns the action ID half of a build ID. 100 func actionID(buildID string) string { 101 i := strings.Index(buildID, buildIDSeparator) 102 if i < 0 { 103 return buildID 104 } 105 return buildID[:i] 106 } 107 108 // contentID returns the content ID half of a build ID. 109 func contentID(buildID string) string { 110 return buildID[strings.LastIndex(buildID, buildIDSeparator)+1:] 111 } 112 113 // hashToString converts the hash h to a string to be recorded 114 // in package archives and binaries as part of the build ID. 115 // We use the first 96 bits of the hash and encode it in base64, 116 // resulting in a 16-byte string. Because this is only used for 117 // detecting the need to rebuild installed files (not for lookups 118 // in the object file cache), 96 bits are sufficient to drive the 119 // probability of a false "do not need to rebuild" decision to effectively zero. 120 // We embed two different hashes in archives and four in binaries, 121 // so cutting to 16 bytes is a significant savings when build IDs are displayed. 122 // (16*4+3 = 67 bytes compared to 64*4+3 = 259 bytes for the 123 // more straightforward option of printing the entire h in hex). 124 func hashToString(h [cache.HashSize]byte) string { 125 const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" 126 const chunks = 5 127 var dst [chunks * 4]byte 128 for i := 0; i < chunks; i++ { 129 v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2]) 130 dst[4*i+0] = b64[(v>>18)&0x3F] 131 dst[4*i+1] = b64[(v>>12)&0x3F] 132 dst[4*i+2] = b64[(v>>6)&0x3F] 133 dst[4*i+3] = b64[v&0x3F] 134 } 135 return string(dst[:]) 136 } 137 138 // toolID returns the unique ID to use for the current copy of the 139 // named tool (asm, compile, cover, link). 140 // 141 // It is important that if the tool changes (for example a compiler bug is fixed 142 // and the compiler reinstalled), toolID returns a different string, so that old 143 // package archives look stale and are rebuilt (with the fixed compiler). 144 // This suggests using a content hash of the tool binary, as stored in the build ID. 145 // 146 // Unfortunately, we can't just open the tool binary, because the tool might be 147 // invoked via a wrapper program specified by -toolexec and we don't know 148 // what the wrapper program does. In particular, we want "-toolexec toolstash" 149 // to continue working: it does no good if "-toolexec toolstash" is executing a 150 // stashed copy of the compiler but the go command is acting as if it will run 151 // the standard copy of the compiler. The solution is to ask the tool binary to tell 152 // us its own build ID using the "-V=full" flag now supported by all tools. 153 // Then we know we're getting the build ID of the compiler that will actually run 154 // during the build. (How does the compiler binary know its own content hash? 155 // We store it there using updateBuildID after the standard link step.) 156 // 157 // A final twist is that we'd prefer to have reproducible builds for release toolchains. 158 // It should be possible to cross-compile for Windows from either Linux or Mac 159 // or Windows itself and produce the same binaries, bit for bit. If the tool ID, 160 // which influences the action ID half of the build ID, is based on the content ID, 161 // then the Linux compiler binary and Mac compiler binary will have different tool IDs 162 // and therefore produce executables with different action IDs. 163 // To avoids this problem, for releases we use the release version string instead 164 // of the compiler binary's content hash. This assumes that all compilers built 165 // on all different systems are semantically equivalent, which is of course only true 166 // modulo bugs. (Producing the exact same executables also requires that the different 167 // build setups agree on details like $GOROOT and file name paths, but at least the 168 // tool IDs do not make it impossible.) 169 func (b *Builder) toolID(name string) string { 170 b.id.Lock() 171 id := b.toolIDCache[name] 172 b.id.Unlock() 173 174 if id != "" { 175 return id 176 } 177 178 path := base.Tool(name) 179 desc := "go tool " + name 180 181 // Special case: undocumented $GOVETTOOL overrides usual vet, for testing vet. 182 if name == "vet" && VetTool != "" { 183 path = VetTool 184 desc = VetTool 185 } 186 187 cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full") 188 cmd := exec.Command(cmdline[0], cmdline[1:]...) 189 cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) 190 var stdout, stderr bytes.Buffer 191 cmd.Stdout = &stdout 192 cmd.Stderr = &stderr 193 if err := cmd.Run(); err != nil { 194 base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes()) 195 } 196 197 line := stdout.String() 198 f := strings.Fields(line) 199 if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") { 200 base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line) 201 } 202 if f[2] == "devel" { 203 // On the development branch, use the content ID part of the build ID. 204 id = contentID(f[len(f)-1]) 205 } else { 206 // For a release, the output is like: "compile version go1.9.1". Use the whole line. 207 id = f[2] 208 } 209 210 // For the compiler, add any experiments. 211 if name == "compile" { 212 id += " " + objabi.Expstring() 213 } 214 215 b.id.Lock() 216 b.toolIDCache[name] = id 217 b.id.Unlock() 218 219 return id 220 } 221 222 // gccToolID returns the unique ID to use for a tool that is invoked 223 // by the GCC driver. This is in particular gccgo, but this can also 224 // be used for gcc, g++, gfortran, etc.; those tools all use the GCC 225 // driver under different names. The approach used here should also 226 // work for sufficiently new versions of clang. Unlike toolID, the 227 // name argument is the program to run. The language argument is the 228 // type of input file as passed to the GCC driver's -x option. 229 // 230 // For these tools we have no -V=full option to dump the build ID, 231 // but we can run the tool with -v -### to reliably get the compiler proper 232 // and hash that. That will work in the presence of -toolexec. 233 // 234 // In order to get reproducible builds for released compilers, we 235 // detect a released compiler by the absence of "experimental" in the 236 // --version output, and in that case we just use the version string. 237 func (b *Builder) gccgoToolID(name, language string) (string, error) { 238 key := name + "." + language 239 b.id.Lock() 240 id := b.toolIDCache[key] 241 b.id.Unlock() 242 243 if id != "" { 244 return id, nil 245 } 246 247 // Invoke the driver with -### to see the subcommands and the 248 // version strings. Use -x to set the language. Pretend to 249 // compile an empty file on standard input. 250 cmdline := str.StringList(cfg.BuildToolexec, name, "-###", "-x", language, "-c", "-") 251 cmd := exec.Command(cmdline[0], cmdline[1:]...) 252 cmd.Env = base.EnvForDir(cmd.Dir, os.Environ()) 253 // Force untranslated output so that we see the string "version". 254 cmd.Env = append(cmd.Env, "LC_ALL=C") 255 out, err := cmd.CombinedOutput() 256 if err != nil { 257 return "", fmt.Errorf("%s: %v; output: %q", name, err, out) 258 } 259 260 version := "" 261 lines := strings.Split(string(out), "\n") 262 for _, line := range lines { 263 if fields := strings.Fields(line); len(fields) > 1 && fields[1] == "version" { 264 version = line 265 break 266 } 267 } 268 if version == "" { 269 return "", fmt.Errorf("%s: can not find version number in %q", name, out) 270 } 271 272 if !strings.Contains(version, "experimental") { 273 // This is a release. Use this line as the tool ID. 274 id = version 275 } else { 276 // This is a development version. The first line with 277 // a leading space is the compiler proper. 278 compiler := "" 279 for _, line := range lines { 280 if len(line) > 1 && line[0] == ' ' { 281 compiler = line 282 break 283 } 284 } 285 if compiler == "" { 286 return "", fmt.Errorf("%s: can not find compilation command in %q", name, out) 287 } 288 289 fields := strings.Fields(compiler) 290 if len(fields) == 0 { 291 return "", fmt.Errorf("%s: compilation command confusion %q", name, out) 292 } 293 exe := fields[0] 294 if !strings.ContainsAny(exe, `/\`) { 295 if lp, err := exec.LookPath(exe); err == nil { 296 exe = lp 297 } 298 } 299 if _, err := os.Stat(exe); err != nil { 300 return "", fmt.Errorf("%s: can not find compiler %q: %v; output %q", name, exe, err, out) 301 } 302 id = b.fileHash(exe) 303 } 304 305 b.id.Lock() 306 b.toolIDCache[name] = id 307 b.id.Unlock() 308 309 return id, nil 310 } 311 312 // Check if assembler used by gccgo is GNU as. 313 func assemblerIsGas() bool { 314 cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as") 315 assembler, err := cmd.Output() 316 if err == nil { 317 cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version") 318 out, err := cmd.Output() 319 return err == nil && strings.Contains(string(out), "GNU") 320 } else { 321 return false 322 } 323 } 324 325 // gccgoBuildIDELFFile creates an assembler file that records the 326 // action's build ID in an SHF_EXCLUDE section. 327 func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) { 328 sfile := a.Objdir + "_buildid.s" 329 330 var buf bytes.Buffer 331 if cfg.Goos != "solaris" || assemblerIsGas() { 332 fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n") 333 } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" { 334 fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n") 335 } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64" 336 fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n") 337 } 338 fmt.Fprintf(&buf, "\t.byte ") 339 for i := 0; i < len(a.buildID); i++ { 340 if i > 0 { 341 if i%8 == 0 { 342 fmt.Fprintf(&buf, "\n\t.byte ") 343 } else { 344 fmt.Fprintf(&buf, ",") 345 } 346 } 347 fmt.Fprintf(&buf, "%#02x", a.buildID[i]) 348 } 349 fmt.Fprintf(&buf, "\n") 350 if cfg.Goos != "solaris" { 351 secType := "@progbits" 352 if cfg.Goarch == "arm" { 353 secType = "%progbits" 354 } 355 fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",%s`+"\n", secType) 356 fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",%s`+"\n", secType) 357 } 358 359 if cfg.BuildN || cfg.BuildX { 360 for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) { 361 b.Showcmd("", "echo '%s' >> %s", line, sfile) 362 } 363 if cfg.BuildN { 364 return sfile, nil 365 } 366 } 367 368 if err := ioutil.WriteFile(sfile, buf.Bytes(), 0666); err != nil { 369 return "", err 370 } 371 372 return sfile, nil 373 } 374 375 // buildID returns the build ID found in the given file. 376 // If no build ID is found, buildID returns the content hash of the file. 377 func (b *Builder) buildID(file string) string { 378 b.id.Lock() 379 id := b.buildIDCache[file] 380 b.id.Unlock() 381 382 if id != "" { 383 return id 384 } 385 386 id, err := buildid.ReadFile(file) 387 if err != nil { 388 id = b.fileHash(file) 389 } 390 391 b.id.Lock() 392 b.buildIDCache[file] = id 393 b.id.Unlock() 394 395 return id 396 } 397 398 // fileHash returns the content hash of the named file. 399 func (b *Builder) fileHash(file string) string { 400 sum, err := cache.FileHash(file) 401 if err != nil { 402 return "" 403 } 404 return hashToString(sum) 405 } 406 407 // useCache tries to satisfy the action a, which has action ID actionHash, 408 // by using a cached result from an earlier build. At the moment, the only 409 // cached result is the installed package or binary at target. 410 // If useCache decides that the cache can be used, it sets a.buildID 411 // and a.built for use by parent actions and then returns true. 412 // Otherwise it sets a.buildID to a temporary build ID for use in the build 413 // and returns false. When useCache returns false the expectation is that 414 // the caller will build the target and then call updateBuildID to finish the 415 // build ID computation. 416 // When useCache returns false, it may have initiated buffering of output 417 // during a's work. The caller should defer b.flushOutput(a), to make sure 418 // that flushOutput is eventually called regardless of whether the action 419 // succeeds. The flushOutput call must happen after updateBuildID. 420 func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID, target string) bool { 421 // The second half of the build ID here is a placeholder for the content hash. 422 // It's important that the overall buildID be unlikely verging on impossible 423 // to appear in the output by chance, but that should be taken care of by 424 // the actionID half; if it also appeared in the input that would be like an 425 // engineered 96-bit partial SHA256 collision. 426 a.actionID = actionHash 427 actionID := hashToString(actionHash) 428 contentID := actionID // temporary placeholder, likely unique 429 a.buildID = actionID + buildIDSeparator + contentID 430 431 // Executable binaries also record the main build ID in the middle. 432 // See "Build IDs" comment above. 433 if a.Mode == "link" { 434 mainpkg := a.Deps[0] 435 a.buildID = actionID + buildIDSeparator + mainpkg.buildID + buildIDSeparator + contentID 436 } 437 438 // Check to see if target exists and matches the expected action ID. 439 // If so, it's up to date and we can reuse it instead of rebuilding it. 440 var buildID string 441 if target != "" && !cfg.BuildA { 442 buildID, _ = buildid.ReadFile(target) 443 if strings.HasPrefix(buildID, actionID+buildIDSeparator) { 444 a.buildID = buildID 445 a.built = target 446 // Poison a.Target to catch uses later in the build. 447 a.Target = "DO NOT USE - " + a.Mode 448 return true 449 } 450 } 451 452 // Special case for building a main package: if the only thing we 453 // want the package for is to link a binary, and the binary is 454 // already up-to-date, then to avoid a rebuild, report the package 455 // as up-to-date as well. See "Build IDs" comment above. 456 // TODO(rsc): Rewrite this code to use a TryCache func on the link action. 457 if target != "" && !cfg.BuildA && !b.NeedExport && a.Mode == "build" && len(a.triggers) == 1 && a.triggers[0].Mode == "link" { 458 buildID, err := buildid.ReadFile(target) 459 if err == nil { 460 id := strings.Split(buildID, buildIDSeparator) 461 if len(id) == 4 && id[1] == actionID { 462 // Temporarily assume a.buildID is the package build ID 463 // stored in the installed binary, and see if that makes 464 // the upcoming link action ID a match. If so, report that 465 // we built the package, safe in the knowledge that the 466 // link step will not ask us for the actual package file. 467 // Note that (*Builder).LinkAction arranged that all of 468 // a.triggers[0]'s dependencies other than a are also 469 // dependencies of a, so that we can be sure that, 470 // other than a.buildID, b.linkActionID is only accessing 471 // build IDs of completed actions. 472 oldBuildID := a.buildID 473 a.buildID = id[1] + buildIDSeparator + id[2] 474 linkID := hashToString(b.linkActionID(a.triggers[0])) 475 if id[0] == linkID { 476 // Best effort attempt to display output from the compile and link steps. 477 // If it doesn't work, it doesn't work: reusing the cached binary is more 478 // important than reprinting diagnostic information. 479 if c := cache.Default(); c != nil { 480 showStdout(b, c, a.actionID, "stdout") // compile output 481 showStdout(b, c, a.actionID, "link-stdout") // link output 482 } 483 484 // Poison a.Target to catch uses later in the build. 485 a.Target = "DO NOT USE - main build pseudo-cache Target" 486 a.built = "DO NOT USE - main build pseudo-cache built" 487 return true 488 } 489 // Otherwise restore old build ID for main build. 490 a.buildID = oldBuildID 491 } 492 } 493 } 494 495 // Special case for linking a test binary: if the only thing we 496 // want the binary for is to run the test, and the test result is cached, 497 // then to avoid the link step, report the link as up-to-date. 498 // We avoid the nested build ID problem in the previous special case 499 // by recording the test results in the cache under the action ID half. 500 if !cfg.BuildA && len(a.triggers) == 1 && a.triggers[0].TryCache != nil && a.triggers[0].TryCache(b, a.triggers[0]) { 501 // Best effort attempt to display output from the compile and link steps. 502 // If it doesn't work, it doesn't work: reusing the test result is more 503 // important than reprinting diagnostic information. 504 if c := cache.Default(); c != nil { 505 showStdout(b, c, a.Deps[0].actionID, "stdout") // compile output 506 showStdout(b, c, a.Deps[0].actionID, "link-stdout") // link output 507 } 508 509 // Poison a.Target to catch uses later in the build. 510 a.Target = "DO NOT USE - pseudo-cache Target" 511 a.built = "DO NOT USE - pseudo-cache built" 512 return true 513 } 514 515 if b.IsCmdList { 516 // Invoked during go list to compute and record staleness. 517 if p := a.Package; p != nil && !p.Stale { 518 p.Stale = true 519 if cfg.BuildA { 520 p.StaleReason = "build -a flag in use" 521 } else { 522 p.StaleReason = "build ID mismatch" 523 for _, p1 := range p.Internal.Imports { 524 if p1.Stale && p1.StaleReason != "" { 525 if strings.HasPrefix(p1.StaleReason, "stale dependency: ") { 526 p.StaleReason = p1.StaleReason 527 break 528 } 529 if strings.HasPrefix(p.StaleReason, "build ID mismatch") { 530 p.StaleReason = "stale dependency: " + p1.ImportPath 531 } 532 } 533 } 534 } 535 } 536 537 // Fall through to update a.buildID from the build artifact cache, 538 // which will affect the computation of buildIDs for targets 539 // higher up in the dependency graph. 540 } 541 542 // Check the build artifact cache. 543 // We treat hits in this cache as being "stale" for the purposes of go list 544 // (in effect, "stale" means whether p.Target is up-to-date), 545 // but we're still happy to use results from the build artifact cache. 546 if c := cache.Default(); c != nil { 547 if !cfg.BuildA { 548 if file, _, err := c.GetFile(actionHash); err == nil { 549 if buildID, err := buildid.ReadFile(file); err == nil { 550 if err := showStdout(b, c, a.actionID, "stdout"); err == nil { 551 a.built = file 552 a.Target = "DO NOT USE - using cache" 553 a.buildID = buildID 554 if p := a.Package; p != nil { 555 // Clearer than explaining that something else is stale. 556 p.StaleReason = "not installed but available in build cache" 557 } 558 return true 559 } 560 } 561 } 562 } 563 564 // Begin saving output for later writing to cache. 565 a.output = []byte{} 566 } 567 568 return false 569 } 570 571 func showStdout(b *Builder, c *cache.Cache, actionID cache.ActionID, key string) error { 572 stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(actionID, key)) 573 if err != nil { 574 return err 575 } 576 577 if len(stdout) > 0 { 578 if cfg.BuildX || cfg.BuildN { 579 b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) 580 } 581 if !cfg.BuildN { 582 b.Print(string(stdout)) 583 } 584 } 585 return nil 586 } 587 588 // flushOutput flushes the output being queued in a. 589 func (b *Builder) flushOutput(a *Action) { 590 b.Print(string(a.output)) 591 a.output = nil 592 } 593 594 // updateBuildID updates the build ID in the target written by action a. 595 // It requires that useCache was called for action a and returned false, 596 // and that the build was then carried out and given the temporary 597 // a.buildID to record as the build ID in the resulting package or binary. 598 // updateBuildID computes the final content ID and updates the build IDs 599 // in the binary. 600 // 601 // Keep in sync with src/cmd/buildid/buildid.go 602 func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { 603 if cfg.BuildX || cfg.BuildN { 604 if rewrite { 605 b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList(base.Tool("buildid"), "-w", target))) 606 } 607 if cfg.BuildN { 608 return nil 609 } 610 } 611 612 // Cache output from compile/link, even if we don't do the rest. 613 if c := cache.Default(); c != nil { 614 switch a.Mode { 615 case "build": 616 c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) 617 case "link": 618 // Even though we don't cache the binary, cache the linker text output. 619 // We might notice that an installed binary is up-to-date but still 620 // want to pretend to have run the linker. 621 // Store it under the main package's action ID 622 // to make it easier to find when that's all we have. 623 for _, a1 := range a.Deps { 624 if p1 := a1.Package; p1 != nil && p1.Name == "main" { 625 c.PutBytes(cache.Subkey(a1.actionID, "link-stdout"), a.output) 626 break 627 } 628 } 629 } 630 } 631 632 // Find occurrences of old ID and compute new content-based ID. 633 r, err := os.Open(target) 634 if err != nil { 635 return err 636 } 637 matches, hash, err := buildid.FindAndHash(r, a.buildID, 0) 638 r.Close() 639 if err != nil { 640 return err 641 } 642 newID := a.buildID[:strings.LastIndex(a.buildID, buildIDSeparator)] + buildIDSeparator + hashToString(hash) 643 if len(newID) != len(a.buildID) { 644 return fmt.Errorf("internal error: build ID length mismatch %q vs %q", a.buildID, newID) 645 } 646 647 // Replace with new content-based ID. 648 a.buildID = newID 649 if len(matches) == 0 { 650 // Assume the user specified -buildid= to override what we were going to choose. 651 return nil 652 } 653 654 if rewrite { 655 w, err := os.OpenFile(target, os.O_WRONLY, 0) 656 if err != nil { 657 return err 658 } 659 err = buildid.Rewrite(w, matches, newID) 660 if err != nil { 661 w.Close() 662 return err 663 } 664 if err := w.Close(); err != nil { 665 return err 666 } 667 } 668 669 // Cache package builds, but not binaries (link steps). 670 // The expectation is that binaries are not reused 671 // nearly as often as individual packages, and they're 672 // much larger, so the cache-footprint-to-utility ratio 673 // of binaries is much lower for binaries. 674 // Not caching the link step also makes sure that repeated "go run" at least 675 // always rerun the linker, so that they don't get too fast. 676 // (We don't want people thinking go is a scripting language.) 677 // Note also that if we start caching binaries, then we will 678 // copy the binaries out of the cache to run them, and then 679 // that will mean the go process is itself writing a binary 680 // and then executing it, so we will need to defend against 681 // ETXTBSY problems as discussed in exec.go and golang.org/issue/22220. 682 if c := cache.Default(); c != nil && a.Mode == "build" { 683 r, err := os.Open(target) 684 if err == nil { 685 if a.output == nil { 686 panic("internal error: a.output not set") 687 } 688 outputID, _, err := c.Put(a.actionID, r) 689 r.Close() 690 if err == nil && cfg.BuildX { 691 b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cp", target, c.OutputFile(outputID)))) 692 } 693 if b.NeedExport { 694 if err != nil { 695 return err 696 } 697 a.Package.Export = c.OutputFile(outputID) 698 } 699 } 700 } 701 702 return nil 703 }