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 "fmt" 19 "path/filepath" 20 "strings" 21 "sync" 22 "text/scanner" 23 24 "github.com/google/blueprint/parser" 25 "github.com/google/blueprint/pathtools" 26 "github.com/google/blueprint/proptools" 27) 28 29// A Module handles generating all of the Ninja build actions needed to build a 30// single module based on properties defined in a Blueprints file. Module 31// objects are initially created during the parse phase of a Context using one 32// of the registered module types (and the associated ModuleFactory function). 33// The Module's properties struct is automatically filled in with the property 34// values specified in the Blueprints file (see Context.RegisterModuleType for more 35// information on this). 36// 37// A Module can be split into multiple Modules by a Mutator. All existing 38// properties set on the module will be duplicated to the new Module, and then 39// modified as necessary by the Mutator. 40// 41// The Module implementation can access the build configuration as well as any 42// modules on which on which it depends (as defined by the "deps" property 43// specified in the Blueprints file, dynamically added by implementing the 44// (deprecated) DynamicDependerModule interface, or dynamically added by a 45// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions. 46// This ModuleContext is also used to create Ninja build actions and to report 47// errors to the user. 48// 49// In addition to implementing the GenerateBuildActions method, a Module should 50// implement methods that provide dependant modules and singletons information 51// they need to generate their build actions. These methods will only be called 52// after GenerateBuildActions is called because the Context calls 53// GenerateBuildActions in dependency-order (and singletons are invoked after 54// all the Modules). The set of methods a Module supports will determine how 55// dependant Modules interact with it. 56// 57// For example, consider a Module that is responsible for generating a library 58// that other modules can link against. The library Module might implement the 59// following interface: 60// 61// type LibraryProducer interface { 62// LibraryFileName() string 63// } 64// 65// func IsLibraryProducer(module blueprint.Module) { 66// _, ok := module.(LibraryProducer) 67// return ok 68// } 69// 70// A binary-producing Module that depends on the library Module could then do: 71// 72// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) { 73// ... 74// var libraryFiles []string 75// ctx.VisitDepsDepthFirstIf(IsLibraryProducer, 76// func(module blueprint.Module) { 77// libProducer := module.(LibraryProducer) 78// libraryFiles = append(libraryFiles, libProducer.LibraryFileName()) 79// }) 80// ... 81// } 82// 83// to build the list of library file names that should be included in its link 84// command. 85// 86// GenerateBuildActions may be called from multiple threads. It is guaranteed to 87// be called after it has finished being called on all dependencies and on all 88// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list. 89// Any accesses to global variables or to Module objects that are not dependencies 90// or variants of the current Module must be synchronized by the implementation of 91// GenerateBuildActions. 92type Module interface { 93 // Name returns a string used to uniquely identify each module. The return 94 // value must be unique across all modules. It is only called once, during 95 // initial blueprint parsing. To change the name later a mutator must call 96 // MutatorContext.Rename 97 // 98 // In most cases, Name should return the contents of a "name:" property from 99 // the blueprint file. An embeddable SimpleName object can be used for this 100 // case. 101 Name() string 102 103 // GenerateBuildActions is called by the Context that created the Module 104 // during its generate phase. This call should generate all Ninja build 105 // actions (rules, pools, and build statements) needed to build the module. 106 GenerateBuildActions(ModuleContext) 107} 108 109// A DynamicDependerModule is a Module that may add dependencies that do not 110// appear in its "deps" property. Any Module that implements this interface 111// will have its DynamicDependencies method called by the Context that created 112// it during generate phase. 113// 114// Deprecated, use a BottomUpMutator instead 115type DynamicDependerModule interface { 116 Module 117 118 // DynamicDependencies is called by the Context that created the 119 // DynamicDependerModule during its generate phase. This call should return 120 // the list of module names that the DynamicDependerModule depends on 121 // dynamically. Module names that already appear in the "deps" property may 122 // but do not need to be included in the returned list. 123 DynamicDependencies(DynamicDependerModuleContext) []string 124} 125 126type EarlyModuleContext interface { 127 // Module returns the current module as a Module. It should rarely be necessary, as the module already has a 128 // reference to itself. 129 Module() Module 130 131 // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when 132 // the module was created, but may have been modified by calls to BaseMutatorContext.Rename. 133 ModuleName() string 134 135 // ModuleDir returns the path to the directory that contains the defintion of the module. 136 ModuleDir() string 137 138 // ModuleType returns the name of the module type that was used to create the module, as specified in 139 // RegisterModuleType. 140 ModuleType() string 141 142 // BlueprintFile returns the name of the blueprint file that contains the definition of this 143 // module. 144 BlueprintsFile() string 145 146 // Config returns the config object that was passed to Context.PrepareBuildActions. 147 Config() interface{} 148 149 // ContainsProperty returns true if the specified property name was set in the module definition. 150 ContainsProperty(name string) bool 151 152 // Errorf reports an error at the specified position of the module definition file. 153 Errorf(pos scanner.Position, fmt string, args ...interface{}) 154 155 // ModuleErrorf reports an error at the line number of the module type in the module definition. 156 ModuleErrorf(fmt string, args ...interface{}) 157 158 // PropertyErrorf reports an error at the line number of a property in the module definition. 159 PropertyErrorf(property, fmt string, args ...interface{}) 160 161 // Failed returns true if any errors have been reported. In most cases the module can continue with generating 162 // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error 163 // has prevented the module from creating necessary data it can return early when Failed returns true. 164 Failed() bool 165 166 // GlobWithDeps returns a list of files and directories that match the 167 // specified pattern but do not match any of the patterns in excludes. 168 // Any directories will have a '/' suffix. It also adds efficient 169 // dependencies to rerun the primary builder whenever a file matching 170 // the pattern as added or removed, without rerunning if a file that 171 // does not match the pattern is added to a searched directory. 172 GlobWithDeps(pattern string, excludes []string) ([]string, error) 173 174 // Fs returns a pathtools.Filesystem that can be used to interact with files. Using the Filesystem interface allows 175 // the module to be used in build system tests that run against a mock filesystem. 176 Fs() pathtools.FileSystem 177 178 // AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The 179 // primary builder will be rerun whenever the specified files are modified. 180 AddNinjaFileDeps(deps ...string) 181 182 moduleInfo() *moduleInfo 183 error(err error) 184 185 // Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the 186 // default SimpleNameInterface if Context.SetNameInterface was not called. 187 Namespace() Namespace 188 189 // ModuleFactories returns a map of all of the global ModuleFactories by name. 190 ModuleFactories() map[string]ModuleFactory 191} 192 193type BaseModuleContext interface { 194 EarlyModuleContext 195 196 // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if 197 // none exists. It panics if the dependency does not have the specified tag. 198 GetDirectDepWithTag(name string, tag DependencyTag) Module 199 200 // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified 201 // name, or nil if none exists. If there are multiple dependencies on the same module it returns 202 // the first DependencyTag. 203 GetDirectDep(name string) (Module, DependencyTag) 204 205 // VisitDirectDeps calls visit for each direct dependency. If there are multiple direct dependencies on the same 206 // module visit will be called multiple times on that module and OtherModuleDependencyTag will return a different 207 // tag for each. 208 // 209 // The Module passed to the visit function should not be retained outside of the visit function, it may be 210 // invalidated by future mutators. 211 VisitDirectDeps(visit func(Module)) 212 213 // VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are 214 // multiple direct dependencies on the same module pred and visit will be called multiple times on that module and 215 // OtherModuleDependencyTag will return a different tag for each. 216 // 217 // The Module passed to the visit function should not be retained outside of the visit function, it may be 218 // invalidated by future mutators. 219 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 220 221 // VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first 222 // order. visit will only be called once for any given module, even if there are multiple paths through the 223 // dependency tree to the module or multiple direct dependencies with different tags. OtherModuleDependencyTag will 224 // return the tag for the first path found to the module. 225 // 226 // The Module passed to the visit function should not be retained outside of the visit function, it may be 227 // invalidated by future mutators. 228 VisitDepsDepthFirst(visit func(Module)) 229 230 // VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing 231 // the dependency tree in depth first order. visit will only be called once for any given module, even if there are 232 // multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. 233 // OtherModuleDependencyTag will return the tag for the first path found to the module. The return value of pred 234 // does not affect which branches of the tree are traversed. 235 // 236 // The Module passed to the visit function should not be retained outside of the visit function, it may be 237 // invalidated by future mutators. 238 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 239 240 // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may 241 // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the 242 // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited 243 // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. 244 // 245 // The Modules passed to the visit function should not be retained outside of the visit function, they may be 246 // invalidated by future mutators. 247 WalkDeps(visit func(Module, Module) bool) 248 249 // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in 250 // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the 251 // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are 252 // only done once for all variants of a module. 253 PrimaryModule() Module 254 255 // FinalModule returns the last variant of the current module. Variants of a module are always visited in 256 // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all 257 // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform 258 // singleton actions that are only done once for all variants of a module. 259 FinalModule() Module 260 261 // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always 262 // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read 263 // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any 264 // data modified by the current mutator. 265 VisitAllModuleVariants(visit func(Module)) 266 267 // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. 268 // It is intended for use inside the visit functions of Visit* and WalkDeps. 269 OtherModuleName(m Module) string 270 271 // OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information. 272 // It is intended for use inside the visit functions of Visit* and WalkDeps. 273 OtherModuleDir(m Module) string 274 275 // OtherModuleSubDir returns the unique subdirectory name of another Module. See ModuleContext.ModuleSubDir for 276 // more information. 277 // It is intended for use inside the visit functions of Visit* and WalkDeps. 278 OtherModuleSubDir(m Module) string 279 280 // OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information. 281 // It is intended for use inside the visit functions of Visit* and WalkDeps. 282 OtherModuleType(m Module) string 283 284 // OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information. 285 // It is intended for use inside the visit functions of Visit* and WalkDeps. 286 OtherModuleErrorf(m Module, fmt string, args ...interface{}) 287 288 // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency 289 // on the module. When called inside a Visit* method with current module being visited, and there are multiple 290 // dependencies on the module being visited, it returns the dependency tag used for the current dependency. 291 OtherModuleDependencyTag(m Module) DependencyTag 292 293 // OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface 294 // passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. 295 OtherModuleExists(name string) bool 296 297 // OtherModuleDependencyVariantExists returns true if a module with the 298 // specified name and variant exists. The variant must match the given 299 // variations. It must also match all the non-local variations of the current 300 // module. In other words, it checks for the module that AddVariationDependencies 301 // would add a dependency on with the same arguments. 302 OtherModuleDependencyVariantExists(variations []Variation, name string) bool 303 304 // OtherModuleFarDependencyVariantExists returns true if a module with the 305 // specified name and variant exists. The variant must match the given 306 // variations, but not the non-local variations of the current module. In 307 // other words, it checks for the module that AddFarVariationDependencies 308 // would add a dependency on with the same arguments. 309 OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool 310 311 // OtherModuleReverseDependencyVariantExists returns true if a module with the 312 // specified name exists with the same variations as the current module. In 313 // other words, it checks for the module that AddReverseDependency would add a 314 // dependency on with the same argument. 315 OtherModuleReverseDependencyVariantExists(name string) bool 316 317 // OtherModuleProvider returns the value for a provider for the given module. If the value is 318 // not set it returns the zero value of the type of the provider, so the return value can always 319 // be type asserted to the type of the provider. The value returned may be a deep copy of the 320 // value originally passed to SetProvider. 321 OtherModuleProvider(m Module, provider ProviderKey) interface{} 322 323 // OtherModuleHasProvider returns true if the provider for the given module has been set. 324 OtherModuleHasProvider(m Module, provider ProviderKey) bool 325 326 // Provider returns the value for a provider for the current module. If the value is 327 // not set it returns the zero value of the type of the provider, so the return value can always 328 // be type asserted to the type of the provider. It panics if called before the appropriate 329 // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep 330 // copy of the value originally passed to SetProvider. 331 Provider(provider ProviderKey) interface{} 332 333 // HasProvider returns true if the provider for the current module has been set. 334 HasProvider(provider ProviderKey) bool 335 336 // SetProvider sets the value for a provider for the current module. It panics if not called 337 // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value 338 // is not of the appropriate type, or if the value has already been set. The value should not 339 // be modified after being passed to SetProvider. 340 SetProvider(provider ProviderKey, value interface{}) 341} 342 343type DynamicDependerModuleContext BottomUpMutatorContext 344 345type ModuleContext interface { 346 BaseModuleContext 347 348 // ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path 349 // to ensure that each variant of a module gets its own intermediates directory to write to. 350 ModuleSubDir() string 351 352 // Variable creates a new ninja variable scoped to the module. It can be referenced by calls to Rule and Build 353 // in the same module. 354 Variable(pctx PackageContext, name, value string) 355 356 // Rule creates a new ninja rule scoped to the module. It can be referenced by calls to Build in the same module. 357 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 358 359 // Build creates a new ninja build statement. 360 Build(pctx PackageContext, params BuildParams) 361 362 // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, 363 // but do not exist. It can be used with Context.SetAllowMissingDependencies to allow the primary builder to 364 // handle missing dependencies on its own instead of having Blueprint treat them as an error. 365 GetMissingDependencies() []string 366} 367 368var _ BaseModuleContext = (*baseModuleContext)(nil) 369 370type baseModuleContext struct { 371 context *Context 372 config interface{} 373 module *moduleInfo 374 errs []error 375 visitingParent *moduleInfo 376 visitingDep depInfo 377 ninjaFileDeps []string 378} 379 380func (d *baseModuleContext) moduleInfo() *moduleInfo { 381 return d.module 382} 383 384func (d *baseModuleContext) Module() Module { 385 return d.module.logicModule 386} 387 388func (d *baseModuleContext) ModuleName() string { 389 return d.module.Name() 390} 391 392func (d *baseModuleContext) ModuleType() string { 393 return d.module.typeName 394} 395 396func (d *baseModuleContext) ContainsProperty(name string) bool { 397 _, ok := d.module.propertyPos[name] 398 return ok 399} 400 401func (d *baseModuleContext) ModuleDir() string { 402 return filepath.Dir(d.module.relBlueprintsFile) 403} 404 405func (d *baseModuleContext) BlueprintsFile() string { 406 return d.module.relBlueprintsFile 407} 408 409func (d *baseModuleContext) Config() interface{} { 410 return d.config 411} 412 413func (d *baseModuleContext) error(err error) { 414 if err != nil { 415 d.errs = append(d.errs, err) 416 } 417} 418 419func (d *baseModuleContext) Errorf(pos scanner.Position, 420 format string, args ...interface{}) { 421 422 d.error(&BlueprintError{ 423 Err: fmt.Errorf(format, args...), 424 Pos: pos, 425 }) 426} 427 428func (d *baseModuleContext) ModuleErrorf(format string, 429 args ...interface{}) { 430 431 d.error(&ModuleError{ 432 BlueprintError: BlueprintError{ 433 Err: fmt.Errorf(format, args...), 434 Pos: d.module.pos, 435 }, 436 module: d.module, 437 }) 438} 439 440func (d *baseModuleContext) PropertyErrorf(property, format string, 441 args ...interface{}) { 442 443 pos := d.module.propertyPos[property] 444 445 if !pos.IsValid() { 446 pos = d.module.pos 447 } 448 449 d.error(&PropertyError{ 450 ModuleError: ModuleError{ 451 BlueprintError: BlueprintError{ 452 Err: fmt.Errorf(format, args...), 453 Pos: pos, 454 }, 455 module: d.module, 456 }, 457 property: property, 458 }) 459} 460 461func (d *baseModuleContext) Failed() bool { 462 return len(d.errs) > 0 463} 464 465func (d *baseModuleContext) GlobWithDeps(pattern string, 466 excludes []string) ([]string, error) { 467 return d.context.glob(pattern, excludes) 468} 469 470func (d *baseModuleContext) Fs() pathtools.FileSystem { 471 return d.context.fs 472} 473 474func (d *baseModuleContext) Namespace() Namespace { 475 return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module)) 476} 477 478var _ ModuleContext = (*moduleContext)(nil) 479 480type moduleContext struct { 481 baseModuleContext 482 scope *localScope 483 actionDefs localBuildActions 484 handledMissingDeps bool 485} 486 487func (m *baseModuleContext) OtherModuleName(logicModule Module) string { 488 module := m.context.moduleInfo[logicModule] 489 return module.Name() 490} 491 492func (m *baseModuleContext) OtherModuleDir(logicModule Module) string { 493 module := m.context.moduleInfo[logicModule] 494 return filepath.Dir(module.relBlueprintsFile) 495} 496 497func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string { 498 module := m.context.moduleInfo[logicModule] 499 return module.variant.name 500} 501 502func (m *baseModuleContext) OtherModuleType(logicModule Module) string { 503 module := m.context.moduleInfo[logicModule] 504 return module.typeName 505} 506 507func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string, 508 args ...interface{}) { 509 510 module := m.context.moduleInfo[logicModule] 511 m.errs = append(m.errs, &ModuleError{ 512 BlueprintError: BlueprintError{ 513 Err: fmt.Errorf(format, args...), 514 Pos: module.pos, 515 }, 516 module: module, 517 }) 518} 519 520func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag { 521 // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps 522 if logicModule == m.visitingDep.module.logicModule { 523 return m.visitingDep.tag 524 } 525 526 for _, dep := range m.visitingParent.directDeps { 527 if dep.module.logicModule == logicModule { 528 return dep.tag 529 } 530 } 531 532 return nil 533} 534 535func (m *baseModuleContext) OtherModuleExists(name string) bool { 536 _, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace()) 537 return exists 538} 539 540func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Variation, name string) bool { 541 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 542 if possibleDeps == nil { 543 return false 544 } 545 found, _ := findVariant(m.module, possibleDeps, variations, false, false) 546 return found != nil 547} 548 549func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool { 550 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 551 if possibleDeps == nil { 552 return false 553 } 554 found, _ := findVariant(m.module, possibleDeps, variations, true, false) 555 return found != nil 556} 557 558func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { 559 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 560 if possibleDeps == nil { 561 return false 562 } 563 found, _ := findVariant(m.module, possibleDeps, nil, false, true) 564 return found != nil 565} 566 567func (m *baseModuleContext) OtherModuleProvider(logicModule Module, provider ProviderKey) interface{} { 568 module := m.context.moduleInfo[logicModule] 569 value, _ := m.context.provider(module, provider) 570 return value 571} 572 573func (m *baseModuleContext) OtherModuleHasProvider(logicModule Module, provider ProviderKey) bool { 574 module := m.context.moduleInfo[logicModule] 575 _, ok := m.context.provider(module, provider) 576 return ok 577} 578 579func (m *baseModuleContext) Provider(provider ProviderKey) interface{} { 580 value, _ := m.context.provider(m.module, provider) 581 return value 582} 583 584func (m *baseModuleContext) HasProvider(provider ProviderKey) bool { 585 _, ok := m.context.provider(m.module, provider) 586 return ok 587} 588 589func (m *baseModuleContext) SetProvider(provider ProviderKey, value interface{}) { 590 m.context.setProvider(m.module, provider, value) 591} 592 593func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) { 594 for _, dep := range m.module.directDeps { 595 if dep.module.Name() == name { 596 return dep.module.logicModule, dep.tag 597 } 598 } 599 600 return nil, nil 601} 602 603func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module { 604 var deps []depInfo 605 for _, dep := range m.module.directDeps { 606 if dep.module.Name() == name { 607 if dep.tag == tag { 608 return dep.module.logicModule 609 } 610 deps = append(deps, dep) 611 } 612 } 613 614 if len(deps) != 0 { 615 panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps)) 616 } 617 618 return nil 619} 620 621func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) { 622 defer func() { 623 if r := recover(); r != nil { 624 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s", 625 m.module, funcName(visit), m.visitingDep.module)) 626 } 627 }() 628 629 m.visitingParent = m.module 630 631 for _, dep := range m.module.directDeps { 632 m.visitingDep = dep 633 visit(dep.module.logicModule) 634 } 635 636 m.visitingParent = nil 637 m.visitingDep = depInfo{} 638} 639 640func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 641 defer func() { 642 if r := recover(); r != nil { 643 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s", 644 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 645 } 646 }() 647 648 m.visitingParent = m.module 649 650 for _, dep := range m.module.directDeps { 651 m.visitingDep = dep 652 if pred(dep.module.logicModule) { 653 visit(dep.module.logicModule) 654 } 655 } 656 657 m.visitingParent = nil 658 m.visitingDep = depInfo{} 659} 660 661func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { 662 defer func() { 663 if r := recover(); r != nil { 664 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s", 665 m.module, funcName(visit), m.visitingDep.module)) 666 } 667 }() 668 669 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 670 m.visitingParent = parent 671 m.visitingDep = dep 672 visit(dep.module.logicModule) 673 }) 674 675 m.visitingParent = nil 676 m.visitingDep = depInfo{} 677} 678 679func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, 680 visit func(Module)) { 681 682 defer func() { 683 if r := recover(); r != nil { 684 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s", 685 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 686 } 687 }() 688 689 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 690 if pred(dep.module.logicModule) { 691 m.visitingParent = parent 692 m.visitingDep = dep 693 visit(dep.module.logicModule) 694 } 695 }) 696 697 m.visitingParent = nil 698 m.visitingDep = depInfo{} 699} 700 701func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) { 702 m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool { 703 m.visitingParent = parent 704 m.visitingDep = dep 705 return visit(dep.module.logicModule, parent.logicModule) 706 }, nil) 707 708 m.visitingParent = nil 709 m.visitingDep = depInfo{} 710} 711 712func (m *baseModuleContext) PrimaryModule() Module { 713 return m.module.group.modules.firstModule().logicModule 714} 715 716func (m *baseModuleContext) FinalModule() Module { 717 return m.module.group.modules.lastModule().logicModule 718} 719 720func (m *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { 721 m.context.visitAllModuleVariants(m.module, visit) 722} 723 724func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) { 725 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...) 726} 727 728func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory { 729 ret := make(map[string]ModuleFactory) 730 for k, v := range m.context.moduleFactories { 731 ret[k] = v 732 } 733 return ret 734} 735 736func (m *moduleContext) ModuleSubDir() string { 737 return m.module.variant.name 738} 739 740func (m *moduleContext) Variable(pctx PackageContext, name, value string) { 741 m.scope.ReparentTo(pctx) 742 743 v, err := m.scope.AddLocalVariable(name, value) 744 if err != nil { 745 panic(err) 746 } 747 748 m.actionDefs.variables = append(m.actionDefs.variables, v) 749} 750 751func (m *moduleContext) Rule(pctx PackageContext, name string, 752 params RuleParams, argNames ...string) Rule { 753 754 m.scope.ReparentTo(pctx) 755 756 r, err := m.scope.AddLocalRule(name, ¶ms, argNames...) 757 if err != nil { 758 panic(err) 759 } 760 761 m.actionDefs.rules = append(m.actionDefs.rules, r) 762 763 return r 764} 765 766func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { 767 m.scope.ReparentTo(pctx) 768 769 def, err := parseBuildParams(m.scope, ¶ms) 770 if err != nil { 771 panic(err) 772 } 773 774 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def) 775} 776 777func (m *moduleContext) GetMissingDependencies() []string { 778 m.handledMissingDeps = true 779 return m.module.missingDeps 780} 781 782// 783// MutatorContext 784// 785 786type mutatorContext struct { 787 baseModuleContext 788 name string 789 reverseDeps []reverseDep 790 rename []rename 791 replace []replace 792 newVariations modulesOrAliases // new variants of existing modules 793 newModules []*moduleInfo // brand new modules 794 defaultVariation *string 795 pauseCh chan<- pauseSpec 796} 797 798type BaseMutatorContext interface { 799 BaseModuleContext 800 801 // Rename all variants of a module. The new name is not visible to calls to ModuleName, 802 // AddDependency or OtherModuleName until after this mutator pass is complete. 803 Rename(name string) 804 805 // MutatorName returns the name that this mutator was registered with. 806 MutatorName() string 807} 808 809type EarlyMutatorContext interface { 810 BaseMutatorContext 811 812 // CreateVariations splits a module into mulitple variants, one for each name in the variationNames 813 // parameter. It returns a list of new modules in the same order as the variationNames 814 // list. 815 // 816 // If any of the dependencies of the module being operated on were already split 817 // by calling CreateVariations with the same name, the dependency will automatically 818 // be updated to point the matching variant. 819 // 820 // If a module is split, and then a module depending on the first module is not split 821 // when the Mutator is later called on it, the dependency of the depending module will 822 // automatically be updated to point to the first variant. 823 CreateVariations(...string) []Module 824 825 // CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames 826 // parameter. It returns a list of new modules in the same order as the variantNames 827 // list. 828 // 829 // Local variations do not affect automatic dependency resolution - dependencies added 830 // to the split module via deps or DynamicDependerModule must exactly match a variant 831 // that contains all the non-local variations. 832 CreateLocalVariations(...string) []Module 833} 834 835type TopDownMutatorContext interface { 836 BaseMutatorContext 837 838 // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies 839 // the specified property structs to it as if the properties were set in a blueprint file. 840 CreateModule(ModuleFactory, ...interface{}) Module 841} 842 843type BottomUpMutatorContext interface { 844 BaseMutatorContext 845 846 // AddDependency adds a dependency to the given module. It returns a slice of modules for each 847 // dependency (some entries may be nil). Does not affect the ordering of the current mutator 848 // pass, but will be ordered correctly for all future mutator passes. 849 // 850 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 851 // new dependencies have had the current mutator called on them. If the mutator is not 852 // parallel this method does not affect the ordering of the current mutator pass, but will 853 // be ordered correctly for all future mutator passes. 854 AddDependency(module Module, tag DependencyTag, name ...string) []Module 855 856 // AddReverseDependency adds a dependency from the destination to the given module. 857 // Does not affect the ordering of the current mutator pass, but will be ordered 858 // correctly for all future mutator passes. All reverse dependencies for a destination module are 859 // collected until the end of the mutator pass, sorted by name, and then appended to the destination 860 // module's dependency list. 861 AddReverseDependency(module Module, tag DependencyTag, name string) 862 863 // CreateVariations splits a module into mulitple variants, one for each name in the variationNames 864 // parameter. It returns a list of new modules in the same order as the variationNames 865 // list. 866 // 867 // If any of the dependencies of the module being operated on were already split 868 // by calling CreateVariations with the same name, the dependency will automatically 869 // be updated to point the matching variant. 870 // 871 // If a module is split, and then a module depending on the first module is not split 872 // when the Mutator is later called on it, the dependency of the depending module will 873 // automatically be updated to point to the first variant. 874 CreateVariations(...string) []Module 875 876 // CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames 877 // parameter. It returns a list of new modules in the same order as the variantNames 878 // list. 879 // 880 // Local variations do not affect automatic dependency resolution - dependencies added 881 // to the split module via deps or DynamicDependerModule must exactly match a variant 882 // that contains all the non-local variations. 883 CreateLocalVariations(...string) []Module 884 885 // SetDependencyVariation sets all dangling dependencies on the current module to point to the variation 886 // with given name. This function ignores the default variation set by SetDefaultDependencyVariation. 887 SetDependencyVariation(string) 888 889 // SetDefaultDependencyVariation sets the default variation when a dangling reference is detected 890 // during the subsequent calls on Create*Variations* functions. To reset, set it to nil. 891 SetDefaultDependencyVariation(*string) 892 893 // AddVariationDependencies adds deps as dependencies of the current module, but uses the variations 894 // argument to select which variant of the dependency to use. It returns a slice of modules for 895 // each dependency (some entries may be nil). A variant of the dependency must exist that matches 896 // the all of the non-local variations of the current module, plus the variations argument. 897 // 898 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 899 // new dependencies have had the current mutator called on them. If the mutator is not 900 // parallel this method does not affect the ordering of the current mutator pass, but will 901 // be ordered correctly for all future mutator passes. 902 AddVariationDependencies([]Variation, DependencyTag, ...string) []Module 903 904 // AddFarVariationDependencies adds deps as dependencies of the current module, but uses the 905 // variations argument to select which variant of the dependency to use. It returns a slice of 906 // modules for each dependency (some entries may be nil). A variant of the dependency must 907 // exist that matches the variations argument, but may also have other variations. 908 // For any unspecified variation the first variant will be used. 909 // 910 // Unlike AddVariationDependencies, the variations of the current module are ignored - the 911 // dependency only needs to match the supplied variations. 912 // 913 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 914 // new dependencies have had the current mutator called on them. If the mutator is not 915 // parallel this method does not affect the ordering of the current mutator pass, but will 916 // be ordered correctly for all future mutator passes. 917 AddFarVariationDependencies([]Variation, DependencyTag, ...string) []Module 918 919 // AddInterVariantDependency adds a dependency between two variants of the same module. Variants are always 920 // ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change 921 // that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps, 922 // WalkDeps, etc. 923 AddInterVariantDependency(tag DependencyTag, from, to Module) 924 925 // ReplaceDependencies replaces all dependencies on the identical variant of the module with the 926 // specified name with the current variant of this module. Replacements don't take effect until 927 // after the mutator pass is finished. 928 ReplaceDependencies(string) 929 930 // ReplaceDependencies replaces all dependencies on the identical variant of the module with the 931 // specified name with the current variant of this module as long as the supplied predicate returns 932 // true. 933 // 934 // Replacements don't take effect until after the mutator pass is finished. 935 ReplaceDependenciesIf(string, ReplaceDependencyPredicate) 936 937 // AliasVariation takes a variationName that was passed to CreateVariations for this module, 938 // and creates an alias from the current variant (before the mutator has run) to the new 939 // variant. The alias will be valid until the next time a mutator calls CreateVariations or 940 // CreateLocalVariations on this module without also calling AliasVariation. The alias can 941 // be used to add dependencies on the newly created variant using the variant map from 942 // before CreateVariations was run. 943 AliasVariation(variationName string) 944 945 // CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this 946 // module, and creates an alias from a new fromVariationName variant the toVariationName 947 // variant. The alias will be valid until the next time a mutator calls CreateVariations or 948 // CreateLocalVariations on this module without also calling AliasVariation. The alias can 949 // be used to add dependencies on the toVariationName variant using the fromVariationName 950 // variant. 951 CreateAliasVariation(fromVariationName, toVariationName string) 952 953 // SetVariationProvider sets the value for a provider for the given newly created variant of 954 // the current module, i.e. one of the Modules returned by CreateVariations.. It panics if 955 // not called during the appropriate mutator or GenerateBuildActions pass for the provider, 956 // if the value is not of the appropriate type, or if the module is not a newly created 957 // variant of the current module. The value should not be modified after being passed to 958 // SetVariationProvider. 959 SetVariationProvider(module Module, provider ProviderKey, value interface{}) 960} 961 962// A Mutator function is called for each Module, and can use 963// MutatorContext.CreateVariations to split a Module into multiple Modules, 964// modifying properties on the new modules to differentiate them. It is called 965// after parsing all Blueprint files, but before generating any build rules, 966// and is always called on dependencies before being called on the depending module. 967// 968// The Mutator function should only modify members of properties structs, and not 969// members of the module struct itself, to ensure the modified values are copied 970// if a second Mutator chooses to split the module a second time. 971type TopDownMutator func(mctx TopDownMutatorContext) 972type BottomUpMutator func(mctx BottomUpMutatorContext) 973type EarlyMutator func(mctx EarlyMutatorContext) 974 975// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be 976// used to transfer information on a dependency between the mutator that called AddDependency 977// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the 978// interface (pointing to the same concrete object) from their original module. 979type DependencyTag interface { 980 dependencyTag(DependencyTag) 981} 982 983type BaseDependencyTag struct { 984} 985 986func (BaseDependencyTag) dependencyTag(DependencyTag) { 987} 988 989var _ DependencyTag = BaseDependencyTag{} 990 991func (mctx *mutatorContext) MutatorName() string { 992 return mctx.name 993} 994 995func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module { 996 return mctx.createVariations(variationNames, false) 997} 998 999func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module { 1000 return mctx.createVariations(variationNames, true) 1001} 1002 1003func (mctx *mutatorContext) SetVariationProvider(module Module, provider ProviderKey, value interface{}) { 1004 for _, variant := range mctx.newVariations { 1005 if m := variant.module(); m != nil && m.logicModule == module { 1006 mctx.context.setProvider(m, provider, value) 1007 return 1008 } 1009 } 1010 panic(fmt.Errorf("module %q is not a newly created variant of %q", module, mctx.module)) 1011} 1012 1013type pendingAlias struct { 1014 fromVariant variant 1015 target *moduleInfo 1016} 1017 1018func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module { 1019 ret := []Module{} 1020 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames, local) 1021 if len(errs) > 0 { 1022 mctx.errs = append(mctx.errs, errs...) 1023 } 1024 1025 for _, module := range modules { 1026 ret = append(ret, module.module().logicModule) 1027 } 1028 1029 if mctx.newVariations != nil { 1030 panic("module already has variations from this mutator") 1031 } 1032 mctx.newVariations = modules 1033 1034 if len(ret) != len(variationNames) { 1035 panic("oops!") 1036 } 1037 1038 return ret 1039} 1040 1041func (mctx *mutatorContext) AliasVariation(variationName string) { 1042 for _, moduleOrAlias := range mctx.module.splitModules { 1043 if alias := moduleOrAlias.alias(); alias != nil { 1044 if alias.variant.variations.equal(mctx.module.variant.variations) { 1045 panic(fmt.Errorf("AliasVariation already called")) 1046 } 1047 } 1048 } 1049 1050 for _, variant := range mctx.newVariations { 1051 if variant.moduleOrAliasVariant().variations[mctx.name] == variationName { 1052 alias := &moduleAlias{ 1053 variant: mctx.module.variant, 1054 target: variant.moduleOrAliasTarget(), 1055 } 1056 // Prepend the alias so that AddFarVariationDependencies subset match matches 1057 // the alias before matching the first variation. 1058 mctx.module.splitModules = append(modulesOrAliases{alias}, mctx.module.splitModules...) 1059 return 1060 } 1061 } 1062 1063 var foundVariations []string 1064 for _, variant := range mctx.newVariations { 1065 foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name]) 1066 } 1067 panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations)) 1068} 1069 1070func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) { 1071 newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false) 1072 1073 for _, moduleOrAlias := range mctx.module.splitModules { 1074 if moduleOrAlias.moduleOrAliasVariant().variations.equal(newVariant.variations) { 1075 if alias := moduleOrAlias.alias(); alias != nil { 1076 panic(fmt.Errorf("can't alias %q to %q, already aliased to %q", aliasVariationName, targetVariationName, alias.target.variant.name)) 1077 } else { 1078 panic(fmt.Errorf("can't alias %q to %q, there is already a variant with that name", aliasVariationName, targetVariationName)) 1079 } 1080 } 1081 } 1082 1083 for _, variant := range mctx.newVariations { 1084 if variant.moduleOrAliasVariant().variations[mctx.name] == targetVariationName { 1085 // Append the alias here so that it comes after any aliases created by AliasVariation. 1086 mctx.module.splitModules = append(mctx.module.splitModules, &moduleAlias{ 1087 variant: newVariant, 1088 target: variant.moduleOrAliasTarget(), 1089 }) 1090 return 1091 } 1092 } 1093 1094 var foundVariations []string 1095 for _, variant := range mctx.newVariations { 1096 foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name]) 1097 } 1098 panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations)) 1099} 1100 1101func (mctx *mutatorContext) SetDependencyVariation(variationName string) { 1102 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil) 1103} 1104 1105func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) { 1106 mctx.defaultVariation = variationName 1107} 1108 1109func (mctx *mutatorContext) Module() Module { 1110 return mctx.module.logicModule 1111} 1112 1113func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) []Module { 1114 depInfos := make([]Module, 0, len(deps)) 1115 for _, dep := range deps { 1116 modInfo := mctx.context.moduleInfo[module] 1117 depInfo, errs := mctx.context.addDependency(modInfo, tag, dep) 1118 if len(errs) > 0 { 1119 mctx.errs = append(mctx.errs, errs...) 1120 } 1121 if !mctx.pause(depInfo) { 1122 // Pausing not supported by this mutator, new dependencies can't be returned. 1123 depInfo = nil 1124 } 1125 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1126 } 1127 return depInfos 1128} 1129 1130func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) { 1131 if _, ok := tag.(BaseDependencyTag); ok { 1132 panic("BaseDependencyTag is not allowed to be used directly!") 1133 } 1134 1135 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName) 1136 if len(errs) > 0 { 1137 mctx.errs = append(mctx.errs, errs...) 1138 return 1139 } 1140 1141 mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{ 1142 destModule, 1143 depInfo{mctx.context.moduleInfo[module], tag}, 1144 }) 1145} 1146 1147func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag, 1148 deps ...string) []Module { 1149 1150 depInfos := make([]Module, 0, len(deps)) 1151 for _, dep := range deps { 1152 depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false) 1153 if len(errs) > 0 { 1154 mctx.errs = append(mctx.errs, errs...) 1155 } 1156 if !mctx.pause(depInfo) { 1157 // Pausing not supported by this mutator, new dependencies can't be returned. 1158 depInfo = nil 1159 } 1160 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1161 } 1162 return depInfos 1163} 1164 1165func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag, 1166 deps ...string) []Module { 1167 1168 depInfos := make([]Module, 0, len(deps)) 1169 for _, dep := range deps { 1170 depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true) 1171 if len(errs) > 0 { 1172 mctx.errs = append(mctx.errs, errs...) 1173 } 1174 if !mctx.pause(depInfo) { 1175 // Pausing not supported by this mutator, new dependencies can't be returned. 1176 depInfo = nil 1177 } 1178 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1179 } 1180 return depInfos 1181} 1182 1183func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) { 1184 mctx.context.addInterVariantDependency(mctx.module, tag, from, to) 1185} 1186 1187func (mctx *mutatorContext) ReplaceDependencies(name string) { 1188 mctx.ReplaceDependenciesIf(name, nil) 1189} 1190 1191type ReplaceDependencyPredicate func(from Module, tag DependencyTag, to Module) bool 1192 1193func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate ReplaceDependencyPredicate) { 1194 target := mctx.context.moduleMatchingVariant(mctx.module, name) 1195 1196 if target == nil { 1197 panic(fmt.Errorf("ReplaceDependencies could not find identical variant {%s} for module %s\n"+ 1198 "available variants:\n %s", 1199 mctx.context.prettyPrintVariant(mctx.module.variant.variations), 1200 name, 1201 mctx.context.prettyPrintGroupVariants(mctx.context.moduleGroupFromName(name, mctx.module.namespace())))) 1202 } 1203 1204 mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate}) 1205} 1206 1207func (mctx *mutatorContext) Rename(name string) { 1208 mctx.rename = append(mctx.rename, rename{mctx.module.group, name}) 1209} 1210 1211func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { 1212 module := newModule(factory) 1213 1214 module.relBlueprintsFile = mctx.module.relBlueprintsFile 1215 module.pos = mctx.module.pos 1216 module.propertyPos = mctx.module.propertyPos 1217 module.createdBy = mctx.module 1218 1219 for _, p := range props { 1220 err := proptools.AppendMatchingProperties(module.properties, p, nil) 1221 if err != nil { 1222 panic(err) 1223 } 1224 } 1225 1226 mctx.newModules = append(mctx.newModules, module) 1227 1228 return module.logicModule 1229} 1230 1231// pause waits until the given dependency has been visited by the mutator's parallelVisit call. 1232// It returns true if the pause was supported, false if the pause was not supported and did not 1233// occur, which will happen when the mutator is not parallelizable. If the dependency is nil 1234// it returns true if pausing is supported or false if it is not. 1235func (mctx *mutatorContext) pause(dep *moduleInfo) bool { 1236 if mctx.pauseCh != nil { 1237 if dep != nil { 1238 unpause := make(unpause) 1239 mctx.pauseCh <- pauseSpec{ 1240 paused: mctx.module, 1241 until: dep, 1242 unpause: unpause, 1243 } 1244 <-unpause 1245 } 1246 return true 1247 } 1248 return false 1249} 1250 1251// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property 1252// called "name". Modules that embed it must also add SimpleName.Properties to their property 1253// structure list. 1254type SimpleName struct { 1255 Properties struct { 1256 Name string 1257 } 1258} 1259 1260func (s *SimpleName) Name() string { 1261 return s.Properties.Name 1262} 1263 1264// Load Hooks 1265 1266type LoadHookContext interface { 1267 EarlyModuleContext 1268 1269 // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies 1270 // the specified property structs to it as if the properties were set in a blueprint file. 1271 CreateModule(ModuleFactory, ...interface{}) Module 1272 1273 // RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints 1274 // file. 1275 RegisterScopedModuleType(name string, factory ModuleFactory) 1276} 1277 1278func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { 1279 module := newModule(factory) 1280 1281 module.relBlueprintsFile = l.module.relBlueprintsFile 1282 module.pos = l.module.pos 1283 module.propertyPos = l.module.propertyPos 1284 module.createdBy = l.module 1285 1286 for _, p := range props { 1287 err := proptools.AppendMatchingProperties(module.properties, p, nil) 1288 if err != nil { 1289 panic(err) 1290 } 1291 } 1292 1293 l.newModules = append(l.newModules, module) 1294 1295 return module.logicModule 1296} 1297 1298func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) { 1299 if _, exists := l.context.moduleFactories[name]; exists { 1300 panic(fmt.Errorf("A global module type named %q already exists", name)) 1301 } 1302 1303 if _, exists := (*l.scopedModuleFactories)[name]; exists { 1304 panic(fmt.Errorf("A module type named %q already exists in this scope", name)) 1305 } 1306 1307 if *l.scopedModuleFactories == nil { 1308 (*l.scopedModuleFactories) = make(map[string]ModuleFactory) 1309 } 1310 1311 (*l.scopedModuleFactories)[name] = factory 1312} 1313 1314type loadHookContext struct { 1315 baseModuleContext 1316 newModules []*moduleInfo 1317 scopedModuleFactories *map[string]ModuleFactory 1318} 1319 1320type LoadHook func(ctx LoadHookContext) 1321 1322// Load hooks need to be added by module factories, which don't have any parameter to get to the 1323// Context, and only produce a Module interface with no base implementation, so the load hooks 1324// must be stored in a global map. The key is a pointer allocated by the module factory, so there 1325// is no chance of collisions even if tests are running in parallel with multiple contexts. The 1326// contents should be short-lived, they are added during a module factory and removed immediately 1327// after the module factory returns. 1328var pendingHooks sync.Map 1329 1330func AddLoadHook(module Module, hook LoadHook) { 1331 // Only one goroutine can be processing a given module, so no additional locking is required 1332 // for the slice stored in the sync.Map. 1333 v, exists := pendingHooks.Load(module) 1334 if !exists { 1335 v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook)) 1336 } 1337 hooks := v.(*[]LoadHook) 1338 *hooks = append(*hooks, hook) 1339} 1340 1341func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo, 1342 scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, deps []string, errs []error) { 1343 1344 if v, exists := pendingHooks.Load(module.logicModule); exists { 1345 hooks := v.(*[]LoadHook) 1346 mctx := &loadHookContext{ 1347 baseModuleContext: baseModuleContext{ 1348 context: ctx, 1349 config: config, 1350 module: module, 1351 }, 1352 scopedModuleFactories: scopedModuleFactories, 1353 } 1354 1355 for _, hook := range *hooks { 1356 hook(mctx) 1357 newModules = append(newModules, mctx.newModules...) 1358 deps = append(deps, mctx.ninjaFileDeps...) 1359 errs = append(errs, mctx.errs...) 1360 } 1361 pendingHooks.Delete(module.logicModule) 1362 1363 return newModules, deps, errs 1364 } 1365 1366 return nil, nil, nil 1367} 1368 1369// Check the syntax of a generated blueprint file. 1370// 1371// This is intended to perform a quick syntactic check for generated blueprint 1372// code, where syntactically correct means: 1373// * No variable definitions. 1374// * Valid module types. 1375// * Valid property names. 1376// * Valid values for the property type. 1377// 1378// It does not perform any semantic checking of properties, existence of referenced 1379// files, or dependencies. 1380// 1381// At a low level it: 1382// * Parses the contents. 1383// * Invokes relevant factory to create Module instances. 1384// * Unpacks the properties into the Module. 1385// * Does not invoke load hooks or any mutators. 1386// 1387// The filename is only used for reporting errors. 1388func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error { 1389 scope := parser.NewScope(nil) 1390 file, errs := parser.Parse(filename, strings.NewReader(contents), scope) 1391 if len(errs) != 0 { 1392 return errs 1393 } 1394 1395 for _, def := range file.Defs { 1396 switch def := def.(type) { 1397 case *parser.Module: 1398 _, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false) 1399 errs = append(errs, moduleErrs...) 1400 1401 default: 1402 panic(fmt.Errorf("unknown definition type: %T", def)) 1403 } 1404 } 1405 1406 return errs 1407} 1408 1409func maybeLogicModule(module *moduleInfo) Module { 1410 if module != nil { 1411 return module.logicModule 1412 } else { 1413 return nil 1414 } 1415} 1416