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 "text/scanner" 21 22 "github.com/google/blueprint/pathtools" 23 "github.com/google/blueprint/proptools" 24) 25 26// A Module handles generating all of the Ninja build actions needed to build a 27// single module based on properties defined in a Blueprints file. Module 28// objects are initially created during the parse phase of a Context using one 29// of the registered module types (and the associated ModuleFactory function). 30// The Module's properties struct is automatically filled in with the property 31// values specified in the Blueprints file (see Context.RegisterModuleType for more 32// information on this). 33// 34// A Module can be split into multiple Modules by a Mutator. All existing 35// properties set on the module will be duplicated to the new Module, and then 36// modified as necessary by the Mutator. 37// 38// The Module implementation can access the build configuration as well as any 39// modules on which on which it depends (as defined by the "deps" property 40// specified in the Blueprints file, dynamically added by implementing the 41// (deprecated) DynamicDependerModule interface, or dynamically added by a 42// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions. 43// This ModuleContext is also used to create Ninja build actions and to report 44// errors to the user. 45// 46// In addition to implementing the GenerateBuildActions method, a Module should 47// implement methods that provide dependant modules and singletons information 48// they need to generate their build actions. These methods will only be called 49// after GenerateBuildActions is called because the Context calls 50// GenerateBuildActions in dependency-order (and singletons are invoked after 51// all the Modules). The set of methods a Module supports will determine how 52// dependant Modules interact with it. 53// 54// For example, consider a Module that is responsible for generating a library 55// that other modules can link against. The library Module might implement the 56// following interface: 57// 58// type LibraryProducer interface { 59// LibraryFileName() string 60// } 61// 62// func IsLibraryProducer(module blueprint.Module) { 63// _, ok := module.(LibraryProducer) 64// return ok 65// } 66// 67// A binary-producing Module that depends on the library Module could then do: 68// 69// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) { 70// ... 71// var libraryFiles []string 72// ctx.VisitDepsDepthFirstIf(IsLibraryProducer, 73// func(module blueprint.Module) { 74// libProducer := module.(LibraryProducer) 75// libraryFiles = append(libraryFiles, libProducer.LibraryFileName()) 76// }) 77// ... 78// } 79// 80// to build the list of library file names that should be included in its link 81// command. 82// 83// GenerateBuildActions may be called from multiple threads. It is guaranteed to 84// be called after it has finished being called on all dependencies and on all 85// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list. 86// Any accesses to global variables or to Module objects that are not dependencies 87// or variants of the current Module must be synchronized by the implementation of 88// GenerateBuildActions. 89type Module interface { 90 // Name returns a string used to uniquely identify each module. The return 91 // value must be unique across all modules. It is only called once, during 92 // initial blueprint parsing. To change the name later a mutator must call 93 // MutatorContext.Rename 94 // 95 // In most cases, Name should return the contents of a "name:" property from 96 // the blueprint file. An embeddable SimpleName object can be used for this 97 // case. 98 Name() string 99 100 // GenerateBuildActions is called by the Context that created the Module 101 // during its generate phase. This call should generate all Ninja build 102 // actions (rules, pools, and build statements) needed to build the module. 103 GenerateBuildActions(ModuleContext) 104} 105 106// A DynamicDependerModule is a Module that may add dependencies that do not 107// appear in its "deps" property. Any Module that implements this interface 108// will have its DynamicDependencies method called by the Context that created 109// it during generate phase. 110// 111// Deprecated, use a BottomUpMutator instead 112type DynamicDependerModule interface { 113 Module 114 115 // DynamicDependencies is called by the Context that created the 116 // DynamicDependerModule during its generate phase. This call should return 117 // the list of module names that the DynamicDependerModule depends on 118 // dynamically. Module names that already appear in the "deps" property may 119 // but do not need to be included in the returned list. 120 DynamicDependencies(DynamicDependerModuleContext) []string 121} 122 123type BaseModuleContext interface { 124 ModuleName() string 125 ModuleDir() string 126 ModuleType() string 127 Config() interface{} 128 129 ContainsProperty(name string) bool 130 Errorf(pos scanner.Position, fmt string, args ...interface{}) 131 ModuleErrorf(fmt string, args ...interface{}) 132 PropertyErrorf(property, fmt string, args ...interface{}) 133 Failed() bool 134 135 // GlobWithDeps returns a list of files and directories that match the 136 // specified pattern but do not match any of the patterns in excludes. 137 // Any directories will have a '/' suffix. It also adds efficient 138 // dependencies to rerun the primary builder whenever a file matching 139 // the pattern as added or removed, without rerunning if a file that 140 // does not match the pattern is added to a searched directory. 141 GlobWithDeps(pattern string, excludes []string) ([]string, error) 142 143 Fs() pathtools.FileSystem 144 AddNinjaFileDeps(deps ...string) 145 146 moduleInfo() *moduleInfo 147 error(err error) 148 149 Namespace() Namespace 150} 151 152type DynamicDependerModuleContext BottomUpMutatorContext 153 154type ModuleContext interface { 155 BaseModuleContext 156 157 OtherModuleName(m Module) string 158 OtherModuleDir(m Module) string 159 OtherModuleSubDir(m Module) string 160 OtherModuleType(m Module) string 161 OtherModuleErrorf(m Module, fmt string, args ...interface{}) 162 OtherModuleDependencyTag(m Module) DependencyTag 163 164 GetDirectDepWithTag(name string, tag DependencyTag) Module 165 GetDirectDep(name string) (Module, DependencyTag) 166 167 VisitDirectDeps(visit func(Module)) 168 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 169 VisitDepsDepthFirst(visit func(Module)) 170 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 171 WalkDeps(visit func(child, parent Module) bool) 172 173 ModuleSubDir() string 174 175 Variable(pctx PackageContext, name, value string) 176 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 177 Build(pctx PackageContext, params BuildParams) 178 179 PrimaryModule() Module 180 FinalModule() Module 181 VisitAllModuleVariants(visit func(Module)) 182 183 GetMissingDependencies() []string 184} 185 186var _ BaseModuleContext = (*baseModuleContext)(nil) 187 188type baseModuleContext struct { 189 context *Context 190 config interface{} 191 module *moduleInfo 192 errs []error 193 visitingParent *moduleInfo 194 visitingDep depInfo 195 ninjaFileDeps []string 196} 197 198func (d *baseModuleContext) moduleInfo() *moduleInfo { 199 return d.module 200} 201 202func (d *baseModuleContext) ModuleName() string { 203 return d.module.Name() 204} 205 206func (d *baseModuleContext) ModuleType() string { 207 return d.module.typeName 208} 209 210func (d *baseModuleContext) ContainsProperty(name string) bool { 211 _, ok := d.module.propertyPos[name] 212 return ok 213} 214 215func (d *baseModuleContext) ModuleDir() string { 216 return filepath.Dir(d.module.relBlueprintsFile) 217} 218 219func (d *baseModuleContext) Config() interface{} { 220 return d.config 221} 222 223func (d *baseModuleContext) error(err error) { 224 if err != nil { 225 d.errs = append(d.errs, err) 226 } 227} 228 229func (d *baseModuleContext) Errorf(pos scanner.Position, 230 format string, args ...interface{}) { 231 232 d.error(&BlueprintError{ 233 Err: fmt.Errorf(format, args...), 234 Pos: pos, 235 }) 236} 237 238func (d *baseModuleContext) ModuleErrorf(format string, 239 args ...interface{}) { 240 241 d.error(&ModuleError{ 242 BlueprintError: BlueprintError{ 243 Err: fmt.Errorf(format, args...), 244 Pos: d.module.pos, 245 }, 246 module: d.module, 247 }) 248} 249 250func (d *baseModuleContext) PropertyErrorf(property, format string, 251 args ...interface{}) { 252 253 pos := d.module.propertyPos[property] 254 255 if !pos.IsValid() { 256 pos = d.module.pos 257 } 258 259 d.error(&PropertyError{ 260 ModuleError: ModuleError{ 261 BlueprintError: BlueprintError{ 262 Err: fmt.Errorf(format, args...), 263 Pos: pos, 264 }, 265 module: d.module, 266 }, 267 property: property, 268 }) 269} 270 271func (d *baseModuleContext) Failed() bool { 272 return len(d.errs) > 0 273} 274 275func (d *baseModuleContext) GlobWithDeps(pattern string, 276 excludes []string) ([]string, error) { 277 return d.context.glob(pattern, excludes) 278} 279 280func (d *baseModuleContext) Fs() pathtools.FileSystem { 281 return d.context.fs 282} 283 284func (d *baseModuleContext) Namespace() Namespace { 285 return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module)) 286} 287 288var _ ModuleContext = (*moduleContext)(nil) 289 290type moduleContext struct { 291 baseModuleContext 292 scope *localScope 293 actionDefs localBuildActions 294 handledMissingDeps bool 295} 296 297func (m *baseModuleContext) OtherModuleName(logicModule Module) string { 298 module := m.context.moduleInfo[logicModule] 299 return module.Name() 300} 301 302func (m *baseModuleContext) OtherModuleDir(logicModule Module) string { 303 module := m.context.moduleInfo[logicModule] 304 return filepath.Dir(module.relBlueprintsFile) 305} 306 307func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string { 308 module := m.context.moduleInfo[logicModule] 309 return module.variantName 310} 311 312func (m *baseModuleContext) OtherModuleType(logicModule Module) string { 313 module := m.context.moduleInfo[logicModule] 314 return module.typeName 315} 316 317func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string, 318 args ...interface{}) { 319 320 module := m.context.moduleInfo[logicModule] 321 m.errs = append(m.errs, &ModuleError{ 322 BlueprintError: BlueprintError{ 323 Err: fmt.Errorf(format, args...), 324 Pos: module.pos, 325 }, 326 module: module, 327 }) 328} 329 330// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency 331// on the module. When called inside a Visit* method with current module being visited, and there are multiple 332// dependencies on the module being visited, it returns the dependency tag used for the current dependency. 333func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag { 334 // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps 335 if logicModule == m.visitingDep.module.logicModule { 336 return m.visitingDep.tag 337 } 338 339 for _, dep := range m.visitingParent.directDeps { 340 if dep.module.logicModule == logicModule { 341 return dep.tag 342 } 343 } 344 345 return nil 346} 347 348// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified 349// name, or nil if none exists. If there are multiple dependencies on the same module it returns 350// the first DependencyTag. 351func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) { 352 for _, dep := range m.module.directDeps { 353 if dep.module.Name() == name { 354 return dep.module.logicModule, dep.tag 355 } 356 } 357 358 return nil, nil 359} 360 361// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if 362// none exists. It panics if the dependency does not have the specified tag. 363func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module { 364 var deps []depInfo 365 for _, dep := range m.module.directDeps { 366 if dep.module.Name() == name { 367 if dep.tag == tag { 368 return dep.module.logicModule 369 } 370 deps = append(deps, dep) 371 } 372 } 373 374 if len(deps) != 0 { 375 panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps)) 376 } 377 378 return nil 379} 380 381// VisitDirectDeps calls visit for each direct dependency. If there are multiple direct dependencies on the same module 382// visit will be called multiple times on that module and OtherModuleDependencyTag will return a different tag for each. 383func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) { 384 defer func() { 385 if r := recover(); r != nil { 386 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s", 387 m.module, funcName(visit), m.visitingDep.module)) 388 } 389 }() 390 391 m.visitingParent = m.module 392 393 for _, dep := range m.module.directDeps { 394 m.visitingDep = dep 395 visit(dep.module.logicModule) 396 } 397 398 m.visitingParent = nil 399 m.visitingDep = depInfo{} 400} 401 402// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are multiple 403// direct dependencies on the same module pred and visit will be called multiple times on that module and 404// OtherModuleDependencyTag will return a different tag for each. 405func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 406 defer func() { 407 if r := recover(); r != nil { 408 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s", 409 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 410 } 411 }() 412 413 m.visitingParent = m.module 414 415 for _, dep := range m.module.directDeps { 416 m.visitingDep = dep 417 if pred(dep.module.logicModule) { 418 visit(dep.module.logicModule) 419 } 420 } 421 422 m.visitingParent = nil 423 m.visitingDep = depInfo{} 424} 425 426// VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first order. 427// visit will only be called once for any given module, even if there are multiple paths through the dependency tree 428// to the module or multiple direct dependencies with different tags. OtherModuleDependencyTag will return the tag for 429// the first path found to the module. 430func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { 431 defer func() { 432 if r := recover(); r != nil { 433 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s", 434 m.module, funcName(visit), m.visitingDep.module)) 435 } 436 }() 437 438 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 439 m.visitingParent = parent 440 m.visitingDep = dep 441 visit(dep.module.logicModule) 442 }) 443 444 m.visitingParent = nil 445 m.visitingDep = depInfo{} 446} 447 448// VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing the 449// dependency tree in depth first order. visit will only be called once for any given module, even if there are 450// multiple paths through the dependency tree to the module or multiple direct dependencies with different tags. 451// OtherModuleDependencyTag will return the tag for the first path found to the module. The return value of pred does 452// not affect which branches of the tree are traversed. 453func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, 454 visit func(Module)) { 455 456 defer func() { 457 if r := recover(); r != nil { 458 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s", 459 m.module, funcName(pred), funcName(visit), m.visitingDep.module)) 460 } 461 }() 462 463 m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) { 464 if pred(dep.module.logicModule) { 465 m.visitingParent = parent 466 m.visitingDep = dep 467 visit(dep.module.logicModule) 468 } 469 }) 470 471 m.visitingParent = nil 472 m.visitingDep = depInfo{} 473} 474 475// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may be 476// called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the 477// child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited 478// (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. 479func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) { 480 m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool { 481 m.visitingParent = parent 482 m.visitingDep = dep 483 return visit(dep.module.logicModule, parent.logicModule) 484 }, nil) 485 486 m.visitingParent = nil 487 m.visitingDep = depInfo{} 488} 489 490func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) { 491 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...) 492} 493 494func (m *moduleContext) ModuleSubDir() string { 495 return m.module.variantName 496} 497 498func (m *moduleContext) Variable(pctx PackageContext, name, value string) { 499 m.scope.ReparentTo(pctx) 500 501 v, err := m.scope.AddLocalVariable(name, value) 502 if err != nil { 503 panic(err) 504 } 505 506 m.actionDefs.variables = append(m.actionDefs.variables, v) 507} 508 509func (m *moduleContext) Rule(pctx PackageContext, name string, 510 params RuleParams, argNames ...string) Rule { 511 512 m.scope.ReparentTo(pctx) 513 514 r, err := m.scope.AddLocalRule(name, ¶ms, argNames...) 515 if err != nil { 516 panic(err) 517 } 518 519 m.actionDefs.rules = append(m.actionDefs.rules, r) 520 521 return r 522} 523 524func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { 525 m.scope.ReparentTo(pctx) 526 527 def, err := parseBuildParams(m.scope, ¶ms) 528 if err != nil { 529 panic(err) 530 } 531 532 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def) 533} 534 535func (m *moduleContext) PrimaryModule() Module { 536 return m.module.group.modules[0].logicModule 537} 538 539func (m *moduleContext) FinalModule() Module { 540 return m.module.group.modules[len(m.module.group.modules)-1].logicModule 541} 542 543func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { 544 m.context.visitAllModuleVariants(m.module, visit) 545} 546 547func (m *moduleContext) GetMissingDependencies() []string { 548 m.handledMissingDeps = true 549 return m.module.missingDeps 550} 551 552// 553// MutatorContext 554// 555 556type mutatorContext struct { 557 baseModuleContext 558 name string 559 reverseDeps []reverseDep 560 rename []rename 561 replace []replace 562 newVariations []*moduleInfo // new variants of existing modules 563 newModules []*moduleInfo // brand new modules 564} 565 566type baseMutatorContext interface { 567 BaseModuleContext 568 569 OtherModuleExists(name string) bool 570 Rename(name string) 571 Module() Module 572} 573 574type EarlyMutatorContext interface { 575 baseMutatorContext 576 577 CreateVariations(...string) []Module 578 CreateLocalVariations(...string) []Module 579} 580 581type TopDownMutatorContext interface { 582 baseMutatorContext 583 584 OtherModuleName(m Module) string 585 OtherModuleDir(m Module) string 586 OtherModuleSubDir(m Module) string 587 OtherModuleType(m Module) string 588 OtherModuleErrorf(m Module, fmt string, args ...interface{}) 589 OtherModuleDependencyTag(m Module) DependencyTag 590 591 CreateModule(ModuleFactory, ...interface{}) 592 593 GetDirectDepWithTag(name string, tag DependencyTag) Module 594 GetDirectDep(name string) (Module, DependencyTag) 595 596 VisitDirectDeps(visit func(Module)) 597 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 598 VisitDepsDepthFirst(visit func(Module)) 599 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 600 WalkDeps(visit func(Module, Module) bool) 601} 602 603type BottomUpMutatorContext interface { 604 baseMutatorContext 605 606 AddDependency(module Module, tag DependencyTag, name ...string) 607 AddReverseDependency(module Module, tag DependencyTag, name string) 608 CreateVariations(...string) []Module 609 CreateLocalVariations(...string) []Module 610 SetDependencyVariation(string) 611 AddVariationDependencies([]Variation, DependencyTag, ...string) 612 AddFarVariationDependencies([]Variation, DependencyTag, ...string) 613 AddInterVariantDependency(tag DependencyTag, from, to Module) 614 ReplaceDependencies(string) 615} 616 617// A Mutator function is called for each Module, and can use 618// MutatorContext.CreateVariations to split a Module into multiple Modules, 619// modifying properties on the new modules to differentiate them. It is called 620// after parsing all Blueprint files, but before generating any build rules, 621// and is always called on dependencies before being called on the depending module. 622// 623// The Mutator function should only modify members of properties structs, and not 624// members of the module struct itself, to ensure the modified values are copied 625// if a second Mutator chooses to split the module a second time. 626type TopDownMutator func(mctx TopDownMutatorContext) 627type BottomUpMutator func(mctx BottomUpMutatorContext) 628type EarlyMutator func(mctx EarlyMutatorContext) 629 630// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be 631// used to transfer information on a dependency between the mutator that called AddDependency 632// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the 633// interface (pointing to the same concrete object) from their original module. 634type DependencyTag interface { 635 dependencyTag(DependencyTag) 636} 637 638type BaseDependencyTag struct { 639} 640 641func (BaseDependencyTag) dependencyTag(DependencyTag) { 642} 643 644var _ DependencyTag = BaseDependencyTag{} 645 646// Split a module into mulitple variants, one for each name in the variationNames 647// parameter. It returns a list of new modules in the same order as the variationNames 648// list. 649// 650// If any of the dependencies of the module being operated on were already split 651// by calling CreateVariations with the same name, the dependency will automatically 652// be updated to point the matching variant. 653// 654// If a module is split, and then a module depending on the first module is not split 655// when the Mutator is later called on it, the dependency of the depending module will 656// automatically be updated to point to the first variant. 657func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module { 658 return mctx.createVariations(variationNames, false) 659} 660 661// Split a module into mulitple variants, one for each name in the variantNames 662// parameter. It returns a list of new modules in the same order as the variantNames 663// list. 664// 665// Local variations do not affect automatic dependency resolution - dependencies added 666// to the split module via deps or DynamicDependerModule must exactly match a variant 667// that contains all the non-local variations. 668func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module { 669 return mctx.createVariations(variationNames, true) 670} 671 672func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module { 673 ret := []Module{} 674 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames) 675 if len(errs) > 0 { 676 mctx.errs = append(mctx.errs, errs...) 677 } 678 679 for i, module := range modules { 680 ret = append(ret, module.logicModule) 681 if !local { 682 module.dependencyVariant[mctx.name] = variationNames[i] 683 } 684 } 685 686 if mctx.newVariations != nil { 687 panic("module already has variations from this mutator") 688 } 689 mctx.newVariations = modules 690 691 if len(ret) != len(variationNames) { 692 panic("oops!") 693 } 694 695 return ret 696} 697 698// Set all dangling dependencies on the current module to point to the variation 699// with given name. 700func (mctx *mutatorContext) SetDependencyVariation(variationName string) { 701 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName) 702} 703 704func (mctx *mutatorContext) Module() Module { 705 return mctx.module.logicModule 706} 707 708// Add a dependency to the given module. 709// Does not affect the ordering of the current mutator pass, but will be ordered 710// correctly for all future mutator passes. 711func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) { 712 for _, dep := range deps { 713 modInfo := mctx.context.moduleInfo[module] 714 errs := mctx.context.addDependency(modInfo, tag, dep) 715 if len(errs) > 0 { 716 mctx.errs = append(mctx.errs, errs...) 717 } 718 } 719} 720 721// Add a dependency from the destination to the given module. 722// Does not affect the ordering of the current mutator pass, but will be ordered 723// correctly for all future mutator passes. All reverse dependencies for a destination module are 724// collected until the end of the mutator pass, sorted by name, and then appended to the destination 725// module's dependency list. 726func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) { 727 if _, ok := tag.(BaseDependencyTag); ok { 728 panic("BaseDependencyTag is not allowed to be used directly!") 729 } 730 731 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName) 732 if len(errs) > 0 { 733 mctx.errs = append(mctx.errs, errs...) 734 return 735 } 736 737 mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{ 738 destModule, 739 depInfo{mctx.context.moduleInfo[module], tag}, 740 }) 741} 742 743// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations 744// argument to select which variant of the dependency to use. A variant of the dependency must 745// exist that matches the all of the non-local variations of the current module, plus the variations 746// argument. 747func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag, 748 deps ...string) { 749 750 for _, dep := range deps { 751 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false) 752 if len(errs) > 0 { 753 mctx.errs = append(mctx.errs, errs...) 754 } 755 } 756} 757 758// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the 759// variations argument to select which variant of the dependency to use. A variant of the 760// dependency must exist that matches the variations argument, but may also have other variations. 761// For any unspecified variation the first variant will be used. 762// 763// Unlike AddVariationDependencies, the variations of the current module are ignored - the 764// depdendency only needs to match the supplied variations. 765func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag, 766 deps ...string) { 767 768 for _, dep := range deps { 769 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true) 770 if len(errs) > 0 { 771 mctx.errs = append(mctx.errs, errs...) 772 } 773 } 774} 775 776func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) { 777 mctx.context.addInterVariantDependency(mctx.module, tag, from, to) 778} 779 780// ReplaceDependencies replaces all dependencies on the identical variant of the module with the 781// specified name with the current variant of this module. Replacements don't take effect until 782// after the mutator pass is finished. 783func (mctx *mutatorContext) ReplaceDependencies(name string) { 784 target := mctx.context.moduleMatchingVariant(mctx.module, name) 785 786 if target == nil { 787 panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q", 788 mctx.module.variantName, name)) 789 } 790 791 mctx.replace = append(mctx.replace, replace{target, mctx.module}) 792} 793 794func (mctx *mutatorContext) OtherModuleExists(name string) bool { 795 _, exists := mctx.context.nameInterface.ModuleFromName(name, mctx.module.namespace()) 796 return exists 797} 798 799// Rename all variants of a module. The new name is not visible to calls to ModuleName, 800// AddDependency or OtherModuleName until after this mutator pass is complete. 801func (mctx *mutatorContext) Rename(name string) { 802 mctx.rename = append(mctx.rename, rename{mctx.module.group, name}) 803} 804 805// Create a new module by calling the factory method for the specified moduleType, and apply 806// the specified property structs to it as if the properties were set in a blueprint file. 807func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) { 808 module := mctx.context.newModule(factory) 809 810 module.relBlueprintsFile = mctx.module.relBlueprintsFile 811 module.pos = mctx.module.pos 812 813 for _, p := range props { 814 err := proptools.AppendMatchingProperties(module.properties, p, nil) 815 if err != nil { 816 panic(err) 817 } 818 } 819 820 mctx.newModules = append(mctx.newModules, module) 821} 822 823// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property 824// called "name". Modules that embed it must also add SimpleName.Properties to their property 825// structure list. 826type SimpleName struct { 827 Properties struct { 828 Name string 829 } 830} 831 832func (s *SimpleName) Name() string { 833 return s.Properties.Name 834} 835