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