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