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