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 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 definition 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 // Context.RegisterModuleType(). 140 ModuleType() string 141 142 // BlueprintsFile 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 // VisitDepsDepthFirstIf 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 // ModuleFromName returns (module, true) if a module exists by the given name and same context namespace, 298 // or (nil, false) if it does not exist. It panics if there is either more than one 299 // module of the given name, or if the given name refers to an alias instead of a module. 300 // There are no guarantees about which variant of the module will be returned. 301 // Prefer retrieving the module using GetDirectDep or a visit function, when possible, as 302 // this will guarantee the appropriate module-variant dependency is returned. 303 // 304 // WARNING: This should _only_ be used within the context of bp2build, where variants and 305 // dependencies are not created. 306 ModuleFromName(name string) (Module, bool) 307 308 // OtherModuleDependencyVariantExists returns true if a module with the 309 // specified name and variant exists. The variant must match the given 310 // variations. It must also match all the non-local variations of the current 311 // module. In other words, it checks for the module that AddVariationDependencies 312 // would add a dependency on with the same arguments. 313 OtherModuleDependencyVariantExists(variations []Variation, name string) bool 314 315 // OtherModuleFarDependencyVariantExists returns true if a module with the 316 // specified name and variant exists. The variant must match the given 317 // variations, but not the non-local variations of the current module. In 318 // other words, it checks for the module that AddFarVariationDependencies 319 // would add a dependency on with the same arguments. 320 OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool 321 322 // OtherModuleReverseDependencyVariantExists returns true if a module with the 323 // specified name exists with the same variations as the current module. In 324 // other words, it checks for the module that AddReverseDependency would add a 325 // dependency on with the same argument. 326 OtherModuleReverseDependencyVariantExists(name string) bool 327 328 // OtherModuleProvider returns the value for a provider for the given module. If the value is 329 // not set it returns the zero value of the type of the provider, so the return value can always 330 // be type asserted to the type of the provider. The value returned may be a deep copy of the 331 // value originally passed to SetProvider. 332 OtherModuleProvider(m Module, provider ProviderKey) interface{} 333 334 // OtherModuleHasProvider returns true if the provider for the given module has been set. 335 OtherModuleHasProvider(m Module, provider ProviderKey) bool 336 337 // Provider returns the value for a provider for the current module. If the value is 338 // not set it returns the zero value of the type of the provider, so the return value can always 339 // be type asserted to the type of the provider. It panics if called before the appropriate 340 // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep 341 // copy of the value originally passed to SetProvider. 342 Provider(provider ProviderKey) interface{} 343 344 // HasProvider returns true if the provider for the current module has been set. 345 HasProvider(provider ProviderKey) bool 346 347 // SetProvider sets the value for a provider for the current module. It panics if not called 348 // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value 349 // is not of the appropriate type, or if the value has already been set. The value should not 350 // be modified after being passed to SetProvider. 351 SetProvider(provider ProviderKey, value interface{}) 352} 353 354type DynamicDependerModuleContext BottomUpMutatorContext 355 356type ModuleContext interface { 357 BaseModuleContext 358 359 // ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path 360 // to ensure that each variant of a module gets its own intermediates directory to write to. 361 ModuleSubDir() string 362 363 // Variable creates a new ninja variable scoped to the module. It can be referenced by calls to Rule and Build 364 // in the same module. 365 Variable(pctx PackageContext, name, value string) 366 367 // Rule creates a new ninja rule scoped to the module. It can be referenced by calls to Build in the same module. 368 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 369 370 // Build creates a new ninja build statement. 371 Build(pctx PackageContext, params BuildParams) 372 373 // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, 374 // but do not exist. It can be used with Context.SetAllowMissingDependencies to allow the primary builder to 375 // handle missing dependencies on its own instead of having Blueprint treat them as an error. 376 GetMissingDependencies() []string 377} 378 379var _ BaseModuleContext = (*baseModuleContext)(nil) 380 381type baseModuleContext struct { 382 context *Context 383 config interface{} 384 module *moduleInfo 385 errs []error 386 visitingParent *moduleInfo 387 visitingDep depInfo 388 ninjaFileDeps []string 389} 390 391func (d *baseModuleContext) moduleInfo() *moduleInfo { 392 return d.module 393} 394 395func (d *baseModuleContext) Module() Module { 396 return d.module.logicModule 397} 398 399func (d *baseModuleContext) ModuleName() string { 400 return d.module.Name() 401} 402 403func (d *baseModuleContext) ModuleType() string { 404 return d.module.typeName 405} 406 407func (d *baseModuleContext) ContainsProperty(name string) bool { 408 _, ok := d.module.propertyPos[name] 409 return ok 410} 411 412func (d *baseModuleContext) ModuleDir() string { 413 return filepath.Dir(d.module.relBlueprintsFile) 414} 415 416func (d *baseModuleContext) BlueprintsFile() string { 417 return d.module.relBlueprintsFile 418} 419 420func (d *baseModuleContext) Config() interface{} { 421 return d.config 422} 423 424func (d *baseModuleContext) error(err error) { 425 if err != nil { 426 d.errs = append(d.errs, err) 427 } 428} 429 430func (d *baseModuleContext) Errorf(pos scanner.Position, 431 format string, args ...interface{}) { 432 433 d.error(&BlueprintError{ 434 Err: fmt.Errorf(format, args...), 435 Pos: pos, 436 }) 437} 438 439func (d *baseModuleContext) ModuleErrorf(format string, 440 args ...interface{}) { 441 442 d.error(&ModuleError{ 443 BlueprintError: BlueprintError{ 444 Err: fmt.Errorf(format, args...), 445 Pos: d.module.pos, 446 }, 447 module: d.module, 448 }) 449} 450 451func (d *baseModuleContext) PropertyErrorf(property, format string, 452 args ...interface{}) { 453 454 pos := d.module.propertyPos[property] 455 456 if !pos.IsValid() { 457 pos = d.module.pos 458 } 459 460 d.error(&PropertyError{ 461 ModuleError: ModuleError{ 462 BlueprintError: BlueprintError{ 463 Err: fmt.Errorf(format, args...), 464 Pos: pos, 465 }, 466 module: d.module, 467 }, 468 property: property, 469 }) 470} 471 472func (d *baseModuleContext) Failed() bool { 473 return len(d.errs) > 0 474} 475 476func (d *baseModuleContext) GlobWithDeps(pattern string, 477 excludes []string) ([]string, error) { 478 return d.context.glob(pattern, excludes) 479} 480 481func (d *baseModuleContext) Fs() pathtools.FileSystem { 482 return d.context.fs 483} 484 485func (d *baseModuleContext) Namespace() Namespace { 486 return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module)) 487} 488 489var _ ModuleContext = (*moduleContext)(nil) 490 491type moduleContext struct { 492 baseModuleContext 493 scope *localScope 494 actionDefs localBuildActions 495 handledMissingDeps bool 496} 497 498func (m *baseModuleContext) OtherModuleName(logicModule Module) string { 499 module := m.context.moduleInfo[logicModule] 500 return module.Name() 501} 502 503func (m *baseModuleContext) OtherModuleDir(logicModule Module) string { 504 module := m.context.moduleInfo[logicModule] 505 return filepath.Dir(module.relBlueprintsFile) 506} 507 508func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string { 509 module := m.context.moduleInfo[logicModule] 510 return module.variant.name 511} 512 513func (m *baseModuleContext) OtherModuleType(logicModule Module) string { 514 module := m.context.moduleInfo[logicModule] 515 return module.typeName 516} 517 518func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string, 519 args ...interface{}) { 520 521 module := m.context.moduleInfo[logicModule] 522 m.errs = append(m.errs, &ModuleError{ 523 BlueprintError: BlueprintError{ 524 Err: fmt.Errorf(format, args...), 525 Pos: module.pos, 526 }, 527 module: module, 528 }) 529} 530 531func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag { 532 // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps 533 if logicModule == m.visitingDep.module.logicModule { 534 return m.visitingDep.tag 535 } 536 537 for _, dep := range m.visitingParent.directDeps { 538 if dep.module.logicModule == logicModule { 539 return dep.tag 540 } 541 } 542 543 return nil 544} 545 546func (m *baseModuleContext) ModuleFromName(name string) (Module, bool) { 547 moduleGroup, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace()) 548 if exists { 549 if len(moduleGroup.modules) != 1 { 550 panic(fmt.Errorf("Expected exactly one module named %q, but got %d", name, len(moduleGroup.modules))) 551 } 552 moduleInfo := moduleGroup.modules[0].module() 553 if moduleInfo != nil { 554 return moduleInfo.logicModule, true 555 } else { 556 panic(fmt.Errorf(`Expected actual module named %q, but group did not contain a module. 557 There may instead be an alias by that name.`, name)) 558 } 559 } 560 return nil, exists 561} 562 563func (m *baseModuleContext) OtherModuleExists(name string) bool { 564 _, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace()) 565 return exists 566} 567 568func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Variation, name string) bool { 569 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 570 if possibleDeps == nil { 571 return false 572 } 573 found, _ := findVariant(m.module, possibleDeps, variations, false, false) 574 return found != nil 575} 576 577func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool { 578 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 579 if possibleDeps == nil { 580 return false 581 } 582 found, _ := findVariant(m.module, possibleDeps, variations, true, false) 583 return found != nil 584} 585 586func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { 587 possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace()) 588 if possibleDeps == nil { 589 return false 590 } 591 found, _ := findVariant(m.module, possibleDeps, nil, false, true) 592 return found != nil 593} 594 595func (m *baseModuleContext) OtherModuleProvider(logicModule Module, provider ProviderKey) interface{} { 596 module := m.context.moduleInfo[logicModule] 597 value, _ := m.context.provider(module, provider) 598 return value 599} 600 601func (m *baseModuleContext) OtherModuleHasProvider(logicModule Module, provider ProviderKey) bool { 602 module := m.context.moduleInfo[logicModule] 603 _, ok := m.context.provider(module, provider) 604 return ok 605} 606 607func (m *baseModuleContext) Provider(provider ProviderKey) interface{} { 608 value, _ := m.context.provider(m.module, provider) 609 return value 610} 611 612func (m *baseModuleContext) HasProvider(provider ProviderKey) bool { 613 _, ok := m.context.provider(m.module, provider) 614 return ok 615} 616 617func (m *baseModuleContext) SetProvider(provider ProviderKey, value interface{}) { 618 m.context.setProvider(m.module, provider, value) 619} 620 621func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) { 622 for _, dep := range m.module.directDeps { 623 if dep.module.Name() == name { 624 return dep.module.logicModule, dep.tag 625 } 626 } 627 628 return nil, nil 629} 630 631func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module { 632 var deps []depInfo 633 for _, dep := range m.module.directDeps { 634 if dep.module.Name() == name { 635 if dep.tag == tag { 636 return dep.module.logicModule 637 } 638 deps = append(deps, dep) 639 } 640 } 641 642 if len(deps) != 0 { 643 panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps)) 644 } 645 646 return nil 647} 648 649func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) { 650 defer func() { 651 if r := recover(); r != nil { 652 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s", 653 m.module, funcName(visit), m.visitingDep.module)) 654 } 655 }() 656 657 m.visitingParent = m.module 658 659 for _, dep := range m.module.directDeps { 660 m.visitingDep = dep 661 visit(dep.module.logicModule) 662 } 663 664 m.visitingParent = nil 665 m.visitingDep = depInfo{} 666} 667 668func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 669 defer func() { 670 if r := recover(); r != nil { 671 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s", 672 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 673 } 674 }() 675 676 m.visitingParent = m.module 677 678 for _, dep := range m.module.directDeps { 679 m.visitingDep = dep 680 if pred(dep.module.logicModule) { 681 visit(dep.module.logicModule) 682 } 683 } 684 685 m.visitingParent = nil 686 m.visitingDep = depInfo{} 687} 688 689func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { 690 defer func() { 691 if r := recover(); r != nil { 692 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s", 693 m.module, funcName(visit), m.visitingDep.module)) 694 } 695 }() 696 697 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 698 m.visitingParent = parent 699 m.visitingDep = dep 700 visit(dep.module.logicModule) 701 }) 702 703 m.visitingParent = nil 704 m.visitingDep = depInfo{} 705} 706 707func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, 708 visit func(Module)) { 709 710 defer func() { 711 if r := recover(); r != nil { 712 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s", 713 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 714 } 715 }() 716 717 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 718 if pred(dep.module.logicModule) { 719 m.visitingParent = parent 720 m.visitingDep = dep 721 visit(dep.module.logicModule) 722 } 723 }) 724 725 m.visitingParent = nil 726 m.visitingDep = depInfo{} 727} 728 729func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) { 730 m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool { 731 m.visitingParent = parent 732 m.visitingDep = dep 733 return visit(dep.module.logicModule, parent.logicModule) 734 }, nil) 735 736 m.visitingParent = nil 737 m.visitingDep = depInfo{} 738} 739 740func (m *baseModuleContext) PrimaryModule() Module { 741 return m.module.group.modules.firstModule().logicModule 742} 743 744func (m *baseModuleContext) FinalModule() Module { 745 return m.module.group.modules.lastModule().logicModule 746} 747 748func (m *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { 749 m.context.visitAllModuleVariants(m.module, visit) 750} 751 752func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) { 753 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...) 754} 755 756func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory { 757 ret := make(map[string]ModuleFactory) 758 for k, v := range m.context.moduleFactories { 759 ret[k] = v 760 } 761 return ret 762} 763 764func (m *moduleContext) ModuleSubDir() string { 765 return m.module.variant.name 766} 767 768func (m *moduleContext) Variable(pctx PackageContext, name, value string) { 769 m.scope.ReparentTo(pctx) 770 771 v, err := m.scope.AddLocalVariable(name, value) 772 if err != nil { 773 panic(err) 774 } 775 776 m.actionDefs.variables = append(m.actionDefs.variables, v) 777} 778 779func (m *moduleContext) Rule(pctx PackageContext, name string, 780 params RuleParams, argNames ...string) Rule { 781 782 m.scope.ReparentTo(pctx) 783 784 r, err := m.scope.AddLocalRule(name, ¶ms, argNames...) 785 if err != nil { 786 panic(err) 787 } 788 789 m.actionDefs.rules = append(m.actionDefs.rules, r) 790 791 return r 792} 793 794func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { 795 m.scope.ReparentTo(pctx) 796 797 def, err := parseBuildParams(m.scope, ¶ms) 798 if err != nil { 799 panic(err) 800 } 801 802 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def) 803} 804 805func (m *moduleContext) GetMissingDependencies() []string { 806 m.handledMissingDeps = true 807 return m.module.missingDeps 808} 809 810// 811// MutatorContext 812// 813 814type mutatorContext struct { 815 baseModuleContext 816 name string 817 reverseDeps []reverseDep 818 rename []rename 819 replace []replace 820 newVariations modulesOrAliases // new variants of existing modules 821 newModules []*moduleInfo // brand new modules 822 defaultVariation *string 823 pauseCh chan<- pauseSpec 824} 825 826type BaseMutatorContext interface { 827 BaseModuleContext 828 829 // Rename all variants of a module. The new name is not visible to calls to ModuleName, 830 // AddDependency or OtherModuleName until after this mutator pass is complete. 831 Rename(name string) 832 833 // MutatorName returns the name that this mutator was registered with. 834 MutatorName() string 835} 836 837type TopDownMutatorContext interface { 838 BaseMutatorContext 839 840 // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies 841 // the specified property structs to it as if the properties were set in a blueprint file. 842 CreateModule(ModuleFactory, string, ...interface{}) Module 843} 844 845type BottomUpMutatorContext interface { 846 BaseMutatorContext 847 848 // AddDependency adds a dependency to the given module. It returns a slice of modules for each 849 // dependency (some entries may be nil). Does not affect the ordering of the current mutator 850 // pass, but will be ordered correctly for all future mutator passes. 851 // 852 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 853 // new dependencies have had the current mutator called on them. If the mutator is not 854 // parallel this method does not affect the ordering of the current mutator pass, but will 855 // be ordered correctly for all future mutator passes. 856 AddDependency(module Module, tag DependencyTag, name ...string) []Module 857 858 // AddReverseDependency adds a dependency from the destination to the given module. 859 // Does not affect the ordering of the current mutator pass, but will be ordered 860 // correctly for all future mutator passes. All reverse dependencies for a destination module are 861 // collected until the end of the mutator pass, sorted by name, and then appended to the destination 862 // module's dependency list. 863 AddReverseDependency(module Module, tag DependencyTag, name string) 864 865 // CreateVariations splits a module into multiple variants, one for each name in the variationNames 866 // parameter. It returns a list of new modules in the same order as the variationNames 867 // list. 868 // 869 // If any of the dependencies of the module being operated on were already split 870 // by calling CreateVariations with the same name, the dependency will automatically 871 // be updated to point the matching variant. 872 // 873 // If a module is split, and then a module depending on the first module is not split 874 // when the Mutator is later called on it, the dependency of the depending module will 875 // automatically be updated to point to the first variant. 876 CreateVariations(variationNames ...string) []Module 877 878 // CreateLocalVariations splits a module into multiple variants, one for each name in the variationNames 879 // parameter. It returns a list of new modules in the same order as the variantNames 880 // list. 881 // 882 // Local variations do not affect automatic dependency resolution - dependencies added 883 // to the split module via deps or DynamicDependerModule must exactly match a variant 884 // that contains all the non-local variations. 885 CreateLocalVariations(variationNames ...string) []Module 886 887 // SetDependencyVariation sets all dangling dependencies on the current module to point to the variation 888 // with given name. This function ignores the default variation set by SetDefaultDependencyVariation. 889 SetDependencyVariation(string) 890 891 // SetDefaultDependencyVariation sets the default variation when a dangling reference is detected 892 // during the subsequent calls on Create*Variations* functions. To reset, set it to nil. 893 SetDefaultDependencyVariation(*string) 894 895 // AddVariationDependencies adds deps as dependencies of the current module, but uses the variations 896 // argument to select which variant of the dependency to use. It returns a slice of modules for 897 // each dependency (some entries may be nil). A variant of the dependency must exist that matches 898 // the all of the non-local variations of the current module, plus the variations argument. 899 // 900 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 901 // new dependencies have had the current mutator called on them. If the mutator is not 902 // parallel this method does not affect the ordering of the current mutator pass, but will 903 // be ordered correctly for all future mutator passes. 904 AddVariationDependencies([]Variation, DependencyTag, ...string) []Module 905 906 // AddFarVariationDependencies adds deps as dependencies of the current module, but uses the 907 // variations argument to select which variant of the dependency to use. It returns a slice of 908 // modules for each dependency (some entries may be nil). A variant of the dependency must 909 // exist that matches the variations argument, but may also have other variations. 910 // For any unspecified variation the first variant will be used. 911 // 912 // Unlike AddVariationDependencies, the variations of the current module are ignored - the 913 // dependency only needs to match the supplied variations. 914 // 915 // If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the 916 // new dependencies have had the current mutator called on them. If the mutator is not 917 // parallel this method does not affect the ordering of the current mutator pass, but will 918 // be ordered correctly for all future mutator passes. 919 AddFarVariationDependencies([]Variation, DependencyTag, ...string) []Module 920 921 // AddInterVariantDependency adds a dependency between two variants of the same module. Variants are always 922 // ordered in the same order as they were listed in CreateVariations, and AddInterVariantDependency does not change 923 // that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps, 924 // WalkDeps, etc. 925 AddInterVariantDependency(tag DependencyTag, from, to Module) 926 927 // ReplaceDependencies replaces all dependencies on the identical variant of the module with the 928 // specified name with the current variant of this module. Replacements don't take effect until 929 // after the mutator pass is finished. 930 ReplaceDependencies(string) 931 932 // ReplaceDependenciesIf replaces all dependencies on the identical variant of the module with the 933 // specified name with the current variant of this module as long as the supplied predicate returns 934 // true. 935 // 936 // Replacements don't take effect until after the mutator pass is finished. 937 ReplaceDependenciesIf(string, ReplaceDependencyPredicate) 938 939 // AliasVariation takes a variationName that was passed to CreateVariations for this module, 940 // and creates an alias from the current variant (before the mutator has run) to the new 941 // variant. The alias will be valid until the next time a mutator calls CreateVariations or 942 // CreateLocalVariations on this module without also calling AliasVariation. The alias can 943 // be used to add dependencies on the newly created variant using the variant map from 944 // before CreateVariations was run. 945 AliasVariation(variationName string) 946 947 // CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this 948 // module, and creates an alias from a new fromVariationName variant the toVariationName 949 // variant. The alias will be valid until the next time a mutator calls CreateVariations or 950 // CreateLocalVariations on this module without also calling AliasVariation. The alias can 951 // be used to add dependencies on the toVariationName variant using the fromVariationName 952 // variant. 953 CreateAliasVariation(fromVariationName, toVariationName string) 954 955 // SetVariationProvider sets the value for a provider for the given newly created variant of 956 // the current module, i.e. one of the Modules returned by CreateVariations.. It panics if 957 // not called during the appropriate mutator or GenerateBuildActions pass for the provider, 958 // if the value is not of the appropriate type, or if the module is not a newly created 959 // variant of the current module. The value should not be modified after being passed to 960 // SetVariationProvider. 961 SetVariationProvider(module Module, provider ProviderKey, value interface{}) 962} 963 964// A Mutator function is called for each Module, and can use 965// MutatorContext.CreateVariations to split a Module into multiple Modules, 966// modifying properties on the new modules to differentiate them. It is called 967// after parsing all Blueprint files, but before generating any build rules, 968// and is always called on dependencies before being called on the depending module. 969// 970// The Mutator function should only modify members of properties structs, and not 971// members of the module struct itself, to ensure the modified values are copied 972// if a second Mutator chooses to split the module a second time. 973type TopDownMutator func(mctx TopDownMutatorContext) 974type BottomUpMutator func(mctx BottomUpMutatorContext) 975 976// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be 977// used to transfer information on a dependency between the mutator that called AddDependency 978// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the 979// interface (pointing to the same concrete object) from their original module. 980type DependencyTag interface { 981 dependencyTag(DependencyTag) 982} 983 984type BaseDependencyTag struct { 985} 986 987func (BaseDependencyTag) dependencyTag(DependencyTag) { 988} 989 990var _ DependencyTag = BaseDependencyTag{} 991 992func (mctx *mutatorContext) MutatorName() string { 993 return mctx.name 994} 995 996func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module { 997 depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation) 998 return mctx.createVariations(variationNames, depChooser, false) 999} 1000 1001func (mctx *mutatorContext) createVariationsWithTransition(transition Transition, variationNames ...string) []Module { 1002 return mctx.createVariations(variationNames, chooseDepByTransition(mctx.name, transition), false) 1003} 1004 1005func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module { 1006 depChooser := chooseDepInherit(mctx.name, mctx.defaultVariation) 1007 return mctx.createVariations(variationNames, depChooser, true) 1008} 1009 1010func (mctx *mutatorContext) SetVariationProvider(module Module, provider ProviderKey, value interface{}) { 1011 for _, variant := range mctx.newVariations { 1012 if m := variant.module(); m != nil && m.logicModule == module { 1013 mctx.context.setProvider(m, provider, value) 1014 return 1015 } 1016 } 1017 panic(fmt.Errorf("module %q is not a newly created variant of %q", module, mctx.module)) 1018} 1019 1020func (mctx *mutatorContext) createVariations(variationNames []string, depChooser depChooser, local bool) []Module { 1021 var ret []Module 1022 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, depChooser, variationNames, local) 1023 if len(errs) > 0 { 1024 mctx.errs = append(mctx.errs, errs...) 1025 } 1026 1027 for _, module := range modules { 1028 ret = append(ret, module.module().logicModule) 1029 } 1030 1031 if mctx.newVariations != nil { 1032 panic("module already has variations from this mutator") 1033 } 1034 mctx.newVariations = modules 1035 1036 if len(ret) != len(variationNames) { 1037 panic("oops!") 1038 } 1039 1040 return ret 1041} 1042 1043func (mctx *mutatorContext) AliasVariation(variationName string) { 1044 for _, moduleOrAlias := range mctx.module.splitModules { 1045 if alias := moduleOrAlias.alias(); alias != nil { 1046 if alias.variant.variations.equal(mctx.module.variant.variations) { 1047 panic(fmt.Errorf("AliasVariation already called")) 1048 } 1049 } 1050 } 1051 1052 for _, variant := range mctx.newVariations { 1053 if variant.moduleOrAliasVariant().variations[mctx.name] == variationName { 1054 alias := &moduleAlias{ 1055 variant: mctx.module.variant, 1056 target: variant.moduleOrAliasTarget(), 1057 } 1058 // Prepend the alias so that AddFarVariationDependencies subset match matches 1059 // the alias before matching the first variation. 1060 mctx.module.splitModules = append(modulesOrAliases{alias}, mctx.module.splitModules...) 1061 return 1062 } 1063 } 1064 1065 var foundVariations []string 1066 for _, variant := range mctx.newVariations { 1067 foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name]) 1068 } 1069 panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations)) 1070} 1071 1072func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) { 1073 newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false) 1074 1075 for _, moduleOrAlias := range mctx.module.splitModules { 1076 if moduleOrAlias.moduleOrAliasVariant().variations.equal(newVariant.variations) { 1077 if alias := moduleOrAlias.alias(); alias != nil { 1078 panic(fmt.Errorf("can't alias %q to %q, already aliased to %q", aliasVariationName, targetVariationName, alias.target.variant.name)) 1079 } else { 1080 panic(fmt.Errorf("can't alias %q to %q, there is already a variant with that name", aliasVariationName, targetVariationName)) 1081 } 1082 } 1083 } 1084 1085 for _, variant := range mctx.newVariations { 1086 if variant.moduleOrAliasVariant().variations[mctx.name] == targetVariationName { 1087 // Append the alias here so that it comes after any aliases created by AliasVariation. 1088 mctx.module.splitModules = append(mctx.module.splitModules, &moduleAlias{ 1089 variant: newVariant, 1090 target: variant.moduleOrAliasTarget(), 1091 }) 1092 return 1093 } 1094 } 1095 1096 var foundVariations []string 1097 for _, variant := range mctx.newVariations { 1098 foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name]) 1099 } 1100 panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations)) 1101} 1102 1103func (mctx *mutatorContext) applyTransition(transition Transition) { 1104 mctx.context.convertDepsToVariation(mctx.module, chooseDepByTransition(mctx.name, transition)) 1105} 1106 1107func (mctx *mutatorContext) SetDependencyVariation(variationName string) { 1108 mctx.context.convertDepsToVariation(mctx.module, chooseDepExplicit( 1109 mctx.name, variationName, nil)) 1110} 1111 1112func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) { 1113 mctx.defaultVariation = variationName 1114} 1115 1116func (mctx *mutatorContext) Module() Module { 1117 return mctx.module.logicModule 1118} 1119 1120func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) []Module { 1121 depInfos := make([]Module, 0, len(deps)) 1122 for _, dep := range deps { 1123 modInfo := mctx.context.moduleInfo[module] 1124 depInfo, errs := mctx.context.addDependency(modInfo, tag, dep) 1125 if len(errs) > 0 { 1126 mctx.errs = append(mctx.errs, errs...) 1127 } 1128 if !mctx.pause(depInfo) { 1129 // Pausing not supported by this mutator, new dependencies can't be returned. 1130 depInfo = nil 1131 } 1132 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1133 } 1134 return depInfos 1135} 1136 1137func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) { 1138 if _, ok := tag.(BaseDependencyTag); ok { 1139 panic("BaseDependencyTag is not allowed to be used directly!") 1140 } 1141 1142 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName) 1143 if len(errs) > 0 { 1144 mctx.errs = append(mctx.errs, errs...) 1145 return 1146 } 1147 1148 mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{ 1149 destModule, 1150 depInfo{mctx.context.moduleInfo[module], tag}, 1151 }) 1152} 1153 1154func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag, 1155 deps ...string) []Module { 1156 1157 depInfos := make([]Module, 0, len(deps)) 1158 for _, dep := range deps { 1159 depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false) 1160 if len(errs) > 0 { 1161 mctx.errs = append(mctx.errs, errs...) 1162 } 1163 if !mctx.pause(depInfo) { 1164 // Pausing not supported by this mutator, new dependencies can't be returned. 1165 depInfo = nil 1166 } 1167 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1168 } 1169 return depInfos 1170} 1171 1172func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag, 1173 deps ...string) []Module { 1174 1175 depInfos := make([]Module, 0, len(deps)) 1176 for _, dep := range deps { 1177 depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true) 1178 if len(errs) > 0 { 1179 mctx.errs = append(mctx.errs, errs...) 1180 } 1181 if !mctx.pause(depInfo) { 1182 // Pausing not supported by this mutator, new dependencies can't be returned. 1183 depInfo = nil 1184 } 1185 depInfos = append(depInfos, maybeLogicModule(depInfo)) 1186 } 1187 return depInfos 1188} 1189 1190func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) { 1191 mctx.context.addInterVariantDependency(mctx.module, tag, from, to) 1192} 1193 1194func (mctx *mutatorContext) ReplaceDependencies(name string) { 1195 mctx.ReplaceDependenciesIf(name, nil) 1196} 1197 1198type ReplaceDependencyPredicate func(from Module, tag DependencyTag, to Module) bool 1199 1200func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate ReplaceDependencyPredicate) { 1201 target := mctx.context.moduleMatchingVariant(mctx.module, name) 1202 1203 if target == nil { 1204 panic(fmt.Errorf("ReplaceDependencies could not find identical variant {%s} for module %s\n"+ 1205 "available variants:\n %s", 1206 mctx.context.prettyPrintVariant(mctx.module.variant.variations), 1207 name, 1208 mctx.context.prettyPrintGroupVariants(mctx.context.moduleGroupFromName(name, mctx.module.namespace())))) 1209 } 1210 1211 mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate}) 1212} 1213 1214func (mctx *mutatorContext) Rename(name string) { 1215 mctx.rename = append(mctx.rename, rename{mctx.module.group, name}) 1216} 1217 1218func (mctx *mutatorContext) CreateModule(factory ModuleFactory, typeName string, props ...interface{}) Module { 1219 module := newModule(factory) 1220 1221 module.relBlueprintsFile = mctx.module.relBlueprintsFile 1222 module.pos = mctx.module.pos 1223 module.propertyPos = mctx.module.propertyPos 1224 module.createdBy = mctx.module 1225 module.typeName = typeName 1226 1227 for _, p := range props { 1228 err := proptools.AppendMatchingProperties(module.properties, p, nil) 1229 if err != nil { 1230 panic(err) 1231 } 1232 } 1233 1234 mctx.newModules = append(mctx.newModules, module) 1235 1236 return module.logicModule 1237} 1238 1239// pause waits until the given dependency has been visited by the mutator's parallelVisit call. 1240// It returns true if the pause was supported, false if the pause was not supported and did not 1241// occur, which will happen when the mutator is not parallelizable. If the dependency is nil 1242// it returns true if pausing is supported or false if it is not. 1243func (mctx *mutatorContext) pause(dep *moduleInfo) bool { 1244 if mctx.pauseCh != nil { 1245 if dep != nil { 1246 unpause := make(unpause) 1247 mctx.pauseCh <- pauseSpec{ 1248 paused: mctx.module, 1249 until: dep, 1250 unpause: unpause, 1251 } 1252 <-unpause 1253 } 1254 return true 1255 } 1256 return false 1257} 1258 1259// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property 1260// called "name". Modules that embed it must also add SimpleName.Properties to their property 1261// structure list. 1262type SimpleName struct { 1263 Properties struct { 1264 Name string 1265 } 1266} 1267 1268func (s *SimpleName) Name() string { 1269 return s.Properties.Name 1270} 1271 1272// Load Hooks 1273 1274type LoadHookContext interface { 1275 EarlyModuleContext 1276 1277 // CreateModule creates a new module by calling the factory method for the specified moduleType, and applies 1278 // the specified property structs to it as if the properties were set in a blueprint file. 1279 CreateModule(ModuleFactory, string, ...interface{}) Module 1280 1281 // RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints 1282 // file. 1283 RegisterScopedModuleType(name string, factory ModuleFactory) 1284} 1285 1286func (l *loadHookContext) CreateModule(factory ModuleFactory, typeName string, props ...interface{}) Module { 1287 module := newModule(factory) 1288 1289 module.relBlueprintsFile = l.module.relBlueprintsFile 1290 module.pos = l.module.pos 1291 module.propertyPos = l.module.propertyPos 1292 module.createdBy = l.module 1293 module.typeName = typeName 1294 1295 for _, p := range props { 1296 err := proptools.AppendMatchingProperties(module.properties, p, nil) 1297 if err != nil { 1298 panic(err) 1299 } 1300 } 1301 1302 l.newModules = append(l.newModules, module) 1303 1304 return module.logicModule 1305} 1306 1307func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) { 1308 if _, exists := l.context.moduleFactories[name]; exists { 1309 panic(fmt.Errorf("A global module type named %q already exists", name)) 1310 } 1311 1312 if _, exists := (*l.scopedModuleFactories)[name]; exists { 1313 panic(fmt.Errorf("A module type named %q already exists in this scope", name)) 1314 } 1315 1316 if *l.scopedModuleFactories == nil { 1317 *l.scopedModuleFactories = make(map[string]ModuleFactory) 1318 } 1319 1320 (*l.scopedModuleFactories)[name] = factory 1321} 1322 1323type loadHookContext struct { 1324 baseModuleContext 1325 newModules []*moduleInfo 1326 scopedModuleFactories *map[string]ModuleFactory 1327} 1328 1329type LoadHook func(ctx LoadHookContext) 1330 1331// Load hooks need to be added by module factories, which don't have any parameter to get to the 1332// Context, and only produce a Module interface with no base implementation, so the load hooks 1333// must be stored in a global map. The key is a pointer allocated by the module factory, so there 1334// is no chance of collisions even if tests are running in parallel with multiple contexts. The 1335// contents should be short-lived, they are added during a module factory and removed immediately 1336// after the module factory returns. 1337var pendingHooks sync.Map 1338 1339func AddLoadHook(module Module, hook LoadHook) { 1340 // Only one goroutine can be processing a given module, so no additional locking is required 1341 // for the slice stored in the sync.Map. 1342 v, exists := pendingHooks.Load(module) 1343 if !exists { 1344 v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook)) 1345 } 1346 hooks := v.(*[]LoadHook) 1347 *hooks = append(*hooks, hook) 1348} 1349 1350func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo, 1351 scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, deps []string, errs []error) { 1352 1353 if v, exists := pendingHooks.Load(module.logicModule); exists { 1354 hooks := v.(*[]LoadHook) 1355 1356 for _, hook := range *hooks { 1357 mctx := &loadHookContext{ 1358 baseModuleContext: baseModuleContext{ 1359 context: ctx, 1360 config: config, 1361 module: module, 1362 }, 1363 scopedModuleFactories: scopedModuleFactories, 1364 } 1365 hook(mctx) 1366 newModules = append(newModules, mctx.newModules...) 1367 deps = append(deps, mctx.ninjaFileDeps...) 1368 errs = append(errs, mctx.errs...) 1369 } 1370 pendingHooks.Delete(module.logicModule) 1371 1372 return newModules, deps, errs 1373 } 1374 1375 return nil, nil, nil 1376} 1377 1378// Check the syntax of a generated blueprint file. 1379// 1380// This is intended to perform a quick syntactic check for generated blueprint 1381// code, where syntactically correct means: 1382// * No variable definitions. 1383// * Valid module types. 1384// * Valid property names. 1385// * Valid values for the property type. 1386// 1387// It does not perform any semantic checking of properties, existence of referenced 1388// files, or dependencies. 1389// 1390// At a low level it: 1391// * Parses the contents. 1392// * Invokes relevant factory to create Module instances. 1393// * Unpacks the properties into the Module. 1394// * Does not invoke load hooks or any mutators. 1395// 1396// The filename is only used for reporting errors. 1397func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error { 1398 scope := parser.NewScope(nil) 1399 file, errs := parser.Parse(filename, strings.NewReader(contents), scope) 1400 if len(errs) != 0 { 1401 return errs 1402 } 1403 1404 for _, def := range file.Defs { 1405 switch def := def.(type) { 1406 case *parser.Module: 1407 _, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false) 1408 errs = append(errs, moduleErrs...) 1409 1410 default: 1411 panic(fmt.Errorf("unknown definition type: %T", def)) 1412 } 1413 } 1414 1415 return errs 1416} 1417 1418func maybeLogicModule(module *moduleInfo) Module { 1419 if module != nil { 1420 return module.logicModule 1421 } else { 1422 return nil 1423 } 1424} 1425