Home | History | Annotate | Download | only in blueprint
      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 
     15 package blueprint
     16 
     17 import (
     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.
     86 type 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
     99 type 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 
    110 type 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 
    125 type DynamicDependerModuleContext BottomUpMutatorContext
    126 
    127 type 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 
    154 var _ BaseModuleContext = (*baseModuleContext)(nil)
    155 
    156 type baseModuleContext struct {
    157 	context *Context
    158 	config  interface{}
    159 	module  *moduleInfo
    160 	errs    []error
    161 }
    162 
    163 func (d *baseModuleContext) moduleInfo() *moduleInfo {
    164 	return d.module
    165 }
    166 
    167 func (d *baseModuleContext) ModuleName() string {
    168 	return d.module.properties.Name
    169 }
    170 
    171 func (d *baseModuleContext) ContainsProperty(name string) bool {
    172 	_, ok := d.module.propertyPos[name]
    173 	return ok
    174 }
    175 
    176 func (d *baseModuleContext) ModuleDir() string {
    177 	return filepath.Dir(d.module.relBlueprintsFile)
    178 }
    179 
    180 func (d *baseModuleContext) Config() interface{} {
    181 	return d.config
    182 }
    183 
    184 func (d *baseModuleContext) error(err error) {
    185 	if err != nil {
    186 		d.errs = append(d.errs, err)
    187 	}
    188 }
    189 
    190 func (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 
    199 func (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 
    208 func (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 
    225 func (d *baseModuleContext) Failed() bool {
    226 	return len(d.errs) > 0
    227 }
    228 
    229 var _ ModuleContext = (*moduleContext)(nil)
    230 
    231 type moduleContext struct {
    232 	baseModuleContext
    233 	scope              *localScope
    234 	ninjaFileDeps      []string
    235 	actionDefs         localBuildActions
    236 	handledMissingDeps bool
    237 }
    238 
    239 func (m *moduleContext) OtherModuleName(logicModule Module) string {
    240 	module := m.context.moduleInfo[logicModule]
    241 	return module.properties.Name
    242 }
    243 
    244 func (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 
    254 func (m *moduleContext) VisitDirectDeps(visit func(Module)) {
    255 	m.context.visitDirectDeps(m.module, visit)
    256 }
    257 
    258 func (m *moduleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
    259 	m.context.visitDirectDepsIf(m.module, pred, visit)
    260 }
    261 
    262 func (m *moduleContext) VisitDepsDepthFirst(visit func(Module)) {
    263 	m.context.visitDepsDepthFirst(m.module, visit)
    264 }
    265 
    266 func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
    267 	visit func(Module)) {
    268 
    269 	m.context.visitDepsDepthFirstIf(m.module, pred, visit)
    270 }
    271 
    272 func (m *moduleContext) WalkDeps(visit func(Module, Module) bool) {
    273 	m.context.walkDeps(m.module, visit)
    274 }
    275 
    276 func (m *moduleContext) ModuleSubDir() string {
    277 	return m.module.variantName
    278 }
    279 
    280 func (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 
    291 func (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, &params, 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 
    306 func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
    307 	m.scope.ReparentTo(pctx)
    308 
    309 	def, err := parseBuildParams(m.scope, &params)
    310 	if err != nil {
    311 		panic(err)
    312 	}
    313 
    314 	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
    315 }
    316 
    317 func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
    318 	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
    319 }
    320 
    321 func (m *moduleContext) PrimaryModule() Module {
    322 	return m.module.group.modules[0].logicModule
    323 }
    324 
    325 func (m *moduleContext) FinalModule() Module {
    326 	return m.module.group.modules[len(m.module.group.modules)-1].logicModule
    327 }
    328 
    329 func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
    330 	m.context.visitAllModuleVariants(m.module, visit)
    331 }
    332 
    333 func (m *moduleContext) GetMissingDependencies() []string {
    334 	m.handledMissingDeps = true
    335 	return m.module.missingDeps
    336 }
    337 
    338 //
    339 // MutatorContext
    340 //
    341 
    342 type mutatorContext struct {
    343 	baseModuleContext
    344 	name        string
    345 	reverseDeps map[*moduleInfo][]*moduleInfo
    346 }
    347 
    348 type baseMutatorContext interface {
    349 	BaseModuleContext
    350 
    351 	Module() Module
    352 }
    353 
    354 type EarlyMutatorContext interface {
    355 	baseMutatorContext
    356 
    357 	CreateVariations(...string) []Module
    358 	CreateLocalVariations(...string) []Module
    359 }
    360 
    361 type 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 
    374 type 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.
    395 type TopDownMutator func(mctx TopDownMutatorContext)
    396 type BottomUpMutator func(mctx BottomUpMutatorContext)
    397 type 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.
    410 func (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.
    421 func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
    422 	return mctx.createVariations(variationNames, true)
    423 }
    424 
    425 func (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.
    448 func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
    449 	mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
    450 }
    451 
    452 func (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.
    459 func (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.
    473 func (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.
    488 func (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.
    506 func (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 
    517 func (mctx *mutatorContext) OtherModuleName(logicModule Module) string {
    518 	module := mctx.context.moduleInfo[logicModule]
    519 	return module.properties.Name
    520 }
    521 
    522 func (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 
    532 func (mctx *mutatorContext) VisitDirectDeps(visit func(Module)) {
    533 	mctx.context.visitDirectDeps(mctx.module, visit)
    534 }
    535 
    536 func (mctx *mutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
    537 	mctx.context.visitDirectDepsIf(mctx.module, pred, visit)
    538 }
    539 
    540 func (mctx *mutatorContext) VisitDepsDepthFirst(visit func(Module)) {
    541 	mctx.context.visitDepsDepthFirst(mctx.module, visit)
    542 }
    543 
    544 func (mctx *mutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool,
    545 	visit func(Module)) {
    546 
    547 	mctx.context.visitDepsDepthFirstIf(mctx.module, pred, visit)
    548 }
    549 
    550 func (mctx *mutatorContext) WalkDeps(visit func(Module, Module) bool) {
    551 	mctx.context.walkDeps(mctx.module, visit)
    552 }
    553