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