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