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 23// A Module handles generating all of the Ninja build actions needed to build a 24// single module based on properties defined in a Blueprints file. Module 25// objects are initially created during the parse phase of a Context using one 26// of the registered module types (and the associated ModuleFactory function). 27// The Module's properties struct is automatically filled in with the property 28// values specified in the Blueprints file (see Context.RegisterModuleType for more 29// information on this). 30// 31// A Module can be split into multiple Modules by a Mutator. All existing 32// properties set on the module will be duplicated to the new Module, and then 33// modified as necessary by the Mutator. 34// 35// The Module implementation can access the build configuration as well as any 36// modules on which on which it depends (as defined by the "deps" property 37// specified in the Blueprints file, dynamically added by implementing the 38// (deprecated) DynamicDependerModule interface, or dynamically added by a 39// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions. 40// This ModuleContext is also used to create Ninja build actions and to report 41// errors to the user. 42// 43// In addition to implementing the GenerateBuildActions method, a Module should 44// implement methods that provide dependant modules and singletons information 45// they need to generate their build actions. These methods will only be called 46// after GenerateBuildActions is called because the Context calls 47// GenerateBuildActions in dependency-order (and singletons are invoked after 48// all the Modules). The set of methods a Module supports will determine how 49// dependant Modules interact with it. 50// 51// For example, consider a Module that is responsible for generating a library 52// that other modules can link against. The library Module might implement the 53// following interface: 54// 55// type LibraryProducer interface { 56// LibraryFileName() string 57// } 58// 59// func IsLibraryProducer(module blueprint.Module) { 60// _, ok := module.(LibraryProducer) 61// return ok 62// } 63// 64// A binary-producing Module that depends on the library Module could then do: 65// 66// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) { 67// ... 68// var libraryFiles []string 69// ctx.VisitDepsDepthFirstIf(IsLibraryProducer, 70// func(module blueprint.Module) { 71// libProducer := module.(LibraryProducer) 72// libraryFiles = append(libraryFiles, libProducer.LibraryFileName()) 73// }) 74// ... 75// } 76// 77// to build the list of library file names that should be included in its link 78// command. 79// 80// GenerateBuildActions may be called from multiple threads. It is guaranteed to 81// be called after it has finished being called on all dependencies and on all 82// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list. 83// Any accesses to global variables or to Module objects that are not dependencies 84// or variants of the current Module must be synchronized by the implementation of 85// GenerateBuildActions. 86type Module interface { 87 // GenerateBuildActions is called by the Context that created the Module 88 // during its generate phase. This call should generate all Ninja build 89 // actions (rules, pools, and build statements) needed to build the module. 90 GenerateBuildActions(ModuleContext) 91} 92 93// A DynamicDependerModule is a Module that may add dependencies that do not 94// appear in its "deps" property. Any Module that implements this interface 95// will have its DynamicDependencies method called by the Context that created 96// it during generate phase. 97// 98// Deprecated, use a BottomUpMutator instead 99type DynamicDependerModule interface { 100 Module 101 102 // DynamicDependencies is called by the Context that created the 103 // DynamicDependerModule during its generate phase. This call should return 104 // the list of module names that the DynamicDependerModule depends on 105 // dynamically. Module names that already appear in the "deps" property may 106 // but do not need to be included in the returned list. 107 DynamicDependencies(DynamicDependerModuleContext) []string 108} 109 110type BaseModuleContext interface { 111 ModuleName() string 112 ModuleDir() string 113 Config() interface{} 114 115 ContainsProperty(name string) bool 116 Errorf(pos scanner.Position, fmt string, args ...interface{}) 117 ModuleErrorf(fmt string, args ...interface{}) 118 PropertyErrorf(property, fmt string, args ...interface{}) 119 Failed() bool 120 121 moduleInfo() *moduleInfo 122 error(err error) 123} 124 125type DynamicDependerModuleContext BottomUpMutatorContext 126 127type ModuleContext interface { 128 BaseModuleContext 129 130 OtherModuleName(m Module) string 131 OtherModuleErrorf(m Module, fmt string, args ...interface{}) 132 133 VisitDirectDeps(visit func(Module)) 134 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 135 VisitDepsDepthFirst(visit func(Module)) 136 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 137 WalkDeps(visit func(Module, Module) bool) 138 139 ModuleSubDir() string 140 141 Variable(pctx PackageContext, name, value string) 142 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule 143 Build(pctx PackageContext, params BuildParams) 144 145 AddNinjaFileDeps(deps ...string) 146 147 PrimaryModule() Module 148 FinalModule() Module 149 VisitAllModuleVariants(visit func(Module)) 150 151 GetMissingDependencies() []string 152} 153 154var _ BaseModuleContext = (*baseModuleContext)(nil) 155 156type baseModuleContext struct { 157 context *Context 158 config interface{} 159 module *moduleInfo 160 errs []error 161} 162 163func (d *baseModuleContext) moduleInfo() *moduleInfo { 164 return d.module 165} 166 167func (d *baseModuleContext) ModuleName() string { 168 return d.module.properties.Name 169} 170 171func (d *baseModuleContext) ContainsProperty(name string) bool { 172 _, ok := d.module.propertyPos[name] 173 return ok 174} 175 176func (d *baseModuleContext) ModuleDir() string { 177 return filepath.Dir(d.module.relBlueprintsFile) 178} 179 180func (d *baseModuleContext) Config() interface{} { 181 return d.config 182} 183 184func (d *baseModuleContext) error(err error) { 185 if err != nil { 186 d.errs = append(d.errs, err) 187 } 188} 189 190func (d *baseModuleContext) Errorf(pos scanner.Position, 191 format string, args ...interface{}) { 192 193 d.error(&Error{ 194 Err: fmt.Errorf(format, args...), 195 Pos: pos, 196 }) 197} 198 199func (d *baseModuleContext) ModuleErrorf(format string, 200 args ...interface{}) { 201 202 d.error(&Error{ 203 Err: fmt.Errorf(format, args...), 204 Pos: d.module.pos, 205 }) 206} 207 208func (d *baseModuleContext) PropertyErrorf(property, format string, 209 args ...interface{}) { 210 211 pos := d.module.propertyPos[property] 212 213 if !pos.IsValid() { 214 pos = d.module.pos 215 } 216 217 format = property + ": " + format 218 219 d.error(&Error{ 220 Err: fmt.Errorf(format, args...), 221 Pos: pos, 222 }) 223} 224 225func (d *baseModuleContext) Failed() bool { 226 return len(d.errs) > 0 227} 228 229var _ ModuleContext = (*moduleContext)(nil) 230 231type moduleContext struct { 232 baseModuleContext 233 scope *localScope 234 ninjaFileDeps []string 235 actionDefs localBuildActions 236 handledMissingDeps bool 237} 238 239func (m *moduleContext) OtherModuleName(logicModule Module) string { 240 module := m.context.moduleInfo[logicModule] 241 return module.properties.Name 242} 243 244func (m *moduleContext) OtherModuleErrorf(logicModule Module, format string, 245 args ...interface{}) { 246 247 module := m.context.moduleInfo[logicModule] 248 m.errs = append(m.errs, &Error{ 249 Err: fmt.Errorf(format, args...), 250 Pos: module.pos, 251 }) 252} 253 254func (m *moduleContext) VisitDirectDeps(visit func(Module)) { 255 m.context.visitDirectDeps(m.module, visit) 256} 257 258func (m *moduleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 259 m.context.visitDirectDepsIf(m.module, pred, visit) 260} 261 262func (m *moduleContext) VisitDepsDepthFirst(visit func(Module)) { 263 m.context.visitDepsDepthFirst(m.module, visit) 264} 265 266func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool, 267 visit func(Module)) { 268 269 m.context.visitDepsDepthFirstIf(m.module, pred, visit) 270} 271 272func (m *moduleContext) WalkDeps(visit func(Module, Module) bool) { 273 m.context.walkDeps(m.module, visit) 274} 275 276func (m *moduleContext) ModuleSubDir() string { 277 return m.module.variantName 278} 279 280func (m *moduleContext) Variable(pctx PackageContext, name, value string) { 281 m.scope.ReparentTo(pctx) 282 283 v, err := m.scope.AddLocalVariable(name, value) 284 if err != nil { 285 panic(err) 286 } 287 288 m.actionDefs.variables = append(m.actionDefs.variables, v) 289} 290 291func (m *moduleContext) Rule(pctx PackageContext, name string, 292 params RuleParams, argNames ...string) Rule { 293 294 m.scope.ReparentTo(pctx) 295 296 r, err := m.scope.AddLocalRule(name, ¶ms, argNames...) 297 if err != nil { 298 panic(err) 299 } 300 301 m.actionDefs.rules = append(m.actionDefs.rules, r) 302 303 return r 304} 305 306func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { 307 m.scope.ReparentTo(pctx) 308 309 def, err := parseBuildParams(m.scope, ¶ms) 310 if err != nil { 311 panic(err) 312 } 313 314 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def) 315} 316 317func (m *moduleContext) AddNinjaFileDeps(deps ...string) { 318 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...) 319} 320 321func (m *moduleContext) PrimaryModule() Module { 322 return m.module.group.modules[0].logicModule 323} 324 325func (m *moduleContext) FinalModule() Module { 326 return m.module.group.modules[len(m.module.group.modules)-1].logicModule 327} 328 329func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { 330 m.context.visitAllModuleVariants(m.module, visit) 331} 332 333func (m *moduleContext) GetMissingDependencies() []string { 334 m.handledMissingDeps = true 335 return m.module.missingDeps 336} 337 338// 339// MutatorContext 340// 341 342type mutatorContext struct { 343 baseModuleContext 344 name string 345 reverseDeps map[*moduleInfo][]*moduleInfo 346} 347 348type baseMutatorContext interface { 349 BaseModuleContext 350 351 Module() Module 352} 353 354type EarlyMutatorContext interface { 355 baseMutatorContext 356 357 CreateVariations(...string) []Module 358 CreateLocalVariations(...string) []Module 359} 360 361type TopDownMutatorContext interface { 362 baseMutatorContext 363 364 OtherModuleName(m Module) string 365 OtherModuleErrorf(m Module, fmt string, args ...interface{}) 366 367 VisitDirectDeps(visit func(Module)) 368 VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) 369 VisitDepsDepthFirst(visit func(Module)) 370 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) 371 WalkDeps(visit func(Module, Module) bool) 372} 373 374type BottomUpMutatorContext interface { 375 baseMutatorContext 376 377 AddDependency(module Module, name ...string) 378 AddReverseDependency(module Module, name string) 379 CreateVariations(...string) []Module 380 CreateLocalVariations(...string) []Module 381 SetDependencyVariation(string) 382 AddVariationDependencies([]Variation, ...string) 383 AddFarVariationDependencies([]Variation, ...string) 384} 385 386// A Mutator function is called for each Module, and can use 387// MutatorContext.CreateVariations to split a Module into multiple Modules, 388// modifying properties on the new modules to differentiate them. It is called 389// after parsing all Blueprint files, but before generating any build rules, 390// and is always called on dependencies before being called on the depending module. 391// 392// The Mutator function should only modify members of properties structs, and not 393// members of the module struct itself, to ensure the modified values are copied 394// if a second Mutator chooses to split the module a second time. 395type TopDownMutator func(mctx TopDownMutatorContext) 396type BottomUpMutator func(mctx BottomUpMutatorContext) 397type EarlyMutator func(mctx EarlyMutatorContext) 398 399// Split a module into mulitple variants, one for each name in the variationNames 400// parameter. It returns a list of new modules in the same order as the variationNames 401// list. 402// 403// If any of the dependencies of the module being operated on were already split 404// by calling CreateVariations with the same name, the dependency will automatically 405// be updated to point the matching variant. 406// 407// If a module is split, and then a module depending on the first module is not split 408// when the Mutator is later called on it, the dependency of the depending module will 409// automatically be updated to point to the first variant. 410func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module { 411 return mctx.createVariations(variationNames, false) 412} 413 414// Split a module into mulitple variants, one for each name in the variantNames 415// parameter. It returns a list of new modules in the same order as the variantNames 416// list. 417// 418// Local variations do not affect automatic dependency resolution - dependencies added 419// to the split module via deps or DynamicDependerModule must exactly match a variant 420// that contains all the non-local variations. 421func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module { 422 return mctx.createVariations(variationNames, true) 423} 424 425func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module { 426 ret := []Module{} 427 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames) 428 if len(errs) > 0 { 429 mctx.errs = append(mctx.errs, errs...) 430 } 431 432 for i, module := range modules { 433 ret = append(ret, module.logicModule) 434 if !local { 435 module.dependencyVariant[mctx.name] = variationNames[i] 436 } 437 } 438 439 if len(ret) != len(variationNames) { 440 panic("oops!") 441 } 442 443 return ret 444} 445 446// Set all dangling dependencies on the current module to point to the variation 447// with given name. 448func (mctx *mutatorContext) SetDependencyVariation(variationName string) { 449 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName) 450} 451 452func (mctx *mutatorContext) Module() Module { 453 return mctx.module.logicModule 454} 455 456// Add a dependency to the given module. 457// Does not affect the ordering of the current mutator pass, but will be ordered 458// correctly for all future mutator passes. 459func (mctx *mutatorContext) AddDependency(module Module, deps ...string) { 460 for _, dep := range deps { 461 errs := mctx.context.addDependency(mctx.context.moduleInfo[module], dep) 462 if len(errs) > 0 { 463 mctx.errs = append(mctx.errs, errs...) 464 } 465 } 466} 467 468// Add a dependency from the destination to the given module. 469// Does not affect the ordering of the current mutator pass, but will be ordered 470// correctly for all future mutator passes. All reverse dependencies for a destination module are 471// collected until the end of the mutator pass, sorted by name, and then appended to the destination 472// module's dependency list. 473func (mctx *mutatorContext) AddReverseDependency(module Module, destName string) { 474 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName) 475 if len(errs) > 0 { 476 mctx.errs = append(mctx.errs, errs...) 477 return 478 } 479 480 mctx.reverseDeps[destModule] = append(mctx.reverseDeps[destModule], 481 mctx.context.moduleInfo[module]) 482} 483 484// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations 485// argument to select which variant of the dependency to use. A variant of the dependency must 486// exist that matches the all of the non-local variations of the current module, plus the variations 487// argument. 488func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, 489 deps ...string) { 490 491 for _, dep := range deps { 492 errs := mctx.context.addVariationDependency(mctx.module, variations, dep, false) 493 if len(errs) > 0 { 494 mctx.errs = append(mctx.errs, errs...) 495 } 496 } 497} 498 499// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the 500// variations argument to select which variant of the dependency to use. A variant of the 501// dependency must exist that matches the variations argument, but may also have other variations. 502// For any unspecified variation the first variant will be used. 503// 504// Unlike AddVariationDependencies, the variations of the current module are ignored - the 505// depdendency only needs to match the supplied variations. 506func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, 507 deps ...string) { 508 509 for _, dep := range deps { 510 errs := mctx.context.addVariationDependency(mctx.module, variations, dep, true) 511 if len(errs) > 0 { 512 mctx.errs = append(mctx.errs, errs...) 513 } 514 } 515} 516 517func (mctx *mutatorContext) OtherModuleName(logicModule Module) string { 518 module := mctx.context.moduleInfo[logicModule] 519 return module.properties.Name 520} 521 522func (mctx *mutatorContext) OtherModuleErrorf(logicModule Module, format string, 523 args ...interface{}) { 524 525 module := mctx.context.moduleInfo[logicModule] 526 mctx.errs = append(mctx.errs, &Error{ 527 Err: fmt.Errorf(format, args...), 528 Pos: module.pos, 529 }) 530} 531 532func (mctx *mutatorContext) VisitDirectDeps(visit func(Module)) { 533 mctx.context.visitDirectDeps(mctx.module, visit) 534} 535 536func (mctx *mutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { 537 mctx.context.visitDirectDepsIf(mctx.module, pred, visit) 538} 539 540func (mctx *mutatorContext) VisitDepsDepthFirst(visit func(Module)) { 541 mctx.context.visitDepsDepthFirst(mctx.module, visit) 542} 543 544func (mctx *mutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool, 545 visit func(Module)) { 546 547 mctx.context.visitDepsDepthFirstIf(mctx.module, pred, visit) 548} 549 550func (mctx *mutatorContext) WalkDeps(visit func(Module, Module) bool) { 551 mctx.context.walkDeps(mctx.module, visit) 552} 553