src/cmd/go/internal/work/exec.go GO 4,004 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 4,004.
1// Copyright 2011 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45// Action graph execution.67package work89import (10	"bytes"11	"cmd/internal/cov/covcmd"12	"cmd/internal/pathcache"13	"context"14	"crypto/sha256"15	"encoding/json"16	"errors"17	"fmt"18	"go/token"19	"internal/lazyregexp"20	"io"21	"io/fs"22	"log"23	"math/rand"24	"os"25	"os/exec"26	"path/filepath"27	"regexp"28	"runtime"29	"slices"30	"sort"31	"strconv"32	"strings"33	"sync"34	"time"3536	"cmd/go/internal/base"37	"cmd/go/internal/cache"38	"cmd/go/internal/cfg"39	"cmd/go/internal/fsys"40	"cmd/go/internal/gover"41	"cmd/go/internal/load"42	"cmd/go/internal/modinfo"43	"cmd/go/internal/modload"44	"cmd/go/internal/str"45	"cmd/go/internal/trace"46	"cmd/internal/buildid"47	"cmd/internal/quoted"48	"cmd/internal/sys"4950	"golang.org/x/tools/go/analysis"51)5253const DefaultCFlags = "-O2 -g"5455// actionList returns the list of actions in the dag rooted at root56// as visited in a depth-first post-order traversal.57func actionList(root *Action) []*Action {58	seen := map[*Action]bool{}59	all := []*Action{}60	var walk func(*Action)61	walk = func(a *Action) {62		if seen[a] {63			return64		}65		seen[a] = true66		for _, a1 := range a.Deps {67			walk(a1)68		}69		all = append(all, a)70	}71	walk(root)72	return all73}7475// Do runs the action graph rooted at root.76func (b *Builder) Do(ctx context.Context, root *Action) {77	ctx, span := trace.StartSpan(ctx, "exec.Builder.Do ("+root.Mode+" "+root.Target+")")78	defer span.Done()7980	if !b.IsCmdList {81		// If we're doing real work, take time at the end to trim the cache.82		c := cache.Default()83		defer func() {84			if err := c.Close(); err != nil {85				base.Fatalf("go: failed to trim cache: %v", err)86			}87		}()88	}8990	// Build list of all actions, assigning depth-first post-order priority.91	// The original implementation here was a true queue92	// (using a channel) but it had the effect of getting93	// distracted by low-level leaf actions to the detriment94	// of completing higher-level actions. The order of95	// work does not matter much to overall execution time,96	// but when running "go test std" it is nice to see each test97	// results as soon as possible. The priorities assigned98	// ensure that, all else being equal, the execution prefers99	// to do what it would have done first in a simple depth-first100	// dependency order traversal.101	all := actionList(root)102	for i, a := range all {103		a.priority = i104	}105106	// Write action graph, without timing information, in case we fail and exit early.107	writeActionGraph := func() {108		if file := cfg.DebugActiongraph; file != "" {109			if strings.HasSuffix(file, ".go") {110				// Do not overwrite Go source code in:111				//	go build -debug-actiongraph x.go112				base.Fatalf("go: refusing to write action graph to %v\n", file)113			}114			js := actionGraphJSON(root)115			if err := os.WriteFile(file, []byte(js), 0666); err != nil {116				fmt.Fprintf(os.Stderr, "go: writing action graph: %v\n", err)117				base.SetExitStatus(1)118			}119		}120	}121	writeActionGraph()122123	b.readySema = make(chan bool, len(all))124125	// Initialize per-action execution state.126	for _, a := range all {127		for _, a1 := range a.Deps {128			a1.triggers = append(a1.triggers, a)129		}130		a.pending = len(a.Deps)131		if a.pending == 0 {132			b.ready.push(a)133			b.readySema <- true134		}135	}136137	// Handle runs a single action and takes care of triggering138	// any actions that are runnable as a result.139	handle := func(ctx context.Context, a *Action) {140		if a.json != nil {141			a.json.TimeStart = time.Now()142		}143		var err error144		if a.Actor != nil && (a.Failed == nil || a.IgnoreFail) {145			// TODO(matloob): Better action descriptions146			desc := "Executing action (" + a.Mode147			if a.Package != nil {148				desc += " " + a.Package.Desc()149			}150			desc += ")"151			ctx, span := trace.StartSpan(ctx, desc)152			a.traceSpan = span153			for _, d := range a.Deps {154				trace.Flow(ctx, d.traceSpan, a.traceSpan)155			}156			err = a.Actor.Act(b, ctx, a)157			span.Done()158		}159		if a.json != nil {160			a.json.TimeDone = time.Now()161		}162163		// The actions run in parallel but all the updates to the164		// shared work state are serialized through b.exec.165		b.exec.Lock()166		defer b.exec.Unlock()167168		if err != nil {169			if b.AllowErrors && a.Package != nil {170				if a.Package.Error == nil {171					a.Package.Error = &load.PackageError{Err: err}172					a.Package.Incomplete = true173				}174			} else {175				if a.Package != nil {176					if ipe, ok := errors.AsType[load.ImportPathError](err); !ok || ipe.ImportPath() != a.Package.ImportPath {177						err = fmt.Errorf("%s: %v", a.Package.ImportPath, err)178					}179				}180				sh := b.Shell(a)181				sh.Errorf("%s", err)182			}183			if a.Failed == nil {184				a.Failed = a185			}186		}187188		for _, a0 := range a.triggers {189			if a.Failed != nil {190				if a0.Mode == "test barrier" {191					// If this action was triggered by a test, there192					// will be a test barrier action in between the test193					// and the true trigger. But there will be other194					// triggers that are other barriers that are waiting195					// for this one. Propagate the failure to the true196					// trigger, but not to the other barriers.197					for _, bt := range a0.triggers {198						if bt.Mode != "test barrier" {199							bt.Failed = a.Failed200						}201					}202				} else {203					a0.Failed = a.Failed204				}205			}206			if a0.pending--; a0.pending == 0 {207				b.ready.push(a0)208				b.readySema <- true209			}210		}211212		if a == root {213			close(b.readySema)214		}215	}216217	var wg sync.WaitGroup218219	// Kick off goroutines according to parallelism.220	// If we are using the -n flag (just printing commands)221	// drop the parallelism to 1, both to make the output222	// deterministic and because there is no real work anyway.223	par := cfg.BuildP224	if cfg.BuildN {225		par = 1226	}227	for i := 0; i < par; i++ {228		wg.Add(1)229		go func() {230			ctx := trace.StartGoroutine(ctx)231			defer wg.Done()232			for {233				select {234				case _, ok := <-b.readySema:235					if !ok {236						return237					}238					// Receiving a value from b.readySema entitles239					// us to take from the ready queue.240					b.exec.Lock()241					a := b.ready.pop()242					b.exec.Unlock()243					handle(ctx, a)244				case <-base.Interrupted:245					base.SetExitStatus(1)246					return247				}248			}249		}()250	}251252	wg.Wait()253254	if tokens != totalTokens || concurrentProcesses != 0 {255		base.Fatalf("internal error: tokens not restored at end of build: tokens: %d, totalTokens: %d, concurrentProcesses: %d",256			tokens, totalTokens, concurrentProcesses)257	}258259	// Write action graph again, this time with timing information.260	writeActionGraph()261}262263// buildActionID computes the action ID for a build action.264func (b *Builder) buildActionID(a *Action) cache.ActionID {265	p := a.Package266	h := cache.NewHash("build " + p.ImportPath)267268	// Configuration independent of compiler toolchain.269	// Note: buildmode has already been accounted for in buildGcflags270	// and should not be inserted explicitly. Most buildmodes use the271	// same compiler settings and can reuse each other's results.272	// If not, the reason is already recorded in buildGcflags.273	fmt.Fprintf(h, "compile\n")274275	b.addPackageOrigin(h, p)276277	if p.Module != nil {278		fmt.Fprintf(h, "go %s\n", p.Module.GoVersion)279	}280	fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)281	fmt.Fprintf(h, "import %q\n", p.ImportPath)282	fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)283	if cfg.BuildTrimpath {284		fmt.Fprintln(h, "trimpath")285	}286	if p.Internal.ForceLibrary {287		fmt.Fprintf(h, "forcelibrary\n")288	}289	b.addCToolchainIDs(h, p)290	if p.Internal.Cover.Mode != "" {291		fmt.Fprintf(h, "cover %q %q\n", p.Internal.Cover.Mode, b.toolID("cover"))292	}293	if p.Internal.FuzzInstrument {294		if fuzzFlags := fuzzInstrumentFlags(); fuzzFlags != nil {295			fmt.Fprintf(h, "fuzz %q\n", fuzzFlags)296		}297	}298	if p.Internal.BuildInfo != nil {299		fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo.String())300	}301302	// Configuration specific to compiler toolchain.303	switch cfg.BuildToolchainName {304	default:305		base.Fatalf("buildActionID: unknown build toolchain %q", cfg.BuildToolchainName)306	case "gc":307		fmt.Fprintf(h, "compile %s %q %q\n", b.toolID("compile"), forcedGcflags, p.Internal.Gcflags)308		if len(p.SFiles) > 0 {309			fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)310		}311312		// GOARM, GOMIPS, etc.313		key, val, _ := cfg.GetArchEnv()314		fmt.Fprintf(h, "%s=%s\n", key, val)315316		if cfg.CleanGOEXPERIMENT != "" {317			fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)318		}319320		// TODO(rsc): Convince compiler team not to add more magic environment variables,321		// or perhaps restrict the environment variables passed to subprocesses.322		// Because these are clumsy, undocumented special-case hacks323		// for debugging the compiler, they are not settable using 'go env -w',324		// and so here we use os.Getenv, not cfg.Getenv.325		magic := []string{326			"GOCLOBBERDEADHASH",327			"GOSSAFUNC",328			"GOSSADIR",329			"GOCOMPILEDEBUG",330		}331		for _, env := range magic {332			if x := os.Getenv(env); x != "" {333				fmt.Fprintf(h, "magic %s=%s\n", env, x)334			}335		}336337	case "gccgo":338		id, _, err := b.gccgoToolID(BuildToolchain.compiler(), "go")339		if err != nil {340			base.Fatalf("%v", err)341		}342		fmt.Fprintf(h, "compile %s %q %q\n", id, forcedGccgoflags, p.Internal.Gccgoflags)343		fmt.Fprintf(h, "pkgpath %s\n", gccgoPkgpath(p))344		fmt.Fprintf(h, "ar %q\n", BuildToolchain.(gccgoToolchain).ar())345		if len(p.SFiles) > 0 {346			id, _, _ = b.gccgoToolID(BuildToolchain.compiler(), "assembler-with-cpp")347			// Ignore error; different assembler versions348			// are unlikely to make any difference anyhow.349			fmt.Fprintf(h, "asm %q\n", id)350		}351	}352353	// Input files.354	// TODO(matloob): once the build action depends on the cgo actions, we can355	// use those actions' outputs instead of the file names and hashes.356	inputFiles := str.StringList(357		p.GoFiles,358		p.CgoFiles,359		p.CFiles,360		p.CXXFiles,361		p.FFiles,362		p.MFiles,363		p.HFiles,364		p.SFiles,365		p.SysoFiles,366		p.SwigFiles,367		p.SwigCXXFiles,368		p.EmbedFiles,369	)370	for _, file := range inputFiles {371		fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))372	}373	for _, a1 := range a.Deps {374		p1 := a1.Package375		if p1 != nil && p1 != p { // p can show up in its own action deps in a cache or cgo action376			fmt.Fprintf(h, "import %s %s\n", p1.ImportPath, contentID(a1.buildID))377		}378		if a1.Mode == "preprocess PGO profile" {379			fmt.Fprintf(h, "pgofile %s\n", b.fileHash(a1.built))380		}381	}382383	return h.Sum()384}385386// addPackageOrigin writes information about the origin of the package that387// may be embedded in the debug info for the object file. It is used by388// buildActionID.389func (b *Builder) addPackageOrigin(h io.Writer, p *load.Package) {390	if cfg.BuildTrimpath {391		// When -trimpath is used with a package built from the module cache,392		// its debug information refers to the module path and version393		// instead of the directory.394		if p.Module != nil {395			fmt.Fprintf(h, "module %s@%s\n", p.Module.Path, p.Module.Version)396		}397	} else if p.Goroot {398		// The Go compiler always hides the exact value of $GOROOT399		// when building things in GOROOT.400		//401		// The C compiler does not, but for packages in GOROOT we rewrite the path402		// as though -trimpath were set. This used to be so that we did not invalidate403		// the build cache (and especially precompiled archive files) when changing404		// GOROOT_FINAL, but we no longer ship precompiled archive files as of Go 1.20405		// (https://go.dev/issue/47257) and no longer support GOROOT_FINAL406		// (https://go.dev/issue/62047).407		// TODO(bcmills): Figure out whether this behavior is still useful.408		//409		// b.WorkDir is always either trimmed or rewritten to410		// the literal string "/tmp/go-build".411	} else if !strings.HasPrefix(p.Dir, b.WorkDir) {412		// -trimpath is not set and no other rewrite rules apply,413		// so the object file may refer to the absolute directory414		// containing the package.415		fmt.Fprintf(h, "dir %s\n", p.Dir)416	}417}418419// addCToolchainIDs adds the C toolchain hashes and flags to the hash writer.420// It is used by buildActionID.421func (b *Builder) addCToolchainIDs(h io.Writer, p *load.Package) {422	if len(p.CgoFiles)+len(p.SwigFiles)+len(p.SwigCXXFiles) > 0 {423		fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo"))424		cppflags, cflags, cxxflags, fflags, ldflags, _ := b.CFlags(p)425426		ccExe := b.ccExe()427		fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags)428		// Include the C compiler tool ID so that if the C429		// compiler changes we rebuild the package.430		if ccID, _, err := b.gccToolID(ccExe[0], "c"); err == nil {431			fmt.Fprintf(h, "CC ID=%q\n", ccID)432		} else {433			fmt.Fprintf(h, "CC ID ERROR=%q\n", err)434		}435		if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 {436			cxxExe := b.cxxExe()437			fmt.Fprintf(h, "CXX=%q %q\n", cxxExe, cxxflags)438			if cxxID, _, err := b.gccToolID(cxxExe[0], "c++"); err == nil {439				fmt.Fprintf(h, "CXX ID=%q\n", cxxID)440			} else {441				fmt.Fprintf(h, "CXX ID ERROR=%q\n", err)442			}443		}444		if len(p.FFiles) > 0 {445			fcExe := b.fcExe()446			fmt.Fprintf(h, "FC=%q %q\n", fcExe, fflags)447			if fcID, _, err := b.gccToolID(fcExe[0], "f95"); err == nil {448				fmt.Fprintf(h, "FC ID=%q\n", fcID)449			} else {450				fmt.Fprintf(h, "FC ID ERROR=%q\n", err)451			}452		}453		// TODO(rsc): Should we include the SWIG version?454	}455}456457// allowedVersion reports whether the version v is an allowed version of go458// (one that we can compile).459// v is known to be of the form "1.23".460func allowedVersion(v string) bool {461	// Special case: no requirement.462	if v == "" {463		return true464	}465	return gover.Compare(gover.Local(), v) >= 0466}467468func (b *Builder) computeNonGoOverlay(a *Action, p *load.Package, sh *Shell, objdir string, nonGoFileLists [][]string) error {469OverlayLoop:470	for _, fs := range nonGoFileLists {471		for _, f := range fs {472			if fsys.Replaced(mkAbs(p.Dir, f)) {473				a.nonGoOverlay = make(map[string]string)474				break OverlayLoop475			}476		}477	}478	if a.nonGoOverlay != nil {479		for _, fs := range nonGoFileLists {480			for i := range fs {481				from := mkAbs(p.Dir, fs[i])482				dst := objdir + filepath.Base(fs[i])483				if err := sh.CopyFile(dst, fsys.Actual(from), 0666, false); err != nil {484					return err485				}486				a.nonGoOverlay[from] = dst487			}488		}489	}490491	return nil492}493494func (b *Builder) runCover(ctx context.Context, a *Action) error {495	p := a.Package496	sh := b.Shell(a)497498	// Determine the covmeta file name.499	var covMetaFileName string500	if a.Package.Internal.Cover.GenMeta {501		covMetaFileName = a.Objdir + covcmd.MetaFileForPackage(a.Package.ImportPath)502	}503504	if err := sh.Mkdir(a.Objdir); err != nil {505		return err506	}507508	a.actionID = b.coverActionID(a, covMetaFileName)509	if pr, err := b.loadCachedCoverOutputs(a); err == nil {510		a.Provider = pr511		return nil512	}513514	gofiles := slices.Clone(a.Package.GoFiles)515	cgofiles := slices.Clone(a.Package.CgoFiles)516517	outfiles := []string{}518	infiles := []string{}519	for i, file := range str.StringList(gofiles, cgofiles) {520		if base.IsTestFile(file) {521			continue // Not covering this file.522		}523524		var sourceFile string525		var coverFile string526		if base, found := strings.CutSuffix(file, ".cgo1.go"); found {527			// cgo files have absolute paths528			base = filepath.Base(base)529			sourceFile = file530			coverFile = a.Objdir + base + ".cgo1.go"531		} else {532			sourceFile = filepath.Join(p.Dir, file)533			coverFile = a.Objdir + file534		}535		coverFile = strings.TrimSuffix(coverFile, ".go") + ".cover.go"536		infiles = append(infiles, sourceFile)537		outfiles = append(outfiles, coverFile)538		if i < len(gofiles) {539			gofiles[i] = coverFile540		} else {541			cgofiles[i-len(gofiles)] = coverFile542		}543	}544545	var coverCfg string546	if len(infiles) != 0 {547		// Coverage instrumentation creates new top level548		// variables in the target package for things like549		// meta-data containers, counter vars, etc. To avoid550		// collisions with user variables, suffix the var name551		// with 12 hex digits from the SHA-256 hash of the552		// import path. Choice of 12 digits is historical/arbitrary,553		// we just need enough of the hash to avoid accidents,554		// as opposed to precluding determined attempts by555		// users to break things.556		sum := sha256.Sum256([]byte(a.Package.ImportPath))557		coverVar := fmt.Sprintf("goCover_%x_", sum[:6])558		mode := a.Package.Internal.Cover.Mode559		if mode == "" {560			panic("covermode should be set at this point")561		}562		coverCfg = a.Objdir + "coveragecfg"563		if newoutfiles, err := b.cover(a, infiles, outfiles, coverVar, mode, covMetaFileName, coverCfg); err != nil {564			return err565		} else {566			outfiles = newoutfiles567			gofiles = append([]string{newoutfiles[0]}, gofiles...)568		}569	}570571	pr := &coverProvider{covMetaFileName, coverCfg, gofiles, cgofiles}572	a.Provider = pr573574	if !cfg.BuildN {575		if err := b.cacheCoverOutputs(a, pr); err != nil {576			return err577		}578	}579580	return nil581}582583// build is the action for building a single package.584// Note that any new influence on this logic must be reported in b.buildActionID above as well.585func (b *Builder) build(ctx context.Context, a *Action) (err error) {586	p := a.Package587	sh := b.Shell(a)588589	bit := func(x uint32, b bool) uint32 {590		if b {591			return x592		}593		return 0594	}595596	const (597		needBuild uint32 = 1 << iota598		needVet599		needCompiledGoFiles600	)601602	cachedBuild := false603	need := bit(needBuild, !b.IsCmdList && a.needBuild || b.NeedExport) |604		bit(needVet, a.needVet) |605		bit(needCompiledGoFiles, b.NeedCompiledGoFiles)606607	if b.useCache(a, b.buildActionID(a), p.Target, need&needBuild != 0) {608		// We found the main output in the cache.609		// If we don't need any other outputs, we can stop.610		// Otherwise, we need to write files to a.Objdir (needVet).611		// Remember that we might have them in cache612		// and check again after we create a.Objdir.613		cachedBuild = true614		a.output = []byte{} // start saving output in case we miss any cache results615		need &^= needBuild616		if b.NeedExport {617			p.Export = a.built618			p.BuildID = a.buildID619		}620		if need&needCompiledGoFiles != 0 {621			if err := b.loadCachedCompiledGoFiles(a); err == nil {622				need &^= needCompiledGoFiles623			}624		}625	}626627	// Source files might be cached, even if the full action is not628	// (e.g., go list -compiled -find).629	if !cachedBuild && need&needCompiledGoFiles != 0 {630		if err := b.loadCachedCompiledGoFiles(a); err == nil {631			need &^= needCompiledGoFiles632		}633	}634635	if need == 0 {636		return nil637	}638	defer b.flushOutput(a)639640	defer func() {641		if err != nil && b.IsCmdList && b.NeedError && p.Error == nil {642			p.Error = &load.PackageError{Err: err}643		}644	}()645646	if p.Error != nil {647		// Don't try to build anything for packages with errors. There may be a648		// problem with the inputs that makes the package unsafe to build.649		return p.Error650	}651652	if p.Module != nil && !allowedVersion(p.Module.GoVersion) {653		return errors.New("module requires Go " + p.Module.GoVersion + " or later")654	}655656	if err := b.checkDirectives(a); err != nil {657		return err658	}659660	if err := sh.Mkdir(a.Objdir); err != nil {661		return err662	}663664	// Load cached vet config, but only if that's all we have left665	// (need == needVet, not testing just the one bit).666	// If we are going to do a full build anyway,667	// we're going to regenerate the files in the build action anyway.668	if need == needVet {669		if err := b.loadCachedVet(a, a.Deps); err == nil {670			need &^= needVet671		}672	}673674	var coverPr *coverProvider675	var runCgoPr *runCgoProvider676	for _, dep := range a.Deps {677		switch pr := dep.Provider.(type) {678		case *coverProvider:679			coverPr = pr680		case *runCgoProvider:681			runCgoPr = pr682		}683	}684685	if need == 0 {686		return687	}688	defer b.flushOutput(a)689690	if cfg.BuildN {691		// In -n mode, print a banner between packages.692		// The banner is five lines so that when changes to693		// different sections of the bootstrap script have to694		// be merged, the banners give patch something695		// to use to find its context.696		sh.Printf("\n#\n# %s\n#\n\n", p.ImportPath)697	}698699	if cfg.BuildV {700		sh.Printf("%s\n", p.ImportPath)701	}702703	objdir := a.Objdir704705	if err := AllowInstall(a); err != nil {706		return err707	}708709	// make target directory710	dir, _ := filepath.Split(a.Target)711	if dir != "" {712		if err := sh.Mkdir(dir); err != nil {713			return err714		}715	}716717	gofiles := str.StringList(p.GoFiles)718	cfiles := str.StringList(p.CFiles)719	sfiles := str.StringList(p.SFiles)720	var objects, cgoObjects []string721722	// If we're doing coverage, preprocess the .go files and put them in the work directory723	if p.Internal.Cover.Mode != "" {724		gofiles = coverPr.goSources725	}726727	if p.UsesCgo() || p.UsesSwig() {728		if runCgoPr == nil {729			base.Fatalf("internal error: could not find runCgoProvider")730		}731732		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.733		// There is one exception: runtime/cgo's job is to bridge the734		// cgo and non-cgo worlds, so it necessarily has files in both.735		// In that case gcc only gets the gcc_* files.736		cfiles = nil737		if p.Standard && p.ImportPath == "runtime/cgo" {738			// filter to the non-gcc files.739			i := 0740			for _, f := range sfiles {741				if !strings.HasPrefix(f, "gcc_") {742					sfiles[i] = f743					i++744				}745			}746			sfiles = sfiles[:i]747		} else {748			sfiles = nil749		}750		outGo, outObj, err := b.processCgoOutputs(a, runCgoPr, base.Tool("cgo"), objdir)751752		if err != nil {753			return err754		}755		if cfg.BuildToolchainName == "gccgo" {756			cgoObjects = append(cgoObjects, a.Objdir+"_cgo_flags")757		}758		cgoObjects = append(cgoObjects, outObj...)759		gofiles = append(gofiles, outGo...)760	}761762	var srcfiles []string // .go and non-.go763	srcfiles = append(srcfiles, gofiles...)764	srcfiles = append(srcfiles, sfiles...)765	srcfiles = append(srcfiles, cfiles...)766	b.cacheSrcFiles(a, srcfiles)767768	// Sanity check only, since Package.load already checked as well.769	if len(gofiles) == 0 {770		return &load.NoGoError{Package: p}771	}772773	// Prepare Go vet config if needed.774	if need&needVet != 0 {775		buildVetConfig(a, srcfiles, a.Deps)776		need &^= needVet777	}778	if need&needCompiledGoFiles != 0 {779		if err := b.loadCachedCompiledGoFiles(a); err != nil {780			return fmt.Errorf("loading compiled Go files from cache: %w", err)781		}782		need &^= needCompiledGoFiles783	}784	if need == 0 {785		// Nothing left to do.786		return nil787	}788789	// Collect symbol ABI requirements from assembly.790	symabis, err := BuildToolchain.symabis(b, a, sfiles)791	if err != nil {792		return err793	}794795	// Prepare Go import config.796	// We start it off with a comment so it can't be empty, so icfg.Bytes() below is never nil.797	// It should never be empty anyway, but there have been bugs in the past that resulted798	// in empty configs, which then unfortunately turn into "no config passed to compiler",799	// and the compiler falls back to looking in pkg itself, which mostly works,800	// except when it doesn't.801	var icfg bytes.Buffer802	fmt.Fprintf(&icfg, "# import config\n")803	for i, raw := range p.Internal.RawImports {804		final := p.Imports[i]805		if final != raw {806			fmt.Fprintf(&icfg, "importmap %s=%s\n", raw, final)807		}808	}809	for _, a1 := range a.Deps {810		p1 := a1.Package811		if p1 == nil || p1.ImportPath == "" || a1.built == "" {812			continue813		}814		fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)815	}816817	// Prepare Go embed config if needed.818	// Unlike the import config, it's okay for the embed config to be empty.819	var embedcfg []byte820	if len(p.Internal.Embed) > 0 {821		var embed struct {822			Patterns map[string][]string823			Files    map[string]string824		}825		embed.Patterns = p.Internal.Embed826		embed.Files = make(map[string]string)827		for _, file := range p.EmbedFiles {828			embed.Files[file] = fsys.Actual(filepath.Join(p.Dir, file))829		}830		js, err := json.MarshalIndent(&embed, "", "\t")831		if err != nil {832			return fmt.Errorf("marshal embedcfg: %v", err)833		}834		embedcfg = js835	}836837	// Find PGO profile if needed.838	var pgoProfile string839	for _, a1 := range a.Deps {840		if a1.Mode != "preprocess PGO profile" {841			continue842		}843		if pgoProfile != "" {844			return fmt.Errorf("action contains multiple PGO profile dependencies")845		}846		pgoProfile = a1.built847	}848849	var coverageConfig string850	if coverPr != nil {851		coverageConfig = coverPr.coverageConfig852	}853854	if p.Internal.BuildInfo != nil && cfg.ModulesEnabled {855		prog := modload.ModInfoProg(p.Internal.BuildInfo.String(), cfg.BuildToolchainName == "gccgo")856		if len(prog) > 0 {857			if err := sh.writeFile(objdir+"_gomod_.go", prog); err != nil {858				return err859			}860			gofiles = append(gofiles, objdir+"_gomod_.go")861		}862	}863864	// Compile Go.865	objpkg := objdir + "_pkg_.a"866	ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), embedcfg, symabis, len(sfiles) > 0, pgoProfile, coverageConfig, gofiles)867	if len(out) > 0 && (p.UsesCgo() || p.UsesSwig()) && !cfg.BuildX {868		// Fix up output referring to cgo-generated code to be more readable.869		// Replace *[100]_Ctype_foo with *[100]C.foo.870		// If we're using -x, assume we're debugging and want the full dump, so disable the rewrite.871		out = cgoTypeSigRe.ReplaceAll(out, []byte("C."))872	}873	if err := sh.reportCmd("", "", out, err); err != nil {874		return err875	}876	if ofile != objpkg {877		objects = append(objects, ofile)878	}879880	// Copy .h files named for goos or goarch or goos_goarch881	// to names using GOOS and GOARCH.882	// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.883	_goos_goarch := "_" + cfg.Goos + "_" + cfg.Goarch884	_goos := "_" + cfg.Goos885	_goarch := "_" + cfg.Goarch886	for _, file := range p.HFiles {887		name, ext := fileExtSplit(file)888		switch {889		case strings.HasSuffix(name, _goos_goarch):890			targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext891			if err := sh.CopyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil {892				return err893			}894		case strings.HasSuffix(name, _goarch):895			targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext896			if err := sh.CopyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil {897				return err898			}899		case strings.HasSuffix(name, _goos):900			targ := file[:len(name)-len(_goos)] + "_GOOS." + ext901			if err := sh.CopyFile(objdir+targ, filepath.Join(p.Dir, file), 0666, true); err != nil {902				return err903			}904		}905	}906907	if err := b.computeNonGoOverlay(a, p, sh, objdir, [][]string{cfiles}); err != nil {908		return err909	}910911	// Compile C files in a package being built with gccgo. We disallow912	// C files when compiling with gc unless swig or cgo is used.913	for _, file := range cfiles {914		out := file[:len(file)-len(".c")] + ".o"915		if err := BuildToolchain.cc(b, a, objdir+out, file); err != nil {916			return err917		}918		objects = append(objects, out)919	}920921	// Assemble .s files.922	if len(sfiles) > 0 {923		ofiles, err := BuildToolchain.asm(b, a, sfiles)924		if err != nil {925			return err926		}927		objects = append(objects, ofiles...)928	}929930	// For gccgo on ELF systems, we write the build ID as an assembler file.931	// This lets us set the SHF_EXCLUDE flag.932	// This is read by readGccgoArchive in cmd/internal/buildid/buildid.go.933	if a.buildID != "" && cfg.BuildToolchainName == "gccgo" {934		switch cfg.Goos {935		case "aix", "android", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd", "solaris":936			asmfile, err := b.gccgoBuildIDFile(a)937			if err != nil {938				return err939			}940			ofiles, err := BuildToolchain.asm(b, a, []string{asmfile})941			if err != nil {942				return err943			}944			objects = append(objects, ofiles...)945		}946	}947948	// NOTE(rsc): On Windows, it is critically important that the949	// gcc-compiled objects (cgoObjects) be listed after the ordinary950	// objects in the archive. I do not know why this is.951	// https://golang.org/issue/2601952	objects = append(objects, cgoObjects...)953954	// Add system object files.955	for _, syso := range p.SysoFiles {956		objects = append(objects, filepath.Join(p.Dir, syso))957	}958959	// Pack into archive in objdir directory.960	// If the Go compiler wrote an archive, we only need to add the961	// object files for non-Go sources to the archive.962	// If the Go compiler wrote an archive and the package is entirely963	// Go sources, there is no pack to execute at all.964	if len(objects) > 0 {965		if err := BuildToolchain.pack(b, a, objpkg, objects); err != nil {966			return err967		}968	}969970	if err := b.updateBuildID(a, objpkg); err != nil {971		return err972	}973974	a.built = objpkg975	return nil976}977978var cgoTypeSigRe = lazyregexp.New(`\b_C2?(type|func|var|macro)_\B`)979980func (b *Builder) checkDirectives(a *Action) error {981	var msg []byte982	p := a.Package983	var seen map[string]token.Position984	for _, d := range p.Internal.Build.Directives {985		if strings.HasPrefix(d.Text, "//go:debug") {986			key, _, err := load.ParseGoDebug(d.Text)987			if err != nil && err != load.ErrNotGoDebug {988				msg = fmt.Appendf(msg, "%s: invalid //go:debug: %v\n", d.Pos, err)989				continue990			}991			if pos, ok := seen[key]; ok {992				msg = fmt.Appendf(msg, "%s: repeated //go:debug for %v\n\t%s: previous //go:debug\n", d.Pos, key, pos)993				continue994			}995			if seen == nil {996				seen = make(map[string]token.Position)997			}998			seen[key] = d.Pos999		}1000	}1001	if len(msg) > 0 {1002		// We pass a non-nil error to reportCmd to trigger the failure reporting1003		// path, but the content of the error doesn't matter because msg is1004		// non-empty.1005		err := errors.New("invalid directive")1006		return b.Shell(a).reportCmd("", "", msg, err)1007	}1008	return nil1009}10101011func (b *Builder) cacheObjdirFile(a *Action, c cache.Cache, name string) error {1012	f, err := os.Open(a.Objdir + name)1013	if err != nil {1014		return err1015	}1016	defer f.Close()1017	_, _, err = c.Put(cache.Subkey(a.actionID, name), f)1018	return err1019}10201021func (b *Builder) findCachedObjdirFile(a *Action, c cache.Cache, name string) (string, error) {1022	file, _, err := cache.GetFile(c, cache.Subkey(a.actionID, name))1023	if err != nil {1024		return "", fmt.Errorf("loading cached file %s: %w", name, err)1025	}1026	return file, nil1027}10281029func (b *Builder) loadCachedObjdirFile(a *Action, c cache.Cache, name string) error {1030	cached, err := b.findCachedObjdirFile(a, c, name)1031	if err != nil {1032		return err1033	}1034	return b.Shell(a).CopyFile(a.Objdir+name, cached, 0666, true)1035}10361037func (b *Builder) cacheSrcFiles(a *Action, srcfiles []string) {1038	c := cache.Default()1039	var buf bytes.Buffer1040	for _, file := range srcfiles {1041		if !strings.HasPrefix(file, a.Objdir) {1042			// not generated1043			buf.WriteString("./")1044			buf.WriteString(file)1045			buf.WriteString("\n")1046			continue1047		}1048		name := file[len(a.Objdir):]1049		buf.WriteString(name)1050		buf.WriteString("\n")1051		if err := b.cacheObjdirFile(a, c, name); err != nil {1052			return1053		}1054	}1055	cache.PutBytes(c, cache.Subkey(a.actionID, "srcfiles"), buf.Bytes())1056}10571058// coverProviderCached is the structure we'll use to represent a coverProvider1059// in the action cache. It has the same fields as a coverProvider but they'll contain1060// different contents: we replace the acutal objdir name with $OBJDIR so that1061// the cached provider doesn't depend on the objdir used.1062type coverProviderCached struct {1063	CovMetaFile           string1064	CoverageConfig        string1065	GoSources, CgoSources []string1066}10671068func (b *Builder) cacheCoverOutputs(a *Action, pr *coverProvider) error {1069	c := cache.Default()10701071	cacheSrcFileName := func(a *Action, file string) string {1072		if name, ok := strings.CutPrefix(file, a.Objdir); ok {1073			return name1074		}1075		return "./" + file1076	}10771078	b.cacheSrcFiles(a, str.StringList(pr.goSources, pr.cgoSources))1079	var cached coverProviderCached1080	if pr.covMetaFileName != "" {1081		cached.CovMetaFile = strings.TrimPrefix(pr.covMetaFileName, a.Objdir)1082		if err := b.cacheObjdirFile(a, c, cached.CovMetaFile); err != nil {1083			return err1084		}1085	}1086	if pr.coverageConfig != "" {1087		cached.CoverageConfig = strings.TrimPrefix(pr.coverageConfig, a.Objdir)1088		if err := b.cacheObjdirFile(a, c, cached.CoverageConfig); err != nil {1089			return err1090		}1091	}10921093	for _, fn := range pr.goSources {1094		cached.GoSources = append(cached.GoSources, cacheSrcFileName(a, fn))1095	}1096	for _, fn := range pr.cgoSources {1097		cached.CgoSources = append(cached.CgoSources, cacheSrcFileName(a, fn))1098	}1099	js, err := json.Marshal(cached)1100	if err != nil {1101		return err1102	}1103	cache.PutBytes(c, cache.Subkey(a.actionID, "coverprovider"), js)11041105	return nil1106}11071108func (b *Builder) loadCachedCoverOutputs(a *Action) (*coverProvider, error) {1109	c := cache.Default()11101111	if _, err := b.loadCachedSrcFiles(a); err != nil {1112		return nil, err1113	}11141115	var cached coverProviderCached1116	if js, _, err := cache.GetBytes(c, cache.Subkey(a.actionID, "coverprovider")); err != nil {1117		return nil, err1118	} else if err := json.Unmarshal(js, &cached); err != nil {1119		return nil, err1120	}11211122	covMetaFile := cached.CovMetaFile1123	if covMetaFile != "" {1124		if err := b.loadCachedObjdirFile(a, c, covMetaFile); err != nil {1125			return nil, err1126		}1127		covMetaFile = a.Objdir + covMetaFile1128	}1129	coverageConfig := cached.CoverageConfig1130	if coverageConfig != "" {1131		if err := b.loadCachedObjdirFile(a, c, coverageConfig); err != nil {1132			return nil, err1133		}1134		coverageConfig = a.Objdir + coverageConfig1135	}11361137	var goSources, cgoSources []string1138	for _, file := range cached.GoSources {1139		name, ok := strings.CutPrefix(file, "./")1140		if !ok {1141			name = a.Objdir + name1142		}1143		goSources = append(goSources, name)1144	}1145	for _, file := range cached.CgoSources {1146		name, ok := strings.CutPrefix(file, "./")1147		if !ok {1148			name = a.Objdir + name1149		}1150		cgoSources = append(cgoSources, name)1151	}11521153	pr := &coverProvider{1154		covMetaFileName: covMetaFile,1155		coverageConfig:  coverageConfig,1156		goSources:       goSources,1157		cgoSources:      cgoSources,1158	}11591160	return pr, nil1161}11621163func (b *Builder) coverActionID(a *Action, covMetaFileName string) cache.ActionID {1164	p := a.Package1165	h := cache.NewHash("cover " + p.ImportPath)1166	fmt.Fprintf(h, "cover %q\n", b.toolID("cover"))1167	b.addPackageOrigin(h, p)11681169	// Input files for cover.1170	fmt.Fprintf(h, "setup %s %v\n", p.Internal.Cover.Mode, p.Internal.Cover.GenMeta)1171	fmt.Fprintf(h, "config ")1172	if err := json.NewEncoder(h).Encode(coverConfig(p, filepath.Base(covMetaFileName), "")); err != nil {1173		base.Fatal(err)1174	}1175	for _, file := range str.StringList(p.GoFiles, p.CgoFiles) {1176		fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))1177	}11781179	return h.Sum()1180}11811182// cgoCompileActionID returns the action ID for the action to compile1183// a file with the C compiler for cgo.1184func (b *Builder) cgoCompileActionID(a *Action, f string, flags []string) cache.ActionID {1185	h := cache.NewHash("cgo compile file")1186	p := a.Package11871188	fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)11891190	fmt.Fprintf(h, "file %s %s\n", filepath.Base(f), b.fileHash(f))1191	fmt.Fprintf(h, "flags %q\n", replaceAll(flags, a.Objdir, "$OBJDIR/"))11921193	// Package origin, trimpath and Goroot affect the -ffile-prefix-map1194	// flag added during C compilation, which changes the DWARF paths1195	// in the resulting .o file.1196	b.addPackageOrigin(h, p)1197	if cfg.BuildTrimpath {1198		fmt.Fprintln(h, "trimpath")1199	}12001201	// This has too much information.1202	// We only need to choose CC/CXX/FC based on which kind of compilation this1203	// action is doing. Perhaps we could add a getCCIDFunc to cgoCompileActor?1204	// It also includes the flags which are be unnecessary because we know which1205	// flags are passed.1206	b.addCToolchainIDs(h, p)12071208	return h.Sum()1209}12101211// cgoRunActionID returns the ActionID for the action that runs1212// the cgo command.1213func (b *Builder) cgoRunActionID(a *Action) cache.ActionID {1214	p := a.Package1215	h := cache.NewHash("cgo " + p.ImportPath)12161217	fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch)12181219	fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo"))12201221	// cgo mixes the import path into its generated symbol names1222	// (_cgo_<hash>_Cfunc_*), so the generated files are only valid1223	// for the same import path. The hash name argument of NewHash1224	// is debug-only, so the import path must also be written here.1225	fmt.Fprintf(h, "import %q\n", p.ImportPath)12261227	// Add p.Dir, which is needed because cgo embeds absolute1228	// source paths in //line directives of its generated files.1229	// TODO(matloob): Can we change that?1230	fmt.Fprintf(h, "dir %s\n", p.Dir)1231	b.addCToolchainIDs(h, p) // incorporates c/c++/fflags12321233	// msan/asan cause -fsanitize to be passed1234	fmt.Fprintf(h, "msan %v asan %v\n", cfg.BuildMSan, cfg.BuildASan)1235	// exportheader signifies whether _cgo_install.h will be produced1236	fmt.Fprintf(h, "exportheader %v\n", cfg.BuildBuildmode == "c-archive" || cfg.BuildBuildmode == "c-shared")1237	// gccgopkgpath affects cgo's produced symbol names1238	if cfg.BuildToolchainName == "gccgo" {1239		fmt.Fprintf(h, "gccgopkgpath %s\n", gccgoPkgpath(p))1240	}12411242	// Whether there are Obj-C/C++/Fortran files will affect the flags produced.1243	fmt.Fprintf(h, "mfiles %v cxxfiles %v ffiles %v\n", len(p.MFiles) > 0, len(p.CXXFiles)+len(p.SwigCXXFiles) > 0, len(p.FFiles) > 0)12441245	// Cgo and swig input files. These are the direct inputs to the cgo tool.1246	if p.Internal.Cover.Mode != "" {1247		// Use cover action id: cover will generate the new cgo files.1248		for _, dep := range a.Deps {1249			if dep.Mode == "cover" {1250				fmt.Fprintf(h, "cover %x\n", dep.actionID)1251				break1252			}1253		}1254	} else {1255		for _, file := range p.CgoFiles {1256			fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))1257		}1258	}1259	for _, file := range str.StringList(p.SwigFiles, p.SwigCXXFiles) {1260		fmt.Fprintf(h, "file %s %s\n", file, b.fileHash(filepath.Join(p.Dir, file)))1261	}12621263	return h.Sum()1264}12651266// runCgoProviderCached is the JSON-serializable form of a runCgoProvider1267// stored in the action cache. All files are relative to objdir.1268type runCgoProviderCached struct {1269	CFLAGS, CXXFLAGS, FFLAGS, LDFLAGS []string1270	NotCompatibleForInternalLinking   bool1271	GoFiles                           []string // list for the provider1272	Files                             []string // files to restore to objdir1273}12741275func replaceAll(strs []string, from, to string) []string {1276	var replaced []string1277	for _, s := range strs {1278		replaced = append(replaced, strings.ReplaceAll(s, from, to))1279	}1280	return replaced1281}12821283func (b *Builder) cacheRunCgoOutputs(a *Action, pr *runCgoProvider) error {1284	c := cache.Default()12851286	// TODO(matloob): map on a seq would be nice1287	trimObjdirPrefix := func(files []string) []string {1288		var trimmed []string1289		for _, f := range files {1290			trimmed = append(trimmed, strings.TrimPrefix(f, a.Objdir))1291		}1292		return trimmed1293	}12941295	cgo2Files := func(cgo1Files []string) []string {1296		var cgo2 []string1297		for _, f := range cgo1Files {1298			if base, ok := strings.CutSuffix(f, ".cgo1.go"); ok {1299				cgo2 = append(cgo2, base+".cgo2.c")1300			}1301		}1302		return cgo21303	}13041305	_, outC, outCXX := b.swigOutputs(a.Package, a.Objdir)1306	files := str.StringList(1307		[]string{"_cgo_export.c", "_cgo_export.h", "_cgo_main.c"},1308		trimObjdirPrefix(pr.goFiles),1309		trimObjdirPrefix(cgo2Files(pr.goFiles)),1310		trimObjdirPrefix(outC),1311		trimObjdirPrefix(outCXX))1312	for _, name := range []string{"_cgo_install.h", "_cgo_defun.c", "_cgo_flags"} {1313		if _, err := os.Stat(a.Objdir + name); err == nil {1314			files = append(files, name)1315		}1316	}1317	for _, file := range files {1318		if err := b.cacheObjdirFile(a, c, file); err != nil {1319			return err1320		}1321	}13221323	cached := runCgoProviderCached{1324		CFLAGS:                          replaceAll(pr.CFLAGS, a.Objdir, "$OBJDIR/"),1325		CXXFLAGS:                        replaceAll(pr.CXXFLAGS, a.Objdir, "$OBJDIR/"),1326		FFLAGS:                          replaceAll(pr.FFLAGS, a.Objdir, "$OBJDIR/"),1327		LDFLAGS:                         replaceAll(pr.LDFLAGS, a.Objdir, "$OBJDIR/"),1328		NotCompatibleForInternalLinking: pr.notCompatibleForInternalLinking,1329		GoFiles:                         trimObjdirPrefix(pr.goFiles),1330		Files:                           files,1331	}1332	data, err := json.Marshal(cached)1333	if err != nil {1334		return err1335	}1336	cache.PutBytes(c, cache.Subkey(a.actionID, "cgorunprovider"), data)1337	return nil1338}13391340func (b *Builder) loadCachedRunCgoOutputs(a *Action) (*runCgoProvider, error) {1341	c := cache.Default()13421343	var cached runCgoProviderCached1344	js, _, err := cache.GetBytes(c, cache.Subkey(a.actionID, "cgorunprovider"))1345	if err != nil {1346		return nil, err1347	} else if err := json.Unmarshal(js, &cached); err != nil {1348		return nil, err1349	}13501351	for _, name := range cached.Files {1352		if err := b.loadCachedObjdirFile(a, c, name); err != nil {1353			return nil, err1354		}1355	}13561357	var goFilesObjdir []string1358	for _, f := range cached.GoFiles {1359		goFilesObjdir = append(goFilesObjdir, a.Objdir+f)1360	}13611362	pr := &runCgoProvider{1363		CFLAGS:                          replaceAll(cached.CFLAGS, "$OBJDIR/", a.Objdir),1364		CXXFLAGS:                        replaceAll(cached.CXXFLAGS, "$OBJDIR/", a.Objdir),1365		FFLAGS:                          replaceAll(cached.FFLAGS, "$OBJDIR/", a.Objdir),1366		LDFLAGS:                         replaceAll(cached.LDFLAGS, "$OBJDIR/", a.Objdir),1367		notCompatibleForInternalLinking: cached.NotCompatibleForInternalLinking,1368		goFiles:                         goFilesObjdir,1369	}13701371	return pr, nil1372}13731374func (b *Builder) loadCachedSrcFiles(a *Action) ([]string, error) {1375	c := cache.Default()1376	list, _, err := cache.GetBytes(c, cache.Subkey(a.actionID, "srcfiles"))1377	if err != nil {1378		return nil, fmt.Errorf("reading srcfiles list: %w", err)1379	}1380	var srcfiles []string1381	for name := range strings.SplitSeq(string(list), "\n") {1382		if name == "" { // end of list1383			continue1384		}1385		if strings.HasPrefix(name, "./") {1386			srcfiles = append(srcfiles, name[2:])1387			continue1388		}1389		if err := b.loadCachedObjdirFile(a, c, name); err != nil {1390			return nil, err1391		}1392		srcfiles = append(srcfiles, a.Objdir+name)1393	}1394	return srcfiles, nil1395}13961397func (b *Builder) loadCachedVet(a *Action, vetDeps []*Action) error {1398	srcfiles, err := b.loadCachedSrcFiles(a)1399	if err != nil {1400		return err1401	}1402	buildVetConfig(a, srcfiles, vetDeps)1403	return nil1404}14051406func (b *Builder) loadCachedCompiledGoFiles(a *Action) error {1407	c := cache.Default()1408	list, _, err := cache.GetBytes(c, cache.Subkey(a.actionID, "srcfiles"))1409	if err != nil {1410		return fmt.Errorf("reading srcfiles list: %w", err)1411	}1412	var gofiles []string1413	for name := range strings.SplitSeq(string(list), "\n") {1414		if name == "" { // end of list1415			continue1416		} else if !strings.HasSuffix(name, ".go") {1417			continue1418		}1419		if strings.HasPrefix(name, "./") {1420			gofiles = append(gofiles, name[len("./"):])1421			continue1422		}1423		file, err := b.findCachedObjdirFile(a, c, name)1424		if err != nil {1425			return fmt.Errorf("finding %s: %w", name, err)1426		}1427		gofiles = append(gofiles, file)1428	}1429	a.Package.CompiledGoFiles = gofiles1430	return nil1431}14321433// vetConfig is the configuration passed to vet describing a single package.1434type vetConfig struct {1435	ID           string   // package ID (example: "fmt [fmt.test]")1436	Compiler     string   // compiler name (gc, gccgo)1437	Dir          string   // directory containing package1438	ImportPath   string   // canonical import path ("package path")1439	GoFiles      []string // absolute paths to package source files1440	NonGoFiles   []string // absolute paths to package non-Go files1441	IgnoredFiles []string // absolute paths to ignored source files14421443	Module      *analysis.Module  // module information, if any1444	ImportMap   map[string]string // map import path in source code to package path1445	PackageFile map[string]string // map package path to .a file with export data1446	Standard    map[string]bool   // map package path to whether it's in the standard library1447	PackageVetx map[string]string // map package path to vetx data from earlier vet run1448	VetxOnly    bool              // only compute vetx data; don't report detected problems1449	VetxOutput  string            // write vetx data to this output file1450	Stdout      string            // write stdout (JSON, unified diff) to this output file1451	GoVersion   string            // Go version for package1452	FixArchive  string            // write fixed files to this zip archive, if non-empty14531454	SucceedOnTypecheckFailure bool // awful hack; see #18395 and below1455}14561457// analysisModuleFromModulePublic converts a modinfo.ModulePublic to a analysis.Module.1458func analysisModuleFromModulePublic(m *modinfo.ModulePublic) *analysis.Module {1459	if m == nil {1460		return nil1461	}1462	vm := &analysis.Module{1463		Path:      m.Path,1464		Version:   m.Version,1465		Replace:   analysisModuleFromModulePublic(m.Replace),1466		Time:      m.Time,1467		Main:      m.Main,1468		Indirect:  m.Indirect,1469		Dir:       m.Dir,1470		GoMod:     m.GoMod,1471		GoVersion: m.GoVersion,1472	}1473	if m.Error != nil {1474		vm.Error = &analysis.ModuleError{Err: m.Error.Err}1475	}1476	return vm1477}14781479func buildVetConfig(a *Action, srcfiles []string, vetDeps []*Action) {1480	// Classify files based on .go extension.1481	// srcfiles does not include raw cgo files.1482	var gofiles, nongofiles []string1483	for _, name := range srcfiles {1484		if strings.HasSuffix(name, ".go") {1485			gofiles = append(gofiles, name)1486		} else {1487			nongofiles = append(nongofiles, name)1488		}1489	}14901491	ignored := str.StringList(a.Package.IgnoredGoFiles, a.Package.IgnoredOtherFiles)14921493	// Pass list of absolute paths to vet,1494	// so that vet's error messages will use absolute paths,1495	// so that we can reformat them relative to the directory1496	// in which the go command is invoked.1497	vcfg := &vetConfig{1498		ID:           a.Package.ImportPath,1499		Compiler:     cfg.BuildToolchainName,1500		Dir:          a.Package.Dir,1501		GoFiles:      actualFiles(mkAbsFiles(a.Package.Dir, gofiles)),1502		NonGoFiles:   actualFiles(mkAbsFiles(a.Package.Dir, nongofiles)),1503		IgnoredFiles: actualFiles(mkAbsFiles(a.Package.Dir, ignored)),1504		ImportPath:   a.Package.ImportPath,1505		ImportMap:    make(map[string]string),1506		PackageFile:  make(map[string]string),1507		Standard:     make(map[string]bool),1508	}1509	vcfg.GoVersion = "go" + gover.Local()1510	if a.Package.Module != nil {1511		v := a.Package.Module.GoVersion1512		if v == "" {1513			v = gover.DefaultGoModVersion1514		}1515		vcfg.GoVersion = "go" + v1516		vcfg.Module = analysisModuleFromModulePublic(a.Package.Module)1517	}1518	a.vetCfg = vcfg1519	for i, raw := range a.Package.Internal.RawImports {1520		final := a.Package.Imports[i]1521		vcfg.ImportMap[raw] = final1522	}15231524	// Compute the list of mapped imports in the vet config1525	// so that we can add any missing mappings below.1526	vcfgMapped := make(map[string]bool)1527	for _, p := range vcfg.ImportMap {1528		vcfgMapped[p] = true1529	}15301531	for _, a1 := range vetDeps {1532		p1 := a1.Package1533		if p1 == nil || p1.ImportPath == "" || p1 == a.Package {1534			continue1535		}1536		// Add import mapping if needed1537		// (for imports like "runtime/cgo" that appear only in generated code).1538		if !vcfgMapped[p1.ImportPath] {1539			vcfg.ImportMap[p1.ImportPath] = p1.ImportPath1540		}1541		if a1.built != "" {1542			vcfg.PackageFile[p1.ImportPath] = a1.built1543		}1544		if p1.Standard {1545			vcfg.Standard[p1.ImportPath] = true1546		}1547	}1548}15491550// VetTool is the path to the effective vet or fix tool binary.1551// The user may specify a non-default value using -{vet,fix}tool.1552// The caller is expected to set it (if needed) before executing any vet actions.1553var VetTool string15541555// VetFlags are the default flags to pass to vet.1556// The caller is expected to set them before executing any vet actions.1557var VetFlags []string15581559// VetHandleStdout determines how the stdout output of each vet tool1560// invocation should be handled. The default behavior is to copy it to1561// the go command's stdout, atomically.1562var VetHandleStdout = copyToStdout15631564// VetExplicit records whether the vet flags (which may include1565// -{vet,fix}tool) were set explicitly on the command line.1566var VetExplicit bool15671568func (b *Builder) vet(ctx context.Context, a *Action) error {1569	// a.Deps[0] is the build of the package being vetted.15701571	a.Failed = nil // vet of dependency may have failed but we can still succeed15721573	if a.Deps[0].Failed != nil {1574		// The build of the package has failed. Skip vet check.1575		// Vet could return export data for non-typecheck errors,1576		// but we ignore it because the package cannot be compiled.1577		return nil1578	}15791580	vcfg := a.Deps[0].vetCfg1581	if vcfg == nil {1582		// Vet config should only be missing if the build failed.1583		return fmt.Errorf("vet config not found")1584	}15851586	sh := b.Shell(a)15871588	// We use "vet" terminology even when building action graphs for go fix.1589	vcfg.VetxOnly = a.VetxOnly1590	vcfg.VetxOutput = a.Objdir + "vet.out"1591	vcfg.Stdout = a.Objdir + "vet.stdout"1592	if a.needFix {1593		vcfg.FixArchive = a.Objdir + "vet.fix.zip"1594	}1595	vcfg.PackageVetx = make(map[string]string)15961597	h := cache.NewHash("vet " + a.Package.ImportPath)1598	fmt.Fprintf(h, "vet %q\n", b.toolID("vet"))15991600	vetFlags := VetFlags16011602	// In GOROOT, we enable all the vet tests during 'go test',1603	// not just the high-confidence subset. This gets us extra1604	// checking for the standard library (at some compliance cost)1605	// and helps us gain experience about how well the checks1606	// work, to help decide which should be turned on by default.1607	// The command-line still wins.1608	//1609	// Note that this flag change applies even when running vet as1610	// a dependency of vetting a package outside std.1611	// (Otherwise we'd have to introduce a whole separate1612	// space of "vet fmt as a dependency of a std top-level vet"1613	// versus "vet fmt as a dependency of a non-std top-level vet".)1614	// This is OK as long as the packages that are farther down the1615	// dependency tree turn on *more* analysis, as here.1616	// (The unsafeptr check does not write any facts for use by1617	// later vet runs, nor does unreachable.)1618	//1619	// When changing the default analyzer suite, please update1620	// x/tools/go/analysis/unitchecker/vet_std_test.go too so that1621	// it functions as a consistent early-warning system for1622	// changes to analyzers (as opposed to changes in the target1623	// packages, which is the purpose of this logic).1624	if a.Package.Goroot && !VetExplicit && VetTool == base.Tool("vet") {1625		// Turn off -unsafeptr checks.1626		// There's too much unsafe.Pointer code1627		// that vet doesn't like in low-level packages1628		// like runtime, sync, and reflect.1629		// Note that $GOROOT/src/buildall.bash1630		// does the same1631		// and should be updated if these flags are1632		// changed here.1633		vetFlags = []string{"-unsafeptr=false"}16341635		// Also turn off -unreachable checks during go test.1636		// During testing it is very common to make changes1637		// like hard-coded forced returns or panics that make1638		// code unreachable. It's unreasonable to insist on files1639		// not having any unreachable code during "go test".1640		// (buildall.bash still has -unreachable enabled1641		// for the overall whole-tree scan.)1642		if cfg.CmdName == "test" {1643			vetFlags = append(vetFlags, "-unreachable=false")1644		}1645	}16461647	// Note: We could decide that vet should compute export data for1648	// all analyses, in which case we don't need to include the flags here.1649	// But that would mean that if an analysis causes problems like1650	// unexpected crashes there would be no way to turn it off.1651	// It seems better to let the flags disable export analysis too.1652	fmt.Fprintf(h, "vetflags %q\n", vetFlags)16531654	fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID)1655	for _, a1 := range a.Deps {1656		if a1.Mode == "vet" && a1.built != "" {1657			fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built))1658			vcfg.PackageVetx[a1.Package.ImportPath] = a1.built1659		}1660	}1661	var (1662		id            = cache.ActionID(h.Sum())     // for .vetx file1663		stdoutKey     = cache.Subkey(id, "stdout")  // for .stdout file1664		fixArchiveKey = cache.Subkey(id, "fix.zip") // for .fix.zip file1665	)16661667	// Check the cache; -a forces a rebuild.1668	if !cfg.BuildA {1669		c := cache.Default()16701671		// There may be multiple artifacts in the cache.1672		// We need to retrieve them all, or none:1673		// the effect must be transactional.1674		var (1675			vetxFile   string                           // name of cached .vetx file1676			fixArchive string                           // name of cached .fix.zip file1677			stdout     io.Reader = bytes.NewReader(nil) // cached stdout stream1678		)16791680		// Obtain location of cached .vetx file.1681		vetxFile, _, err := cache.GetFile(c, id)1682		if err != nil {1683			goto cachemiss1684		}16851686		// Obtain location of cached .fix.zip file (if needed).1687		if a.needFix {1688			file, _, err := cache.GetFile(c, fixArchiveKey)1689			if err != nil {1690				goto cachemiss1691			}1692			fixArchive = file1693		}16941695		// Copy cached .stdout file to stdout.1696		if file, _, err := cache.GetFile(c, stdoutKey); err == nil {1697			f, err := os.Open(file)1698			if err != nil {1699				goto cachemiss1700			}1701			defer f.Close() // ignore error (can't fail)1702			stdout = f1703		}17041705		// Cache hit: commit transaction.1706		a.built = vetxFile1707		a.FixArchive = fixArchive1708		if err := VetHandleStdout(stdout); err != nil {1709			return err // internal error (don't fall through to cachemiss)1710		}17111712		return nil1713	}1714cachemiss:17151716	js, err := json.MarshalIndent(vcfg, "", "\t")1717	if err != nil {1718		return fmt.Errorf("internal error marshaling vet config: %v", err)1719	}1720	js = append(js, '\n')1721	if err := sh.writeFile(a.Objdir+"vet.cfg", js); err != nil {1722		return err1723	}17241725	// TODO(rsc): Why do we pass $GCCGO to go vet?1726	env := b.cCompilerEnv()1727	if cfg.BuildToolchainName == "gccgo" {1728		env = append(env, "GCCGO="+BuildToolchain.compiler())1729	}17301731	p := a.Package1732	tool := VetTool1733	if tool == "" {1734		panic("VetTool unset")1735	}17361737	if err := sh.run(p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, vetFlags, a.Objdir+"vet.cfg"); err != nil {1738		return err1739	}17401741	// Vet tool succeeded, possibly with facts, fixes, or JSON stdout.1742	// Save all in cache.17431744	// Save facts.1745	if f, err := os.Open(vcfg.VetxOutput); err == nil {1746		defer f.Close() // ignore error1747		a.built = vcfg.VetxOutput1748		cache.Default().Put(id, f) // ignore error1749	}17501751	// Save fix archive (if any).1752	if a.needFix {1753		if f, err := os.Open(vcfg.FixArchive); err == nil {1754			defer f.Close() // ignore error1755			a.FixArchive = vcfg.FixArchive1756			cache.Default().Put(fixArchiveKey, f) // ignore error1757		}1758	}17591760	// Save stdout.1761	if f, err := os.Open(vcfg.Stdout); err == nil {1762		defer f.Close() // ignore error1763		if err := VetHandleStdout(f); err != nil {1764			return err1765		}1766		f.Seek(0, io.SeekStart)           // ignore error1767		cache.Default().Put(stdoutKey, f) // ignore error1768	}17691770	return nil1771}17721773var stdoutMu sync.Mutex // serializes concurrent writes (of e.g. JSON values) to stdout17741775// copyToStdout copies the stream to stdout while holding the lock.1776func copyToStdout(r io.Reader) error {1777	stdoutMu.Lock()1778	defer stdoutMu.Unlock()1779	if _, err := io.Copy(os.Stdout, r); err != nil {1780		return fmt.Errorf("copying vet tool stdout: %w", err)1781	}1782	return nil1783}17841785// linkActionID computes the action ID for a link action.1786func (b *Builder) linkActionID(a *Action) cache.ActionID {1787	p := a.Package1788	h := cache.NewHash("link " + p.ImportPath)17891790	// Toolchain-independent configuration.1791	fmt.Fprintf(h, "link\n")1792	// Hash the resolved buildmode (ldBuildmode), not cfg.BuildBuildmode,1793	// so that -buildmode=default produces the same build ID as the1794	// buildmode it resolves to. See go.dev/issue/63559.1795	fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", ldBuildmode, cfg.Goos, cfg.Goarch)1796	fmt.Fprintf(h, "import %q\n", p.ImportPath)1797	fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix)1798	fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG)1799	if cfg.BuildTrimpath {1800		fmt.Fprintln(h, "trimpath")1801	}18021803	// Toolchain-dependent configuration, shared with b.linkSharedActionID.1804	b.printLinkerConfig(h, p)18051806	// Input files.1807	for _, a1 := range a.Deps {1808		p1 := a1.Package1809		if p1 != nil {1810			if a1.built != "" || a1.buildID != "" {1811				buildID := a1.buildID1812				if buildID == "" {1813					buildID = b.buildID(a1.built)1814				}1815				fmt.Fprintf(h, "packagefile %s=%s\n", p1.ImportPath, contentID(buildID))1816			}1817			// Because we put package main's full action ID into the binary's build ID,1818			// we must also put the full action ID into the binary's action ID hash.1819			if p1.Name == "main" {1820				fmt.Fprintf(h, "packagemain %s\n", a1.buildID)1821			}1822			if p1.Shlib != "" {1823				fmt.Fprintf(h, "packageshlib %s=%s\n", p1.ImportPath, contentID(b.buildID(p1.Shlib)))1824			}1825		}1826	}18271828	return h.Sum()1829}18301831// printLinkerConfig prints the linker config into the hash h,1832// as part of the computation of a linker-related action ID.1833func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {1834	switch cfg.BuildToolchainName {1835	default:1836		base.Fatalf("linkActionID: unknown toolchain %q", cfg.BuildToolchainName)18371838	case "gc":1839		fmt.Fprintf(h, "link %s %q %s\n", b.toolID("link"), forcedLdflags, ldBuildmode)1840		if p != nil {1841			fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags)1842		}18431844		// GOARM, GOMIPS, etc.1845		key, val, _ := cfg.GetArchEnv()1846		fmt.Fprintf(h, "%s=%s\n", key, val)18471848		if cfg.CleanGOEXPERIMENT != "" {1849			fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT)1850		}18511852		// The linker writes source file paths that refer to GOROOT,1853		// but only if -trimpath is not specified (see [gctoolchain.ld] in gc.go).1854		gorootFinal := cfg.GOROOT1855		if cfg.BuildTrimpath {1856			gorootFinal = ""1857		}1858		fmt.Fprintf(h, "GOROOT=%s\n", gorootFinal)18591860		// GO_EXTLINK_ENABLED controls whether the external linker is used.1861		fmt.Fprintf(h, "GO_EXTLINK_ENABLED=%s\n", cfg.Getenv("GO_EXTLINK_ENABLED"))18621863		// TODO(rsc): Do cgo settings and flags need to be included?1864		// Or external linker settings and flags?18651866	case "gccgo":1867		id, _, err := b.gccgoToolID(BuildToolchain.linker(), "go")1868		if err != nil {1869			base.Fatalf("%v", err)1870		}1871		fmt.Fprintf(h, "link %s %s\n", id, ldBuildmode)1872		// TODO(iant): Should probably include cgo flags here.1873	}1874}18751876// link is the action for linking a single command.1877// Note that any new influence on this logic must be reported in b.linkActionID above as well.1878func (b *Builder) link(ctx context.Context, a *Action) (err error) {1879	if b.useCache(a, b.linkActionID(a), a.Package.Target, !b.IsCmdList) || b.IsCmdList {1880		return nil1881	}1882	defer b.flushOutput(a)18831884	sh := b.Shell(a)1885	if err := sh.Mkdir(a.Objdir); err != nil {1886		return err1887	}18881889	importcfg := a.Objdir + "importcfg.link"1890	if err := b.writeLinkImportcfg(a, importcfg); err != nil {1891		return err1892	}18931894	if err := AllowInstall(a); err != nil {1895		return err1896	}18971898	// make target directory1899	dir, _ := filepath.Split(a.Target)1900	if dir != "" {1901		if err := sh.Mkdir(dir); err != nil {1902			return err1903		}1904	}19051906	if err := BuildToolchain.ld(b, a, a.Target, importcfg, a.Deps[0].built); err != nil {1907		return err1908	}19091910	// Update the binary with the final build ID.1911	if err := b.updateBuildID(a, a.Target); err != nil {1912		return err1913	}19141915	a.built = a.Target1916	return nil1917}19181919func (b *Builder) writeLinkImportcfg(a *Action, file string) error {1920	// Prepare Go import cfg.1921	var icfg bytes.Buffer1922	for _, a1 := range a.Deps {1923		p1 := a1.Package1924		if p1 == nil {1925			continue1926		}1927		fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)1928		if p1.Shlib != "" {1929			fmt.Fprintf(&icfg, "packageshlib %s=%s\n", p1.ImportPath, p1.Shlib)1930		}1931	}1932	info := ""1933	if a.Package.Internal.BuildInfo != nil {1934		info = a.Package.Internal.BuildInfo.String()1935	}1936	fmt.Fprintf(&icfg, "modinfo %q\n", modload.ModInfoData(info))1937	return b.Shell(a).writeFile(file, icfg.Bytes())1938}19391940// PkgconfigCmd returns a pkg-config binary name1941// defaultPkgConfig is defined in zdefaultcc.go, written by cmd/dist.1942func (b *Builder) PkgconfigCmd() string {1943	return envList("PKG_CONFIG", cfg.DefaultPkgConfig)[0]1944}19451946// splitPkgConfigOutput parses the pkg-config output into a slice of flags.1947// This implements the shell quoting semantics described in1948// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02,1949// except that it does not support parameter or arithmetic expansion or command1950// substitution and hard-codes the <blank> delimiters instead of reading them1951// from LC_LOCALE.1952func splitPkgConfigOutput(out []byte) ([]string, error) {1953	if len(out) == 0 {1954		return nil, nil1955	}1956	var flags []string1957	flag := make([]byte, 0, len(out))1958	didQuote := false // was the current flag parsed from a quoted string?1959	escaped := false  // did we just read `\` in a non-single-quoted context?1960	quote := byte(0)  // what is the quote character around the current string?19611962	for _, c := range out {1963		if escaped {1964			if quote == '"' {1965				// “The <backslash> shall retain its special meaning as an escape1966				// character … only when followed by one of the following characters1967				// when considered special:”1968				switch c {1969				case '$', '`', '"', '\\', '\n':1970					// Handle the escaped character normally.1971				default:1972					// Not an escape character after all.1973					flag = append(flag, '\\', c)1974					escaped = false1975					continue1976				}1977			}19781979			if c == '\n' {1980				// “If a <newline> follows the <backslash>, the shell shall interpret1981				// this as line continuation.”1982			} else {1983				flag = append(flag, c)1984			}1985			escaped = false1986			continue1987		}19881989		if quote != 0 && c == quote {1990			quote = 01991			continue1992		}1993		switch quote {1994		case '\'':1995			// “preserve the literal value of each character”1996			flag = append(flag, c)1997			continue1998		case '"':1999			// “preserve the literal value of all characters within the double-quotes,2000			// with the exception of …”

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.