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