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	"strings"
21	"sync"
22	"text/scanner"
23
24	"github.com/google/blueprint/parser"
25	"github.com/google/blueprint/pathtools"
26	"github.com/google/blueprint/proptools"
27)
28
29// A Module handles generating all of the Ninja build actions needed to build a
30// single module based on properties defined in a Blueprints file.  Module
31// objects are initially created during the parse phase of a Context using one
32// of the registered module types (and the associated ModuleFactory function).
33// The Module's properties struct is automatically filled in with the property
34// values specified in the Blueprints file (see Context.RegisterModuleType for more
35// information on this).
36//
37// A Module can be split into multiple Modules by a Mutator.  All existing
38// properties set on the module will be duplicated to the new Module, and then
39// modified as necessary by the Mutator.
40//
41// The Module implementation can access the build configuration as well as any
42// modules on which on which it depends (as defined by the "deps" property
43// specified in the Blueprints file, dynamically added by implementing the
44// (deprecated) DynamicDependerModule interface, or dynamically added by a
45// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions.
46// This ModuleContext is also used to create Ninja build actions and to report
47// errors to the user.
48//
49// In addition to implementing the GenerateBuildActions method, a Module should
50// implement methods that provide dependant modules and singletons information
51// they need to generate their build actions.  These methods will only be called
52// after GenerateBuildActions is called because the Context calls
53// GenerateBuildActions in dependency-order (and singletons are invoked after
54// all the Modules).  The set of methods a Module supports will determine how
55// dependant Modules interact with it.
56//
57// For example, consider a Module that is responsible for generating a library
58// that other modules can link against.  The library Module might implement the
59// following interface:
60//
61//   type LibraryProducer interface {
62//       LibraryFileName() string
63//   }
64//
65//   func IsLibraryProducer(module blueprint.Module) {
66//       _, ok := module.(LibraryProducer)
67//       return ok
68//   }
69//
70// A binary-producing Module that depends on the library Module could then do:
71//
72//   func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
73//       ...
74//       var libraryFiles []string
75//       ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
76//           func(module blueprint.Module) {
77//               libProducer := module.(LibraryProducer)
78//               libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
79//           })
80//       ...
81//   }
82//
83// to build the list of library file names that should be included in its link
84// command.
85//
86// GenerateBuildActions may be called from multiple threads.  It is guaranteed to
87// be called after it has finished being called on all dependencies and on all
88// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list.
89// Any accesses to global variables or to Module objects that are not dependencies
90// or variants of the current Module must be synchronized by the implementation of
91// GenerateBuildActions.
92type Module interface {
93	// Name returns a string used to uniquely identify each module.  The return
94	// value must be unique across all modules.  It is only called once, during
95	// initial blueprint parsing.  To change the name later a mutator must call
96	// MutatorContext.Rename
97	//
98	// In most cases, Name should return the contents of a "name:" property from
99	// the blueprint file.  An embeddable SimpleName object can be used for this
100	// case.
101	Name() string
102
103	// GenerateBuildActions is called by the Context that created the Module
104	// during its generate phase.  This call should generate all Ninja build
105	// actions (rules, pools, and build statements) needed to build the module.
106	GenerateBuildActions(ModuleContext)
107}
108
109// A DynamicDependerModule is a Module that may add dependencies that do not
110// appear in its "deps" property.  Any Module that implements this interface
111// will have its DynamicDependencies method called by the Context that created
112// it during generate phase.
113//
114// Deprecated, use a BottomUpMutator instead
115type DynamicDependerModule interface {
116	Module
117
118	// DynamicDependencies is called by the Context that created the
119	// DynamicDependerModule during its generate phase.  This call should return
120	// the list of module names that the DynamicDependerModule depends on
121	// dynamically.  Module names that already appear in the "deps" property may
122	// but do not need to be included in the returned list.
123	DynamicDependencies(DynamicDependerModuleContext) []string
124}
125
126type EarlyModuleContext interface {
127	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a
128	// reference to itself.
129	Module() Module
130
131	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
132	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
133	ModuleName() string
134
135	// ModuleDir returns the path to the directory that contains the defintion of the module.
136	ModuleDir() string
137
138	// ModuleType returns the name of the module type that was used to create the module, as specified in
139	// RegisterModuleType.
140	ModuleType() string
141
142	// BlueprintFile returns the name of the blueprint file that contains the definition of this
143	// module.
144	BlueprintsFile() string
145
146	// Config returns the config object that was passed to Context.PrepareBuildActions.
147	Config() interface{}
148
149	// ContainsProperty returns true if the specified property name was set in the module definition.
150	ContainsProperty(name string) bool
151
152	// Errorf reports an error at the specified position of the module definition file.
153	Errorf(pos scanner.Position, fmt string, args ...interface{})
154
155	// ModuleErrorf reports an error at the line number of the module type in the module definition.
156	ModuleErrorf(fmt string, args ...interface{})
157
158	// PropertyErrorf reports an error at the line number of a property in the module definition.
159	PropertyErrorf(property, fmt string, args ...interface{})
160
161	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
162	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
163	// has prevented the module from creating necessary data it can return early when Failed returns true.
164	Failed() bool
165
166	// GlobWithDeps returns a list of files and directories that match the
167	// specified pattern but do not match any of the patterns in excludes.
168	// Any directories will have a '/' suffix.  It also adds efficient
169	// dependencies to rerun the primary builder whenever a file matching
170	// the pattern as added or removed, without rerunning if a file that
171	// does not match the pattern is added to a searched directory.
172	GlobWithDeps(pattern string, excludes []string) ([]string, error)
173
174	// Fs returns a pathtools.Filesystem that can be used to interact with files.  Using the Filesystem interface allows
175	// the module to be used in build system tests that run against a mock filesystem.
176	Fs() pathtools.FileSystem
177
178	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The
179	// primary builder will be rerun whenever the specified files are modified.
180	AddNinjaFileDeps(deps ...string)
181
182	moduleInfo() *moduleInfo
183	error(err error)
184
185	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
186	// default SimpleNameInterface if Context.SetNameInterface was not called.
187	Namespace() Namespace
188
189	// ModuleFactories returns a map of all of the global ModuleFactories by name.
190	ModuleFactories() map[string]ModuleFactory
191}
192
193type BaseModuleContext interface {
194	EarlyModuleContext
195
196	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
197	// none exists.  It panics if the dependency does not have the specified tag.
198	GetDirectDepWithTag(name string, tag DependencyTag) Module
199
200	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified
201	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
202	// the first DependencyTag.
203	GetDirectDep(name string) (Module, DependencyTag)
204
205	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple direct dependencies on the same
206	// module visit will be called multiple times on that module and OtherModuleDependencyTag will return a different
207	// tag for each.
208	//
209	// The Module passed to the visit function should not be retained outside of the visit function, it may be
210	// invalidated by future mutators.
211	VisitDirectDeps(visit func(Module))
212
213	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
214	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
215	// OtherModuleDependencyTag will return a different tag for each.
216	//
217	// The Module passed to the visit function should not be retained outside of the visit function, it may be
218	// invalidated by future mutators.
219	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
220
221	// VisitDepsDepthFirst calls visit for each transitive dependency, traversing the dependency tree in depth first
222	// order. visit will only be called once for any given module, even if there are multiple paths through the
223	// dependency tree to the module or multiple direct dependencies with different tags.  OtherModuleDependencyTag will
224	// return the tag for the first path found to the module.
225	//
226	// The Module passed to the visit function should not be retained outside of the visit function, it may be
227	// invalidated by future mutators.
228	VisitDepsDepthFirst(visit func(Module))
229
230	// VisitDepsDepthFirst calls pred for each transitive dependency, and if pred returns true calls visit, traversing
231	// the dependency tree in depth first order.  visit will only be called once for any given module, even if there are
232	// multiple paths through the dependency tree to the module or multiple direct dependencies with different tags.
233	// OtherModuleDependencyTag will return the tag for the first path found to the module.  The return value of pred
234	// does not affect which branches of the tree are traversed.
235	//
236	// The Module passed to the visit function should not be retained outside of the visit function, it may be
237	// invalidated by future mutators.
238	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
239
240	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
241	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
242	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
243	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.
244	//
245	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
246	// invalidated by future mutators.
247	WalkDeps(visit func(Module, Module) bool)
248
249	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
250	// It is intended for use inside the visit functions of Visit* and WalkDeps.
251	OtherModuleName(m Module) string
252
253	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
254	// It is intended for use inside the visit functions of Visit* and WalkDeps.
255	OtherModuleDir(m Module) string
256
257	// OtherModuleSubDir returns the unique subdirectory name of another Module.  See ModuleContext.ModuleSubDir for
258	// more information.
259	// It is intended for use inside the visit functions of Visit* and WalkDeps.
260	OtherModuleSubDir(m Module) string
261
262	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
263	// It is intended for use inside the visit functions of Visit* and WalkDeps.
264	OtherModuleType(m Module) string
265
266	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
267	// It is intended for use inside the visit functions of Visit* and WalkDeps.
268	OtherModuleErrorf(m Module, fmt string, args ...interface{})
269
270	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
271	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
272	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
273	OtherModuleDependencyTag(m Module) DependencyTag
274
275	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
276	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
277	OtherModuleExists(name string) bool
278}
279
280type DynamicDependerModuleContext BottomUpMutatorContext
281
282type ModuleContext interface {
283	BaseModuleContext
284
285	// ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path
286	// to ensure that each variant of a module gets its own intermediates directory to write to.
287	ModuleSubDir() string
288
289	// Variable creates a new ninja variable scoped to the module.  It can be referenced by calls to Rule and Build
290	// in the same module.
291	Variable(pctx PackageContext, name, value string)
292
293	// Rule creates a new ninja rule scoped to the module.  It can be referenced by calls to Build in the same module.
294	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
295
296	// Build creates a new ninja build statement.
297	Build(pctx PackageContext, params BuildParams)
298
299	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
300	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
301	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
302	// only done once for all variants of a module.
303	PrimaryModule() Module
304
305	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
306	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
307	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
308	// singleton actions that are only done once for all variants of a module.
309	FinalModule() Module
310
311	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
312	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
313	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
314	// data modified by the current mutator.
315	VisitAllModuleVariants(visit func(Module))
316
317	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
318	// but do not exist.  It can be used with Context.SetAllowMissingDependencies to allow the primary builder to
319	// handle missing dependencies on its own instead of having Blueprint treat them as an error.
320	GetMissingDependencies() []string
321}
322
323var _ BaseModuleContext = (*baseModuleContext)(nil)
324
325type baseModuleContext struct {
326	context        *Context
327	config         interface{}
328	module         *moduleInfo
329	errs           []error
330	visitingParent *moduleInfo
331	visitingDep    depInfo
332	ninjaFileDeps  []string
333}
334
335func (d *baseModuleContext) moduleInfo() *moduleInfo {
336	return d.module
337}
338
339func (d *baseModuleContext) Module() Module {
340	return d.module.logicModule
341}
342
343func (d *baseModuleContext) ModuleName() string {
344	return d.module.Name()
345}
346
347func (d *baseModuleContext) ModuleType() string {
348	return d.module.typeName
349}
350
351func (d *baseModuleContext) ContainsProperty(name string) bool {
352	_, ok := d.module.propertyPos[name]
353	return ok
354}
355
356func (d *baseModuleContext) ModuleDir() string {
357	return filepath.Dir(d.module.relBlueprintsFile)
358}
359
360func (d *baseModuleContext) BlueprintsFile() string {
361	return d.module.relBlueprintsFile
362}
363
364func (d *baseModuleContext) Config() interface{} {
365	return d.config
366}
367
368func (d *baseModuleContext) error(err error) {
369	if err != nil {
370		d.errs = append(d.errs, err)
371	}
372}
373
374func (d *baseModuleContext) Errorf(pos scanner.Position,
375	format string, args ...interface{}) {
376
377	d.error(&BlueprintError{
378		Err: fmt.Errorf(format, args...),
379		Pos: pos,
380	})
381}
382
383func (d *baseModuleContext) ModuleErrorf(format string,
384	args ...interface{}) {
385
386	d.error(&ModuleError{
387		BlueprintError: BlueprintError{
388			Err: fmt.Errorf(format, args...),
389			Pos: d.module.pos,
390		},
391		module: d.module,
392	})
393}
394
395func (d *baseModuleContext) PropertyErrorf(property, format string,
396	args ...interface{}) {
397
398	pos := d.module.propertyPos[property]
399
400	if !pos.IsValid() {
401		pos = d.module.pos
402	}
403
404	d.error(&PropertyError{
405		ModuleError: ModuleError{
406			BlueprintError: BlueprintError{
407				Err: fmt.Errorf(format, args...),
408				Pos: pos,
409			},
410			module: d.module,
411		},
412		property: property,
413	})
414}
415
416func (d *baseModuleContext) Failed() bool {
417	return len(d.errs) > 0
418}
419
420func (d *baseModuleContext) GlobWithDeps(pattern string,
421	excludes []string) ([]string, error) {
422	return d.context.glob(pattern, excludes)
423}
424
425func (d *baseModuleContext) Fs() pathtools.FileSystem {
426	return d.context.fs
427}
428
429func (d *baseModuleContext) Namespace() Namespace {
430	return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module))
431}
432
433var _ ModuleContext = (*moduleContext)(nil)
434
435type moduleContext struct {
436	baseModuleContext
437	scope              *localScope
438	actionDefs         localBuildActions
439	handledMissingDeps bool
440}
441
442func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
443	module := m.context.moduleInfo[logicModule]
444	return module.Name()
445}
446
447func (m *baseModuleContext) OtherModuleDir(logicModule Module) string {
448	module := m.context.moduleInfo[logicModule]
449	return filepath.Dir(module.relBlueprintsFile)
450}
451
452func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string {
453	module := m.context.moduleInfo[logicModule]
454	return module.variantName
455}
456
457func (m *baseModuleContext) OtherModuleType(logicModule Module) string {
458	module := m.context.moduleInfo[logicModule]
459	return module.typeName
460}
461
462func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
463	args ...interface{}) {
464
465	module := m.context.moduleInfo[logicModule]
466	m.errs = append(m.errs, &ModuleError{
467		BlueprintError: BlueprintError{
468			Err: fmt.Errorf(format, args...),
469			Pos: module.pos,
470		},
471		module: module,
472	})
473}
474
475func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
476	// fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
477	if logicModule == m.visitingDep.module.logicModule {
478		return m.visitingDep.tag
479	}
480
481	for _, dep := range m.visitingParent.directDeps {
482		if dep.module.logicModule == logicModule {
483			return dep.tag
484		}
485	}
486
487	return nil
488}
489
490func (m *baseModuleContext) OtherModuleExists(name string) bool {
491	_, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
492	return exists
493}
494
495func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
496	for _, dep := range m.module.directDeps {
497		if dep.module.Name() == name {
498			return dep.module.logicModule, dep.tag
499		}
500	}
501
502	return nil, nil
503}
504
505func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module {
506	var deps []depInfo
507	for _, dep := range m.module.directDeps {
508		if dep.module.Name() == name {
509			if dep.tag == tag {
510				return dep.module.logicModule
511			}
512			deps = append(deps, dep)
513		}
514	}
515
516	if len(deps) != 0 {
517		panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps))
518	}
519
520	return nil
521}
522
523func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
524	defer func() {
525		if r := recover(); r != nil {
526			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
527				m.module, funcName(visit), m.visitingDep.module))
528		}
529	}()
530
531	m.visitingParent = m.module
532
533	for _, dep := range m.module.directDeps {
534		m.visitingDep = dep
535		visit(dep.module.logicModule)
536	}
537
538	m.visitingParent = nil
539	m.visitingDep = depInfo{}
540}
541
542func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
543	defer func() {
544		if r := recover(); r != nil {
545			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
546				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
547		}
548	}()
549
550	m.visitingParent = m.module
551
552	for _, dep := range m.module.directDeps {
553		m.visitingDep = dep
554		if pred(dep.module.logicModule) {
555			visit(dep.module.logicModule)
556		}
557	}
558
559	m.visitingParent = nil
560	m.visitingDep = depInfo{}
561}
562
563func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
564	defer func() {
565		if r := recover(); r != nil {
566			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
567				m.module, funcName(visit), m.visitingDep.module))
568		}
569	}()
570
571	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
572		m.visitingParent = parent
573		m.visitingDep = dep
574		visit(dep.module.logicModule)
575	})
576
577	m.visitingParent = nil
578	m.visitingDep = depInfo{}
579}
580
581func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
582	visit func(Module)) {
583
584	defer func() {
585		if r := recover(); r != nil {
586			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
587				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
588		}
589	}()
590
591	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
592		if pred(dep.module.logicModule) {
593			m.visitingParent = parent
594			m.visitingDep = dep
595			visit(dep.module.logicModule)
596		}
597	})
598
599	m.visitingParent = nil
600	m.visitingDep = depInfo{}
601}
602
603func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) {
604	m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool {
605		m.visitingParent = parent
606		m.visitingDep = dep
607		return visit(dep.module.logicModule, parent.logicModule)
608	}, nil)
609
610	m.visitingParent = nil
611	m.visitingDep = depInfo{}
612}
613
614func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
615	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
616}
617
618func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
619	ret := make(map[string]ModuleFactory)
620	for k, v := range m.context.moduleFactories {
621		ret[k] = v
622	}
623	return ret
624}
625
626func (m *moduleContext) ModuleSubDir() string {
627	return m.module.variantName
628}
629
630func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
631	m.scope.ReparentTo(pctx)
632
633	v, err := m.scope.AddLocalVariable(name, value)
634	if err != nil {
635		panic(err)
636	}
637
638	m.actionDefs.variables = append(m.actionDefs.variables, v)
639}
640
641func (m *moduleContext) Rule(pctx PackageContext, name string,
642	params RuleParams, argNames ...string) Rule {
643
644	m.scope.ReparentTo(pctx)
645
646	r, err := m.scope.AddLocalRule(name, &params, argNames...)
647	if err != nil {
648		panic(err)
649	}
650
651	m.actionDefs.rules = append(m.actionDefs.rules, r)
652
653	return r
654}
655
656func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
657	m.scope.ReparentTo(pctx)
658
659	def, err := parseBuildParams(m.scope, &params)
660	if err != nil {
661		panic(err)
662	}
663
664	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
665}
666
667func (m *moduleContext) PrimaryModule() Module {
668	return m.module.group.modules[0].logicModule
669}
670
671func (m *moduleContext) FinalModule() Module {
672	return m.module.group.modules[len(m.module.group.modules)-1].logicModule
673}
674
675func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
676	m.context.visitAllModuleVariants(m.module, visit)
677}
678
679func (m *moduleContext) GetMissingDependencies() []string {
680	m.handledMissingDeps = true
681	return m.module.missingDeps
682}
683
684//
685// MutatorContext
686//
687
688type mutatorContext struct {
689	baseModuleContext
690	name             string
691	reverseDeps      []reverseDep
692	rename           []rename
693	replace          []replace
694	newVariations    []*moduleInfo // new variants of existing modules
695	newModules       []*moduleInfo // brand new modules
696	defaultVariation *string
697}
698
699type BaseMutatorContext interface {
700	BaseModuleContext
701
702	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
703	// AddDependency or OtherModuleName until after this mutator pass is complete.
704	Rename(name string)
705
706	// MutatorName returns the name that this mutator was registered with.
707	MutatorName() string
708}
709
710type EarlyMutatorContext interface {
711	BaseMutatorContext
712
713	// CreateVariations splits  a module into mulitple variants, one for each name in the variationNames
714	// parameter.  It returns a list of new modules in the same order as the variationNames
715	// list.
716	//
717	// If any of the dependencies of the module being operated on were already split
718	// by calling CreateVariations with the same name, the dependency will automatically
719	// be updated to point the matching variant.
720	//
721	// If a module is split, and then a module depending on the first module is not split
722	// when the Mutator is later called on it, the dependency of the depending module will
723	// automatically be updated to point to the first variant.
724	CreateVariations(...string) []Module
725
726	// CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames
727	// parameter.  It returns a list of new modules in the same order as the variantNames
728	// list.
729	//
730	// Local variations do not affect automatic dependency resolution - dependencies added
731	// to the split module via deps or DynamicDependerModule must exactly match a variant
732	// that contains all the non-local variations.
733	CreateLocalVariations(...string) []Module
734}
735
736type TopDownMutatorContext interface {
737	BaseMutatorContext
738
739	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
740	// the specified property structs to it as if the properties were set in a blueprint file.
741	CreateModule(ModuleFactory, ...interface{}) Module
742}
743
744type BottomUpMutatorContext interface {
745	BaseMutatorContext
746
747	// AddDependency adds a dependency to the given module.
748	// Does not affect the ordering of the current mutator pass, but will be ordered
749	// correctly for all future mutator passes.
750	AddDependency(module Module, tag DependencyTag, name ...string)
751
752	// AddReverseDependency adds a dependency from the destination to the given module.
753	// Does not affect the ordering of the current mutator pass, but will be ordered
754	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
755	// collected until the end of the mutator pass, sorted by name, and then appended to the destination
756	// module's dependency list.
757	AddReverseDependency(module Module, tag DependencyTag, name string)
758
759	// CreateVariations splits  a module into mulitple variants, one for each name in the variationNames
760	// parameter.  It returns a list of new modules in the same order as the variationNames
761	// list.
762	//
763	// If any of the dependencies of the module being operated on were already split
764	// by calling CreateVariations with the same name, the dependency will automatically
765	// be updated to point the matching variant.
766	//
767	// If a module is split, and then a module depending on the first module is not split
768	// when the Mutator is later called on it, the dependency of the depending module will
769	// automatically be updated to point to the first variant.
770	CreateVariations(...string) []Module
771
772	// CreateLocationVariations splits a module into mulitple variants, one for each name in the variantNames
773	// parameter.  It returns a list of new modules in the same order as the variantNames
774	// list.
775	//
776	// Local variations do not affect automatic dependency resolution - dependencies added
777	// to the split module via deps or DynamicDependerModule must exactly match a variant
778	// that contains all the non-local variations.
779	CreateLocalVariations(...string) []Module
780
781	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
782	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
783	SetDependencyVariation(string)
784
785	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
786	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
787	SetDefaultDependencyVariation(*string)
788
789	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
790	// argument to select which variant of the dependency to use.  A variant of the dependency must
791	// exist that matches the all of the non-local variations of the current module, plus the variations
792	// argument.
793	AddVariationDependencies([]Variation, DependencyTag, ...string)
794
795	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
796	// variations argument to select which variant of the dependency to use.  A variant of the
797	// dependency must exist that matches the variations argument, but may also have other variations.
798	// For any unspecified variation the first variant will be used.
799	//
800	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
801	// dependency only needs to match the supplied variations.
802	AddFarVariationDependencies([]Variation, DependencyTag, ...string)
803
804	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
805	// ordered in the same orderas they were listed in CreateVariations, and AddInterVariantDependency does not change
806	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
807	// WalkDeps, etc.
808	AddInterVariantDependency(tag DependencyTag, from, to Module)
809
810	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
811	// specified name with the current variant of this module.  Replacements don't take effect until
812	// after the mutator pass is finished.
813	ReplaceDependencies(string)
814
815	// AliasVariation takes a variationName that was passed to CreateVariations for this module, and creates an
816	// alias from the current variant to the new variant.  The alias will be valid until the next time a mutator
817	// calls CreateVariations or CreateLocalVariations on this module without also calling AliasVariation.  The
818	// alias can be used to add dependencies on the newly created variant using the variant map from before
819	// CreateVariations was run.
820	AliasVariation(variationName string)
821}
822
823// A Mutator function is called for each Module, and can use
824// MutatorContext.CreateVariations to split a Module into multiple Modules,
825// modifying properties on the new modules to differentiate them.  It is called
826// after parsing all Blueprint files, but before generating any build rules,
827// and is always called on dependencies before being called on the depending module.
828//
829// The Mutator function should only modify members of properties structs, and not
830// members of the module struct itself, to ensure the modified values are copied
831// if a second Mutator chooses to split the module a second time.
832type TopDownMutator func(mctx TopDownMutatorContext)
833type BottomUpMutator func(mctx BottomUpMutatorContext)
834type EarlyMutator func(mctx EarlyMutatorContext)
835
836// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag.  It can be
837// used to transfer information on a dependency between the mutator that called AddDependency
838// and the GenerateBuildActions method.  Variants created by CreateVariations have a copy of the
839// interface (pointing to the same concrete object) from their original module.
840type DependencyTag interface {
841	dependencyTag(DependencyTag)
842}
843
844type BaseDependencyTag struct {
845}
846
847func (BaseDependencyTag) dependencyTag(DependencyTag) {
848}
849
850var _ DependencyTag = BaseDependencyTag{}
851
852func (mctx *mutatorContext) MutatorName() string {
853	return mctx.name
854}
855
856func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
857	return mctx.createVariations(variationNames, false)
858}
859
860func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
861	return mctx.createVariations(variationNames, true)
862}
863
864func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
865	ret := []Module{}
866	modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames)
867	if len(errs) > 0 {
868		mctx.errs = append(mctx.errs, errs...)
869	}
870
871	for i, module := range modules {
872		ret = append(ret, module.logicModule)
873		if !local {
874			if module.dependencyVariant == nil {
875				module.dependencyVariant = make(variationMap)
876			}
877			module.dependencyVariant[mctx.name] = variationNames[i]
878		}
879	}
880
881	if mctx.newVariations != nil {
882		panic("module already has variations from this mutator")
883	}
884	mctx.newVariations = modules
885
886	if len(ret) != len(variationNames) {
887		panic("oops!")
888	}
889
890	return ret
891}
892
893func (mctx *mutatorContext) AliasVariation(variationName string) {
894	if mctx.module.aliasTarget != nil {
895		panic(fmt.Errorf("AliasVariation already called"))
896	}
897
898	for _, variant := range mctx.newVariations {
899		if variant.variant[mctx.name] == variationName {
900			mctx.module.aliasTarget = variant
901			return
902		}
903	}
904
905	var foundVariations []string
906	for _, variant := range mctx.newVariations {
907		foundVariations = append(foundVariations, variant.variant[mctx.name])
908	}
909	panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
910}
911
912func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
913	mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil)
914}
915
916func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) {
917	mctx.defaultVariation = variationName
918}
919
920func (mctx *mutatorContext) Module() Module {
921	return mctx.module.logicModule
922}
923
924func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
925	for _, dep := range deps {
926		modInfo := mctx.context.moduleInfo[module]
927		errs := mctx.context.addDependency(modInfo, tag, dep)
928		if len(errs) > 0 {
929			mctx.errs = append(mctx.errs, errs...)
930		}
931	}
932}
933
934func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
935	if _, ok := tag.(BaseDependencyTag); ok {
936		panic("BaseDependencyTag is not allowed to be used directly!")
937	}
938
939	destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
940	if len(errs) > 0 {
941		mctx.errs = append(mctx.errs, errs...)
942		return
943	}
944
945	mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
946		destModule,
947		depInfo{mctx.context.moduleInfo[module], tag},
948	})
949}
950
951func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
952	deps ...string) {
953
954	for _, dep := range deps {
955		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
956		if len(errs) > 0 {
957			mctx.errs = append(mctx.errs, errs...)
958		}
959	}
960}
961
962func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
963	deps ...string) {
964
965	for _, dep := range deps {
966		errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
967		if len(errs) > 0 {
968			mctx.errs = append(mctx.errs, errs...)
969		}
970	}
971}
972
973func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
974	mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
975}
976
977func (mctx *mutatorContext) ReplaceDependencies(name string) {
978	target := mctx.context.moduleMatchingVariant(mctx.module, name)
979
980	if target == nil {
981		panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
982			mctx.module.variantName, name))
983	}
984
985	mctx.replace = append(mctx.replace, replace{target, mctx.module})
986}
987
988func (mctx *mutatorContext) Rename(name string) {
989	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
990}
991
992func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
993	module := newModule(factory)
994
995	module.relBlueprintsFile = mctx.module.relBlueprintsFile
996	module.pos = mctx.module.pos
997	module.propertyPos = mctx.module.propertyPos
998	module.createdBy = mctx.module
999
1000	for _, p := range props {
1001		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1002		if err != nil {
1003			panic(err)
1004		}
1005	}
1006
1007	mctx.newModules = append(mctx.newModules, module)
1008
1009	return module.logicModule
1010}
1011
1012// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
1013// called "name".  Modules that embed it must also add SimpleName.Properties to their property
1014// structure list.
1015type SimpleName struct {
1016	Properties struct {
1017		Name string
1018	}
1019}
1020
1021func (s *SimpleName) Name() string {
1022	return s.Properties.Name
1023}
1024
1025// Load Hooks
1026
1027type LoadHookContext interface {
1028	EarlyModuleContext
1029
1030	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
1031	// the specified property structs to it as if the properties were set in a blueprint file.
1032	CreateModule(ModuleFactory, ...interface{}) Module
1033
1034	// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
1035	// file.
1036	RegisterScopedModuleType(name string, factory ModuleFactory)
1037}
1038
1039func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
1040	module := newModule(factory)
1041
1042	module.relBlueprintsFile = l.module.relBlueprintsFile
1043	module.pos = l.module.pos
1044	module.propertyPos = l.module.propertyPos
1045	module.createdBy = l.module
1046
1047	for _, p := range props {
1048		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1049		if err != nil {
1050			panic(err)
1051		}
1052	}
1053
1054	l.newModules = append(l.newModules, module)
1055
1056	return module.logicModule
1057}
1058
1059func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
1060	if _, exists := l.context.moduleFactories[name]; exists {
1061		panic(fmt.Errorf("A global module type named %q already exists", name))
1062	}
1063
1064	if _, exists := (*l.scopedModuleFactories)[name]; exists {
1065		panic(fmt.Errorf("A module type named %q already exists in this scope", name))
1066	}
1067
1068	if *l.scopedModuleFactories == nil {
1069		(*l.scopedModuleFactories) = make(map[string]ModuleFactory)
1070	}
1071
1072	(*l.scopedModuleFactories)[name] = factory
1073}
1074
1075type loadHookContext struct {
1076	baseModuleContext
1077	newModules            []*moduleInfo
1078	scopedModuleFactories *map[string]ModuleFactory
1079}
1080
1081type LoadHook func(ctx LoadHookContext)
1082
1083// Load hooks need to be added by module factories, which don't have any parameter to get to the
1084// Context, and only produce a Module interface with no base implementation, so the load hooks
1085// must be stored in a global map.  The key is a pointer allocated by the module factory, so there
1086// is no chance of collisions even if tests are running in parallel with multiple contexts.  The
1087// contents should be short-lived, they are added during a module factory and removed immediately
1088// after the module factory returns.
1089var pendingHooks sync.Map
1090
1091func AddLoadHook(module Module, hook LoadHook) {
1092	// Only one goroutine can be processing a given module, so no additional locking is required
1093	// for the slice stored in the sync.Map.
1094	v, exists := pendingHooks.Load(module)
1095	if !exists {
1096		v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
1097	}
1098	hooks := v.(*[]LoadHook)
1099	*hooks = append(*hooks, hook)
1100}
1101
1102func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
1103	scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, errs []error) {
1104
1105	if v, exists := pendingHooks.Load(module.logicModule); exists {
1106		hooks := v.(*[]LoadHook)
1107		mctx := &loadHookContext{
1108			baseModuleContext: baseModuleContext{
1109				context: ctx,
1110				config:  config,
1111				module:  module,
1112			},
1113			scopedModuleFactories: scopedModuleFactories,
1114		}
1115
1116		for _, hook := range *hooks {
1117			hook(mctx)
1118			newModules = append(newModules, mctx.newModules...)
1119			errs = append(errs, mctx.errs...)
1120		}
1121		pendingHooks.Delete(module.logicModule)
1122
1123		return newModules, errs
1124	}
1125
1126	return nil, nil
1127}
1128
1129// Check the syntax of a generated blueprint file.
1130//
1131// This is intended to perform a quick sanity check for generated blueprint
1132// code to ensure that it is syntactically correct, where syntactically correct
1133// means:
1134// * No variable definitions.
1135// * Valid module types.
1136// * Valid property names.
1137// * Valid values for the property type.
1138//
1139// It does not perform any semantic checking of properties, existence of referenced
1140// files, or dependencies.
1141//
1142// At a low level it:
1143// * Parses the contents.
1144// * Invokes relevant factory to create Module instances.
1145// * Unpacks the properties into the Module.
1146// * Does not invoke load hooks or any mutators.
1147//
1148// The filename is only used for reporting errors.
1149func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error {
1150	scope := parser.NewScope(nil)
1151	file, errs := parser.Parse(filename, strings.NewReader(contents), scope)
1152	if len(errs) != 0 {
1153		return errs
1154	}
1155
1156	for _, def := range file.Defs {
1157		switch def := def.(type) {
1158		case *parser.Module:
1159			_, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false)
1160			errs = append(errs, moduleErrs...)
1161
1162		default:
1163			panic(fmt.Errorf("unknown definition type: %T", def))
1164		}
1165	}
1166
1167	return errs
1168}
1169