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