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