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