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, &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
306func (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
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