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