• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params, 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, &params)
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