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