• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package blueprint
16
17import (
18	"bufio"
19	"bytes"
20	"cmp"
21	"context"
22	"encoding/gob"
23	"encoding/json"
24	"errors"
25	"fmt"
26	"hash/fnv"
27	"io"
28	"io/ioutil"
29	"iter"
30	"maps"
31	"math"
32	"os"
33	"path/filepath"
34	"reflect"
35	"runtime"
36	"runtime/pprof"
37	"slices"
38	"sort"
39	"strconv"
40	"strings"
41	"sync"
42	"sync/atomic"
43	"text/scanner"
44	"text/template"
45	"unsafe"
46
47	"github.com/google/blueprint/metrics"
48	"github.com/google/blueprint/parser"
49	"github.com/google/blueprint/pathtools"
50	"github.com/google/blueprint/pool"
51	"github.com/google/blueprint/proptools"
52	"github.com/google/blueprint/syncmap"
53	"github.com/google/blueprint/uniquelist"
54)
55
56var ErrBuildActionsNotReady = errors.New("build actions are not ready")
57
58const maxErrors = 10
59const MockModuleListFile = "bplist"
60
61const OutFilePermissions = 0666
62
63const BuildActionsCacheFile = "build_actions.gob"
64const OrderOnlyStringsCacheFile = "order_only_strings.gob"
65
66// A Context contains all the state needed to parse a set of Blueprints files
67// and generate a Ninja file.  The process of generating a Ninja file proceeds
68// through a series of four phases.  Each phase corresponds with a some methods
69// on the Context object
70//
71//	      Phase                            Methods
72//	   ------------      -------------------------------------------
73//	1. Registration         RegisterModuleType, RegisterSingletonType
74//
75//	2. Parse                    ParseBlueprintsFiles, Parse
76//
77//	3. Generate            ResolveDependencies, PrepareBuildActions
78//
79//	4. Write                           WriteBuildFile
80//
81// The registration phase prepares the context to process Blueprints files
82// containing various types of modules.  The parse phase reads in one or more
83// Blueprints files and validates their contents against the module types that
84// have been registered.  The generate phase then analyzes the parsed Blueprints
85// contents to create an internal representation for the build actions that must
86// be performed.  This phase also performs validation of the module dependencies
87// and property values defined in the parsed Blueprints files.  Finally, the
88// write phase generates the Ninja manifest text based on the generated build
89// actions.
90type Context struct {
91	context.Context
92
93	// Used for metrics-related event logging.
94	EventHandler *metrics.EventHandler
95
96	BeforePrepareBuildActionsHook func() error
97
98	moduleFactories     map[string]ModuleFactory
99	nameInterface       NameInterface
100	moduleGroups        []*moduleGroup
101	moduleInfo          map[Module]*moduleInfo
102	singletonInfo       []*singletonInfo
103	mutatorInfo         []*mutatorInfo
104	variantMutatorNames []string
105
106	completedTransitionMutators int
107	transitionMutators          []*transitionMutatorImpl
108	transitionMutatorNames      []string
109
110	needsUpdateDependencies uint32 // positive if a mutator modified the dependencies
111
112	dependenciesReady bool // set to true on a successful ResolveDependencies
113	buildActionsReady bool // set to true on a successful PrepareBuildActions
114
115	// set by SetIgnoreUnknownModuleTypes
116	ignoreUnknownModuleTypes bool
117
118	// set by SetAllowMissingDependencies
119	allowMissingDependencies bool
120
121	// set during PrepareBuildActions
122	nameTracker     *nameTracker
123	liveGlobals     *liveTracker
124	globalVariables map[Variable]*ninjaString
125	globalPools     map[Pool]*poolDef
126	globalRules     map[Rule]*ruleDef
127
128	// set during PrepareBuildActions
129	outDir             *ninjaString // The builddir special Ninja variable
130	requiredNinjaMajor int          // For the ninja_required_version variable
131	requiredNinjaMinor int          // For the ninja_required_version variable
132	requiredNinjaMicro int          // For the ninja_required_version variable
133
134	subninjas []string
135
136	// set lazily by sortedModuleGroups
137	cachedSortedModuleGroups []*moduleGroup
138	// cache deps modified to determine whether cachedSortedModuleGroups needs to be recalculated
139	cachedDepsModified bool
140
141	globs    map[globKey]pathtools.GlobResult
142	globLock sync.Mutex
143
144	srcDir         string
145	fs             pathtools.FileSystem
146	moduleListFile string
147
148	// Mutators indexed by the ID of the provider associated with them.  Not all mutators will
149	// have providers, and not all providers will have a mutator, or if they do the mutator may
150	// not be registered in this Context.
151	providerMutators []*mutatorInfo
152
153	// True for the index of any mutators that have already run over all modules
154	finishedMutators []bool
155
156	// If true, RunBlueprint will skip cloning modules at the end of RunBlueprint.
157	// Cloning modules intentionally invalidates some Module values after
158	// mutators run (to ensure that mutators don't set such Module values in a way
159	// which ruins the integrity of the graph). However, keeping Module values
160	// changed by mutators may be a desirable outcome (such as for tooling or tests).
161	SkipCloneModulesAfterMutators bool
162
163	// String values that can be used to gate build graph traversal
164	includeTags *IncludeTags
165
166	sourceRootDirs *SourceRootDirs
167
168	// True if an incremental analysis can be attempted, i.e., there is no Soong
169	// code changes, no environmental variable changes and no product config
170	// variable changes.
171	incrementalAnalysis bool
172
173	// True if the flag --incremental-build-actions is set, in which case Soong
174	// will try to do a incremental build. Mainly two tasks will involve here:
175	// caching the providers of all the participating modules, and restoring the
176	// providers and skip the build action generations if there is a cache hit.
177	// Enabling this flag will only guarantee the former task to be performed, the
178	// latter will depend on the flag above.
179	incrementalEnabled bool
180
181	buildActionsCache       BuildActionCache
182	buildActionsToCacheLock sync.Mutex
183	orderOnlyStringsCache   OrderOnlyStringsCache
184	orderOnlyStrings        syncmap.SyncMap[uniquelist.UniqueList[string], *orderOnlyStringsInfo]
185}
186
187type orderOnlyStringsInfo struct {
188	dedup       bool
189	incremental bool
190	dedupName   string
191}
192
193// A container for String keys. The keys can be used to gate build graph traversal
194type SourceRootDirs struct {
195	dirs []string
196}
197
198func (dirs *SourceRootDirs) Add(names ...string) {
199	dirs.dirs = append(dirs.dirs, names...)
200}
201
202func (dirs *SourceRootDirs) SourceRootDirAllowed(path string) (bool, string) {
203	sort.Slice(dirs.dirs, func(i, j int) bool {
204		return len(dirs.dirs[i]) < len(dirs.dirs[j])
205	})
206	last := len(dirs.dirs)
207	for i := range dirs.dirs {
208		// iterate from longest paths (most specific)
209		prefix := dirs.dirs[last-i-1]
210		disallowedPrefix := false
211		if len(prefix) >= 1 && prefix[0] == '-' {
212			prefix = prefix[1:]
213			disallowedPrefix = true
214		}
215		if strings.HasPrefix(path, prefix) {
216			if disallowedPrefix {
217				return false, prefix
218			} else {
219				return true, prefix
220			}
221		}
222	}
223	return true, ""
224}
225
226func (c *Context) AddSourceRootDirs(dirs ...string) {
227	c.sourceRootDirs.Add(dirs...)
228}
229
230// A container for String keys. The keys can be used to gate build graph traversal
231type IncludeTags map[string]bool
232
233func (tags *IncludeTags) Add(names ...string) {
234	for _, name := range names {
235		(*tags)[name] = true
236	}
237}
238
239func (tags *IncludeTags) Contains(tag string) bool {
240	_, exists := (*tags)[tag]
241	return exists
242}
243
244func (c *Context) AddIncludeTags(names ...string) {
245	c.includeTags.Add(names...)
246}
247
248func (c *Context) ContainsIncludeTag(name string) bool {
249	return c.includeTags.Contains(name)
250}
251
252// iterateAllVariants returns an iter.Seq that iterates over every variant of every module.
253func (c *Context) iterateAllVariants() iter.Seq[*moduleInfo] {
254	return func(yield func(*moduleInfo) bool) {
255		for _, group := range c.moduleGroups {
256			for _, module := range group.modules {
257				if !yield(module) {
258					return
259				}
260			}
261		}
262	}
263}
264
265// An Error describes a problem that was encountered that is related to a
266// particular location in a Blueprints file.
267type BlueprintError struct {
268	Err error            // the error that occurred
269	Pos scanner.Position // the relevant Blueprints file location
270}
271
272// A ModuleError describes a problem that was encountered that is related to a
273// particular module in a Blueprints file
274type ModuleError struct {
275	BlueprintError
276	module *moduleInfo
277}
278
279// A PropertyError describes a problem that was encountered that is related to a
280// particular property in a Blueprints file
281type PropertyError struct {
282	ModuleError
283	property string
284}
285
286func (e *BlueprintError) Error() string {
287	return fmt.Sprintf("%s: %s", e.Pos, e.Err)
288}
289
290func (e *ModuleError) Error() string {
291	return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
292}
293
294func (e *PropertyError) Error() string {
295	return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
296}
297
298type localBuildActions struct {
299	variables []*localVariable
300	rules     []*localRule
301	buildDefs []*buildDef
302}
303
304type moduleList []*moduleInfo
305
306func (l moduleList) firstModule() *moduleInfo {
307	if len(l) > 0 {
308		return l[0]
309	}
310	panic(fmt.Errorf("no first module!"))
311}
312
313func (l moduleList) lastModule() *moduleInfo {
314	if len(l) > 0 {
315		return l[len(l)-1]
316	}
317	panic(fmt.Errorf("no last module!"))
318}
319
320type moduleGroup struct {
321	name      string
322	ninjaName string
323
324	modules moduleList
325
326	namespace Namespace
327}
328
329func (group *moduleGroup) moduleByVariantName(name string) *moduleInfo {
330	for _, module := range group.modules {
331		if module.variant.name == name {
332			return module
333		}
334	}
335	return nil
336}
337
338type moduleInfo struct {
339	// set during Parse
340	typeName          string
341	factory           ModuleFactory
342	relBlueprintsFile string
343	pos               scanner.Position
344	propertyPos       map[string]scanner.Position
345	createdBy         *moduleInfo
346
347	variant variant
348
349	logicModule Module
350	group       *moduleGroup
351	properties  []interface{}
352
353	// set during ResolveDependencies
354	missingDeps   []string
355	newDirectDeps []*moduleInfo
356
357	// set during updateDependencies
358	reverseDeps []*moduleInfo
359	forwardDeps []*moduleInfo
360	directDeps  []depInfo
361
362	// used by parallelVisit
363	waitingCount int
364
365	// set during each runMutator
366	splitModules           moduleList
367	obsoletedByNewVariants bool
368
369	// Used by TransitionMutator implementations
370
371	// incomingTransitionInfos stores the map from variation to TransitionInfo object for transitions that were
372	// requested by reverse dependencies.  It is updated by reverse dependencies and protected by
373	// incomingTransitionInfosLock.  It is invalid after the TransitionMutator top down mutator has run on
374	// this module.
375	incomingTransitionInfos     map[string]TransitionInfo
376	incomingTransitionInfosLock sync.Mutex
377	// splitTransitionInfos and splitTransitionVariations stores the list of TransitionInfo objects, and their
378	// corresponding variations, returned by Split or requested by reverse dependencies.  They are valid after the
379	// TransitionMutator top down mutator has run on this module, and invalid after the bottom up mutator has run.
380	splitTransitionInfos      []TransitionInfo
381	splitTransitionVariations []string
382	currentTransitionMutator  string
383
384	// transitionInfos stores the final TransitionInfo for this module indexed by transitionMutatorImpl.index
385	transitionInfos []TransitionInfo
386
387	// outgoingTransitionCache stores the final variation for each dependency, indexed by the source variation
388	// index in splitTransitionInfos and then by the index of the dependency in directDeps
389	outgoingTransitionCache [][]string
390
391	// set during PrepareBuildActions
392	actionDefs localBuildActions
393
394	providers                  []interface{}
395	providerInitialValueHashes []uint64
396
397	startedMutator  int
398	finishedMutator int
399
400	startedGenerateBuildActions  bool
401	finishedGenerateBuildActions bool
402
403	incrementalInfo
404}
405
406type incrementalInfo struct {
407	incrementalRestored bool
408	buildActionCacheKey *BuildActionCacheKey
409	orderOnlyStrings    []string
410}
411
412type variant struct {
413	name       string
414	variations variationMap
415}
416
417type depInfo struct {
418	module *moduleInfo
419	tag    DependencyTag
420}
421
422func (module *moduleInfo) Name() string {
423	// If this is called from a LoadHook (which is run before the module has been registered)
424	// then group will not be set and so the name is retrieved from logicModule.Name().
425	// Usually, using that method is not safe as it does not track renames (group.name does).
426	// However, when called from LoadHook it is safe as there is no way to rename a module
427	// until after the LoadHook has run and the module has been registered.
428	if module.group != nil {
429		return module.group.name
430	} else {
431		return module.logicModule.Name()
432	}
433}
434
435func (module *moduleInfo) String() string {
436	s := fmt.Sprintf("module %q", module.Name())
437	if module.variant.name != "" {
438		s += fmt.Sprintf(" variant %q", module.variant.name)
439	}
440	if module.createdBy != nil {
441		s += fmt.Sprintf(" (created by %s)", module.createdBy)
442	}
443
444	return s
445}
446
447func (module *moduleInfo) namespace() Namespace {
448	return module.group.namespace
449}
450
451func (module *moduleInfo) ModuleCacheKey() string {
452	variant := module.variant.name
453	if variant == "" {
454		variant = "none"
455	}
456	return calculateFileNameHash(fmt.Sprintf("%s-%s-%s-%s",
457		filepath.Dir(module.relBlueprintsFile), module.Name(), variant, module.typeName))
458
459}
460
461func calculateFileNameHash(name string) string {
462	hash, err := proptools.CalculateHash(name)
463	if err != nil {
464		panic(newPanicErrorf(err, "failed to calculate hash for file name: %s", name))
465	}
466	return strconv.FormatUint(hash, 16)
467}
468
469func (c *Context) setModuleTransitionInfo(module *moduleInfo, t *transitionMutatorImpl, info TransitionInfo) {
470	if len(module.transitionInfos) == 0 {
471		module.transitionInfos = make([]TransitionInfo, len(c.transitionMutators))
472	}
473	module.transitionInfos[t.index] = info
474}
475
476// A Variation is a way that a variant of a module differs from other variants of the same module.
477// For example, two variants of the same module might have Variation{"arch","arm"} and
478// Variation{"arch","arm64"}
479type Variation struct {
480	// Mutator is the axis on which this variation applies, i.e. "arch" or "link"
481	Mutator string
482	// Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
483	// "shared" or "static" for link.
484	Variation string
485}
486
487// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
488type variationMap struct {
489	variations map[string]string
490}
491
492func (vm variationMap) clone() variationMap {
493	return variationMap{
494		variations: maps.Clone(vm.variations),
495	}
496}
497
498func (vm variationMap) cloneMatching(mutators []string) variationMap {
499	newVariations := make(map[string]string)
500	for _, mutator := range mutators {
501		if variation, ok := vm.variations[mutator]; ok {
502			newVariations[mutator] = variation
503		}
504	}
505	return variationMap{
506		variations: newVariations,
507	}
508}
509
510// Compare this variationMap to another one.  Returns true if the every entry in this map
511// exists and has the same value in the other map.
512func (vm variationMap) subsetOf(other variationMap) bool {
513	for k, v1 := range vm.variations {
514		if v2, ok := other.variations[k]; !ok || v1 != v2 {
515			return false
516		}
517	}
518	return true
519}
520
521func (vm variationMap) equal(other variationMap) bool {
522	return maps.Equal(vm.variations, other.variations)
523}
524
525func (vm *variationMap) set(mutator, variation string) {
526	if variation == "" {
527		if vm.variations != nil {
528			delete(vm.variations, mutator)
529		}
530	} else {
531		if vm.variations == nil {
532			vm.variations = make(map[string]string)
533		}
534		vm.variations[mutator] = variation
535	}
536}
537
538func (vm variationMap) get(mutator string) string {
539	return vm.variations[mutator]
540}
541
542func (vm variationMap) delete(mutator string) {
543	delete(vm.variations, mutator)
544}
545
546func (vm variationMap) empty() bool {
547	return len(vm.variations) == 0
548}
549
550// differenceKeysCount returns the count of keys that exist in this variationMap that don't exist in the argument.  It
551// ignores the values.
552func (vm variationMap) differenceKeysCount(other variationMap) int {
553	divergence := 0
554	for mutator, _ := range vm.variations {
555		if _, exists := other.variations[mutator]; !exists {
556			divergence += 1
557		}
558	}
559	return divergence
560}
561
562type singletonInfo struct {
563	// set during RegisterSingletonType
564	factory   SingletonFactory
565	singleton Singleton
566	name      string
567	parallel  bool
568
569	// set during PrepareBuildActions
570	actionDefs localBuildActions
571}
572
573type mutatorInfo struct {
574	// set during RegisterMutator
575	transitionPropagateMutator func(BaseModuleContext)
576	bottomUpMutator            BottomUpMutator
577	name                       string
578	index                      int
579	transitionMutator          *transitionMutatorImpl
580
581	usesRename              bool
582	usesReverseDependencies bool
583	usesReplaceDependencies bool
584	usesCreateModule        bool
585	mutatesDependencies     bool
586	mutatesGlobalState      bool
587}
588
589func newContext() *Context {
590	eventHandler := metrics.EventHandler{}
591	return &Context{
592		Context:               context.Background(),
593		EventHandler:          &eventHandler,
594		moduleFactories:       make(map[string]ModuleFactory),
595		nameInterface:         NewSimpleNameInterface(),
596		moduleInfo:            make(map[Module]*moduleInfo),
597		globs:                 make(map[globKey]pathtools.GlobResult),
598		fs:                    pathtools.OsFs,
599		includeTags:           &IncludeTags{},
600		sourceRootDirs:        &SourceRootDirs{},
601		outDir:                nil,
602		requiredNinjaMajor:    1,
603		requiredNinjaMinor:    7,
604		requiredNinjaMicro:    0,
605		buildActionsCache:     make(BuildActionCache),
606		orderOnlyStringsCache: make(OrderOnlyStringsCache),
607		orderOnlyStrings:      syncmap.SyncMap[uniquelist.UniqueList[string], *orderOnlyStringsInfo]{},
608	}
609}
610
611// NewContext creates a new Context object.  The created context initially has
612// no module or singleton factories registered, so the RegisterModuleFactory and
613// RegisterSingletonFactory methods must be called before it can do anything
614// useful.
615func NewContext() *Context {
616	ctx := newContext()
617
618	ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
619
620	return ctx
621}
622
623// A ModuleFactory function creates a new Module object.  See the
624// Context.RegisterModuleType method for details about how a registered
625// ModuleFactory is used by a Context.
626type ModuleFactory func() (m Module, propertyStructs []interface{})
627
628// RegisterModuleType associates a module type name (which can appear in a
629// Blueprints file) with a Module factory function.  When the given module type
630// name is encountered in a Blueprints file during parsing, the Module factory
631// is invoked to instantiate a new Module object to handle the build action
632// generation for the module.  If a Mutator splits a module into multiple variants,
633// the factory is invoked again to create a new Module for each variant.
634//
635// The module type names given here must be unique for the context.  The factory
636// function should be a named function so that its package and name can be
637// included in the generated Ninja file for debugging purposes.
638//
639// The factory function returns two values.  The first is the newly created
640// Module object.  The second is a slice of pointers to that Module object's
641// properties structs.  Each properties struct is examined when parsing a module
642// definition of this type in a Blueprints file.  Exported fields of the
643// properties structs are automatically set to the property values specified in
644// the Blueprints file.  The properties struct field names determine the name of
645// the Blueprints file properties that are used - the Blueprints property name
646// matches that of the properties struct field name with the first letter
647// converted to lower-case.
648//
649// The fields of the properties struct must be either []string, a string, or
650// bool. The Context will panic if a Module gets instantiated with a properties
651// struct containing a field that is not one these supported types.
652//
653// Any properties that appear in the Blueprints files that are not built-in
654// module properties (such as "name" and "deps") and do not have a corresponding
655// field in the returned module properties struct result in an error during the
656// Context's parse phase.
657//
658// As an example, the follow code:
659//
660//	type myModule struct {
661//	    properties struct {
662//	        Foo string
663//	        Bar []string
664//	    }
665//	}
666//
667//	func NewMyModule() (blueprint.Module, []interface{}) {
668//	    module := new(myModule)
669//	    properties := &module.properties
670//	    return module, []interface{}{properties}
671//	}
672//
673//	func main() {
674//	    ctx := blueprint.NewContext()
675//	    ctx.RegisterModuleType("my_module", NewMyModule)
676//	    // ...
677//	}
678//
679// would support parsing a module defined in a Blueprints file as follows:
680//
681//	my_module {
682//	    name: "myName",
683//	    foo:  "my foo string",
684//	    bar:  ["my", "bar", "strings"],
685//	}
686//
687// The factory function may be called from multiple goroutines.  Any accesses
688// to global variables must be synchronized.
689func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
690	if _, present := c.moduleFactories[name]; present {
691		panic(fmt.Errorf("module type %q is already registered", name))
692	}
693	c.moduleFactories[name] = factory
694}
695
696// A SingletonFactory function creates a new Singleton object.  See the
697// Context.RegisterSingletonType method for details about how a registered
698// SingletonFactory is used by a Context.
699type SingletonFactory func() Singleton
700
701// RegisterSingletonType registers a singleton type that will be invoked to
702// generate build actions.  Each registered singleton type is instantiated
703// and invoked exactly once as part of the generate phase.
704//
705// Those singletons registered with parallel=true are run in parallel, after
706// which the other registered singletons are run in registration order.
707//
708// The singleton type names given here must be unique for the context.  The
709// factory function should be a named function so that its package and name can
710// be included in the generated Ninja file for debugging purposes.
711func (c *Context) RegisterSingletonType(name string, factory SingletonFactory, parallel bool) {
712	for _, s := range c.singletonInfo {
713		if s.name == name {
714			panic(fmt.Errorf("singleton %q is already registered", name))
715		}
716	}
717
718	c.singletonInfo = append(c.singletonInfo, &singletonInfo{
719		factory:   factory,
720		singleton: factory(),
721		name:      name,
722		parallel:  parallel,
723	})
724}
725
726func (c *Context) SetNameInterface(i NameInterface) {
727	c.nameInterface = i
728}
729
730func (c *Context) SetIncrementalAnalysis(incremental bool) {
731	c.incrementalAnalysis = incremental
732}
733
734func (c *Context) GetIncrementalAnalysis() bool {
735	return c.incrementalAnalysis
736}
737
738func (c *Context) SetIncrementalEnabled(incremental bool) {
739	c.incrementalEnabled = incremental
740}
741
742func (c *Context) GetIncrementalEnabled() bool {
743	return c.incrementalEnabled
744}
745
746func (c *Context) updateBuildActionsCache(key *BuildActionCacheKey, data *BuildActionCachedData) {
747	if key != nil {
748		c.buildActionsToCacheLock.Lock()
749		defer c.buildActionsToCacheLock.Unlock()
750		c.buildActionsCache[*key] = data
751	}
752}
753
754func (c *Context) getBuildActionsFromCache(key *BuildActionCacheKey) *BuildActionCachedData {
755	if c.buildActionsCache != nil && key != nil {
756		return c.buildActionsCache[*key]
757	}
758	return nil
759}
760
761func (c *Context) CacheAllBuildActions(soongOutDir string) error {
762	return errors.Join(writeToCache(c, soongOutDir, BuildActionsCacheFile, &c.buildActionsCache),
763		writeToCache(c, soongOutDir, OrderOnlyStringsCacheFile, &c.orderOnlyStringsCache))
764}
765
766func writeToCache[T any](ctx *Context, soongOutDir string, fileName string, data *T) error {
767	file, err := ctx.fs.OpenFile(filepath.Join(ctx.SrcDir(), soongOutDir, fileName),
768		os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions)
769	if err != nil {
770		return err
771	}
772	defer file.Close()
773
774	encoder := gob.NewEncoder(file)
775	return encoder.Encode(data)
776}
777
778func (c *Context) RestoreAllBuildActions(soongOutDir string) error {
779	return errors.Join(restoreFromCache(c, soongOutDir, BuildActionsCacheFile, &c.buildActionsCache),
780		restoreFromCache(c, soongOutDir, OrderOnlyStringsCacheFile, &c.orderOnlyStringsCache))
781}
782
783func restoreFromCache[T any](ctx *Context, soongOutDir string, fileName string, data *T) error {
784	file, err := ctx.fs.Open(filepath.Join(ctx.SrcDir(), soongOutDir, fileName))
785	if err != nil {
786		if os.IsNotExist(err) {
787			err = nil
788		}
789		return err
790	}
791	defer file.Close()
792
793	decoder := gob.NewDecoder(file)
794	return decoder.Decode(data)
795}
796
797func (c *Context) SetSrcDir(path string) {
798	c.srcDir = path
799	c.fs = pathtools.NewOsFs(path)
800}
801
802func (c *Context) SrcDir() string {
803	return c.srcDir
804}
805
806func singletonPkgPath(singleton Singleton) string {
807	typ := reflect.TypeOf(singleton)
808	for typ.Kind() == reflect.Ptr {
809		typ = typ.Elem()
810	}
811	return typ.PkgPath()
812}
813
814func singletonTypeName(singleton Singleton) string {
815	typ := reflect.TypeOf(singleton)
816	for typ.Kind() == reflect.Ptr {
817		typ = typ.Elem()
818	}
819	return typ.PkgPath() + "." + typ.Name()
820}
821
822// registerTransitionPropagateMutator registers a mutator that will be invoked to propagate transition mutator
823// configuration info top-down between Modules.
824func (c *Context) registerTransitionPropagateMutator(name string, mutator func(mctx BaseModuleContext)) MutatorHandle {
825	for _, m := range c.mutatorInfo {
826		if m.name == name && m.transitionPropagateMutator != nil {
827			panic(fmt.Errorf("mutator %q is already registered", name))
828		}
829	}
830
831	info := &mutatorInfo{
832		transitionPropagateMutator: mutator,
833
834		name:  name,
835		index: len(c.mutatorInfo),
836	}
837
838	c.mutatorInfo = append(c.mutatorInfo, info)
839
840	return info
841}
842
843// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
844// Each registered mutator is invoked in registration order once per Module, and will not be invoked on a
845// module until the invocations on all of the modules dependencies have returned.
846//
847// The mutator type names given here must be unique to all bottom up or early
848// mutators in the Context.
849func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
850	for _, m := range c.variantMutatorNames {
851		if m == name {
852			panic(fmt.Errorf("mutator %q is already registered", name))
853		}
854	}
855
856	info := &mutatorInfo{
857		bottomUpMutator: mutator,
858		name:            name,
859		index:           len(c.mutatorInfo),
860	}
861	c.mutatorInfo = append(c.mutatorInfo, info)
862
863	c.variantMutatorNames = append(c.variantMutatorNames, name)
864
865	return info
866}
867
868// HasMutatorFinished returns true if the given mutator has finished running.
869// It will panic if given an invalid mutator name.
870func (c *Context) HasMutatorFinished(mutatorName string) bool {
871	for _, mutator := range c.mutatorInfo {
872		if mutator.name == mutatorName {
873			return len(c.finishedMutators) > mutator.index && c.finishedMutators[mutator.index]
874		}
875	}
876	panic(fmt.Sprintf("unknown mutator %q", mutatorName))
877}
878
879type MutatorHandle interface {
880	// UsesRename marks the mutator as using the BottomUpMutatorContext.Rename method, which prevents
881	// coalescing adjacent mutators into a single mutator pass.
882	UsesRename() MutatorHandle
883
884	// UsesReverseDependencies marks the mutator as using the BottomUpMutatorContext.AddReverseDependency
885	// method, which prevents coalescing adjacent mutators into a single mutator pass.
886	UsesReverseDependencies() MutatorHandle
887
888	// UsesReplaceDependencies marks the mutator as using the BottomUpMutatorContext.ReplaceDependencies
889	// method, which prevents coalescing adjacent mutators into a single mutator pass.
890	UsesReplaceDependencies() MutatorHandle
891
892	// UsesCreateModule marks the mutator as using the BottomUpMutatorContext.CreateModule method,
893	// which prevents coalescing adjacent mutators into a single mutator pass.
894	UsesCreateModule() MutatorHandle
895
896	// MutatesDependencies marks the mutator as modifying properties in dependencies, which prevents
897	// coalescing adjacent mutators into a single mutator pass.
898	MutatesDependencies() MutatorHandle
899
900	// MutatesGlobalState marks the mutator as modifying global state, which prevents coalescing
901	// adjacent mutators into a single mutator pass.
902	MutatesGlobalState() MutatorHandle
903
904	setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle
905}
906
907func (mutator *mutatorInfo) UsesRename() MutatorHandle {
908	mutator.usesRename = true
909	return mutator
910}
911
912func (mutator *mutatorInfo) UsesReverseDependencies() MutatorHandle {
913	mutator.usesReverseDependencies = true
914	return mutator
915}
916
917func (mutator *mutatorInfo) UsesReplaceDependencies() MutatorHandle {
918	mutator.usesReplaceDependencies = true
919	return mutator
920}
921
922func (mutator *mutatorInfo) UsesCreateModule() MutatorHandle {
923	mutator.usesCreateModule = true
924	return mutator
925}
926
927func (mutator *mutatorInfo) MutatesDependencies() MutatorHandle {
928	mutator.mutatesDependencies = true
929	return mutator
930}
931
932func (mutator *mutatorInfo) MutatesGlobalState() MutatorHandle {
933	mutator.mutatesGlobalState = true
934	return mutator
935}
936
937func (mutator *mutatorInfo) setTransitionMutator(impl *transitionMutatorImpl) MutatorHandle {
938	mutator.transitionMutator = impl
939	return mutator
940}
941
942// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
943// where it encounters an unknown module type while parsing Blueprints files. By
944// default, the context will report unknown module types as an error.  If this
945// method is called with ignoreUnknownModuleTypes set to true then the context
946// will silently ignore unknown module types.
947//
948// This method should generally not be used.  It exists to facilitate the
949// bootstrapping process.
950func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
951	c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
952}
953
954// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
955// unresolved dependencies.  If the module's GenerateBuildActions calls
956// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
957// for missing dependencies.
958func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
959	c.allowMissingDependencies = allowMissingDependencies
960}
961
962func (c *Context) SetModuleListFile(listFile string) {
963	c.moduleListFile = listFile
964}
965
966func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
967	reader, err := c.fs.Open(c.moduleListFile)
968	if err != nil {
969		return nil, err
970	}
971	defer reader.Close()
972	bytes, err := ioutil.ReadAll(reader)
973	if err != nil {
974		return nil, err
975	}
976	text := string(bytes)
977
978	text = strings.Trim(text, "\n")
979	lines := strings.Split(text, "\n")
980	for i := range lines {
981		lines[i] = filepath.Join(baseDir, lines[i])
982	}
983
984	return lines, nil
985}
986
987// a fileParseContext tells the status of parsing a particular file
988type fileParseContext struct {
989	// name of file
990	fileName string
991
992	// scope to use when resolving variables
993	Scope *parser.Scope
994
995	// pointer to the one in the parent directory
996	parent *fileParseContext
997
998	// is closed once FileHandler has completed for this file
999	doneVisiting chan struct{}
1000}
1001
1002// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
1003// at rootFile.  When it encounters a Blueprints file with a set of subdirs
1004// listed it recursively parses any Blueprints files found in those
1005// subdirectories.
1006//
1007// If no errors are encountered while parsing the files, the list of paths on
1008// which the future output will depend is returned.  This list will include both
1009// Blueprints file paths as well as directory paths for cases where wildcard
1010// subdirs are found.
1011func (c *Context) ParseBlueprintsFiles(rootFile string,
1012	config interface{}) (deps []string, errs []error) {
1013
1014	baseDir := filepath.Dir(rootFile)
1015	pathsToParse, err := c.ListModulePaths(baseDir)
1016	if err != nil {
1017		return nil, []error{err}
1018	}
1019	return c.ParseFileList(baseDir, pathsToParse, config)
1020}
1021
1022type shouldVisitFileInfo struct {
1023	shouldVisitFile bool
1024	skippedModules  []string
1025	reasonForSkip   string
1026	errs            []error
1027}
1028
1029// Returns a boolean for whether this file should be analyzed
1030// Evaluates to true if the file either
1031// 1. does not contain a blueprint_package_includes
1032// 2. contains a blueprint_package_includes and all requested tags are set
1033// This should be processed before adding any modules to the build graph
1034func shouldVisitFile(c *Context, file *parser.File) shouldVisitFileInfo {
1035	skippedModules := []string{}
1036	for _, def := range file.Defs {
1037		switch def := def.(type) {
1038		case *parser.Module:
1039			skippedModules = append(skippedModules, def.Name())
1040		}
1041	}
1042
1043	shouldVisit, invalidatingPrefix := c.sourceRootDirs.SourceRootDirAllowed(file.Name)
1044	if !shouldVisit {
1045		return shouldVisitFileInfo{
1046			shouldVisitFile: shouldVisit,
1047			skippedModules:  skippedModules,
1048			reasonForSkip: fmt.Sprintf(
1049				"%q is a descendant of %q, and that path prefix was not included in PRODUCT_SOURCE_ROOT_DIRS",
1050				file.Name,
1051				invalidatingPrefix,
1052			),
1053		}
1054	}
1055	return shouldVisitFileInfo{shouldVisitFile: true}
1056}
1057
1058func (c *Context) ParseFileList(rootDir string, filePaths []string,
1059	config interface{}) (deps []string, errs []error) {
1060
1061	if len(filePaths) < 1 {
1062		return nil, []error{fmt.Errorf("no paths provided to parse")}
1063	}
1064
1065	c.dependenciesReady = false
1066
1067	type newModuleInfo struct {
1068		*moduleInfo
1069		deps  []string
1070		added chan<- struct{}
1071	}
1072
1073	type newSkipInfo struct {
1074		shouldVisitFileInfo
1075		file string
1076	}
1077
1078	moduleCh := make(chan newModuleInfo)
1079	errsCh := make(chan []error)
1080	doneCh := make(chan struct{})
1081	skipCh := make(chan newSkipInfo)
1082	var numErrs uint32
1083	var numGoroutines int32
1084
1085	// handler must be reentrant
1086	handleOneFile := func(file *parser.File) {
1087		if atomic.LoadUint32(&numErrs) > maxErrors {
1088			return
1089		}
1090
1091		addedCh := make(chan struct{})
1092
1093		var scopedModuleFactories map[string]ModuleFactory
1094
1095		var addModule func(module *moduleInfo) []error
1096		addModule = func(module *moduleInfo) []error {
1097			// Run any load hooks immediately before it is sent to the moduleCh and is
1098			// registered by name. This allows load hooks to set and/or modify any aspect
1099			// of the module (including names) using information that is not available when
1100			// the module factory is called.
1101			newModules, newDeps, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
1102			if len(errs) > 0 {
1103				return errs
1104			}
1105
1106			moduleCh <- newModuleInfo{module, newDeps, addedCh}
1107			<-addedCh
1108			for _, n := range newModules {
1109				errs = addModule(n)
1110				if len(errs) > 0 {
1111					return errs
1112				}
1113			}
1114			return nil
1115		}
1116		shouldVisitInfo := shouldVisitFile(c, file)
1117		errs := shouldVisitInfo.errs
1118		if len(errs) > 0 {
1119			atomic.AddUint32(&numErrs, uint32(len(errs)))
1120			errsCh <- errs
1121		}
1122		if !shouldVisitInfo.shouldVisitFile {
1123			skipCh <- newSkipInfo{
1124				file:                file.Name,
1125				shouldVisitFileInfo: shouldVisitInfo,
1126			}
1127			// TODO: Write a file that lists the skipped bp files
1128			return
1129		}
1130
1131		for _, def := range file.Defs {
1132			switch def := def.(type) {
1133			case *parser.Module:
1134				module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes)
1135				if len(errs) == 0 && module != nil {
1136					errs = addModule(module)
1137				}
1138
1139				if len(errs) > 0 {
1140					atomic.AddUint32(&numErrs, uint32(len(errs)))
1141					errsCh <- errs
1142				}
1143
1144			case *parser.Assignment:
1145				// Already handled via Scope object
1146			default:
1147				panic("unknown definition type")
1148			}
1149
1150		}
1151	}
1152
1153	atomic.AddInt32(&numGoroutines, 1)
1154	go func() {
1155		var errs []error
1156		deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
1157		if len(errs) > 0 {
1158			errsCh <- errs
1159		}
1160		doneCh <- struct{}{}
1161	}()
1162
1163	var hookDeps []string
1164loop:
1165	for {
1166		select {
1167		case newErrs := <-errsCh:
1168			errs = append(errs, newErrs...)
1169		case module := <-moduleCh:
1170			newErrs := c.addModule(module.moduleInfo)
1171			hookDeps = append(hookDeps, module.deps...)
1172			if module.added != nil {
1173				module.added <- struct{}{}
1174			}
1175			if len(newErrs) > 0 {
1176				errs = append(errs, newErrs...)
1177			}
1178		case <-doneCh:
1179			n := atomic.AddInt32(&numGoroutines, -1)
1180			if n == 0 {
1181				break loop
1182			}
1183		case skipped := <-skipCh:
1184			nctx := newNamespaceContextFromFilename(skipped.file)
1185			for _, name := range skipped.skippedModules {
1186				c.nameInterface.NewSkippedModule(nctx, name, SkippedModuleInfo{
1187					filename: skipped.file,
1188					reason:   skipped.reasonForSkip,
1189				})
1190			}
1191		}
1192	}
1193
1194	deps = append(deps, hookDeps...)
1195	return deps, errs
1196}
1197
1198type FileHandler func(*parser.File)
1199
1200// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
1201// calling the given file handler on each
1202//
1203// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
1204// it recursively parses any Blueprints files found in those subdirectories.
1205//
1206// If any of the file paths is an ancestor directory of any other of file path, the ancestor
1207// will be parsed and visited first.
1208//
1209// the file handler will be called from a goroutine, so it must be reentrant.
1210//
1211// If no errors are encountered while parsing the files, the list of paths on
1212// which the future output will depend is returned.  This list will include both
1213// Blueprints file paths as well as directory paths for cases where wildcard
1214// subdirs are found.
1215//
1216// visitor will be called asynchronously, and will only be called once visitor for each
1217// ancestor directory has completed.
1218//
1219// WalkBlueprintsFiles will not return until all calls to visitor have returned.
1220func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
1221	visitor FileHandler) (deps []string, errs []error) {
1222
1223	// make a mapping from ancestors to their descendants to facilitate parsing ancestors first
1224	descendantsMap, err := findBlueprintDescendants(filePaths)
1225	if err != nil {
1226		panic(err.Error())
1227	}
1228	blueprintsSet := make(map[string]bool)
1229
1230	// Channels to receive data back from openAndParse goroutines
1231	blueprintsCh := make(chan fileParseContext)
1232	errsCh := make(chan []error)
1233	depsCh := make(chan string)
1234
1235	// Channel to notify main loop that a openAndParse goroutine has finished
1236	doneParsingCh := make(chan fileParseContext)
1237
1238	// Number of outstanding goroutines to wait for
1239	activeCount := 0
1240	var pending []fileParseContext
1241	tooManyErrors := false
1242
1243	// Limit concurrent calls to parseBlueprintFiles to 200
1244	// Darwin has a default limit of 256 open files
1245	maxActiveCount := 200
1246
1247	// count the number of pending calls to visitor()
1248	visitorWaitGroup := sync.WaitGroup{}
1249
1250	startParseBlueprintsFile := func(blueprint fileParseContext) {
1251		if blueprintsSet[blueprint.fileName] {
1252			return
1253		}
1254		blueprintsSet[blueprint.fileName] = true
1255		activeCount++
1256		deps = append(deps, blueprint.fileName)
1257		visitorWaitGroup.Add(1)
1258		go func() {
1259			file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
1260				&blueprint)
1261			if len(errs) > 0 {
1262				errsCh <- errs
1263			}
1264			for _, blueprint := range blueprints {
1265				blueprintsCh <- blueprint
1266			}
1267			for _, dep := range deps {
1268				depsCh <- dep
1269			}
1270			doneParsingCh <- blueprint
1271
1272			if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
1273				// wait for visitor() of parent to complete
1274				<-blueprint.parent.doneVisiting
1275			}
1276
1277			if len(errs) == 0 {
1278				// process this file
1279				visitor(file)
1280			}
1281			if blueprint.doneVisiting != nil {
1282				close(blueprint.doneVisiting)
1283			}
1284			visitorWaitGroup.Done()
1285		}()
1286	}
1287
1288	foundParseableBlueprint := func(blueprint fileParseContext) {
1289		if activeCount >= maxActiveCount {
1290			pending = append(pending, blueprint)
1291		} else {
1292			startParseBlueprintsFile(blueprint)
1293		}
1294	}
1295
1296	startParseDescendants := func(blueprint fileParseContext) {
1297		descendants, hasDescendants := descendantsMap[blueprint.fileName]
1298		if hasDescendants {
1299			for _, descendant := range descendants {
1300				foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
1301			}
1302		}
1303	}
1304
1305	// begin parsing any files that have no ancestors
1306	startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
1307
1308loop:
1309	for {
1310		if len(errs) > maxErrors {
1311			tooManyErrors = true
1312		}
1313
1314		select {
1315		case newErrs := <-errsCh:
1316			errs = append(errs, newErrs...)
1317		case dep := <-depsCh:
1318			deps = append(deps, dep)
1319		case blueprint := <-blueprintsCh:
1320			if tooManyErrors {
1321				continue
1322			}
1323			foundParseableBlueprint(blueprint)
1324		case blueprint := <-doneParsingCh:
1325			activeCount--
1326			if !tooManyErrors {
1327				startParseDescendants(blueprint)
1328			}
1329			if activeCount < maxActiveCount && len(pending) > 0 {
1330				// start to process the next one from the queue
1331				next := pending[len(pending)-1]
1332				pending = pending[:len(pending)-1]
1333				startParseBlueprintsFile(next)
1334			}
1335			if activeCount == 0 {
1336				break loop
1337			}
1338		}
1339	}
1340
1341	sort.Strings(deps)
1342
1343	// wait for every visitor() to complete
1344	visitorWaitGroup.Wait()
1345
1346	return
1347}
1348
1349// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
1350// filenames to contents stored as a byte slice.
1351func (c *Context) MockFileSystem(files map[string][]byte) {
1352	// look for a module list file
1353	_, ok := files[MockModuleListFile]
1354	if !ok {
1355		// no module list file specified; find every file named Blueprints
1356		pathsToParse := []string{}
1357		for candidate := range files {
1358			if filepath.Base(candidate) == "Android.bp" {
1359				pathsToParse = append(pathsToParse, candidate)
1360			}
1361		}
1362		if len(pathsToParse) < 1 {
1363			panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
1364		}
1365		// put the list of Blueprints files into a list file
1366		files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
1367	}
1368	c.SetModuleListFile(MockModuleListFile)
1369
1370	// mock the filesystem
1371	c.fs = pathtools.MockFs(files)
1372}
1373
1374func (c *Context) SetFs(fs pathtools.FileSystem) {
1375	c.fs = fs
1376}
1377
1378// openAndParse opens and parses a single Blueprints file, and returns the results
1379func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
1380	parent *fileParseContext) (file *parser.File,
1381	subBlueprints []fileParseContext, deps []string, errs []error) {
1382
1383	f, err := c.fs.Open(filename)
1384	if err != nil {
1385		// couldn't open the file; see if we can provide a clearer error than "could not open file"
1386		stats, statErr := c.fs.Lstat(filename)
1387		if statErr == nil {
1388			isSymlink := stats.Mode()&os.ModeSymlink != 0
1389			if isSymlink {
1390				err = fmt.Errorf("could not open symlink %v : %v", filename, err)
1391				target, readlinkErr := os.Readlink(filename)
1392				if readlinkErr == nil {
1393					_, targetStatsErr := c.fs.Lstat(target)
1394					if targetStatsErr != nil {
1395						err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
1396					}
1397				}
1398			} else {
1399				err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
1400			}
1401		}
1402		return nil, nil, nil, []error{err}
1403	}
1404
1405	func() {
1406		defer func() {
1407			err = f.Close()
1408			if err != nil {
1409				errs = append(errs, err)
1410			}
1411		}()
1412		file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
1413	}()
1414
1415	if len(errs) > 0 {
1416		return nil, nil, nil, errs
1417	}
1418
1419	for _, b := range subBlueprints {
1420		deps = append(deps, b.fileName)
1421	}
1422
1423	return file, subBlueprints, deps, nil
1424}
1425
1426// parseOne parses a single Blueprints file from the given reader, creating Module
1427// objects for each of the module definitions encountered.  If the Blueprints
1428// file contains an assignment to the "subdirs" variable, then the
1429// subdirectories listed are searched for Blueprints files returned in the
1430// subBlueprints return value.  If the Blueprints file contains an assignment
1431// to the "build" variable, then the file listed are returned in the
1432// subBlueprints return value.
1433//
1434// rootDir specifies the path to the root directory of the source tree, while
1435// filename specifies the path to the Blueprints file.  These paths are used for
1436// error reporting and for determining the module's directory.
1437func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
1438	scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
1439
1440	relBlueprintsFile, err := filepath.Rel(rootDir, filename)
1441	if err != nil {
1442		return nil, nil, []error{err}
1443	}
1444
1445	scope.DontInherit("subdirs")
1446	scope.DontInherit("optional_subdirs")
1447	scope.DontInherit("build")
1448	file, errs = parser.ParseAndEval(filename, reader, scope)
1449	if len(errs) > 0 {
1450		for i, err := range errs {
1451			if parseErr, ok := err.(*parser.ParseError); ok {
1452				err = &BlueprintError{
1453					Err: parseErr.Err,
1454					Pos: parseErr.Pos,
1455				}
1456				errs[i] = err
1457			}
1458		}
1459
1460		// If there were any parse errors don't bother trying to interpret the
1461		// result.
1462		return nil, nil, errs
1463	}
1464	file.Name = relBlueprintsFile
1465
1466	build, buildPos, err := getLocalStringListFromScope(scope, "build")
1467	if err != nil {
1468		errs = append(errs, err)
1469	}
1470	for _, buildEntry := range build {
1471		if strings.Contains(buildEntry, "/") {
1472			errs = append(errs, &BlueprintError{
1473				Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1474				Pos: buildPos,
1475			})
1476		}
1477	}
1478
1479	if err != nil {
1480		errs = append(errs, err)
1481	}
1482
1483	var blueprints []string
1484
1485	newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1486	blueprints = append(blueprints, newBlueprints...)
1487	errs = append(errs, newErrs...)
1488
1489	subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
1490	for i, b := range blueprints {
1491		subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
1492	}
1493	return file, subBlueprintsAndScope, errs
1494}
1495
1496func (c *Context) findBuildBlueprints(dir string, build []string,
1497	buildPos scanner.Position) ([]string, []error) {
1498
1499	var blueprints []string
1500	var errs []error
1501
1502	for _, file := range build {
1503		pattern := filepath.Join(dir, file)
1504		var matches []string
1505		var err error
1506
1507		matches, err = c.glob(pattern, nil)
1508
1509		if err != nil {
1510			errs = append(errs, &BlueprintError{
1511				Err: fmt.Errorf("%q: %s", pattern, err.Error()),
1512				Pos: buildPos,
1513			})
1514			continue
1515		}
1516
1517		if len(matches) == 0 {
1518			errs = append(errs, &BlueprintError{
1519				Err: fmt.Errorf("%q: not found", pattern),
1520				Pos: buildPos,
1521			})
1522		}
1523
1524		for _, foundBlueprints := range matches {
1525			if strings.HasSuffix(foundBlueprints, "/") {
1526				errs = append(errs, &BlueprintError{
1527					Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1528					Pos: buildPos,
1529				})
1530			}
1531			blueprints = append(blueprints, foundBlueprints)
1532		}
1533	}
1534
1535	return blueprints, errs
1536}
1537
1538func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
1539	subBlueprintsName string, optional bool) ([]string, []error) {
1540
1541	var blueprints []string
1542	var errs []error
1543
1544	for _, subdir := range subdirs {
1545		pattern := filepath.Join(dir, subdir, subBlueprintsName)
1546		var matches []string
1547		var err error
1548
1549		matches, err = c.glob(pattern, nil)
1550
1551		if err != nil {
1552			errs = append(errs, &BlueprintError{
1553				Err: fmt.Errorf("%q: %s", pattern, err.Error()),
1554				Pos: subdirsPos,
1555			})
1556			continue
1557		}
1558
1559		if len(matches) == 0 && !optional {
1560			errs = append(errs, &BlueprintError{
1561				Err: fmt.Errorf("%q: not found", pattern),
1562				Pos: subdirsPos,
1563			})
1564		}
1565
1566		for _, subBlueprints := range matches {
1567			if strings.HasSuffix(subBlueprints, "/") {
1568				errs = append(errs, &BlueprintError{
1569					Err: fmt.Errorf("%q: is a directory", subBlueprints),
1570					Pos: subdirsPos,
1571				})
1572			}
1573			blueprints = append(blueprints, subBlueprints)
1574		}
1575	}
1576
1577	return blueprints, errs
1578}
1579
1580func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1581	if assignment := scope.GetLocal(v); assignment == nil {
1582		return nil, scanner.Position{}, nil
1583	} else {
1584		switch value := assignment.Value.(type) {
1585		case *parser.List:
1586			ret := make([]string, 0, len(value.Values))
1587
1588			for _, listValue := range value.Values {
1589				s, ok := listValue.(*parser.String)
1590				if !ok {
1591					// The parser should not produce this.
1592					panic("non-string value found in list")
1593				}
1594
1595				ret = append(ret, s.Value)
1596			}
1597
1598			return ret, assignment.EqualsPos, nil
1599		case *parser.Bool, *parser.String:
1600			return nil, scanner.Position{}, &BlueprintError{
1601				Err: fmt.Errorf("%q must be a list of strings", v),
1602				Pos: assignment.EqualsPos,
1603			}
1604		default:
1605			panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
1606		}
1607	}
1608}
1609
1610// Clones a build logic module by calling the factory method for its module type, and then cloning
1611// property values.  Any values stored in the module object that are not stored in properties
1612// structs will be lost.
1613func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
1614	newLogicModule, newProperties := origModule.factory()
1615
1616	if len(newProperties) != len(origModule.properties) {
1617		panic("mismatched properties array length in " + origModule.Name())
1618	}
1619
1620	for i := range newProperties {
1621		dst := reflect.ValueOf(newProperties[i])
1622		src := reflect.ValueOf(origModule.properties[i])
1623
1624		proptools.CopyProperties(dst, src)
1625	}
1626
1627	return newLogicModule, newProperties
1628}
1629
1630func newVariant(module *moduleInfo, mutatorName string, variationName string) variant {
1631
1632	newVariantName := module.variant.name
1633	if variationName != "" {
1634		if newVariantName == "" {
1635			newVariantName = variationName
1636		} else {
1637			newVariantName += "_" + variationName
1638		}
1639	}
1640
1641	newVariations := module.variant.variations.clone()
1642	newVariations.set(mutatorName, variationName)
1643
1644	return variant{newVariantName, newVariations}
1645}
1646
1647func (c *Context) createVariations(origModule *moduleInfo, mutator *mutatorInfo,
1648	depChooser depChooser, variationNames []string) (moduleList, []error) {
1649
1650	if mutator.transitionMutator == nil {
1651		panic(fmt.Errorf("method createVariations called from mutator that was not a TransitionMutator"))
1652	}
1653
1654	if len(variationNames) == 0 {
1655		panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
1656			mutator.name, origModule.Name()))
1657	}
1658
1659	var newModules moduleList
1660
1661	var errs []error
1662
1663	for i, variationName := range variationNames {
1664		var newLogicModule Module
1665		var newProperties []interface{}
1666
1667		if i == 0 && mutator.transitionMutator == nil {
1668			// Reuse the existing module for the first new variant
1669			// This both saves creating a new module, and causes the insertion in c.moduleInfo below
1670			// with logicModule as the key to replace the original entry in c.moduleInfo
1671			newLogicModule, newProperties = origModule.logicModule, origModule.properties
1672		} else {
1673			newLogicModule, newProperties = c.cloneLogicModule(origModule)
1674		}
1675
1676		m := *origModule
1677		newModule := &m
1678		newModule.directDeps = slices.Clone(origModule.directDeps)
1679		newModule.reverseDeps = nil
1680		newModule.forwardDeps = nil
1681		newModule.logicModule = newLogicModule
1682		newModule.variant = newVariant(origModule, mutator.name, variationName)
1683		newModule.properties = newProperties
1684		newModule.providers = slices.Clone(origModule.providers)
1685		newModule.providerInitialValueHashes = slices.Clone(origModule.providerInitialValueHashes)
1686		newModule.transitionInfos = slices.Clone(origModule.transitionInfos)
1687
1688		newModules = append(newModules, newModule)
1689
1690		newErrs := c.convertDepsToVariation(newModule, i, depChooser)
1691		if len(newErrs) > 0 {
1692			errs = append(errs, newErrs...)
1693		}
1694	}
1695
1696	// Mark original variant as invalid.  Modules that depend on this module will still
1697	// depend on origModule, but we'll fix it when the mutator is called on them.
1698	origModule.obsoletedByNewVariants = true
1699	origModule.splitModules = newModules
1700
1701	atomic.AddUint32(&c.needsUpdateDependencies, 1)
1702
1703	return newModules, errs
1704}
1705
1706type depChooser func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string)
1707
1708func chooseDep(candidates moduleList, mutatorName, variationName string, defaultVariationName *string) (*moduleInfo, string) {
1709	for _, m := range candidates {
1710		if m.variant.variations.get(mutatorName) == variationName {
1711			return m, ""
1712		}
1713	}
1714
1715	if defaultVariationName != nil {
1716		// give it a second chance; match with defaultVariationName
1717		for _, m := range candidates {
1718			if m.variant.variations.get(mutatorName) == *defaultVariationName {
1719				return m, ""
1720			}
1721		}
1722	}
1723
1724	return nil, variationName
1725}
1726
1727func chooseDepByIndexes(mutatorName string, variations [][]string) depChooser {
1728	return func(source *moduleInfo, variationIndex, depIndex int, dep depInfo) (*moduleInfo, string) {
1729		desiredVariation := variations[variationIndex][depIndex]
1730		return chooseDep(dep.module.splitModules, mutatorName, desiredVariation, nil)
1731	}
1732}
1733
1734func (c *Context) convertDepsToVariation(module *moduleInfo, variationIndex int, depChooser depChooser) (errs []error) {
1735	for i, dep := range module.directDeps {
1736		if dep.module.obsoletedByNewVariants {
1737			newDep, missingVariation := depChooser(module, variationIndex, i, dep)
1738			if newDep == nil {
1739				errs = append(errs, &BlueprintError{
1740					Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
1741						missingVariation, dep.module.Name(), module.Name()),
1742					Pos: module.pos,
1743				})
1744				continue
1745			}
1746			module.directDeps[i].module = newDep
1747		}
1748	}
1749
1750	return errs
1751}
1752
1753func (c *Context) prettyPrintVariant(variations variationMap) string {
1754	var names []string
1755	for _, m := range c.variantMutatorNames {
1756		if v := variations.get(m); v != "" {
1757			names = append(names, m+":"+v)
1758		}
1759	}
1760	if len(names) == 0 {
1761		return "<empty variant>"
1762	}
1763
1764	return strings.Join(names, ",")
1765}
1766
1767func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1768	var variants []string
1769	for _, module := range group.modules {
1770		variants = append(variants, c.prettyPrintVariant(module.variant.variations))
1771	}
1772	return strings.Join(variants, "\n  ")
1773}
1774
1775func newModule(factory ModuleFactory) *moduleInfo {
1776	logicModule, properties := factory()
1777
1778	return &moduleInfo{
1779		logicModule: logicModule,
1780		factory:     factory,
1781		properties:  properties,
1782	}
1783}
1784
1785func processModuleDef(moduleDef *parser.Module,
1786	relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) {
1787
1788	factory, ok := moduleFactories[moduleDef.Type]
1789	if !ok && scopedModuleFactories != nil {
1790		factory, ok = scopedModuleFactories[moduleDef.Type]
1791	}
1792	if !ok {
1793		if ignoreUnknownModuleTypes {
1794			return nil, nil
1795		}
1796
1797		return nil, []error{
1798			&BlueprintError{
1799				Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1800				Pos: moduleDef.TypePos,
1801			},
1802		}
1803	}
1804
1805	module := newModule(factory)
1806	module.typeName = moduleDef.Type
1807
1808	module.relBlueprintsFile = relBlueprintsFile
1809
1810	propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
1811	if len(errs) > 0 {
1812		for i, err := range errs {
1813			if unpackErr, ok := err.(*proptools.UnpackError); ok {
1814				err = &BlueprintError{
1815					Err: unpackErr.Err,
1816					Pos: unpackErr.Pos,
1817				}
1818				errs[i] = err
1819			}
1820		}
1821		return nil, errs
1822	}
1823
1824	module.pos = moduleDef.TypePos
1825	module.propertyPos = make(map[string]scanner.Position)
1826	for name, propertyDef := range propertyMap {
1827		module.propertyPos[name] = propertyDef.ColonPos
1828	}
1829
1830	return module, nil
1831}
1832
1833func (c *Context) addModule(module *moduleInfo) []error {
1834	name := module.logicModule.Name()
1835	if name == "" {
1836		return []error{
1837			&BlueprintError{
1838				Err: fmt.Errorf("property 'name' is missing from a module"),
1839				Pos: module.pos,
1840			},
1841		}
1842	}
1843	c.moduleInfo[module.logicModule] = module
1844
1845	group := &moduleGroup{
1846		name:    name,
1847		modules: moduleList{module},
1848	}
1849	module.group = group
1850	namespace, errs := c.nameInterface.NewModule(
1851		newNamespaceContext(module),
1852		ModuleGroup{moduleGroup: group},
1853		module.logicModule)
1854	if len(errs) > 0 {
1855		for i := range errs {
1856			errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1857		}
1858		return errs
1859	}
1860	group.namespace = namespace
1861
1862	c.moduleGroups = append(c.moduleGroups, group)
1863
1864	return nil
1865}
1866
1867// ResolveDependencies checks that the dependencies specified by all of the
1868// modules defined in the parsed Blueprints files are valid.  This means that
1869// the modules depended upon are defined and that no circular dependencies
1870// exist.
1871func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
1872	c.BeginEvent("resolve_deps")
1873	defer c.EndEvent("resolve_deps")
1874	return c.resolveDependencies(c.Context, config)
1875}
1876
1877// coalesceMutators takes the list of mutators and returns a list of lists of mutators,
1878// where sublist is a compatible group of mutators that can be run with relaxed
1879// intra-mutator ordering.
1880func coalesceMutators(mutators []*mutatorInfo) [][]*mutatorInfo {
1881	var coalescedMutators [][]*mutatorInfo
1882	var last *mutatorInfo
1883
1884	// Returns true if the mutator can be coalesced with other mutators that
1885	// also return true.
1886	coalescable := func(m *mutatorInfo) bool {
1887		return m.bottomUpMutator != nil &&
1888			m.transitionMutator == nil &&
1889			!m.usesCreateModule &&
1890			!m.usesReplaceDependencies &&
1891			!m.usesReverseDependencies &&
1892			!m.usesRename &&
1893			!m.mutatesGlobalState &&
1894			!m.mutatesDependencies
1895	}
1896
1897	for _, mutator := range mutators {
1898		if last != nil && coalescable(last) && coalescable(mutator) {
1899			lastGroup := &coalescedMutators[len(coalescedMutators)-1]
1900			*lastGroup = append(*lastGroup, mutator)
1901		} else {
1902			coalescedMutators = append(coalescedMutators, []*mutatorInfo{mutator})
1903			last = mutator
1904		}
1905	}
1906
1907	return coalescedMutators
1908}
1909
1910func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1911	pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
1912		c.initProviders()
1913
1914		errs = c.updateDependencies()
1915		if len(errs) > 0 {
1916			return
1917		}
1918
1919		mutatorGroups := coalesceMutators(c.mutatorInfo)
1920
1921		deps, errs = c.runMutators(ctx, config, mutatorGroups)
1922		if len(errs) > 0 {
1923			return
1924		}
1925
1926		c.BeginEvent("clone_modules")
1927		if !c.SkipCloneModulesAfterMutators {
1928			c.cloneModules()
1929		}
1930		defer c.EndEvent("clone_modules")
1931
1932		c.clearTransitionMutatorInputVariants()
1933
1934		c.dependenciesReady = true
1935	})
1936
1937	if len(errs) > 0 {
1938		return nil, errs
1939	}
1940
1941	return deps, nil
1942}
1943
1944// Default dependencies handling.  If the module implements the (deprecated)
1945// DynamicDependerModule interface then this set consists of the union of those
1946// module names returned by its DynamicDependencies method and those added by calling
1947// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
1948func blueprintDepsMutator(ctx BottomUpMutatorContext) {
1949	if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
1950		func() {
1951			defer func() {
1952				if r := recover(); r != nil {
1953					ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1954				}
1955			}()
1956			dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
1957
1958			if ctx.Failed() {
1959				return
1960			}
1961
1962			ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
1963		}()
1964	}
1965}
1966
1967// applyTransitions takes a variationMap being used to add a dependency on a module in a moduleGroup
1968// and applies the OutgoingTransition and IncomingTransition methods of each completed TransitionMutator to
1969// modify the requested variation.  It finds a variant that existed before the TransitionMutator ran that is
1970// a subset of the requested variant to use as the module context for IncomingTransition.
1971func (c *Context) applyTransitions(config any, module *moduleInfo, group *moduleGroup, variant variationMap,
1972	requestedVariations []Variation, far bool) (variationMap, []error) {
1973	for _, transitionMutator := range c.transitionMutators[:c.completedTransitionMutators] {
1974		explicitlyRequested := slices.ContainsFunc(requestedVariations, func(variation Variation) bool {
1975			return variation.Mutator == transitionMutator.name
1976		})
1977
1978		var outgoingTransitionInfo TransitionInfo
1979		if explicitlyRequested {
1980			sourceVariation := variant.get(transitionMutator.name)
1981			outgoingTransitionInfo = transitionMutator.mutator.TransitionInfoFromVariation(sourceVariation)
1982		} else {
1983			// Apply the outgoing transition if it was not explicitly requested.
1984			var srcTransitionInfo TransitionInfo
1985			if (!far || transitionMutator.neverFar) && len(module.transitionInfos) > transitionMutator.index {
1986				srcTransitionInfo = module.transitionInfos[transitionMutator.index]
1987			}
1988			ctx := outgoingTransitionContextPool.Get()
1989			*ctx = outgoingTransitionContextImpl{
1990				transitionContextImpl{context: c, source: module, dep: nil,
1991					depTag: nil, postMutator: true, config: config},
1992			}
1993			outgoingTransitionInfo = transitionMutator.mutator.OutgoingTransition(ctx, srcTransitionInfo)
1994			errs := ctx.errs
1995			outgoingTransitionContextPool.Put(ctx)
1996			ctx = nil
1997			if len(errs) > 0 {
1998				return variationMap{}, errs
1999			}
2000		}
2001
2002		earlierVariantCreatingMutators := c.transitionMutatorNames[:transitionMutator.index]
2003		filteredVariant := variant.cloneMatching(earlierVariantCreatingMutators)
2004
2005		check := func(inputVariant variationMap) bool {
2006			filteredInputVariant := inputVariant.cloneMatching(earlierVariantCreatingMutators)
2007			return filteredInputVariant.equal(filteredVariant)
2008		}
2009
2010		// Find an appropriate module to use as the context for the IncomingTransition.  First check if any of the
2011		// saved inputVariants for the transition mutator match the filtered variant.
2012		var matchingInputVariant *moduleInfo
2013		for _, inputVariant := range transitionMutator.inputVariants[group] {
2014			if check(inputVariant.variant.variations) {
2015				matchingInputVariant = inputVariant
2016				break
2017			}
2018		}
2019
2020		if matchingInputVariant == nil {
2021			// If no inputVariants match, check all the variants of the module for a match.  This can happen if
2022			// the mutator only created a single "" variant when it ran on this module.  Matching against all variants
2023			// is slightly worse  than checking the input variants, as the selected variant could have been modified
2024			// by a later mutator in a way that affects the results of IncomingTransition.
2025			for _, module := range group.modules {
2026				if check(module.variant.variations) {
2027					matchingInputVariant = module
2028					break
2029				}
2030			}
2031		}
2032
2033		if matchingInputVariant != nil {
2034			// Apply the incoming transition.
2035			ctx := incomingTransitionContextPool.Get()
2036			*ctx = incomingTransitionContextImpl{
2037				transitionContextImpl{context: c, source: nil, dep: matchingInputVariant,
2038					depTag: nil, postMutator: true, config: config},
2039			}
2040
2041			finalTransitionInfo := transitionMutator.mutator.IncomingTransition(ctx, outgoingTransitionInfo)
2042			errs := ctx.errs
2043			incomingTransitionContextPool.Put(ctx)
2044			ctx = nil
2045			if len(errs) > 0 {
2046				return variationMap{}, errs
2047			}
2048			variation := ""
2049			if finalTransitionInfo != nil {
2050				variation = finalTransitionInfo.Variation()
2051			}
2052			variant.set(transitionMutator.name, variation)
2053		}
2054
2055		if (matchingInputVariant == nil && !explicitlyRequested) || variant.get(transitionMutator.name) == "" {
2056			// The transition mutator didn't apply anything to the target variant, remove the variation unless it
2057			// was explicitly requested when adding the dependency.
2058			variant.delete(transitionMutator.name)
2059		}
2060	}
2061
2062	return variant, nil
2063}
2064
2065func (c *Context) findVariant(module *moduleInfo, config any,
2066	possibleDeps *moduleGroup, requestedVariations []Variation, far bool, reverse bool) (*moduleInfo, variationMap, []error) {
2067
2068	// We can't just append variant.Variant to module.dependencyVariant.variantName and
2069	// compare the strings because the result won't be in mutator registration order.
2070	// Create a new map instead, and then deep compare the maps.
2071	var newVariant variationMap
2072	if !far {
2073		newVariant = module.variant.variations.clone()
2074	} else {
2075		for _, transitionMutator := range c.transitionMutators {
2076			if transitionMutator.neverFar {
2077				newVariant.set(transitionMutator.name, module.variant.variations.get(transitionMutator.name))
2078			}
2079		}
2080	}
2081	for _, v := range requestedVariations {
2082		newVariant.set(v.Mutator, v.Variation)
2083	}
2084
2085	if !reverse {
2086		var errs []error
2087		newVariant, errs = c.applyTransitions(config, module, possibleDeps, newVariant, requestedVariations, far)
2088		if len(errs) > 0 {
2089			return nil, variationMap{}, errs
2090		}
2091	}
2092
2093	// check returns a bool for whether the requested newVariant matches the given variant from possibleDeps, and a
2094	// divergence score.  A score of 0 is best match, and a positive integer is a worse match.
2095	// For a non-far search, the score is always 0 as the match must always be exact.  For a far search,
2096	// the score is the number of variants that are present in the given variant but not newVariant.
2097	check := func(variant variationMap) (bool, int) {
2098		if far {
2099			if newVariant.subsetOf(variant) {
2100				return true, variant.differenceKeysCount(newVariant)
2101			}
2102		} else {
2103			if variant.equal(newVariant) {
2104				return true, 0
2105			}
2106		}
2107		return false, math.MaxInt
2108	}
2109
2110	var foundDep *moduleInfo
2111	bestDivergence := math.MaxInt
2112	for _, m := range possibleDeps.modules {
2113		if match, divergence := check(m.variant.variations); match && divergence < bestDivergence {
2114			foundDep = m
2115			bestDivergence = divergence
2116			if !far {
2117				// non-far dependencies use equality, so only the first match needs to be checked.
2118				break
2119			}
2120		}
2121	}
2122
2123	return foundDep, newVariant, nil
2124}
2125
2126func (c *Context) addVariationDependency(module *moduleInfo, mutator *mutatorInfo, config any, variations []Variation,
2127	tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
2128	if _, ok := tag.(BaseDependencyTag); ok {
2129		panic("BaseDependencyTag is not allowed to be used directly!")
2130	}
2131
2132	possibleDeps := c.moduleGroupFromName(depName, module.namespace())
2133	if possibleDeps == nil {
2134		return nil, c.discoveredMissingDependencies(module, depName, variationMap{})
2135	}
2136
2137	foundDep, newVariant, errs := c.findVariant(module, config, possibleDeps, variations, far, false)
2138	if errs != nil {
2139		return nil, errs
2140	}
2141
2142	if foundDep == nil {
2143		if c.allowMissingDependencies {
2144			// Allow missing variants.
2145			return nil, c.discoveredMissingDependencies(module, depName, newVariant)
2146		}
2147		return nil, []error{&BlueprintError{
2148			Err: fmt.Errorf("dependency %q of %q missing variant:\n  %s\navailable variants:\n  %s",
2149				depName, module.Name(),
2150				c.prettyPrintVariant(newVariant),
2151				c.prettyPrintGroupVariants(possibleDeps)),
2152			Pos: module.pos,
2153		}}
2154	}
2155
2156	if module == foundDep {
2157		return nil, []error{&BlueprintError{
2158			Err: fmt.Errorf("%q depends on itself", depName),
2159			Pos: module.pos,
2160		}}
2161	}
2162	// AddVariationDependency allows adding a dependency on itself, but only if
2163	// that module is earlier in the module list than this one, since we always
2164	// run GenerateBuildActions in order for the variants of a module
2165	if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
2166		return nil, []error{&BlueprintError{
2167			Err: fmt.Errorf("%q depends on later version of itself", depName),
2168			Pos: module.pos,
2169		}}
2170	}
2171
2172	// The mutator will pause until the newly added dependency has finished running the current mutator,
2173	// so it is safe to add the new dependency directly to directDeps and forwardDeps where it will be visible
2174	// to future calls to VisitDirectDeps.  Set newDirectDeps so that at the end of the mutator the reverseDeps
2175	// of the dependencies can be updated to point to this module without running a full c.updateDependencies()
2176	module.directDeps = append(module.directDeps, depInfo{foundDep, tag})
2177	module.forwardDeps = append(module.forwardDeps, foundDep)
2178	module.newDirectDeps = append(module.newDirectDeps, foundDep)
2179	return foundDep, nil
2180}
2181
2182// findBlueprintDescendants returns a map linking parent Blueprint files to child Blueprints files
2183// For example, if paths = []string{"a/b/c/Android.bp", "a/Android.bp"},
2184// then descendants = {"":[]string{"a/Android.bp"}, "a/Android.bp":[]string{"a/b/c/Android.bp"}}
2185func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
2186	// make mapping from dir path to file path
2187	filesByDir := make(map[string]string, len(paths))
2188	for _, path := range paths {
2189		dir := filepath.Dir(path)
2190		_, alreadyFound := filesByDir[dir]
2191		if alreadyFound {
2192			return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
2193		}
2194		filesByDir[dir] = path
2195	}
2196
2197	findAncestor := func(childFile string) (ancestor string) {
2198		prevAncestorDir := filepath.Dir(childFile)
2199		for {
2200			ancestorDir := filepath.Dir(prevAncestorDir)
2201			if ancestorDir == prevAncestorDir {
2202				// reached the root dir without any matches; assign this as a descendant of ""
2203				return ""
2204			}
2205
2206			ancestorFile, ancestorExists := filesByDir[ancestorDir]
2207			if ancestorExists {
2208				return ancestorFile
2209			}
2210			prevAncestorDir = ancestorDir
2211		}
2212	}
2213	// generate the descendants map
2214	descendants = make(map[string][]string, len(filesByDir))
2215	for _, childFile := range filesByDir {
2216		ancestorFile := findAncestor(childFile)
2217		descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
2218	}
2219	return descendants, nil
2220}
2221
2222type visitOrderer interface {
2223	// returns the number of modules that this module needs to wait for
2224	waitCount(module *moduleInfo) int
2225	// returns the list of modules that are waiting for this module
2226	propagate(module *moduleInfo) []*moduleInfo
2227}
2228
2229type unorderedVisitorImpl struct{}
2230
2231func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
2232	return 0
2233}
2234
2235func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
2236	return nil
2237}
2238
2239type bottomUpVisitorImpl struct{}
2240
2241func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
2242	return len(module.forwardDeps)
2243}
2244
2245func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
2246	return module.reverseDeps
2247}
2248
2249type topDownVisitorImpl struct{}
2250
2251func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
2252	return len(module.reverseDeps)
2253}
2254
2255func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
2256	return module.forwardDeps
2257}
2258
2259func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
2260	for i := 0; i < len(modules); i++ {
2261		module := modules[len(modules)-1-i]
2262		if visit(module, nil) {
2263			return
2264		}
2265	}
2266}
2267
2268var (
2269	bottomUpVisitor bottomUpVisitorImpl
2270	topDownVisitor  topDownVisitorImpl
2271)
2272
2273// pauseSpec describes a pause that a module needs to occur until another module has been visited,
2274// at which point the unpause channel will be closed.
2275type pauseSpec struct {
2276	paused  *moduleInfo
2277	until   *moduleInfo
2278	unpause unpause
2279}
2280
2281type unpause chan struct{}
2282
2283const parallelVisitLimit = 1000
2284
2285// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
2286// of its dependencies has finished.  A visit function can write a pauseSpec to the pause channel
2287// to wait for another dependency to be visited.  If a visit function returns true to cancel
2288// while another visitor is paused, the paused visitor will never be resumed and its goroutine
2289// will stay paused forever.
2290func parallelVisit(moduleIter iter.Seq[*moduleInfo], order visitOrderer, limit int,
2291	visit func(module *moduleInfo, pause chan<- pauseSpec) bool) []error {
2292
2293	doneCh := make(chan *moduleInfo)
2294	cancelCh := make(chan bool)
2295	pauseCh := make(chan pauseSpec)
2296	cancel := false
2297
2298	var backlog []*moduleInfo      // Visitors that are ready to start but backlogged due to limit.
2299	var unpauseBacklog []pauseSpec // Visitors that are ready to unpause but backlogged due to limit.
2300
2301	active := 0  // Number of visitors running, not counting paused visitors.
2302	visited := 0 // Number of finished visitors.
2303
2304	pauseMap := make(map[*moduleInfo][]pauseSpec)
2305
2306	for module := range moduleIter {
2307		module.waitingCount = order.waitCount(module)
2308	}
2309
2310	// Call the visitor on a module if there are fewer active visitors than the parallelism
2311	// limit, otherwise add it to the backlog.
2312	startOrBacklog := func(module *moduleInfo) {
2313		if active < limit {
2314			active++
2315			go func() {
2316				ret := visit(module, pauseCh)
2317				if ret {
2318					cancelCh <- true
2319				}
2320				doneCh <- module
2321			}()
2322		} else {
2323			backlog = append(backlog, module)
2324		}
2325	}
2326
2327	// Unpause the already-started but paused  visitor on a module if there are fewer active
2328	// visitors than the parallelism limit, otherwise add it to the backlog.
2329	unpauseOrBacklog := func(pauseSpec pauseSpec) {
2330		if active < limit {
2331			active++
2332			close(pauseSpec.unpause)
2333		} else {
2334			unpauseBacklog = append(unpauseBacklog, pauseSpec)
2335		}
2336	}
2337
2338	// Start any modules in the backlog up to the parallelism limit.  Unpause paused modules first
2339	// since they may already be holding resources.
2340	unpauseOrStartFromBacklog := func() {
2341		for active < limit && len(unpauseBacklog) > 0 {
2342			unpause := unpauseBacklog[0]
2343			unpauseBacklog = unpauseBacklog[1:]
2344			unpauseOrBacklog(unpause)
2345		}
2346		for active < limit && len(backlog) > 0 {
2347			toVisit := backlog[0]
2348			backlog = backlog[1:]
2349			startOrBacklog(toVisit)
2350		}
2351	}
2352
2353	toVisit := 0
2354
2355	// Start or backlog any modules that are not waiting for any other modules.
2356	for module := range moduleIter {
2357		toVisit++
2358		if module.waitingCount == 0 {
2359			startOrBacklog(module)
2360		}
2361	}
2362
2363	for active > 0 {
2364		select {
2365		case <-cancelCh:
2366			cancel = true
2367			backlog = nil
2368		case doneModule := <-doneCh:
2369			active--
2370			if !cancel {
2371				// Mark this module as done.
2372				doneModule.waitingCount = -1
2373				visited++
2374
2375				// Unpause or backlog any modules that were waiting for this one.
2376				if unpauses, ok := pauseMap[doneModule]; ok {
2377					delete(pauseMap, doneModule)
2378					for _, unpause := range unpauses {
2379						unpauseOrBacklog(unpause)
2380					}
2381				}
2382
2383				// Start any backlogged modules up to limit.
2384				unpauseOrStartFromBacklog()
2385
2386				// Decrement waitingCount on the next modules in the tree based
2387				// on propagation order, and start or backlog them if they are
2388				// ready to start.
2389				for _, module := range order.propagate(doneModule) {
2390					module.waitingCount--
2391					if module.waitingCount == 0 {
2392						startOrBacklog(module)
2393					}
2394				}
2395			}
2396		case pauseSpec := <-pauseCh:
2397			if pauseSpec.until.waitingCount == -1 {
2398				// Module being paused for is already finished, resume immediately.
2399				close(pauseSpec.unpause)
2400			} else {
2401				// Register for unpausing.
2402				pauseMap[pauseSpec.until] = append(pauseMap[pauseSpec.until], pauseSpec)
2403
2404				// Don't count paused visitors as active so that this can't deadlock
2405				// if 1000 visitors are paused simultaneously.
2406				active--
2407				unpauseOrStartFromBacklog()
2408			}
2409		}
2410	}
2411
2412	if !cancel {
2413		// Invariant check: no backlogged modules, these weren't waiting on anything except
2414		// the parallelism limit so they should have run.
2415		if len(backlog) > 0 {
2416			panic(fmt.Errorf("parallelVisit finished with %d backlogged visitors", len(backlog)))
2417		}
2418
2419		// Invariant check: no backlogged paused modules, these weren't waiting on anything
2420		// except the parallelism limit so they should have run.
2421		if len(unpauseBacklog) > 0 {
2422			panic(fmt.Errorf("parallelVisit finished with %d backlogged unpaused visitors", len(unpauseBacklog)))
2423		}
2424
2425		if len(pauseMap) > 0 {
2426			// Probably a deadlock due to a newly added dependency cycle. Start from each module in
2427			// the order of the input modules list and perform a depth-first search for the module
2428			// it is paused on, ignoring modules that are marked as done.  Note this traverses from
2429			// modules to the modules that would have been unblocked when that module finished, i.e
2430			// the reverse of the visitOrderer.
2431
2432			// In order to reduce duplicated work, once a module has been checked and determined
2433			// not to be part of a cycle add it and everything that depends on it to the checked
2434			// map.
2435			checked := make(map[*moduleInfo]struct{})
2436
2437			var check func(module, end *moduleInfo) []*moduleInfo
2438			check = func(module, end *moduleInfo) []*moduleInfo {
2439				if module.waitingCount == -1 {
2440					// This module was finished, it can't be part of a loop.
2441					return nil
2442				}
2443				if module == end {
2444					// This module is the end of the loop, start rolling up the cycle.
2445					return []*moduleInfo{module}
2446				}
2447
2448				if _, alreadyChecked := checked[module]; alreadyChecked {
2449					return nil
2450				}
2451
2452				for _, dep := range order.propagate(module) {
2453					cycle := check(dep, end)
2454					if cycle != nil {
2455						return append([]*moduleInfo{module}, cycle...)
2456					}
2457				}
2458				for _, depPauseSpec := range pauseMap[module] {
2459					cycle := check(depPauseSpec.paused, end)
2460					if cycle != nil {
2461						return append([]*moduleInfo{module}, cycle...)
2462					}
2463				}
2464
2465				checked[module] = struct{}{}
2466				return nil
2467			}
2468
2469			// Iterate over the modules list instead of pauseMap to provide deterministic ordering.
2470			for module := range moduleIter {
2471				for _, pauseSpec := range pauseMap[module] {
2472					cycle := check(pauseSpec.paused, pauseSpec.until)
2473					if len(cycle) > 0 {
2474						return cycleError(cycle)
2475					}
2476				}
2477			}
2478		}
2479
2480		// Invariant check: if there was no deadlock and no cancellation every module
2481		// should have been visited.
2482		if visited != toVisit {
2483			panic(fmt.Errorf("parallelVisit ran %d visitors, expected %d", visited, toVisit))
2484		}
2485
2486		// Invariant check: if there was no deadlock and no cancellation  every module
2487		// should have been visited, so there is nothing left to be paused on.
2488		if len(pauseMap) > 0 {
2489			panic(fmt.Errorf("parallelVisit finished with %d paused visitors", len(pauseMap)))
2490		}
2491	}
2492
2493	return nil
2494}
2495
2496func cycleError(cycle []*moduleInfo) (errs []error) {
2497	// The cycle list is in reverse order because all the 'check' calls append
2498	// their own module to the list.
2499	errs = append(errs, &BlueprintError{
2500		Err: fmt.Errorf("encountered dependency cycle:"),
2501		Pos: cycle[len(cycle)-1].pos,
2502	})
2503
2504	// Iterate backwards through the cycle list.
2505	curModule := cycle[0]
2506	for i := len(cycle) - 1; i >= 0; i-- {
2507		nextModule := cycle[i]
2508		errs = append(errs, &BlueprintError{
2509			Err: fmt.Errorf("    %s depends on %s",
2510				curModule, nextModule),
2511			Pos: curModule.pos,
2512		})
2513		curModule = nextModule
2514	}
2515
2516	return errs
2517}
2518
2519// updateDependencies recursively walks the module dependency graph and updates
2520// additional fields based on the dependencies.  It builds a sorted list of modules
2521// such that dependencies of a module always appear first, and populates reverse
2522// dependency links and counts of total dependencies.  It also reports errors when
2523// it encounters dependency cycles.  This should be called after resolveDependencies,
2524// as well as after any mutator pass has called addDependency
2525func (c *Context) updateDependencies() (errs []error) {
2526	c.cachedDepsModified = true
2527	visited := make(map[*moduleInfo]bool, len(c.moduleInfo)) // modules that were already checked
2528	checking := make(map[*moduleInfo]bool)                   // modules actively being checked
2529
2530	var check func(group *moduleInfo) []*moduleInfo
2531
2532	check = func(module *moduleInfo) []*moduleInfo {
2533		visited[module] = true
2534		checking[module] = true
2535		defer delete(checking, module)
2536
2537		// Reset the forward and reverse deps without reducing their capacity to avoid reallocation.
2538		module.reverseDeps = module.reverseDeps[:0]
2539		module.forwardDeps = module.forwardDeps[:0]
2540
2541		// Add an implicit dependency ordering on all earlier modules in the same module group
2542		selfIndex := slices.Index(module.group.modules, module)
2543		module.forwardDeps = slices.Grow(module.forwardDeps, selfIndex+len(module.directDeps))
2544		module.forwardDeps = append(module.forwardDeps, module.group.modules[:selfIndex]...)
2545
2546		for _, dep := range module.directDeps {
2547			module.forwardDeps = append(module.forwardDeps, dep.module)
2548		}
2549
2550		for _, dep := range module.forwardDeps {
2551			if checking[dep] {
2552				// This is a cycle.
2553				return []*moduleInfo{dep, module}
2554			}
2555
2556			if !visited[dep] {
2557				cycle := check(dep)
2558				if cycle != nil {
2559					if cycle[0] == module {
2560						// We are the "start" of the cycle, so we're responsible
2561						// for generating the errors.
2562						errs = append(errs, cycleError(cycle)...)
2563
2564						// We can continue processing this module's children to
2565						// find more cycles.  Since all the modules that were
2566						// part of the found cycle were marked as visited we
2567						// won't run into that cycle again.
2568					} else {
2569						// We're not the "start" of the cycle, so we just append
2570						// our module to the list and return it.
2571						return append(cycle, module)
2572					}
2573				}
2574			}
2575
2576			dep.reverseDeps = append(dep.reverseDeps, module)
2577		}
2578
2579		return nil
2580	}
2581
2582	for _, module := range c.moduleInfo {
2583		if !visited[module] {
2584			cycle := check(module)
2585			if cycle != nil {
2586				if cycle[len(cycle)-1] != module {
2587					panic("inconceivable!")
2588				}
2589				errs = append(errs, cycleError(cycle)...)
2590			}
2591		}
2592	}
2593
2594	return
2595}
2596
2597type jsonVariations []Variation
2598
2599type jsonModuleName struct {
2600	Name    string
2601	Variant string
2602}
2603
2604type jsonDep struct {
2605	jsonModuleName
2606	Tag string
2607}
2608
2609type JsonModule struct {
2610	jsonModuleName
2611	Deps      []jsonDep
2612	Type      string
2613	Blueprint string
2614	CreatedBy *string
2615	Module    map[string]interface{}
2616}
2617
2618func jsonModuleNameFromModuleInfo(m *moduleInfo) *jsonModuleName {
2619	return &jsonModuleName{
2620		Name:    m.Name(),
2621		Variant: m.variant.name,
2622	}
2623}
2624
2625type JSONDataSupplier interface {
2626	AddJSONData(d *map[string]interface{})
2627}
2628
2629// JSONAction contains the action-related info we expose to json module graph
2630type JSONAction struct {
2631	Inputs  []string
2632	Outputs []string
2633	Desc    string
2634}
2635
2636// JSONActionSupplier allows JSON representation of additional actions that are not registered in
2637// Ninja
2638type JSONActionSupplier interface {
2639	JSONActions() []JSONAction
2640}
2641
2642func jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule {
2643	result := &JsonModule{
2644		jsonModuleName: *jsonModuleNameFromModuleInfo(m),
2645		Deps:           make([]jsonDep, 0),
2646		Type:           m.typeName,
2647		Blueprint:      m.relBlueprintsFile,
2648		Module:         make(map[string]interface{}),
2649	}
2650	if m.createdBy != nil {
2651		n := m.createdBy.Name()
2652		result.CreatedBy = &n
2653	}
2654	if j, ok := m.logicModule.(JSONDataSupplier); ok {
2655		j.AddJSONData(&result.Module)
2656	}
2657	for _, p := range m.providers {
2658		if j, ok := p.(JSONDataSupplier); ok {
2659			j.AddJSONData(&result.Module)
2660		}
2661	}
2662	return result
2663}
2664
2665func jsonModuleWithActionsFromModuleInfo(m *moduleInfo, nameTracker *nameTracker) *JsonModule {
2666	result := &JsonModule{
2667		jsonModuleName: jsonModuleName{
2668			Name:    m.Name(),
2669			Variant: m.variant.name,
2670		},
2671		Deps:      make([]jsonDep, 0),
2672		Type:      m.typeName,
2673		Blueprint: m.relBlueprintsFile,
2674		Module:    make(map[string]interface{}),
2675	}
2676	var actions []JSONAction
2677	for _, bDef := range m.actionDefs.buildDefs {
2678		a := JSONAction{
2679			Inputs: append(append(append(
2680				bDef.InputStrings,
2681				bDef.ImplicitStrings...),
2682				getNinjaStrings(bDef.Inputs, nameTracker)...),
2683				getNinjaStrings(bDef.Implicits, nameTracker)...),
2684
2685			Outputs: append(append(append(
2686				bDef.OutputStrings,
2687				bDef.ImplicitOutputStrings...),
2688				getNinjaStrings(bDef.Outputs, nameTracker)...),
2689				getNinjaStrings(bDef.ImplicitOutputs, nameTracker)...),
2690		}
2691		if d, ok := bDef.Variables["description"]; ok {
2692			a.Desc = d.Value(nameTracker)
2693		}
2694		actions = append(actions, a)
2695	}
2696
2697	if j, ok := m.logicModule.(JSONActionSupplier); ok {
2698		actions = append(actions, j.JSONActions()...)
2699	}
2700	for _, p := range m.providers {
2701		if j, ok := p.(JSONActionSupplier); ok {
2702			actions = append(actions, j.JSONActions()...)
2703		}
2704	}
2705
2706	result.Module["Actions"] = actions
2707	return result
2708}
2709
2710// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value on each.
2711func getNinjaStrings(nStrs []*ninjaString, nameTracker *nameTracker) []string {
2712	var strs []string
2713	for _, nstr := range nStrs {
2714		strs = append(strs, nstr.Value(nameTracker))
2715	}
2716	return strs
2717}
2718
2719func (c *Context) GetWeightedOutputsFromPredicate(predicate func(*JsonModule) (bool, int)) map[string]int {
2720	outputToWeight := make(map[string]int)
2721	for m := range c.iterateAllVariants() {
2722		jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker)
2723		if ok, weight := predicate(jmWithActions); ok {
2724			for _, a := range jmWithActions.Module["Actions"].([]JSONAction) {
2725				for _, o := range a.Outputs {
2726					if val, ok := outputToWeight[o]; ok {
2727						if val > weight {
2728							continue
2729						}
2730					}
2731					outputToWeight[o] = weight
2732				}
2733			}
2734		}
2735	}
2736	return outputToWeight
2737}
2738
2739// PrintJSONGraph prints info of modules in a JSON file.
2740func (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) {
2741	modulesToGraph := make([]*JsonModule, 0)
2742	modulesToActions := make([]*JsonModule, 0)
2743	for m := range c.iterateAllVariants() {
2744		jm := jsonModuleFromModuleInfo(m)
2745		jmWithActions := jsonModuleWithActionsFromModuleInfo(m, c.nameTracker)
2746		for _, d := range m.directDeps {
2747			jm.Deps = append(jm.Deps, jsonDep{
2748				jsonModuleName: *jsonModuleNameFromModuleInfo(d.module),
2749				Tag:            fmt.Sprintf("%T %+v", d.tag, d.tag),
2750			})
2751			jmWithActions.Deps = append(jmWithActions.Deps, jsonDep{
2752				jsonModuleName: jsonModuleName{
2753					Name: d.module.Name(),
2754				},
2755			})
2756
2757		}
2758		modulesToGraph = append(modulesToGraph, jm)
2759		modulesToActions = append(modulesToActions, jmWithActions)
2760	}
2761	writeJson(wGraph, modulesToGraph)
2762	writeJson(wActions, modulesToActions)
2763}
2764
2765func writeJson(w io.Writer, modules []*JsonModule) {
2766	e := json.NewEncoder(w)
2767	e.SetIndent("", "\t")
2768	e.Encode(modules)
2769}
2770
2771// PrepareBuildActions generates an internal representation of all the build
2772// actions that need to be performed.  This process involves invoking the
2773// GenerateBuildActions method on each of the Module objects created during the
2774// parse phase and then on each of the registered Singleton objects.
2775//
2776// If the ResolveDependencies method has not already been called it is called
2777// automatically by this method.
2778//
2779// The config argument is made available to all of the Module and Singleton
2780// objects via the Config method on the ModuleContext and SingletonContext
2781// objects passed to GenerateBuildActions.  It is also passed to the functions
2782// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
2783// config-specific values.
2784//
2785// The returned deps is a list of the ninja files dependencies that were added
2786// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
2787// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
2788// methods.
2789
2790func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
2791	c.BeginEvent("prepare_build_actions")
2792	defer c.EndEvent("prepare_build_actions")
2793	pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
2794		c.buildActionsReady = false
2795
2796		c.liveGlobals = newLiveTracker(c, config)
2797		// Add all the global rules/variable/pools here because when we restore from
2798		// cache we don't have the build defs available to build the globals.
2799		// TODO(b/356414070): Revisit this logic once we have a clearer picture about
2800		// how the incremental build pieces fit together.
2801		if c.GetIncrementalEnabled() {
2802			for _, p := range packageContexts {
2803				for _, v := range p.scope.variables {
2804					err := c.liveGlobals.addVariable(v)
2805					if err != nil {
2806						errs = []error{err}
2807						return
2808					}
2809				}
2810				for _, v := range p.scope.rules {
2811					_, err := c.liveGlobals.addRule(v)
2812					if err != nil {
2813						errs = []error{err}
2814						return
2815					}
2816				}
2817				for _, v := range p.scope.pools {
2818					err := c.liveGlobals.addPool(v)
2819					if err != nil {
2820						errs = []error{err}
2821						return
2822					}
2823				}
2824			}
2825		}
2826
2827		if !c.dependenciesReady {
2828			var extraDeps []string
2829			extraDeps, errs = c.resolveDependencies(ctx, config)
2830			if len(errs) > 0 {
2831				return
2832			}
2833			deps = append(deps, extraDeps...)
2834		}
2835
2836		var depsModules []string
2837		depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
2838		if len(errs) > 0 {
2839			return
2840		}
2841
2842		pprof.Do(c.Context, pprof.Labels("blueprint", "GC"), func(ctx context.Context) {
2843			runtime.GC()
2844		})
2845
2846		var depsSingletons []string
2847		depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
2848		if len(errs) > 0 {
2849			return
2850		}
2851
2852		deps = append(deps, depsModules...)
2853		deps = append(deps, depsSingletons...)
2854
2855		if c.outDir != nil {
2856			err := c.liveGlobals.addNinjaStringDeps(c.outDir)
2857			if err != nil {
2858				errs = []error{err}
2859				return
2860			}
2861		}
2862
2863		pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2864
2865		deps = append(deps, depsPackages...)
2866
2867		nameTracker := c.memoizeFullNames(c.liveGlobals, pkgNames)
2868
2869		// This will panic if it finds a problem since it's a programming error.
2870		c.checkForVariableReferenceCycles(c.liveGlobals.variables, nameTracker)
2871
2872		c.nameTracker = nameTracker
2873		c.globalVariables = c.liveGlobals.variables
2874		c.globalPools = c.liveGlobals.pools
2875		c.globalRules = c.liveGlobals.rules
2876
2877		c.buildActionsReady = true
2878	})
2879
2880	if len(errs) > 0 {
2881		return nil, errs
2882	}
2883
2884	return deps, nil
2885}
2886
2887func (c *Context) runMutators(ctx context.Context, config interface{}, mutatorGroups [][]*mutatorInfo) (deps []string, errs []error) {
2888	c.finishedMutators = make([]bool, len(c.mutatorInfo))
2889
2890	pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
2891		for _, mutatorGroup := range mutatorGroups {
2892			name := mutatorGroup[0].name
2893			if len(mutatorGroup) > 1 {
2894				name += "_plus_" + strconv.Itoa(len(mutatorGroup)-1)
2895			}
2896			pprof.Do(ctx, pprof.Labels("mutator", name), func(context.Context) {
2897				c.BeginEvent(name)
2898				defer c.EndEvent(name)
2899				var newDeps []string
2900				if mutatorGroup[0].transitionPropagateMutator != nil {
2901					newDeps, errs = c.runMutator(config, mutatorGroup, topDownMutator)
2902				} else if mutatorGroup[0].bottomUpMutator != nil {
2903					newDeps, errs = c.runMutator(config, mutatorGroup, bottomUpMutator)
2904				} else {
2905					panic("no mutator set on " + mutatorGroup[0].name)
2906				}
2907				if len(errs) > 0 {
2908					return
2909				}
2910				deps = append(deps, newDeps...)
2911			})
2912			if len(errs) > 0 {
2913				return
2914			}
2915		}
2916	})
2917
2918	if len(errs) > 0 {
2919		return nil, errs
2920	}
2921
2922	return deps, nil
2923}
2924
2925type mutatorDirection interface {
2926	run(mutator []*mutatorInfo, ctx *mutatorContext)
2927	orderer() visitOrderer
2928	fmt.Stringer
2929}
2930
2931type bottomUpMutatorImpl struct{}
2932
2933func (bottomUpMutatorImpl) run(mutatorGroup []*mutatorInfo, ctx *mutatorContext) {
2934	for _, mutator := range mutatorGroup {
2935		ctx.mutator = mutator
2936		ctx.module.startedMutator = mutator.index
2937		mutator.bottomUpMutator(ctx)
2938		ctx.module.finishedMutator = mutator.index
2939	}
2940}
2941
2942func (bottomUpMutatorImpl) orderer() visitOrderer {
2943	return bottomUpVisitor
2944}
2945
2946func (bottomUpMutatorImpl) String() string {
2947	return "bottom up mutator"
2948}
2949
2950type topDownMutatorImpl struct{}
2951
2952func (topDownMutatorImpl) run(mutatorGroup []*mutatorInfo, ctx *mutatorContext) {
2953	if len(mutatorGroup) > 1 {
2954		panic(fmt.Errorf("top down mutator group %s must only have 1 mutator, found %d", mutatorGroup[0].name, len(mutatorGroup)))
2955	}
2956	mutatorGroup[0].transitionPropagateMutator(ctx)
2957}
2958
2959func (topDownMutatorImpl) orderer() visitOrderer {
2960	return topDownVisitor
2961}
2962
2963func (topDownMutatorImpl) String() string {
2964	return "top down mutator"
2965}
2966
2967var (
2968	topDownMutator  topDownMutatorImpl
2969	bottomUpMutator bottomUpMutatorImpl
2970)
2971
2972type reverseDep struct {
2973	module *moduleInfo
2974	dep    depInfo
2975}
2976
2977var mutatorContextPool = pool.New[mutatorContext]()
2978
2979func (c *Context) runMutator(config interface{}, mutatorGroup []*mutatorInfo,
2980	direction mutatorDirection) (deps []string, errs []error) {
2981
2982	newModuleInfo := maps.Clone(c.moduleInfo)
2983
2984	type globalStateChange struct {
2985		reverse    []reverseDep
2986		rename     []rename
2987		replace    []replace
2988		newModules []*moduleInfo
2989		deps       []string
2990	}
2991
2992	type newVariationPair struct {
2993		newVariations   moduleList
2994		origLogicModule Module
2995	}
2996
2997	reverseDeps := make(map[*moduleInfo][]depInfo)
2998	var rename []rename
2999	var replace []replace
3000	var newModules []*moduleInfo
3001
3002	errsCh := make(chan []error)
3003	globalStateCh := make(chan globalStateChange)
3004	newVariationsCh := make(chan newVariationPair)
3005	done := make(chan bool)
3006
3007	c.needsUpdateDependencies = 0
3008
3009	visit := func(module *moduleInfo, pause chan<- pauseSpec) bool {
3010		if module.splitModules != nil {
3011			panic("split module found in sorted module list")
3012		}
3013
3014		mctx := mutatorContextPool.Get()
3015		*mctx = mutatorContext{
3016			baseModuleContext: baseModuleContext{
3017				context: c,
3018				config:  config,
3019				module:  module,
3020			},
3021			mutator: mutatorGroup[0],
3022			pauseCh: pause,
3023		}
3024
3025		origLogicModule := module.logicModule
3026
3027		module.startedMutator = mutatorGroup[0].index
3028
3029		func() {
3030			defer func() {
3031				if r := recover(); r != nil {
3032					in := fmt.Sprintf("%s %q for %s", direction, mutatorGroup[0].name, module)
3033					if err, ok := r.(panicError); ok {
3034						err.addIn(in)
3035						mctx.error(err)
3036					} else {
3037						mctx.error(newPanicErrorf(r, in))
3038					}
3039				}
3040			}()
3041			direction.run(mutatorGroup, mctx)
3042		}()
3043
3044		module.finishedMutator = mutatorGroup[len(mutatorGroup)-1].index
3045
3046		hasErrors := false
3047		if len(mctx.errs) > 0 {
3048			errsCh <- mctx.errs
3049			hasErrors = true
3050		} else {
3051			if len(mctx.newVariations) > 0 {
3052				newVariationsCh <- newVariationPair{mctx.newVariations, origLogicModule}
3053			}
3054
3055			if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 || len(mctx.ninjaFileDeps) > 0 {
3056				globalStateCh <- globalStateChange{
3057					reverse:    mctx.reverseDeps,
3058					replace:    mctx.replace,
3059					rename:     mctx.rename,
3060					newModules: mctx.newModules,
3061					deps:       mctx.ninjaFileDeps,
3062				}
3063			}
3064		}
3065		mutatorContextPool.Put(mctx)
3066		mctx = nil
3067
3068		return hasErrors
3069	}
3070
3071	var obsoleteLogicModules []Module
3072
3073	// Process errs and reverseDeps in a single goroutine
3074	go func() {
3075		for {
3076			select {
3077			case newErrs := <-errsCh:
3078				errs = append(errs, newErrs...)
3079			case globalStateChange := <-globalStateCh:
3080				for _, r := range globalStateChange.reverse {
3081					reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
3082				}
3083				replace = append(replace, globalStateChange.replace...)
3084				rename = append(rename, globalStateChange.rename...)
3085				newModules = append(newModules, globalStateChange.newModules...)
3086				deps = append(deps, globalStateChange.deps...)
3087			case newVariations := <-newVariationsCh:
3088				if newVariations.origLogicModule != newVariations.newVariations[0].logicModule {
3089					obsoleteLogicModules = append(obsoleteLogicModules, newVariations.origLogicModule)
3090				}
3091				for _, module := range newVariations.newVariations {
3092					newModuleInfo[module.logicModule] = module
3093				}
3094			case <-done:
3095				return
3096			}
3097		}
3098	}()
3099
3100	visitErrs := parallelVisit(c.iterateAllVariants(), direction.orderer(), parallelVisitLimit, visit)
3101
3102	if len(visitErrs) > 0 {
3103		return nil, visitErrs
3104	}
3105
3106	for _, mutator := range mutatorGroup {
3107		c.finishedMutators[mutator.index] = true
3108	}
3109
3110	done <- true
3111
3112	if len(errs) > 0 {
3113		return nil, errs
3114	}
3115
3116	for _, obsoleteLogicModule := range obsoleteLogicModules {
3117		delete(newModuleInfo, obsoleteLogicModule)
3118	}
3119
3120	c.moduleInfo = newModuleInfo
3121
3122	transitionMutator := mutatorGroup[0].transitionMutator
3123
3124	var transitionMutatorInputVariants map[*moduleGroup][]*moduleInfo
3125	if transitionMutator != nil {
3126		transitionMutatorInputVariants = make(map[*moduleGroup][]*moduleInfo)
3127	}
3128
3129	for _, group := range c.moduleGroups {
3130		for i := 0; i < len(group.modules); i++ {
3131			module := group.modules[i]
3132
3133			// Update module group to contain newly split variants
3134			if module.splitModules != nil {
3135				if transitionMutator != nil {
3136					// For transition mutators, save the pre-split variant for reusing later in applyTransitions.
3137					transitionMutatorInputVariants[group] = append(transitionMutatorInputVariants[group], module)
3138				}
3139				group.modules, i = spliceModules(group.modules, i, module.splitModules)
3140			}
3141
3142			// Fix up any remaining dependencies on modules that were split into variants
3143			// by replacing them with the first variant
3144			for j, dep := range module.directDeps {
3145				if dep.module.obsoletedByNewVariants {
3146					module.directDeps[j].module = dep.module.splitModules.firstModule()
3147				}
3148			}
3149
3150			if module.createdBy != nil && module.createdBy.obsoletedByNewVariants {
3151				module.createdBy = module.createdBy.splitModules.firstModule()
3152			}
3153
3154			// Add any new forward dependencies to the reverse dependencies of the dependency to avoid
3155			// having to call a full c.updateDependencies().
3156			for _, m := range module.newDirectDeps {
3157				m.reverseDeps = append(m.reverseDeps, module)
3158			}
3159			module.newDirectDeps = nil
3160		}
3161	}
3162
3163	if transitionMutator != nil {
3164		transitionMutator.inputVariants = transitionMutatorInputVariants
3165		c.completedTransitionMutators = transitionMutator.index + 1
3166	}
3167
3168	// Add in any new reverse dependencies that were added by the mutator
3169	for module, deps := range reverseDeps {
3170		sort.Sort(depSorter(deps))
3171		module.directDeps = append(module.directDeps, deps...)
3172		c.needsUpdateDependencies++
3173	}
3174
3175	for _, module := range newModules {
3176		errs = c.addModule(module)
3177		if len(errs) > 0 {
3178			return nil, errs
3179		}
3180		c.needsUpdateDependencies++
3181	}
3182
3183	errs = c.handleRenames(rename)
3184	if len(errs) > 0 {
3185		return nil, errs
3186	}
3187
3188	errs = c.handleReplacements(replace)
3189	if len(errs) > 0 {
3190		return nil, errs
3191	}
3192
3193	if c.needsUpdateDependencies > 0 {
3194		errs = c.updateDependencies()
3195		if len(errs) > 0 {
3196			return nil, errs
3197		}
3198	}
3199
3200	return deps, errs
3201}
3202
3203// clearTransitionMutatorInputVariants removes the inputVariants field from every
3204// TransitionMutator now that all dependencies have been resolved.
3205func (c *Context) clearTransitionMutatorInputVariants() {
3206	for _, mutator := range c.transitionMutators {
3207		mutator.inputVariants = nil
3208	}
3209}
3210
3211// Replaces every build logic module with a clone of itself.  Prevents introducing problems where
3212// a mutator sets a non-property member variable on a module, which works until a later mutator
3213// creates variants of that module.
3214func (c *Context) cloneModules() {
3215	type update struct {
3216		orig  Module
3217		clone *moduleInfo
3218	}
3219	ch := make(chan update)
3220	doneCh := make(chan bool)
3221	go func() {
3222		errs := parallelVisit(c.iterateAllVariants(), unorderedVisitorImpl{}, parallelVisitLimit,
3223			func(m *moduleInfo, pause chan<- pauseSpec) bool {
3224				origLogicModule := m.logicModule
3225				m.logicModule, m.properties = c.cloneLogicModule(m)
3226				ch <- update{origLogicModule, m}
3227				return false
3228			})
3229		if len(errs) > 0 {
3230			panic(errs)
3231		}
3232		doneCh <- true
3233	}()
3234
3235	done := false
3236	for !done {
3237		select {
3238		case <-doneCh:
3239			done = true
3240		case update := <-ch:
3241			delete(c.moduleInfo, update.orig)
3242			c.moduleInfo[update.clone.logicModule] = update.clone
3243		}
3244	}
3245}
3246
3247// Removes modules[i] from the list and inserts newModules... where it was located, returning
3248// the new slice and the index of the last inserted element
3249func spliceModules(modules moduleList, i int, newModules moduleList) (moduleList, int) {
3250	spliceSize := len(newModules)
3251	newLen := len(modules) + spliceSize - 1
3252	var dest moduleList
3253	if cap(modules) >= len(modules)-1+len(newModules) {
3254		// We can fit the splice in the existing capacity, do everything in place
3255		dest = modules[:newLen]
3256	} else {
3257		dest = make(moduleList, newLen)
3258		copy(dest, modules[:i])
3259	}
3260
3261	// Move the end of the slice over by spliceSize-1
3262	copy(dest[i+spliceSize:], modules[i+1:])
3263
3264	// Copy the new modules into the slice
3265	copy(dest[i:], newModules)
3266
3267	return dest, i + spliceSize - 1
3268}
3269
3270func (c *Context) generateModuleBuildActions(config interface{},
3271	liveGlobals *liveTracker) ([]string, []error) {
3272
3273	c.BeginEvent("generateModuleBuildActions")
3274	defer c.EndEvent("generateModuleBuildActions")
3275	var deps []string
3276	var errs []error
3277
3278	cancelCh := make(chan struct{})
3279	errsCh := make(chan []error)
3280	depsCh := make(chan []string)
3281
3282	go func() {
3283		for {
3284			select {
3285			case <-cancelCh:
3286				close(cancelCh)
3287				return
3288			case newErrs := <-errsCh:
3289				errs = append(errs, newErrs...)
3290			case newDeps := <-depsCh:
3291				deps = append(deps, newDeps...)
3292
3293			}
3294		}
3295	}()
3296
3297	visitErrs := parallelVisit(c.iterateAllVariants(), bottomUpVisitor, parallelVisitLimit,
3298		func(module *moduleInfo, pause chan<- pauseSpec) bool {
3299			uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
3300			sanitizedName := toNinjaName(uniqueName)
3301			sanitizedVariant := toNinjaName(module.variant.name)
3302
3303			prefix := moduleNamespacePrefix(sanitizedName + "_" + sanitizedVariant)
3304
3305			// The parent scope of the moduleContext's local scope gets overridden to be that of the
3306			// calling Go package on a per-call basis.  Since the initial parent scope doesn't matter we
3307			// just set it to nil.
3308			scope := newLocalScope(nil, prefix)
3309
3310			mctx := &moduleContext{
3311				baseModuleContext: baseModuleContext{
3312					context: c,
3313					config:  config,
3314					module:  module,
3315				},
3316				scope:              scope,
3317				handledMissingDeps: module.missingDeps == nil,
3318			}
3319
3320			mctx.module.startedGenerateBuildActions = true
3321
3322			func() {
3323				defer func() {
3324					if r := recover(); r != nil {
3325						in := fmt.Sprintf("GenerateBuildActions for %s", module)
3326						if err, ok := r.(panicError); ok {
3327							err.addIn(in)
3328							mctx.error(err)
3329						} else {
3330							mctx.error(newPanicErrorf(r, in))
3331						}
3332					}
3333				}()
3334				if !mctx.restoreModuleBuildActions() {
3335					mctx.module.logicModule.GenerateBuildActions(mctx)
3336				}
3337			}()
3338
3339			mctx.module.finishedGenerateBuildActions = true
3340
3341			if len(mctx.errs) > 0 {
3342				errsCh <- mctx.errs
3343				return true
3344			}
3345
3346			if module.missingDeps != nil && !mctx.handledMissingDeps {
3347				var errs []error
3348				for _, depName := range module.missingDeps {
3349					errs = append(errs, c.missingDependencyError(module, depName))
3350				}
3351				errsCh <- errs
3352				return true
3353			}
3354
3355			depsCh <- mctx.ninjaFileDeps
3356
3357			newErrs := c.processLocalBuildActions(&module.actionDefs,
3358				&mctx.actionDefs, liveGlobals)
3359			if len(newErrs) > 0 {
3360				errsCh <- newErrs
3361				return true
3362			}
3363			return false
3364		})
3365
3366	cancelCh <- struct{}{}
3367	<-cancelCh
3368
3369	errs = append(errs, visitErrs...)
3370
3371	return deps, errs
3372}
3373
3374func (c *Context) generateOneSingletonBuildActions(config interface{},
3375	info *singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
3376
3377	var deps []string
3378	var errs []error
3379
3380	// The parent scope of the singletonContext's local scope gets overridden to be that of the
3381	// calling Go package on a per-call basis.  Since the initial parent scope doesn't matter we
3382	// just set it to nil.
3383	scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
3384
3385	sctx := &singletonContext{
3386		name:    info.name,
3387		context: c,
3388		config:  config,
3389		scope:   scope,
3390		globals: liveGlobals,
3391	}
3392
3393	func() {
3394		defer func() {
3395			if r := recover(); r != nil {
3396				in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
3397				if err, ok := r.(panicError); ok {
3398					err.addIn(in)
3399					sctx.error(err)
3400				} else {
3401					sctx.error(newPanicErrorf(r, in))
3402				}
3403			}
3404		}()
3405		info.singleton.GenerateBuildActions(sctx)
3406	}()
3407
3408	if len(sctx.errs) > 0 {
3409		errs = append(errs, sctx.errs...)
3410		return deps, errs
3411	}
3412
3413	deps = append(deps, sctx.ninjaFileDeps...)
3414
3415	newErrs := c.processLocalBuildActions(&info.actionDefs,
3416		&sctx.actionDefs, liveGlobals)
3417	errs = append(errs, newErrs...)
3418	return deps, errs
3419}
3420
3421func (c *Context) generateParallelSingletonBuildActions(config interface{},
3422	singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
3423
3424	c.BeginEvent("generateParallelSingletonBuildActions")
3425	defer c.EndEvent("generateParallelSingletonBuildActions")
3426
3427	var deps []string
3428	var errs []error
3429
3430	wg := sync.WaitGroup{}
3431	cancelCh := make(chan struct{})
3432	depsCh := make(chan []string)
3433	errsCh := make(chan []error)
3434
3435	go func() {
3436		for {
3437			select {
3438			case <-cancelCh:
3439				close(cancelCh)
3440				return
3441			case dep := <-depsCh:
3442				deps = append(deps, dep...)
3443			case newErrs := <-errsCh:
3444				if len(errs) <= maxErrors {
3445					errs = append(errs, newErrs...)
3446				}
3447			}
3448		}
3449	}()
3450
3451	for _, info := range singletons {
3452		if !info.parallel {
3453			// Skip any singletons registered with parallel=false.
3454			continue
3455		}
3456		wg.Add(1)
3457		go func(inf *singletonInfo) {
3458			defer wg.Done()
3459			newDeps, newErrs := c.generateOneSingletonBuildActions(config, inf, liveGlobals)
3460			depsCh <- newDeps
3461			errsCh <- newErrs
3462		}(info)
3463	}
3464	wg.Wait()
3465
3466	cancelCh <- struct{}{}
3467	<-cancelCh
3468
3469	return deps, errs
3470}
3471
3472func (c *Context) generateSingletonBuildActions(config interface{},
3473	singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
3474
3475	c.BeginEvent("generateSingletonBuildActions")
3476	defer c.EndEvent("generateSingletonBuildActions")
3477
3478	var deps []string
3479	var errs []error
3480
3481	// Run one singleton.  Use a variable to simplify manual validation testing.
3482	var runSingleton = func(info *singletonInfo) {
3483		c.BeginEvent("singleton:" + info.name)
3484		defer c.EndEvent("singleton:" + info.name)
3485		newDeps, newErrs := c.generateOneSingletonBuildActions(config, info, liveGlobals)
3486		deps = append(deps, newDeps...)
3487		errs = append(errs, newErrs...)
3488	}
3489
3490	// Force a resort of the module groups before running singletons so that two singletons running in parallel
3491	// don't cause a data race when they trigger a resort in VisitAllModules.
3492	c.sortedModuleGroups()
3493
3494	// First, take care of any singletons that want to run in parallel.
3495	deps, errs = c.generateParallelSingletonBuildActions(config, singletons, liveGlobals)
3496
3497	for _, info := range singletons {
3498		if !info.parallel {
3499			runSingleton(info)
3500			if len(errs) > maxErrors {
3501				break
3502			}
3503		}
3504	}
3505
3506	return deps, errs
3507}
3508
3509func (c *Context) processLocalBuildActions(out, in *localBuildActions,
3510	liveGlobals *liveTracker) []error {
3511
3512	var errs []error
3513
3514	// First we go through and add everything referenced by the module's
3515	// buildDefs to the live globals set.  This will end up adding the live
3516	// locals to the set as well, but we'll take them out after.
3517	for _, def := range in.buildDefs {
3518		err := liveGlobals.AddBuildDefDeps(def)
3519		if err != nil {
3520			errs = append(errs, err)
3521		}
3522	}
3523
3524	if len(errs) > 0 {
3525		return errs
3526	}
3527
3528	out.buildDefs = append(out.buildDefs, in.buildDefs...)
3529
3530	// We use the now-incorrect set of live "globals" to determine which local
3531	// definitions are live.  As we go through copying those live locals to the
3532	// moduleGroup we remove them from the live globals set.
3533	for _, v := range in.variables {
3534		isLive := liveGlobals.RemoveVariableIfLive(v)
3535		if isLive {
3536			out.variables = append(out.variables, v)
3537		}
3538	}
3539
3540	for _, r := range in.rules {
3541		isLive := liveGlobals.RemoveRuleIfLive(r)
3542		if isLive {
3543			out.rules = append(out.rules, r)
3544		}
3545	}
3546
3547	return nil
3548}
3549
3550func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
3551	visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
3552
3553	visited := make(map[*moduleInfo]bool)
3554	var visiting *moduleInfo
3555
3556	defer func() {
3557		if r := recover(); r != nil {
3558			panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
3559				topModule, funcName(visitDown), funcName(visitUp), visiting))
3560		}
3561	}()
3562
3563	var walk func(module *moduleInfo)
3564	walk = func(module *moduleInfo) {
3565		for _, dep := range module.directDeps {
3566			if allowDuplicates || !visited[dep.module] {
3567				visiting = dep.module
3568				recurse := true
3569				if visitDown != nil {
3570					recurse = visitDown(dep, module)
3571				}
3572				if recurse && !visited[dep.module] {
3573					walk(dep.module)
3574					visited[dep.module] = true
3575				}
3576				if visitUp != nil {
3577					visitUp(dep, module)
3578				}
3579			}
3580		}
3581	}
3582
3583	walk(topModule)
3584}
3585
3586type replace struct {
3587	from, to  *moduleInfo
3588	predicate ReplaceDependencyPredicate
3589}
3590
3591type rename struct {
3592	group *moduleGroup
3593	name  string
3594}
3595
3596// moduleVariantsThatDependOn takes the name of a module and a dependency and returns the all the variants of the
3597// module that depends on the dependency.
3598func (c *Context) moduleVariantsThatDependOn(name string, dep *moduleInfo) []*moduleInfo {
3599	group := c.moduleGroupFromName(name, dep.namespace())
3600	var variants []*moduleInfo
3601
3602	if group == nil {
3603		return nil
3604	}
3605
3606	for _, m := range group.modules {
3607		for _, moduleDep := range m.directDeps {
3608			if moduleDep.module == dep {
3609				variants = append(variants, m)
3610			}
3611		}
3612	}
3613
3614	return variants
3615}
3616
3617func (c *Context) handleRenames(renames []rename) []error {
3618	var errs []error
3619	for _, rename := range renames {
3620		group, name := rename.group, rename.name
3621		if name == group.name || len(group.modules) < 1 {
3622			continue
3623		}
3624
3625		errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
3626	}
3627
3628	return errs
3629}
3630
3631func (c *Context) handleReplacements(replacements []replace) []error {
3632	var errs []error
3633	changedDeps := false
3634	for _, replace := range replacements {
3635		for _, m := range replace.from.reverseDeps {
3636			for i, d := range m.directDeps {
3637				if d.module == replace.from {
3638					// If the replacement has a predicate then check it.
3639					if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) {
3640						m.directDeps[i].module = replace.to
3641						changedDeps = true
3642					}
3643				}
3644			}
3645		}
3646
3647	}
3648
3649	if changedDeps {
3650		c.needsUpdateDependencies++
3651	}
3652	return errs
3653}
3654
3655func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string, depVariations variationMap) (errs []error) {
3656	if !depVariations.empty() {
3657		depName = depName + "{" + c.prettyPrintVariant(depVariations) + "}"
3658	}
3659	if c.allowMissingDependencies {
3660		module.missingDeps = append(module.missingDeps, depName)
3661		return nil
3662	}
3663	return []error{c.missingDependencyError(module, depName)}
3664}
3665
3666func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
3667	guess := namesLike(depName, module.Name(), c.moduleGroups)
3668	err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName, guess)
3669	return &BlueprintError{
3670		Err: err,
3671		Pos: module.pos,
3672	}
3673}
3674
3675func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
3676	group, exists := c.nameInterface.ModuleFromName(name, namespace)
3677	if exists {
3678		return group.moduleGroup
3679	}
3680	return nil
3681}
3682
3683func (c *Context) sortedModuleGroups() []*moduleGroup {
3684	if c.cachedSortedModuleGroups == nil || c.cachedDepsModified {
3685		unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
3686			result := make([]*moduleGroup, 0, len(wrappers))
3687			for _, group := range wrappers {
3688				result = append(result, group.moduleGroup)
3689			}
3690			return result
3691		}
3692
3693		c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
3694		c.cachedDepsModified = false
3695	}
3696
3697	return c.cachedSortedModuleGroups
3698}
3699
3700func (c *Context) visitAllModules(visit func(Module)) {
3701	var module *moduleInfo
3702
3703	defer func() {
3704		if r := recover(); r != nil {
3705			panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
3706				funcName(visit), module))
3707		}
3708	}()
3709
3710	for _, moduleGroup := range c.sortedModuleGroups() {
3711		for _, module := range moduleGroup.modules {
3712			visit(module.logicModule)
3713		}
3714	}
3715}
3716
3717func (c *Context) visitAllModulesIf(pred func(Module) bool,
3718	visit func(Module)) {
3719
3720	var module *moduleInfo
3721
3722	defer func() {
3723		if r := recover(); r != nil {
3724			panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
3725				funcName(pred), funcName(visit), module))
3726		}
3727	}()
3728
3729	for _, moduleGroup := range c.sortedModuleGroups() {
3730		for _, module := range moduleGroup.modules {
3731			if pred(module.logicModule) {
3732				visit(module.logicModule)
3733			}
3734		}
3735	}
3736}
3737
3738func (c *Context) visitAllModuleVariants(module *moduleInfo,
3739	visit func(Module)) {
3740
3741	var variant *moduleInfo
3742
3743	defer func() {
3744		if r := recover(); r != nil {
3745			panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
3746				module, funcName(visit), variant))
3747		}
3748	}()
3749
3750	for _, module := range module.group.modules {
3751		visit(module.logicModule)
3752	}
3753}
3754
3755func (c *Context) visitAllModuleInfos(visit func(*moduleInfo)) {
3756	var module *moduleInfo
3757
3758	defer func() {
3759		if r := recover(); r != nil {
3760			panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
3761				funcName(visit), module))
3762		}
3763	}()
3764
3765	for _, moduleGroup := range c.sortedModuleGroups() {
3766		for _, module := range moduleGroup.modules {
3767			visit(module)
3768		}
3769	}
3770}
3771
3772func (c *Context) requireNinjaVersion(major, minor, micro int) {
3773	if major != 1 {
3774		panic("ninja version with major version != 1 not supported")
3775	}
3776	if c.requiredNinjaMinor < minor {
3777		c.requiredNinjaMinor = minor
3778		c.requiredNinjaMicro = micro
3779	}
3780	if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
3781		c.requiredNinjaMicro = micro
3782	}
3783}
3784
3785func (c *Context) setOutDir(value *ninjaString) {
3786	if c.outDir == nil {
3787		c.outDir = value
3788	}
3789}
3790
3791func (c *Context) makeUniquePackageNames(
3792	liveGlobals *liveTracker) (map[*packageContext]string, []string) {
3793
3794	pkgs := make(map[string]*packageContext)
3795	pkgNames := make(map[*packageContext]string)
3796	longPkgNames := make(map[*packageContext]bool)
3797
3798	processPackage := func(pctx *packageContext) {
3799		if pctx == nil {
3800			// This is a built-in rule and has no package.
3801			return
3802		}
3803		if _, ok := pkgNames[pctx]; ok {
3804			// We've already processed this package.
3805			return
3806		}
3807
3808		otherPkg, present := pkgs[pctx.shortName]
3809		if present {
3810			// Short name collision.  Both this package and the one that's
3811			// already there need to use their full names.  We leave the short
3812			// name in pkgNames for now so future collisions still get caught.
3813			longPkgNames[pctx] = true
3814			longPkgNames[otherPkg] = true
3815		} else {
3816			// No collision so far.  Tentatively set the package's name to be
3817			// its short name.
3818			pkgNames[pctx] = pctx.shortName
3819			pkgs[pctx.shortName] = pctx
3820		}
3821	}
3822
3823	// We try to give all packages their short name, but when we get collisions
3824	// we need to use the full unique package name.
3825	for v, _ := range liveGlobals.variables {
3826		processPackage(v.packageContext())
3827	}
3828	for p, _ := range liveGlobals.pools {
3829		processPackage(p.packageContext())
3830	}
3831	for r, _ := range liveGlobals.rules {
3832		processPackage(r.packageContext())
3833	}
3834
3835	// Add the packages that had collisions using their full unique names.  This
3836	// will overwrite any short names that were added in the previous step.
3837	for pctx := range longPkgNames {
3838		pkgNames[pctx] = pctx.fullName
3839	}
3840
3841	// Create deps list from calls to PackageContext.AddNinjaFileDeps
3842	deps := []string{}
3843	for _, pkg := range pkgs {
3844		deps = append(deps, pkg.ninjaFileDeps...)
3845	}
3846
3847	return pkgNames, deps
3848}
3849
3850// memoizeFullNames stores the full name of each live global variable, rule and pool since each is
3851// guaranteed to be used at least twice, once in the definition and once for each usage, and many
3852// are used much more than once.
3853func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) *nameTracker {
3854	nameTracker := &nameTracker{
3855		pkgNames:  pkgNames,
3856		variables: make(map[Variable]string),
3857		rules:     make(map[Rule]string),
3858		pools:     make(map[Pool]string),
3859	}
3860	for v := range liveGlobals.variables {
3861		nameTracker.variables[v] = v.fullName(pkgNames)
3862	}
3863	for r := range liveGlobals.rules {
3864		nameTracker.rules[r] = r.fullName(pkgNames)
3865	}
3866	for p := range liveGlobals.pools {
3867		nameTracker.pools[p] = p.fullName(pkgNames)
3868	}
3869	return nameTracker
3870}
3871
3872func (c *Context) checkForVariableReferenceCycles(
3873	variables map[Variable]*ninjaString, nameTracker *nameTracker) {
3874
3875	visited := make(map[Variable]bool)  // variables that were already checked
3876	checking := make(map[Variable]bool) // variables actively being checked
3877
3878	var check func(v Variable) []Variable
3879
3880	check = func(v Variable) []Variable {
3881		visited[v] = true
3882		checking[v] = true
3883		defer delete(checking, v)
3884
3885		value := variables[v]
3886		for _, dep := range value.Variables() {
3887			if checking[dep] {
3888				// This is a cycle.
3889				return []Variable{dep, v}
3890			}
3891
3892			if !visited[dep] {
3893				cycle := check(dep)
3894				if cycle != nil {
3895					if cycle[0] == v {
3896						// We are the "start" of the cycle, so we're responsible
3897						// for generating the errors.  The cycle list is in
3898						// reverse order because all the 'check' calls append
3899						// their own module to the list.
3900						msgs := []string{"detected variable reference cycle:"}
3901
3902						// Iterate backwards through the cycle list.
3903						curName := nameTracker.Variable(v)
3904						curValue := value.Value(nameTracker)
3905						for i := len(cycle) - 1; i >= 0; i-- {
3906							next := cycle[i]
3907							nextName := nameTracker.Variable(next)
3908							nextValue := variables[next].Value(nameTracker)
3909
3910							msgs = append(msgs, fmt.Sprintf(
3911								"    %q depends on %q", curName, nextName))
3912							msgs = append(msgs, fmt.Sprintf(
3913								"    [%s = %s]", curName, curValue))
3914
3915							curName = nextName
3916							curValue = nextValue
3917						}
3918
3919						// Variable reference cycles are a programming error,
3920						// not the fault of the Blueprint file authors.
3921						panic(strings.Join(msgs, "\n"))
3922					} else {
3923						// We're not the "start" of the cycle, so we just append
3924						// our module to the list and return it.
3925						return append(cycle, v)
3926					}
3927				}
3928			}
3929		}
3930
3931		return nil
3932	}
3933
3934	for v := range variables {
3935		if !visited[v] {
3936			cycle := check(v)
3937			if cycle != nil {
3938				panic("inconceivable!")
3939			}
3940		}
3941	}
3942}
3943
3944// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
3945// property structs returned by the factory for that module type.
3946func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
3947	ret := make(map[string][]interface{}, len(c.moduleFactories))
3948	for moduleType, factory := range c.moduleFactories {
3949		_, ret[moduleType] = factory()
3950	}
3951
3952	return ret
3953}
3954
3955func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
3956	return maps.Clone(c.moduleFactories)
3957}
3958
3959func (c *Context) ModuleName(logicModule Module) string {
3960	module := c.moduleInfo[logicModule]
3961	return module.Name()
3962}
3963
3964func (c *Context) ModuleDir(logicModule Module) string {
3965	return filepath.Dir(c.BlueprintFile(logicModule))
3966}
3967
3968func (c *Context) ModuleSubDir(logicModule Module) string {
3969	module := c.moduleInfo[logicModule]
3970	return module.variant.name
3971}
3972
3973func (c *Context) ModuleType(logicModule Module) string {
3974	module := c.moduleInfo[logicModule]
3975	return module.typeName
3976}
3977
3978// ModuleProvider returns the value, if any, for the provider for a module.  If the value for the
3979// provider was not set it returns nil and false.  The return value should always be considered read-only.
3980// It panics if called before the appropriate mutator or GenerateBuildActions pass for the provider on the
3981// module.  The value returned may be a deep copy of the value originally passed to SetProvider.
3982func (c *Context) ModuleProvider(logicModule Module, provider AnyProviderKey) (any, bool) {
3983	module := c.moduleInfo[logicModule]
3984	return c.provider(module, provider.provider())
3985}
3986
3987func (c *Context) BlueprintFile(logicModule Module) string {
3988	module := c.moduleInfo[logicModule]
3989	return module.relBlueprintsFile
3990}
3991
3992func (c *Context) moduleErrorf(module *moduleInfo, format string,
3993	args ...interface{}) error {
3994	if module == nil {
3995		// This can happen if ModuleErrorf is called from a load hook
3996		return &BlueprintError{
3997			Err: fmt.Errorf(format, args...),
3998		}
3999	}
4000
4001	return &ModuleError{
4002		BlueprintError: BlueprintError{
4003			Err: fmt.Errorf(format, args...),
4004			Pos: module.pos,
4005		},
4006		module: module,
4007	}
4008}
4009
4010func (c *Context) ModuleErrorf(logicModule Module, format string,
4011	args ...interface{}) error {
4012	return c.moduleErrorf(c.moduleInfo[logicModule], format, args...)
4013}
4014
4015func (c *Context) PropertyErrorf(logicModule Module, property string, format string,
4016	args ...interface{}) error {
4017
4018	module := c.moduleInfo[logicModule]
4019	if module == nil {
4020		// This can happen if PropertyErrorf is called from a load hook
4021		return &BlueprintError{
4022			Err: fmt.Errorf(format, args...),
4023		}
4024	}
4025
4026	pos := module.propertyPos[property]
4027	if !pos.IsValid() {
4028		pos = module.pos
4029	}
4030
4031	return &PropertyError{
4032		ModuleError: ModuleError{
4033			BlueprintError: BlueprintError{
4034				Err: fmt.Errorf(format, args...),
4035				Pos: pos,
4036			},
4037			module: module,
4038		},
4039		property: property,
4040	}
4041}
4042
4043func (c *Context) VisitAllModules(visit func(Module)) {
4044	c.visitAllModules(visit)
4045}
4046
4047func (c *Context) VisitAllModulesIf(pred func(Module) bool,
4048	visit func(Module)) {
4049
4050	c.visitAllModulesIf(pred, visit)
4051}
4052
4053func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
4054	c.VisitDirectDepsWithTags(module, func(m Module, _ DependencyTag) {
4055		visit(m)
4056	})
4057}
4058
4059func (c *Context) VisitDirectDepsWithTags(module Module, visit func(Module, DependencyTag)) {
4060	topModule := c.moduleInfo[module]
4061
4062	var visiting *moduleInfo
4063
4064	defer func() {
4065		if r := recover(); r != nil {
4066			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
4067				topModule, funcName(visit), visiting))
4068		}
4069	}()
4070
4071	for _, dep := range topModule.directDeps {
4072		visiting = dep.module
4073		visit(dep.module.logicModule, dep.tag)
4074	}
4075}
4076
4077func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
4078	topModule := c.moduleInfo[module]
4079
4080	var visiting *moduleInfo
4081
4082	defer func() {
4083		if r := recover(); r != nil {
4084			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
4085				topModule, funcName(pred), funcName(visit), visiting))
4086		}
4087	}()
4088
4089	for _, dep := range topModule.directDeps {
4090		visiting = dep.module
4091		if pred(dep.module.logicModule) {
4092			visit(dep.module.logicModule)
4093		}
4094	}
4095}
4096
4097func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
4098	topModule := c.moduleInfo[module]
4099
4100	var visiting *moduleInfo
4101
4102	defer func() {
4103		if r := recover(); r != nil {
4104			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
4105				topModule, funcName(visit), visiting))
4106		}
4107	}()
4108
4109	c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
4110		visiting = dep.module
4111		visit(dep.module.logicModule)
4112	})
4113}
4114
4115func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
4116	topModule := c.moduleInfo[module]
4117
4118	var visiting *moduleInfo
4119
4120	defer func() {
4121		if r := recover(); r != nil {
4122			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
4123				topModule, funcName(pred), funcName(visit), visiting))
4124		}
4125	}()
4126
4127	c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
4128		if pred(dep.module.logicModule) {
4129			visiting = dep.module
4130			visit(dep.module.logicModule)
4131		}
4132	})
4133}
4134
4135func (c *Context) PrimaryModule(module Module) Module {
4136	return c.moduleInfo[module].group.modules.firstModule().logicModule
4137}
4138
4139func (c *Context) IsFinalModule(module Module) bool {
4140	return c.moduleInfo[module].group.modules.lastModule().logicModule == module
4141}
4142
4143func (c *Context) VisitAllModuleVariants(module Module,
4144	visit func(Module)) {
4145
4146	c.visitAllModuleVariants(c.moduleInfo[module], visit)
4147}
4148
4149// Singletons returns a list of all registered Singletons.
4150func (c *Context) Singletons() []Singleton {
4151	var ret []Singleton
4152	for _, s := range c.singletonInfo {
4153		ret = append(ret, s.singleton)
4154	}
4155	return ret
4156}
4157
4158// SingletonName returns the name that the given singleton was registered with.
4159func (c *Context) SingletonName(singleton Singleton) string {
4160	for _, s := range c.singletonInfo {
4161		if s.singleton == singleton {
4162			return s.name
4163		}
4164	}
4165	return ""
4166}
4167
4168// Checks that the hashes of all the providers match the hashes from when they were first set.
4169// Does nothing on success, returns a list of errors otherwise. It's recommended to run this
4170// in a goroutine.
4171func (c *Context) VerifyProvidersWereUnchanged() []error {
4172	if !c.buildActionsReady {
4173		return []error{ErrBuildActionsNotReady}
4174	}
4175	toProcess := make(chan *moduleInfo)
4176	errorCh := make(chan []error)
4177	var wg sync.WaitGroup
4178	go func() {
4179		for m := range c.iterateAllVariants() {
4180			toProcess <- m
4181		}
4182		close(toProcess)
4183	}()
4184	for i := 0; i < 1000; i++ {
4185		wg.Add(1)
4186		go func() {
4187			var errors []error
4188			for m := range toProcess {
4189				for i, provider := range m.providers {
4190					if provider != nil {
4191						hash, err := proptools.CalculateHash(provider)
4192						if err != nil {
4193							errors = append(errors, fmt.Errorf("provider %q on module %q was modified after being set, and no longer hashable afterwards: %s", providerRegistry[i].typ, m.Name(), err.Error()))
4194							continue
4195						}
4196						if m.providerInitialValueHashes[i] != hash {
4197							errors = append(errors, fmt.Errorf("provider %q on module %q was modified after being set", providerRegistry[i].typ, m.Name()))
4198						}
4199					} else if m.providerInitialValueHashes[i] != 0 {
4200						// This should be unreachable, because in setProvider we check if the provider has already been set.
4201						errors = append(errors, fmt.Errorf("provider %q on module %q was unset somehow, this is an internal error", providerRegistry[i].typ, m.Name()))
4202					}
4203				}
4204			}
4205			if errors != nil {
4206				errorCh <- errors
4207			}
4208			wg.Done()
4209		}()
4210	}
4211	go func() {
4212		wg.Wait()
4213		close(errorCh)
4214	}()
4215
4216	var errors []error
4217	for newErrors := range errorCh {
4218		errors = append(errors, newErrors...)
4219	}
4220	return errors
4221}
4222
4223// WriteBuildFile writes the Ninja manifest text for the generated build
4224// actions to w.  If this is called before PrepareBuildActions successfully
4225// completes then ErrBuildActionsNotReady is returned.
4226func (c *Context) WriteBuildFile(w StringWriterWriter, shardNinja bool, ninjaFileName string) error {
4227	var err error
4228	pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
4229		if !c.buildActionsReady {
4230			err = ErrBuildActionsNotReady
4231			return
4232		}
4233
4234		nw := newNinjaWriter(w)
4235
4236		if err = c.writeBuildFileHeader(nw); err != nil {
4237			return
4238		}
4239
4240		if err = c.writeNinjaRequiredVersion(nw); err != nil {
4241			return
4242		}
4243
4244		if err = c.writeSubninjas(nw); err != nil {
4245			return
4246		}
4247
4248		// TODO: Group the globals by package.
4249
4250		if err = c.writeGlobalVariables(nw); err != nil {
4251			return
4252		}
4253
4254		if err = c.writeGlobalPools(nw); err != nil {
4255			return
4256		}
4257
4258		if err = c.writeBuildDir(nw); err != nil {
4259			return
4260		}
4261
4262		if err = c.writeGlobalRules(nw); err != nil {
4263			return
4264		}
4265
4266		if err = c.writeAllModuleActions(nw, shardNinja, ninjaFileName); err != nil {
4267			return
4268		}
4269
4270		if err = c.writeAllSingletonActions(nw); err != nil {
4271			return
4272		}
4273	})
4274
4275	return err
4276}
4277
4278type pkgAssociation struct {
4279	PkgName string
4280	PkgPath string
4281}
4282
4283type pkgAssociationSorter struct {
4284	pkgs []pkgAssociation
4285}
4286
4287func (s *pkgAssociationSorter) Len() int {
4288	return len(s.pkgs)
4289}
4290
4291func (s *pkgAssociationSorter) Less(i, j int) bool {
4292	iName := s.pkgs[i].PkgName
4293	jName := s.pkgs[j].PkgName
4294	return iName < jName
4295}
4296
4297func (s *pkgAssociationSorter) Swap(i, j int) {
4298	s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
4299}
4300
4301func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
4302	headerTemplate := template.New("fileHeader")
4303	_, err := headerTemplate.Parse(fileHeaderTemplate)
4304	if err != nil {
4305		// This is a programming error.
4306		panic(err)
4307	}
4308
4309	var pkgs []pkgAssociation
4310	maxNameLen := 0
4311	for pkg, name := range c.nameTracker.pkgNames {
4312		pkgs = append(pkgs, pkgAssociation{
4313			PkgName: name,
4314			PkgPath: pkg.pkgPath,
4315		})
4316		if len(name) > maxNameLen {
4317			maxNameLen = len(name)
4318		}
4319	}
4320
4321	for i := range pkgs {
4322		pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
4323	}
4324
4325	sort.Sort(&pkgAssociationSorter{pkgs})
4326
4327	params := map[string]interface{}{
4328		"Pkgs": pkgs,
4329	}
4330
4331	buf := bytes.NewBuffer(nil)
4332	err = headerTemplate.Execute(buf, params)
4333	if err != nil {
4334		return err
4335	}
4336
4337	return nw.Comment(buf.String())
4338}
4339
4340func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
4341	value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
4342		c.requiredNinjaMicro)
4343
4344	err := nw.Assign("ninja_required_version", value)
4345	if err != nil {
4346		return err
4347	}
4348
4349	return nw.BlankLine()
4350}
4351
4352func (c *Context) writeSubninjas(nw *ninjaWriter) error {
4353	for _, subninja := range c.subninjas {
4354		err := nw.Subninja(subninja)
4355		if err != nil {
4356			return err
4357		}
4358	}
4359	return nw.BlankLine()
4360}
4361
4362func (c *Context) writeBuildDir(nw *ninjaWriter) error {
4363	if c.outDir != nil {
4364		err := nw.Assign("builddir", c.outDir.Value(c.nameTracker))
4365		if err != nil {
4366			return err
4367		}
4368
4369		err = nw.BlankLine()
4370		if err != nil {
4371			return err
4372		}
4373	}
4374	return nil
4375}
4376
4377func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
4378	visited := make(map[Variable]bool)
4379
4380	var walk func(v Variable) error
4381	walk = func(v Variable) error {
4382		visited[v] = true
4383
4384		// First visit variables on which this variable depends.
4385		value := c.globalVariables[v]
4386		for _, dep := range value.Variables() {
4387			if !visited[dep] {
4388				err := walk(dep)
4389				if err != nil {
4390					return err
4391				}
4392			}
4393		}
4394
4395		err := nw.Assign(c.nameTracker.Variable(v), value.Value(c.nameTracker))
4396		if err != nil {
4397			return err
4398		}
4399
4400		err = nw.BlankLine()
4401		if err != nil {
4402			return err
4403		}
4404
4405		return nil
4406	}
4407
4408	globalVariables := make([]Variable, 0, len(c.globalVariables))
4409	for variable := range c.globalVariables {
4410		globalVariables = append(globalVariables, variable)
4411	}
4412
4413	slices.SortFunc(globalVariables, func(a, b Variable) int {
4414		return cmp.Compare(c.nameTracker.Variable(a), c.nameTracker.Variable(b))
4415	})
4416
4417	for _, v := range globalVariables {
4418		if !visited[v] {
4419			err := walk(v)
4420			if err != nil {
4421				return nil
4422			}
4423		}
4424	}
4425
4426	return nil
4427}
4428
4429func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
4430	globalPools := make([]Pool, 0, len(c.globalPools))
4431	for pool := range c.globalPools {
4432		globalPools = append(globalPools, pool)
4433	}
4434
4435	slices.SortFunc(globalPools, func(a, b Pool) int {
4436		return cmp.Compare(c.nameTracker.Pool(a), c.nameTracker.Pool(b))
4437	})
4438
4439	for _, pool := range globalPools {
4440		name := c.nameTracker.Pool(pool)
4441		def := c.globalPools[pool]
4442		err := def.WriteTo(nw, name)
4443		if err != nil {
4444			return err
4445		}
4446
4447		err = nw.BlankLine()
4448		if err != nil {
4449			return err
4450		}
4451	}
4452
4453	return nil
4454}
4455
4456func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
4457	globalRules := make([]Rule, 0, len(c.globalRules))
4458	for rule := range c.globalRules {
4459		globalRules = append(globalRules, rule)
4460	}
4461
4462	slices.SortFunc(globalRules, func(a, b Rule) int {
4463		return cmp.Compare(c.nameTracker.Rule(a), c.nameTracker.Rule(b))
4464	})
4465
4466	for _, rule := range globalRules {
4467		name := c.nameTracker.Rule(rule)
4468		def := c.globalRules[rule]
4469		err := def.WriteTo(nw, name, c.nameTracker)
4470		if err != nil {
4471			return err
4472		}
4473
4474		err = nw.BlankLine()
4475		if err != nil {
4476			return err
4477		}
4478	}
4479
4480	return nil
4481}
4482
4483type depSorter []depInfo
4484
4485func (s depSorter) Len() int {
4486	return len(s)
4487}
4488
4489func (s depSorter) Less(i, j int) bool {
4490	iName := s[i].module.Name()
4491	jName := s[j].module.Name()
4492	if iName == jName {
4493		iName = s[i].module.variant.name
4494		jName = s[j].module.variant.name
4495	}
4496	return iName < jName
4497}
4498
4499func (s depSorter) Swap(i, j int) {
4500	s[i], s[j] = s[j], s[i]
4501}
4502
4503type moduleSorter struct {
4504	modules       []*moduleInfo
4505	nameInterface NameInterface
4506}
4507
4508func (s moduleSorter) Len() int {
4509	return len(s.modules)
4510}
4511
4512func (s moduleSorter) Less(i, j int) bool {
4513	iMod := s.modules[i]
4514	jMod := s.modules[j]
4515	iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
4516	jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
4517	if iName == jName {
4518		iVariantName := s.modules[i].variant.name
4519		jVariantName := s.modules[j].variant.name
4520		if iVariantName == jVariantName {
4521			panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
4522				iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
4523		} else {
4524			return iVariantName < jVariantName
4525		}
4526	} else {
4527		return iName < jName
4528	}
4529}
4530
4531func (s moduleSorter) Swap(i, j int) {
4532	s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
4533}
4534
4535func GetNinjaShardFiles(ninjaFile string) []string {
4536	suffix := ".ninja"
4537	if !strings.HasSuffix(ninjaFile, suffix) {
4538		panic(fmt.Errorf("ninja file name in wrong format : %s", ninjaFile))
4539	}
4540	base := strings.TrimSuffix(ninjaFile, suffix)
4541	ninjaShardCnt := 10
4542	fileNames := make([]string, ninjaShardCnt)
4543
4544	for i := 0; i < ninjaShardCnt; i++ {
4545		fileNames[i] = fmt.Sprintf("%s.%d%s", base, i, suffix)
4546	}
4547	return fileNames
4548}
4549
4550func (c *Context) writeAllModuleActions(nw *ninjaWriter, shardNinja bool, ninjaFileName string) error {
4551	c.BeginEvent("modules")
4552	defer c.EndEvent("modules")
4553
4554	var modules []*moduleInfo
4555	var incModules []*moduleInfo
4556
4557	for _, module := range c.moduleInfo {
4558		if module.buildActionCacheKey != nil {
4559			incModules = append(incModules, module)
4560			continue
4561		}
4562		modules = append(modules, module)
4563	}
4564	sort.Sort(moduleSorter{modules, c.nameInterface})
4565	sort.Sort(moduleSorter{incModules, c.nameInterface})
4566
4567	phonys := c.deduplicateOrderOnlyDeps(append(modules, incModules...))
4568
4569	c.EventHandler.Do("sort_phony_builddefs", func() {
4570		// sorting for determinism, the phony output names are stable
4571		sort.Slice(phonys.buildDefs, func(i int, j int) bool {
4572			return phonys.buildDefs[i].OutputStrings[0] < phonys.buildDefs[j].OutputStrings[0]
4573		})
4574	})
4575
4576	if err := c.writeLocalBuildActions(nw, phonys); err != nil {
4577		return err
4578	}
4579
4580	headerTemplate := template.New("moduleHeader")
4581	if _, err := headerTemplate.Parse(moduleHeaderTemplate); err != nil {
4582		// This is a programming error.
4583		panic(err)
4584	}
4585
4586	if shardNinja {
4587		var wg sync.WaitGroup
4588		errorCh := make(chan error)
4589		files := GetNinjaShardFiles(ninjaFileName)
4590		shardedModules := proptools.ShardByCount(modules, len(files))
4591		for i, batchModules := range shardedModules {
4592			file := files[i]
4593			wg.Add(1)
4594			go func(file string, batchModules []*moduleInfo) {
4595				defer wg.Done()
4596				f, err := c.fs.OpenFile(JoinPath(c.SrcDir(), file), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions)
4597				if err != nil {
4598					errorCh <- fmt.Errorf("error opening Ninja file shard: %s", err)
4599					return
4600				}
4601				defer func() {
4602					err := f.Close()
4603					if err != nil {
4604						errorCh <- err
4605					}
4606				}()
4607				buf := bufio.NewWriterSize(f, 16*1024*1024)
4608				defer func() {
4609					err := buf.Flush()
4610					if err != nil {
4611						errorCh <- err
4612					}
4613				}()
4614				writer := newNinjaWriter(buf)
4615				err = c.writeModuleAction(batchModules, writer, headerTemplate)
4616				if err != nil {
4617					errorCh <- err
4618				}
4619			}(file, batchModules)
4620			nw.Subninja(file)
4621		}
4622
4623		if c.GetIncrementalEnabled() {
4624			suffix := ".ninja"
4625			base := strings.TrimSuffix(ninjaFileName, suffix)
4626			file := fmt.Sprintf("%s.incremental%s", base, suffix)
4627			wg.Add(1)
4628			go func() {
4629				defer wg.Done()
4630				err := writeIncrementalModules(c, file, incModules, headerTemplate)
4631				if err != nil {
4632					errorCh <- err
4633				}
4634			}()
4635			nw.Subninja(file)
4636		}
4637
4638		go func() {
4639			wg.Wait()
4640			close(errorCh)
4641		}()
4642
4643		var errors []error
4644		for newErrors := range errorCh {
4645			errors = append(errors, newErrors)
4646		}
4647		if len(errors) > 0 {
4648			return proptools.MergeErrors(errors)
4649		}
4650		return nil
4651	} else {
4652		return c.writeModuleAction(modules, nw, headerTemplate)
4653	}
4654}
4655
4656func writeIncrementalModules(c *Context, baseFile string, modules []*moduleInfo, headerTemplate *template.Template) error {
4657	bf, err := c.fs.OpenFile(JoinPath(c.SrcDir(), baseFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions)
4658	if err != nil {
4659		return err
4660	}
4661	defer bf.Close()
4662	bBuf := bufio.NewWriterSize(bf, 16*1024*1024)
4663	defer bBuf.Flush()
4664	bWriter := newNinjaWriter(bBuf)
4665	ninjaPath := filepath.Join(filepath.Dir(baseFile), strings.ReplaceAll(filepath.Base(baseFile), ".", "_"))
4666	err = os.MkdirAll(JoinPath(c.SrcDir(), ninjaPath), 0755)
4667	if err != nil {
4668		return err
4669	}
4670
4671	c.buildActionsCache = make(BuildActionCache)
4672	for _, module := range modules {
4673		moduleFile := filepath.Join(ninjaPath, module.ModuleCacheKey()+".ninja")
4674		if !module.incrementalRestored {
4675			err := func() error {
4676				mf, err := c.fs.OpenFile(JoinPath(c.SrcDir(), moduleFile), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, OutFilePermissions)
4677				if err != nil {
4678					return err
4679				}
4680				defer mf.Close()
4681				mBuf := bufio.NewWriterSize(mf, 4*1024*1024)
4682				defer mBuf.Flush()
4683				mWriter := newNinjaWriter(mBuf)
4684				return c.writeModuleAction([]*moduleInfo{module}, mWriter, headerTemplate)
4685			}()
4686			if err != nil {
4687				return err
4688			}
4689		}
4690		if module.buildActionCacheKey != nil {
4691			c.cacheModuleBuildActions(module)
4692		}
4693		bWriter.Subninja(moduleFile)
4694	}
4695	return nil
4696}
4697
4698func (c *Context) writeModuleAction(modules []*moduleInfo, nw *ninjaWriter, headerTemplate *template.Template) error {
4699	buf := bytes.NewBuffer(nil)
4700
4701	for _, module := range modules {
4702		if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
4703			continue
4704		}
4705		buf.Reset()
4706
4707		// In order to make the bootstrap build manifest independent of the
4708		// build dir we need to output the Blueprints file locations in the
4709		// comments as paths relative to the source directory.
4710		relPos := module.pos
4711		relPos.Filename = module.relBlueprintsFile
4712
4713		// Get the name and location of the factory function for the module.
4714		factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
4715		factoryName := factoryFunc.Name()
4716
4717		infoMap := map[string]interface{}{
4718			"name":      module.Name(),
4719			"typeName":  module.typeName,
4720			"goFactory": factoryName,
4721			"pos":       relPos,
4722			"variant":   module.variant.name,
4723		}
4724		if err := headerTemplate.Execute(buf, infoMap); err != nil {
4725			return err
4726		}
4727
4728		if err := nw.Comment(buf.String()); err != nil {
4729			return err
4730		}
4731
4732		if err := nw.BlankLine(); err != nil {
4733			return err
4734		}
4735
4736		if err := c.writeLocalBuildActions(nw, &module.actionDefs); err != nil {
4737			return err
4738		}
4739
4740		if err := nw.BlankLine(); err != nil {
4741			return err
4742		}
4743	}
4744
4745	return nil
4746}
4747
4748func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
4749	c.BeginEvent("singletons")
4750	defer c.EndEvent("singletons")
4751	headerTemplate := template.New("singletonHeader")
4752	_, err := headerTemplate.Parse(singletonHeaderTemplate)
4753	if err != nil {
4754		// This is a programming error.
4755		panic(err)
4756	}
4757
4758	buf := bytes.NewBuffer(nil)
4759
4760	for _, info := range c.singletonInfo {
4761		if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
4762			continue
4763		}
4764
4765		// Get the name of the factory function for the module.
4766		factory := info.factory
4767		factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
4768		factoryName := factoryFunc.Name()
4769
4770		buf.Reset()
4771		infoMap := map[string]interface{}{
4772			"name":      info.name,
4773			"goFactory": factoryName,
4774		}
4775		err = headerTemplate.Execute(buf, infoMap)
4776		if err != nil {
4777			return err
4778		}
4779
4780		err = nw.Comment(buf.String())
4781		if err != nil {
4782			return err
4783		}
4784
4785		err = nw.BlankLine()
4786		if err != nil {
4787			return err
4788		}
4789
4790		err = c.writeLocalBuildActions(nw, &info.actionDefs)
4791		if err != nil {
4792			return err
4793		}
4794
4795		err = nw.BlankLine()
4796		if err != nil {
4797			return err
4798		}
4799	}
4800
4801	return nil
4802}
4803
4804func (c *Context) GetEventHandler() *metrics.EventHandler {
4805	return c.EventHandler
4806}
4807
4808func (c *Context) BeginEvent(name string) {
4809	c.EventHandler.Begin(name)
4810}
4811
4812func (c *Context) EndEvent(name string) {
4813	c.EventHandler.End(name)
4814}
4815
4816func (c *Context) SetBeforePrepareBuildActionsHook(hookFn func() error) {
4817	c.BeforePrepareBuildActionsHook = hookFn
4818}
4819
4820// keyForPhonyCandidate gives a unique identifier for a set of deps.
4821func keyForPhonyCandidate(stringDeps []string) uint64 {
4822	hasher := fnv.New64a()
4823	write := func(s string) {
4824		// The hasher doesn't retain or modify the input slice, so pass the string data directly to avoid
4825		// an extra allocation and copy.
4826		_, err := hasher.Write(unsafe.Slice(unsafe.StringData(s), len(s)))
4827		if err != nil {
4828			panic(fmt.Errorf("write failed: %w", err))
4829		}
4830	}
4831	for _, d := range stringDeps {
4832		write(d)
4833	}
4834	return hasher.Sum64()
4835}
4836
4837// deduplicateOrderOnlyDeps searches for common sets of order-only dependencies across all
4838// buildDef instances in the provided moduleInfo instances. Each such
4839// common set forms a new buildDef representing a phony output that then becomes
4840// the sole order-only dependency of those buildDef instances
4841func (c *Context) deduplicateOrderOnlyDeps(modules []*moduleInfo) *localBuildActions {
4842	c.BeginEvent("deduplicate_order_only_deps")
4843	defer c.EndEvent("deduplicate_order_only_deps")
4844
4845	var phonys []*buildDef
4846	c.orderOnlyStringsCache = make(OrderOnlyStringsCache)
4847	c.orderOnlyStrings.Range(func(key uniquelist.UniqueList[string], info *orderOnlyStringsInfo) bool {
4848		if info.dedup {
4849			dedup := fmt.Sprintf("dedup-%x", keyForPhonyCandidate(key.ToSlice()))
4850			phony := &buildDef{
4851				Rule:          Phony,
4852				OutputStrings: []string{dedup},
4853				InputStrings:  key.ToSlice(),
4854			}
4855			info.dedupName = dedup
4856			phonys = append(phonys, phony)
4857			if info.incremental {
4858				c.orderOnlyStringsCache[phony.OutputStrings[0]] = phony.InputStrings
4859			}
4860		}
4861		return true
4862	})
4863
4864	parallelVisit(slices.Values(modules), unorderedVisitorImpl{}, parallelVisitLimit,
4865		func(m *moduleInfo, pause chan<- pauseSpec) bool {
4866			for _, def := range m.actionDefs.buildDefs {
4867				if info, loaded := c.orderOnlyStrings.Load(def.OrderOnlyStrings); loaded {
4868					if info.dedup {
4869						def.OrderOnlyStrings = uniquelist.Make([]string{info.dedupName})
4870						m.orderOnlyStrings = append(m.orderOnlyStrings, info.dedupName)
4871					}
4872				}
4873			}
4874			return false
4875		})
4876
4877	return &localBuildActions{buildDefs: phonys}
4878}
4879
4880func (c *Context) cacheModuleBuildActions(module *moduleInfo) {
4881	var providers []CachedProvider
4882	for i, p := range module.providers {
4883		if p != nil && providerRegistry[i].mutator == "" {
4884			providers = append(providers,
4885				CachedProvider{
4886					Id:    providerRegistry[i],
4887					Value: &p,
4888				})
4889		}
4890	}
4891
4892	// These show up in the ninja file, so we need to cache these to ensure we
4893	// re-generate ninja file if they changed.
4894	relPos := module.pos
4895	relPos.Filename = module.relBlueprintsFile
4896	data := BuildActionCachedData{
4897		Providers:        providers,
4898		Pos:              &relPos,
4899		OrderOnlyStrings: module.orderOnlyStrings,
4900	}
4901
4902	c.updateBuildActionsCache(module.buildActionCacheKey, &data)
4903}
4904
4905func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
4906	defs *localBuildActions) error {
4907
4908	// Write the local variable assignments.
4909	for _, v := range defs.variables {
4910		// A localVariable doesn't need the package names or config to
4911		// determine its name or value.
4912		name := v.fullName(nil)
4913		value, err := v.value(nil, nil)
4914		if err != nil {
4915			panic(err)
4916		}
4917		err = nw.Assign(name, value.Value(c.nameTracker))
4918		if err != nil {
4919			return err
4920		}
4921	}
4922
4923	if len(defs.variables) > 0 {
4924		err := nw.BlankLine()
4925		if err != nil {
4926			return err
4927		}
4928	}
4929
4930	// Write the local rules.
4931	for _, r := range defs.rules {
4932		// A localRule doesn't need the package names or config to determine
4933		// its name or definition.
4934		name := r.fullName(nil)
4935		def, err := r.def(nil)
4936		if err != nil {
4937			panic(err)
4938		}
4939
4940		err = def.WriteTo(nw, name, c.nameTracker)
4941		if err != nil {
4942			return err
4943		}
4944
4945		err = nw.BlankLine()
4946		if err != nil {
4947			return err
4948		}
4949	}
4950
4951	// Write the build definitions.
4952	for _, buildDef := range defs.buildDefs {
4953		err := buildDef.WriteTo(nw, c.nameTracker)
4954		if err != nil {
4955			return err
4956		}
4957
4958		if len(buildDef.Args) > 0 {
4959			err = nw.BlankLine()
4960			if err != nil {
4961				return err
4962			}
4963		}
4964	}
4965
4966	return nil
4967}
4968
4969func beforeInModuleList(a, b *moduleInfo, list moduleList) bool {
4970	found := false
4971	if a == b {
4972		return false
4973	}
4974	for _, l := range list {
4975		if l == a {
4976			found = true
4977		} else if l == b {
4978			return found
4979		}
4980	}
4981
4982	missing := a
4983	if found {
4984		missing = b
4985	}
4986	panic(fmt.Errorf("element %v not found in list %v", missing, list))
4987}
4988
4989type panicError struct {
4990	panic interface{}
4991	stack []byte
4992	in    string
4993}
4994
4995func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
4996	buf := make([]byte, 4096)
4997	count := runtime.Stack(buf, false)
4998	return panicError{
4999		panic: panic,
5000		in:    fmt.Sprintf(in, a...),
5001		stack: buf[:count],
5002	}
5003}
5004
5005func (p panicError) Error() string {
5006	return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
5007}
5008
5009func (p *panicError) addIn(in string) {
5010	p.in += " in " + in
5011}
5012
5013func funcName(f interface{}) string {
5014	return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
5015}
5016
5017// json representation of a dependency
5018type depJson struct {
5019	Name    string      `json:"name"`
5020	Variant string      `json:"variant"`
5021	TagType string      `json:"tag_type"`
5022	TagData interface{} `json:"tag_data"`
5023}
5024
5025// json representation of a provider
5026type providerJson struct {
5027	Type   string      `json:"type"`
5028	Debug  string      `json:"debug"` // from GetDebugString on the provider data
5029	Fields interface{} `json:"fields"`
5030}
5031
5032// interface for getting debug info from various data.
5033// TODO: Consider having this return a json object instead
5034type Debuggable interface {
5035	GetDebugString() string
5036}
5037
5038// Convert a slice in a reflect.Value to a value suitable for outputting to json
5039func debugSlice(value reflect.Value) interface{} {
5040	size := value.Len()
5041	if size == 0 {
5042		return nil
5043	}
5044	result := make([]interface{}, size)
5045	for i := 0; i < size; i++ {
5046		result[i] = debugValue(value.Index(i))
5047	}
5048	return result
5049}
5050
5051// Convert a map in a reflect.Value to a value suitable for outputting to json
5052func debugMap(value reflect.Value) interface{} {
5053	if value.IsNil() {
5054		return nil
5055	}
5056	result := make(map[string]interface{})
5057	iter := value.MapRange()
5058	for iter.Next() {
5059		// In the (hopefully) rare case of a key collision (which will happen when multiple
5060		// go-typed keys have the same string representation, we'll just overwrite the last
5061		// value.
5062		result[debugKey(iter.Key())] = debugValue(iter.Value())
5063	}
5064	return result
5065}
5066
5067// Convert a value into a string, suitable for being a json map key.
5068func debugKey(value reflect.Value) string {
5069	return fmt.Sprintf("%v", value)
5070}
5071
5072// Convert a single value (possibly a map or slice too) in a reflect.Value to a value suitable for outputting to json
5073func debugValue(value reflect.Value) interface{} {
5074	// Remember if we originally received a reflect.Interface.
5075	wasInterface := value.Kind() == reflect.Interface
5076	// Dereference pointers down to the real type
5077	for value.Kind() == reflect.Ptr || value.Kind() == reflect.Interface {
5078		// If it's nil, return nil
5079		if value.IsNil() {
5080			return nil
5081		}
5082		value = value.Elem()
5083	}
5084
5085	// Skip private fields, maybe other weird corner cases of go's bizarre type system.
5086	if !value.CanInterface() {
5087		return nil
5088	}
5089
5090	switch kind := value.Kind(); kind {
5091	case reflect.Bool, reflect.String, reflect.Int, reflect.Uint:
5092		return value.Interface()
5093	case reflect.Slice:
5094		return debugSlice(value)
5095	case reflect.Struct:
5096		// If we originally received an interface, and there is a String() method, call that.
5097		// TODO: figure out why Path doesn't work correctly otherwise (in aconfigPropagatingDeclarationsInfo)
5098		if s, ok := value.Interface().(interface{ String() string }); wasInterface && ok {
5099			return s.String()
5100		}
5101		return debugStruct(value)
5102	case reflect.Map:
5103		return debugMap(value)
5104	default:
5105		// TODO: add cases as we find them.
5106		return fmt.Sprintf("debugValue(Kind=%v, wasInterface=%v)", kind, wasInterface)
5107	}
5108
5109	return nil
5110}
5111
5112// Convert an object in a reflect.Value to a value suitable for outputting to json
5113func debugStruct(value reflect.Value) interface{} {
5114	result := make(map[string]interface{})
5115	debugStructAppend(value, &result)
5116	if len(result) == 0 {
5117		return nil
5118	}
5119	return result
5120}
5121
5122// Convert an object to a value suiable for outputting to json
5123func debugStructAppend(value reflect.Value, result *map[string]interface{}) {
5124	for value.Kind() == reflect.Ptr {
5125		if value.IsNil() {
5126			return
5127		}
5128		value = value.Elem()
5129	}
5130	if value.IsZero() {
5131		return
5132	}
5133
5134	if value.Kind() != reflect.Struct {
5135		// TODO: could maybe support other types
5136		return
5137	}
5138
5139	structType := value.Type()
5140	for i := 0; i < value.NumField(); i++ {
5141		v := debugValue(value.Field(i))
5142		if v != nil {
5143			(*result)[structType.Field(i).Name] = v
5144		}
5145	}
5146}
5147
5148func debugPropertyStruct(props interface{}, result *map[string]interface{}) {
5149	if props == nil {
5150		return
5151	}
5152	debugStructAppend(reflect.ValueOf(props), result)
5153}
5154
5155// Get the debug json for a single module. Returns thae data as
5156// flattened json text for easy concatenation by GenerateModuleDebugInfo.
5157func getModuleDebugJson(module *moduleInfo) []byte {
5158	info := struct {
5159		Name       string                 `json:"name"`
5160		SourceFile string                 `json:"source_file"`
5161		SourceLine int                    `json:"source_line"`
5162		Type       string                 `json:"type"`
5163		Variant    string                 `json:"variant"`
5164		Deps       []depJson              `json:"deps"`
5165		Providers  []providerJson         `json:"providers"`
5166		Debug      string                 `json:"debug"` // from GetDebugString on the module
5167		Properties map[string]interface{} `json:"properties"`
5168	}{
5169		Name:       module.logicModule.Name(),
5170		SourceFile: module.pos.Filename,
5171		SourceLine: module.pos.Line,
5172		Type:       module.typeName,
5173		Variant:    module.variant.name,
5174		Deps: func() []depJson {
5175			result := make([]depJson, len(module.directDeps))
5176			for i, dep := range module.directDeps {
5177				result[i] = depJson{
5178					Name:    dep.module.logicModule.Name(),
5179					Variant: dep.module.variant.name,
5180				}
5181				t := reflect.TypeOf(dep.tag)
5182				if t != nil {
5183					result[i].TagType = t.PkgPath() + "." + t.Name()
5184					result[i].TagData = debugStruct(reflect.ValueOf(dep.tag))
5185				}
5186			}
5187			return result
5188		}(),
5189		Providers: func() []providerJson {
5190			result := make([]providerJson, 0, len(module.providers))
5191			for _, p := range module.providers {
5192				pj := providerJson{}
5193				include := false
5194
5195				t := reflect.TypeOf(p)
5196				if t != nil {
5197					pj.Type = t.PkgPath() + "." + t.Name()
5198					include = true
5199				}
5200
5201				if dbg, ok := p.(Debuggable); ok {
5202					pj.Debug = dbg.GetDebugString()
5203					if pj.Debug != "" {
5204						include = true
5205					}
5206				}
5207
5208				if p != nil {
5209					pj.Fields = debugValue(reflect.ValueOf(p))
5210					include = true
5211				}
5212
5213				if include {
5214					result = append(result, pj)
5215				}
5216			}
5217			return result
5218		}(),
5219		Debug: func() string {
5220			if dbg, ok := module.logicModule.(Debuggable); ok {
5221				return dbg.GetDebugString()
5222			} else {
5223				return ""
5224			}
5225		}(),
5226		Properties: func() map[string]interface{} {
5227			result := make(map[string]interface{})
5228			for _, props := range module.properties {
5229				debugPropertyStruct(props, &result)
5230			}
5231			return result
5232		}(),
5233	}
5234	buf, _ := json.Marshal(info)
5235	return buf
5236}
5237
5238// Generate out/soong/soong-debug-info.json Called if GENERATE_SOONG_DEBUG=true.
5239func (this *Context) GenerateModuleDebugInfo(filename string) {
5240	err := os.MkdirAll(filepath.Dir(filename), 0777)
5241	if err != nil {
5242		// We expect this to be writable
5243		panic(fmt.Sprintf("couldn't create directory for soong module debug file %s: %s", filepath.Dir(filename), err))
5244	}
5245
5246	f, err := os.Create(filename)
5247	if err != nil {
5248		// We expect this to be writable
5249		panic(fmt.Sprintf("couldn't create soong module debug file %s: %s", filename, err))
5250	}
5251	defer f.Close()
5252
5253	needComma := false
5254	f.WriteString("{\n\"modules\": [\n")
5255
5256	// TODO: Optimize this (parallel execution, etc) if it gets slow.
5257	this.visitAllModuleInfos(func(module *moduleInfo) {
5258		if needComma {
5259			f.WriteString(",\n")
5260		} else {
5261			needComma = true
5262		}
5263
5264		moduleData := getModuleDebugJson(module)
5265		f.Write(moduleData)
5266	})
5267
5268	f.WriteString("\n]\n}")
5269}
5270
5271var fileHeaderTemplate = `******************************************************************************
5272***            This file is generated and should not be edited             ***
5273******************************************************************************
5274{{if .Pkgs}}
5275This file contains variables, rules, and pools with name prefixes indicating
5276they were generated by the following Go packages:
5277{{range .Pkgs}}
5278    {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
5279
5280`
5281
5282var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
5283Module:  {{.name}}
5284Variant: {{.variant}}
5285Type:    {{.typeName}}
5286Factory: {{.goFactory}}
5287Defined: {{.pos}}
5288`
5289
5290var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
5291Singleton: {{.name}}
5292Factory:   {{.goFactory}}
5293`
5294
5295func JoinPath(base, path string) string {
5296	if filepath.IsAbs(path) {
5297		return path
5298	}
5299	return filepath.Join(base, path)
5300}
5301