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