• 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	"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 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 definition 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	// Context.RegisterModuleType().
140	ModuleType() string
141
142	// BlueprintsFile 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	// VisitDepsDepthFirstIf 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	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
250	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
251	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
252	// only done once for all variants of a module.
253	PrimaryModule() Module
254
255	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
256	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
257	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
258	// singleton actions that are only done once for all variants of a module.
259	FinalModule() Module
260
261	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
262	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
263	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
264	// data modified by the current mutator.
265	VisitAllModuleVariants(visit func(Module))
266
267	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
268	// It is intended for use inside the visit functions of Visit* and WalkDeps.
269	OtherModuleName(m Module) string
270
271	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
272	// It is intended for use inside the visit functions of Visit* and WalkDeps.
273	OtherModuleDir(m Module) string
274
275	// OtherModuleSubDir returns the unique subdirectory name of another Module.  See ModuleContext.ModuleSubDir for
276	// more information.
277	// It is intended for use inside the visit functions of Visit* and WalkDeps.
278	OtherModuleSubDir(m Module) string
279
280	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
281	// It is intended for use inside the visit functions of Visit* and WalkDeps.
282	OtherModuleType(m Module) string
283
284	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
285	// It is intended for use inside the visit functions of Visit* and WalkDeps.
286	OtherModuleErrorf(m Module, fmt string, args ...interface{})
287
288	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
289	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
290	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
291	OtherModuleDependencyTag(m Module) DependencyTag
292
293	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
294	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
295	OtherModuleExists(name string) bool
296
297	// ModuleFromName returns (module, true) if a module exists by the given name and same context namespace,
298	// or (nil, false) if it does not exist. It panics if there is either more than one
299	// module of the given name, or if the given name refers to an alias instead of a module.
300	// There are no guarantees about which variant of the module will be returned.
301	// Prefer retrieving the module using GetDirectDep or a visit function, when possible, as
302	// this will guarantee the appropriate module-variant dependency is returned.
303	ModuleFromName(name string) (Module, bool)
304
305	// OtherModuleDependencyVariantExists returns true if a module with the
306	// specified name and variant exists. The variant must match the given
307	// variations. It must also match all the non-local variations of the current
308	// module. In other words, it checks for the module that AddVariationDependencies
309	// would add a dependency on with the same arguments.
310	OtherModuleDependencyVariantExists(variations []Variation, name string) bool
311
312	// OtherModuleFarDependencyVariantExists returns true if a module with the
313	// specified name and variant exists. The variant must match the given
314	// variations, but not the non-local variations of the current module. In
315	// other words, it checks for the module that AddFarVariationDependencies
316	// would add a dependency on with the same arguments.
317	OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool
318
319	// OtherModuleReverseDependencyVariantExists returns true if a module with the
320	// specified name exists with the same variations as the current module. In
321	// other words, it checks for the module that AddReverseDependency would add a
322	// dependency on with the same argument.
323	OtherModuleReverseDependencyVariantExists(name string) bool
324
325	// OtherModuleProvider returns the value for a provider for the given module.  If the value is
326	// not set it returns the zero value of the type of the provider, so the return value can always
327	// be type asserted to the type of the provider.  The value returned may be a deep copy of the
328	// value originally passed to SetProvider.
329	OtherModuleProvider(m Module, provider ProviderKey) interface{}
330
331	// OtherModuleHasProvider returns true if the provider for the given module has been set.
332	OtherModuleHasProvider(m Module, provider ProviderKey) bool
333
334	// Provider returns the value for a provider for the current module.  If the value is
335	// not set it returns the zero value of the type of the provider, so the return value can always
336	// be type asserted to the type of the provider.  It panics if called before the appropriate
337	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
338	// copy of the value originally passed to SetProvider.
339	Provider(provider ProviderKey) interface{}
340
341	// HasProvider returns true if the provider for the current module has been set.
342	HasProvider(provider ProviderKey) bool
343
344	// SetProvider sets the value for a provider for the current module.  It panics if not called
345	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
346	// is not of the appropriate type, or if the value has already been set.  The value should not
347	// be modified after being passed to SetProvider.
348	SetProvider(provider ProviderKey, value interface{})
349}
350
351type DynamicDependerModuleContext BottomUpMutatorContext
352
353type ModuleContext interface {
354	BaseModuleContext
355
356	// ModuleSubDir returns a unique name for the current variant of a module that can be used as part of the path
357	// to ensure that each variant of a module gets its own intermediates directory to write to.
358	ModuleSubDir() string
359
360	// Variable creates a new ninja variable scoped to the module.  It can be referenced by calls to Rule and Build
361	// in the same module.
362	Variable(pctx PackageContext, name, value string)
363
364	// Rule creates a new ninja rule scoped to the module.  It can be referenced by calls to Build in the same module.
365	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
366
367	// Build creates a new ninja build statement.
368	Build(pctx PackageContext, params BuildParams)
369
370	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
371	// but do not exist.  It can be used with Context.SetAllowMissingDependencies to allow the primary builder to
372	// handle missing dependencies on its own instead of having Blueprint treat them as an error.
373	GetMissingDependencies() []string
374}
375
376var _ BaseModuleContext = (*baseModuleContext)(nil)
377
378type baseModuleContext struct {
379	context        *Context
380	config         interface{}
381	module         *moduleInfo
382	errs           []error
383	visitingParent *moduleInfo
384	visitingDep    depInfo
385	ninjaFileDeps  []string
386}
387
388func (d *baseModuleContext) moduleInfo() *moduleInfo {
389	return d.module
390}
391
392func (d *baseModuleContext) Module() Module {
393	return d.module.logicModule
394}
395
396func (d *baseModuleContext) ModuleName() string {
397	return d.module.Name()
398}
399
400func (d *baseModuleContext) ModuleType() string {
401	return d.module.typeName
402}
403
404func (d *baseModuleContext) ContainsProperty(name string) bool {
405	_, ok := d.module.propertyPos[name]
406	return ok
407}
408
409func (d *baseModuleContext) ModuleDir() string {
410	return filepath.Dir(d.module.relBlueprintsFile)
411}
412
413func (d *baseModuleContext) BlueprintsFile() string {
414	return d.module.relBlueprintsFile
415}
416
417func (d *baseModuleContext) Config() interface{} {
418	return d.config
419}
420
421func (d *baseModuleContext) error(err error) {
422	if err != nil {
423		d.errs = append(d.errs, err)
424	}
425}
426
427func (d *baseModuleContext) Errorf(pos scanner.Position,
428	format string, args ...interface{}) {
429
430	d.error(&BlueprintError{
431		Err: fmt.Errorf(format, args...),
432		Pos: pos,
433	})
434}
435
436func (d *baseModuleContext) ModuleErrorf(format string,
437	args ...interface{}) {
438
439	d.error(&ModuleError{
440		BlueprintError: BlueprintError{
441			Err: fmt.Errorf(format, args...),
442			Pos: d.module.pos,
443		},
444		module: d.module,
445	})
446}
447
448func (d *baseModuleContext) PropertyErrorf(property, format string,
449	args ...interface{}) {
450
451	pos := d.module.propertyPos[property]
452
453	if !pos.IsValid() {
454		pos = d.module.pos
455	}
456
457	d.error(&PropertyError{
458		ModuleError: ModuleError{
459			BlueprintError: BlueprintError{
460				Err: fmt.Errorf(format, args...),
461				Pos: pos,
462			},
463			module: d.module,
464		},
465		property: property,
466	})
467}
468
469func (d *baseModuleContext) Failed() bool {
470	return len(d.errs) > 0
471}
472
473func (d *baseModuleContext) GlobWithDeps(pattern string,
474	excludes []string) ([]string, error) {
475	return d.context.glob(pattern, excludes)
476}
477
478func (d *baseModuleContext) Fs() pathtools.FileSystem {
479	return d.context.fs
480}
481
482func (d *baseModuleContext) Namespace() Namespace {
483	return d.context.nameInterface.GetNamespace(newNamespaceContext(d.module))
484}
485
486var _ ModuleContext = (*moduleContext)(nil)
487
488type moduleContext struct {
489	baseModuleContext
490	scope              *localScope
491	actionDefs         localBuildActions
492	handledMissingDeps bool
493}
494
495func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
496	module := m.context.moduleInfo[logicModule]
497	return module.Name()
498}
499
500func (m *baseModuleContext) OtherModuleDir(logicModule Module) string {
501	module := m.context.moduleInfo[logicModule]
502	return filepath.Dir(module.relBlueprintsFile)
503}
504
505func (m *baseModuleContext) OtherModuleSubDir(logicModule Module) string {
506	module := m.context.moduleInfo[logicModule]
507	return module.variant.name
508}
509
510func (m *baseModuleContext) OtherModuleType(logicModule Module) string {
511	module := m.context.moduleInfo[logicModule]
512	return module.typeName
513}
514
515func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
516	args ...interface{}) {
517
518	module := m.context.moduleInfo[logicModule]
519	m.errs = append(m.errs, &ModuleError{
520		BlueprintError: BlueprintError{
521			Err: fmt.Errorf(format, args...),
522			Pos: module.pos,
523		},
524		module: module,
525	})
526}
527
528func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
529	// fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
530	if logicModule == m.visitingDep.module.logicModule {
531		return m.visitingDep.tag
532	}
533
534	for _, dep := range m.visitingParent.directDeps {
535		if dep.module.logicModule == logicModule {
536			return dep.tag
537		}
538	}
539
540	return nil
541}
542
543func (m *baseModuleContext) ModuleFromName(name string) (Module, bool) {
544	moduleGroup, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
545	if exists {
546		if len(moduleGroup.modules) != 1 {
547			panic(fmt.Errorf("Expected exactly one module named %q, but got %d", name, len(moduleGroup.modules)))
548		}
549		moduleInfo := moduleGroup.modules[0].module()
550		if moduleInfo != nil {
551			return moduleInfo.logicModule, true
552		} else {
553			panic(fmt.Errorf(`Expected actual module named %q, but group did not contain a module.
554    There may instead be an alias by that name.`, name))
555		}
556	}
557	return nil, exists
558}
559
560func (m *baseModuleContext) OtherModuleExists(name string) bool {
561	_, exists := m.context.nameInterface.ModuleFromName(name, m.module.namespace())
562	return exists
563}
564
565func (m *baseModuleContext) OtherModuleDependencyVariantExists(variations []Variation, name string) bool {
566	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
567	if possibleDeps == nil {
568		return false
569	}
570	found, _ := findVariant(m.module, possibleDeps, variations, false, false)
571	return found != nil
572}
573
574func (m *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []Variation, name string) bool {
575	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
576	if possibleDeps == nil {
577		return false
578	}
579	found, _ := findVariant(m.module, possibleDeps, variations, true, false)
580	return found != nil
581}
582
583func (m *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
584	possibleDeps := m.context.moduleGroupFromName(name, m.module.namespace())
585	if possibleDeps == nil {
586		return false
587	}
588	found, _ := findVariant(m.module, possibleDeps, nil, false, true)
589	return found != nil
590}
591
592func (m *baseModuleContext) OtherModuleProvider(logicModule Module, provider ProviderKey) interface{} {
593	module := m.context.moduleInfo[logicModule]
594	value, _ := m.context.provider(module, provider)
595	return value
596}
597
598func (m *baseModuleContext) OtherModuleHasProvider(logicModule Module, provider ProviderKey) bool {
599	module := m.context.moduleInfo[logicModule]
600	_, ok := m.context.provider(module, provider)
601	return ok
602}
603
604func (m *baseModuleContext) Provider(provider ProviderKey) interface{} {
605	value, _ := m.context.provider(m.module, provider)
606	return value
607}
608
609func (m *baseModuleContext) HasProvider(provider ProviderKey) bool {
610	_, ok := m.context.provider(m.module, provider)
611	return ok
612}
613
614func (m *baseModuleContext) SetProvider(provider ProviderKey, value interface{}) {
615	m.context.setProvider(m.module, provider, value)
616}
617
618func (m *baseModuleContext) GetDirectDep(name string) (Module, DependencyTag) {
619	for _, dep := range m.module.directDeps {
620		if dep.module.Name() == name {
621			return dep.module.logicModule, dep.tag
622		}
623	}
624
625	return nil, nil
626}
627
628func (m *baseModuleContext) GetDirectDepWithTag(name string, tag DependencyTag) Module {
629	var deps []depInfo
630	for _, dep := range m.module.directDeps {
631		if dep.module.Name() == name {
632			if dep.tag == tag {
633				return dep.module.logicModule
634			}
635			deps = append(deps, dep)
636		}
637	}
638
639	if len(deps) != 0 {
640		panic(fmt.Errorf("Unable to find dependency %q with requested tag %#v. Found: %#v", deps[0].module, tag, deps))
641	}
642
643	return nil
644}
645
646func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
647	defer func() {
648		if r := recover(); r != nil {
649			panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
650				m.module, funcName(visit), m.visitingDep.module))
651		}
652	}()
653
654	m.visitingParent = m.module
655
656	for _, dep := range m.module.directDeps {
657		m.visitingDep = dep
658		visit(dep.module.logicModule)
659	}
660
661	m.visitingParent = nil
662	m.visitingDep = depInfo{}
663}
664
665func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
666	defer func() {
667		if r := recover(); r != nil {
668			panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
669				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
670		}
671	}()
672
673	m.visitingParent = m.module
674
675	for _, dep := range m.module.directDeps {
676		m.visitingDep = dep
677		if pred(dep.module.logicModule) {
678			visit(dep.module.logicModule)
679		}
680	}
681
682	m.visitingParent = nil
683	m.visitingDep = depInfo{}
684}
685
686func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
687	defer func() {
688		if r := recover(); r != nil {
689			panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
690				m.module, funcName(visit), m.visitingDep.module))
691		}
692	}()
693
694	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
695		m.visitingParent = parent
696		m.visitingDep = dep
697		visit(dep.module.logicModule)
698	})
699
700	m.visitingParent = nil
701	m.visitingDep = depInfo{}
702}
703
704func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
705	visit func(Module)) {
706
707	defer func() {
708		if r := recover(); r != nil {
709			panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
710				m.module, funcName(pred), funcName(visit), m.visitingDep.module))
711		}
712	}()
713
714	m.context.walkDeps(m.module, false, nil, func(dep depInfo, parent *moduleInfo) {
715		if pred(dep.module.logicModule) {
716			m.visitingParent = parent
717			m.visitingDep = dep
718			visit(dep.module.logicModule)
719		}
720	})
721
722	m.visitingParent = nil
723	m.visitingDep = depInfo{}
724}
725
726func (m *baseModuleContext) WalkDeps(visit func(child, parent Module) bool) {
727	m.context.walkDeps(m.module, true, func(dep depInfo, parent *moduleInfo) bool {
728		m.visitingParent = parent
729		m.visitingDep = dep
730		return visit(dep.module.logicModule, parent.logicModule)
731	}, nil)
732
733	m.visitingParent = nil
734	m.visitingDep = depInfo{}
735}
736
737func (m *baseModuleContext) PrimaryModule() Module {
738	return m.module.group.modules.firstModule().logicModule
739}
740
741func (m *baseModuleContext) FinalModule() Module {
742	return m.module.group.modules.lastModule().logicModule
743}
744
745func (m *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
746	m.context.visitAllModuleVariants(m.module, visit)
747}
748
749func (m *baseModuleContext) AddNinjaFileDeps(deps ...string) {
750	m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
751}
752
753func (m *baseModuleContext) ModuleFactories() map[string]ModuleFactory {
754	ret := make(map[string]ModuleFactory)
755	for k, v := range m.context.moduleFactories {
756		ret[k] = v
757	}
758	return ret
759}
760
761func (m *moduleContext) ModuleSubDir() string {
762	return m.module.variant.name
763}
764
765func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
766	m.scope.ReparentTo(pctx)
767
768	v, err := m.scope.AddLocalVariable(name, value)
769	if err != nil {
770		panic(err)
771	}
772
773	m.actionDefs.variables = append(m.actionDefs.variables, v)
774}
775
776func (m *moduleContext) Rule(pctx PackageContext, name string,
777	params RuleParams, argNames ...string) Rule {
778
779	m.scope.ReparentTo(pctx)
780
781	r, err := m.scope.AddLocalRule(name, &params, argNames...)
782	if err != nil {
783		panic(err)
784	}
785
786	m.actionDefs.rules = append(m.actionDefs.rules, r)
787
788	return r
789}
790
791func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
792	m.scope.ReparentTo(pctx)
793
794	def, err := parseBuildParams(m.scope, &params)
795	if err != nil {
796		panic(err)
797	}
798
799	m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
800}
801
802func (m *moduleContext) GetMissingDependencies() []string {
803	m.handledMissingDeps = true
804	return m.module.missingDeps
805}
806
807//
808// MutatorContext
809//
810
811type mutatorContext struct {
812	baseModuleContext
813	name             string
814	reverseDeps      []reverseDep
815	rename           []rename
816	replace          []replace
817	newVariations    modulesOrAliases // new variants of existing modules
818	newModules       []*moduleInfo    // brand new modules
819	defaultVariation *string
820	pauseCh          chan<- pauseSpec
821}
822
823type BaseMutatorContext interface {
824	BaseModuleContext
825
826	// Rename all variants of a module.  The new name is not visible to calls to ModuleName,
827	// AddDependency or OtherModuleName until after this mutator pass is complete.
828	Rename(name string)
829
830	// MutatorName returns the name that this mutator was registered with.
831	MutatorName() string
832}
833
834type TopDownMutatorContext interface {
835	BaseMutatorContext
836
837	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
838	// the specified property structs to it as if the properties were set in a blueprint file.
839	CreateModule(ModuleFactory, ...interface{}) Module
840}
841
842type BottomUpMutatorContext interface {
843	BaseMutatorContext
844
845	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
846	// dependency (some entries may be nil).  Does not affect the ordering of the current mutator
847	// pass, but will be ordered correctly for all future mutator passes.
848	//
849	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
850	// new dependencies have had the current mutator called on them.  If the mutator is not
851	// parallel this method does not affect the ordering of the current mutator pass, but will
852	// be ordered correctly for all future mutator passes.
853	AddDependency(module Module, tag DependencyTag, name ...string) []Module
854
855	// AddReverseDependency adds a dependency from the destination to the given module.
856	// Does not affect the ordering of the current mutator pass, but will be ordered
857	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
858	// collected until the end of the mutator pass, sorted by name, and then appended to the destination
859	// module's dependency list.
860	AddReverseDependency(module Module, tag DependencyTag, name string)
861
862	// CreateVariations splits  a module into multiple variants, one for each name in the variationNames
863	// parameter.  It returns a list of new modules in the same order as the variationNames
864	// list.
865	//
866	// If any of the dependencies of the module being operated on were already split
867	// by calling CreateVariations with the same name, the dependency will automatically
868	// be updated to point the matching variant.
869	//
870	// If a module is split, and then a module depending on the first module is not split
871	// when the Mutator is later called on it, the dependency of the depending module will
872	// automatically be updated to point to the first variant.
873	CreateVariations(variationNames ...string) []Module
874
875	// CreateLocalVariations splits a module into multiple variants, one for each name in the variationNames
876	// parameter.  It returns a list of new modules in the same order as the variantNames
877	// list.
878	//
879	// Local variations do not affect automatic dependency resolution - dependencies added
880	// to the split module via deps or DynamicDependerModule must exactly match a variant
881	// that contains all the non-local variations.
882	CreateLocalVariations(variationNames ...string) []Module
883
884	// SetDependencyVariation sets all dangling dependencies on the current module to point to the variation
885	// with given name. This function ignores the default variation set by SetDefaultDependencyVariation.
886	SetDependencyVariation(string)
887
888	// SetDefaultDependencyVariation sets the default variation when a dangling reference is detected
889	// during the subsequent calls on Create*Variations* functions. To reset, set it to nil.
890	SetDefaultDependencyVariation(*string)
891
892	// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
893	// argument to select which variant of the dependency to use.  It returns a slice of modules for
894	// each dependency (some entries may be nil).  A variant of the dependency must exist that matches
895	// the all of the non-local variations of the current module, plus the variations argument.
896	//
897	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
898	// new dependencies have had the current mutator called on them.  If the mutator is not
899	// parallel this method does not affect the ordering of the current mutator pass, but will
900	// be ordered correctly for all future mutator passes.
901	AddVariationDependencies([]Variation, DependencyTag, ...string) []Module
902
903	// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
904	// variations argument to select which variant of the dependency to use.  It returns a slice of
905	// modules for each dependency (some entries may be nil).  A variant of the dependency must
906	// exist that matches the variations argument, but may also have other variations.
907	// For any unspecified variation the first variant will be used.
908	//
909	// Unlike AddVariationDependencies, the variations of the current module are ignored - the
910	// dependency only needs to match the supplied variations.
911	//
912	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
913	// new dependencies have had the current mutator called on them.  If the mutator is not
914	// parallel this method does not affect the ordering of the current mutator pass, but will
915	// be ordered correctly for all future mutator passes.
916	AddFarVariationDependencies([]Variation, DependencyTag, ...string) []Module
917
918	// AddInterVariantDependency adds a dependency between two variants of the same module.  Variants are always
919	// ordered in the same order as they were listed in CreateVariations, and AddInterVariantDependency does not change
920	// that ordering, but it associates a DependencyTag with the dependency and makes it visible to VisitDirectDeps,
921	// WalkDeps, etc.
922	AddInterVariantDependency(tag DependencyTag, from, to Module)
923
924	// ReplaceDependencies replaces all dependencies on the identical variant of the module with the
925	// specified name with the current variant of this module.  Replacements don't take effect until
926	// after the mutator pass is finished.
927	ReplaceDependencies(string)
928
929	// ReplaceDependenciesIf replaces all dependencies on the identical variant of the module with the
930	// specified name with the current variant of this module as long as the supplied predicate returns
931	// true.
932	//
933	// Replacements don't take effect until after the mutator pass is finished.
934	ReplaceDependenciesIf(string, ReplaceDependencyPredicate)
935
936	// AliasVariation takes a variationName that was passed to CreateVariations for this module,
937	// and creates an alias from the current variant (before the mutator has run) to the new
938	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
939	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
940	// be used to add dependencies on the newly created variant using the variant map from
941	// before CreateVariations was run.
942	AliasVariation(variationName string)
943
944	// CreateAliasVariation takes a toVariationName that was passed to CreateVariations for this
945	// module, and creates an alias from a new fromVariationName variant the toVariationName
946	// variant.  The alias will be valid until the next time a mutator calls CreateVariations or
947	// CreateLocalVariations on this module without also calling AliasVariation.  The alias can
948	// be used to add dependencies on the toVariationName variant using the fromVariationName
949	// variant.
950	CreateAliasVariation(fromVariationName, toVariationName string)
951
952	// SetVariationProvider sets the value for a provider for the given newly created variant of
953	// the current module, i.e. one of the Modules returned by CreateVariations..  It panics if
954	// not called during the appropriate mutator or GenerateBuildActions pass for the provider,
955	// if the value is not of the appropriate type, or if the module is not a newly created
956	// variant of the current module.  The value should not be modified after being passed to
957	// SetVariationProvider.
958	SetVariationProvider(module Module, provider ProviderKey, value interface{})
959}
960
961// A Mutator function is called for each Module, and can use
962// MutatorContext.CreateVariations to split a Module into multiple Modules,
963// modifying properties on the new modules to differentiate them.  It is called
964// after parsing all Blueprint files, but before generating any build rules,
965// and is always called on dependencies before being called on the depending module.
966//
967// The Mutator function should only modify members of properties structs, and not
968// members of the module struct itself, to ensure the modified values are copied
969// if a second Mutator chooses to split the module a second time.
970type TopDownMutator func(mctx TopDownMutatorContext)
971type BottomUpMutator func(mctx BottomUpMutatorContext)
972
973// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag.  It can be
974// used to transfer information on a dependency between the mutator that called AddDependency
975// and the GenerateBuildActions method.  Variants created by CreateVariations have a copy of the
976// interface (pointing to the same concrete object) from their original module.
977type DependencyTag interface {
978	dependencyTag(DependencyTag)
979}
980
981type BaseDependencyTag struct {
982}
983
984func (BaseDependencyTag) dependencyTag(DependencyTag) {
985}
986
987var _ DependencyTag = BaseDependencyTag{}
988
989func (mctx *mutatorContext) MutatorName() string {
990	return mctx.name
991}
992
993func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
994	return mctx.createVariations(variationNames, false)
995}
996
997func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
998	return mctx.createVariations(variationNames, true)
999}
1000
1001func (mctx *mutatorContext) SetVariationProvider(module Module, provider ProviderKey, value interface{}) {
1002	for _, variant := range mctx.newVariations {
1003		if m := variant.module(); m != nil && m.logicModule == module {
1004			mctx.context.setProvider(m, provider, value)
1005			return
1006		}
1007	}
1008	panic(fmt.Errorf("module %q is not a newly created variant of %q", module, mctx.module))
1009}
1010
1011func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
1012	var ret []Module
1013	modules, errs := mctx.context.createVariations(mctx.module, mctx.name, mctx.defaultVariation, variationNames, local)
1014	if len(errs) > 0 {
1015		mctx.errs = append(mctx.errs, errs...)
1016	}
1017
1018	for _, module := range modules {
1019		ret = append(ret, module.module().logicModule)
1020	}
1021
1022	if mctx.newVariations != nil {
1023		panic("module already has variations from this mutator")
1024	}
1025	mctx.newVariations = modules
1026
1027	if len(ret) != len(variationNames) {
1028		panic("oops!")
1029	}
1030
1031	return ret
1032}
1033
1034func (mctx *mutatorContext) AliasVariation(variationName string) {
1035	for _, moduleOrAlias := range mctx.module.splitModules {
1036		if alias := moduleOrAlias.alias(); alias != nil {
1037			if alias.variant.variations.equal(mctx.module.variant.variations) {
1038				panic(fmt.Errorf("AliasVariation already called"))
1039			}
1040		}
1041	}
1042
1043	for _, variant := range mctx.newVariations {
1044		if variant.moduleOrAliasVariant().variations[mctx.name] == variationName {
1045			alias := &moduleAlias{
1046				variant: mctx.module.variant,
1047				target:  variant.moduleOrAliasTarget(),
1048			}
1049			// Prepend the alias so that AddFarVariationDependencies subset match matches
1050			// the alias before matching the first variation.
1051			mctx.module.splitModules = append(modulesOrAliases{alias}, mctx.module.splitModules...)
1052			return
1053		}
1054	}
1055
1056	var foundVariations []string
1057	for _, variant := range mctx.newVariations {
1058		foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
1059	}
1060	panic(fmt.Errorf("no %q variation in module variations %q", variationName, foundVariations))
1061}
1062
1063func (mctx *mutatorContext) CreateAliasVariation(aliasVariationName, targetVariationName string) {
1064	newVariant := newVariant(mctx.module, mctx.name, aliasVariationName, false)
1065
1066	for _, moduleOrAlias := range mctx.module.splitModules {
1067		if moduleOrAlias.moduleOrAliasVariant().variations.equal(newVariant.variations) {
1068			if alias := moduleOrAlias.alias(); alias != nil {
1069				panic(fmt.Errorf("can't alias %q to %q, already aliased to %q", aliasVariationName, targetVariationName, alias.target.variant.name))
1070			} else {
1071				panic(fmt.Errorf("can't alias %q to %q, there is already a variant with that name", aliasVariationName, targetVariationName))
1072			}
1073		}
1074	}
1075
1076	for _, variant := range mctx.newVariations {
1077		if variant.moduleOrAliasVariant().variations[mctx.name] == targetVariationName {
1078			// Append the alias here so that it comes after any aliases created by AliasVariation.
1079			mctx.module.splitModules = append(mctx.module.splitModules, &moduleAlias{
1080				variant: newVariant,
1081				target:  variant.moduleOrAliasTarget(),
1082			})
1083			return
1084		}
1085	}
1086
1087	var foundVariations []string
1088	for _, variant := range mctx.newVariations {
1089		foundVariations = append(foundVariations, variant.moduleOrAliasVariant().variations[mctx.name])
1090	}
1091	panic(fmt.Errorf("no %q variation in module variations %q", targetVariationName, foundVariations))
1092}
1093
1094func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
1095	mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName, nil)
1096}
1097
1098func (mctx *mutatorContext) SetDefaultDependencyVariation(variationName *string) {
1099	mctx.defaultVariation = variationName
1100}
1101
1102func (mctx *mutatorContext) Module() Module {
1103	return mctx.module.logicModule
1104}
1105
1106func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) []Module {
1107	depInfos := make([]Module, 0, len(deps))
1108	for _, dep := range deps {
1109		modInfo := mctx.context.moduleInfo[module]
1110		depInfo, errs := mctx.context.addDependency(modInfo, tag, dep)
1111		if len(errs) > 0 {
1112			mctx.errs = append(mctx.errs, errs...)
1113		}
1114		if !mctx.pause(depInfo) {
1115			// Pausing not supported by this mutator, new dependencies can't be returned.
1116			depInfo = nil
1117		}
1118		depInfos = append(depInfos, maybeLogicModule(depInfo))
1119	}
1120	return depInfos
1121}
1122
1123func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
1124	if _, ok := tag.(BaseDependencyTag); ok {
1125		panic("BaseDependencyTag is not allowed to be used directly!")
1126	}
1127
1128	destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
1129	if len(errs) > 0 {
1130		mctx.errs = append(mctx.errs, errs...)
1131		return
1132	}
1133
1134	mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
1135		destModule,
1136		depInfo{mctx.context.moduleInfo[module], tag},
1137	})
1138}
1139
1140func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
1141	deps ...string) []Module {
1142
1143	depInfos := make([]Module, 0, len(deps))
1144	for _, dep := range deps {
1145		depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
1146		if len(errs) > 0 {
1147			mctx.errs = append(mctx.errs, errs...)
1148		}
1149		if !mctx.pause(depInfo) {
1150			// Pausing not supported by this mutator, new dependencies can't be returned.
1151			depInfo = nil
1152		}
1153		depInfos = append(depInfos, maybeLogicModule(depInfo))
1154	}
1155	return depInfos
1156}
1157
1158func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
1159	deps ...string) []Module {
1160
1161	depInfos := make([]Module, 0, len(deps))
1162	for _, dep := range deps {
1163		depInfo, errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
1164		if len(errs) > 0 {
1165			mctx.errs = append(mctx.errs, errs...)
1166		}
1167		if !mctx.pause(depInfo) {
1168			// Pausing not supported by this mutator, new dependencies can't be returned.
1169			depInfo = nil
1170		}
1171		depInfos = append(depInfos, maybeLogicModule(depInfo))
1172	}
1173	return depInfos
1174}
1175
1176func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
1177	mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
1178}
1179
1180func (mctx *mutatorContext) ReplaceDependencies(name string) {
1181	mctx.ReplaceDependenciesIf(name, nil)
1182}
1183
1184type ReplaceDependencyPredicate func(from Module, tag DependencyTag, to Module) bool
1185
1186func (mctx *mutatorContext) ReplaceDependenciesIf(name string, predicate ReplaceDependencyPredicate) {
1187	target := mctx.context.moduleMatchingVariant(mctx.module, name)
1188
1189	if target == nil {
1190		panic(fmt.Errorf("ReplaceDependencies could not find identical variant {%s} for module %s\n"+
1191			"available variants:\n  %s",
1192			mctx.context.prettyPrintVariant(mctx.module.variant.variations),
1193			name,
1194			mctx.context.prettyPrintGroupVariants(mctx.context.moduleGroupFromName(name, mctx.module.namespace()))))
1195	}
1196
1197	mctx.replace = append(mctx.replace, replace{target, mctx.module, predicate})
1198}
1199
1200func (mctx *mutatorContext) Rename(name string) {
1201	mctx.rename = append(mctx.rename, rename{mctx.module.group, name})
1202}
1203
1204func (mctx *mutatorContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
1205	module := newModule(factory)
1206
1207	module.relBlueprintsFile = mctx.module.relBlueprintsFile
1208	module.pos = mctx.module.pos
1209	module.propertyPos = mctx.module.propertyPos
1210	module.createdBy = mctx.module
1211
1212	for _, p := range props {
1213		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1214		if err != nil {
1215			panic(err)
1216		}
1217	}
1218
1219	mctx.newModules = append(mctx.newModules, module)
1220
1221	return module.logicModule
1222}
1223
1224// pause waits until the given dependency has been visited by the mutator's parallelVisit call.
1225// It returns true if the pause was supported, false if the pause was not supported and did not
1226// occur, which will happen when the mutator is not parallelizable.  If the dependency is nil
1227// it returns true if pausing is supported or false if it is not.
1228func (mctx *mutatorContext) pause(dep *moduleInfo) bool {
1229	if mctx.pauseCh != nil {
1230		if dep != nil {
1231			unpause := make(unpause)
1232			mctx.pauseCh <- pauseSpec{
1233				paused:  mctx.module,
1234				until:   dep,
1235				unpause: unpause,
1236			}
1237			<-unpause
1238		}
1239		return true
1240	}
1241	return false
1242}
1243
1244// SimpleName is an embeddable object to implement the ModuleContext.Name method using a property
1245// called "name".  Modules that embed it must also add SimpleName.Properties to their property
1246// structure list.
1247type SimpleName struct {
1248	Properties struct {
1249		Name string
1250	}
1251}
1252
1253func (s *SimpleName) Name() string {
1254	return s.Properties.Name
1255}
1256
1257// Load Hooks
1258
1259type LoadHookContext interface {
1260	EarlyModuleContext
1261
1262	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
1263	// the specified property structs to it as if the properties were set in a blueprint file.
1264	CreateModule(ModuleFactory, string, ...interface{}) Module
1265
1266	// RegisterScopedModuleType creates a new module type that is scoped to the current Blueprints
1267	// file.
1268	RegisterScopedModuleType(name string, factory ModuleFactory)
1269}
1270
1271func (l *loadHookContext) CreateModule(factory ModuleFactory, typeName string, props ...interface{}) Module {
1272	module := newModule(factory)
1273
1274	module.relBlueprintsFile = l.module.relBlueprintsFile
1275	module.pos = l.module.pos
1276	module.propertyPos = l.module.propertyPos
1277	module.createdBy = l.module
1278	module.typeName = typeName
1279
1280	for _, p := range props {
1281		err := proptools.AppendMatchingProperties(module.properties, p, nil)
1282		if err != nil {
1283			panic(err)
1284		}
1285	}
1286
1287	l.newModules = append(l.newModules, module)
1288
1289	return module.logicModule
1290}
1291
1292func (l *loadHookContext) RegisterScopedModuleType(name string, factory ModuleFactory) {
1293	if _, exists := l.context.moduleFactories[name]; exists {
1294		panic(fmt.Errorf("A global module type named %q already exists", name))
1295	}
1296
1297	if _, exists := (*l.scopedModuleFactories)[name]; exists {
1298		panic(fmt.Errorf("A module type named %q already exists in this scope", name))
1299	}
1300
1301	if *l.scopedModuleFactories == nil {
1302		*l.scopedModuleFactories = make(map[string]ModuleFactory)
1303	}
1304
1305	(*l.scopedModuleFactories)[name] = factory
1306}
1307
1308type loadHookContext struct {
1309	baseModuleContext
1310	newModules            []*moduleInfo
1311	scopedModuleFactories *map[string]ModuleFactory
1312}
1313
1314type LoadHook func(ctx LoadHookContext)
1315
1316// Load hooks need to be added by module factories, which don't have any parameter to get to the
1317// Context, and only produce a Module interface with no base implementation, so the load hooks
1318// must be stored in a global map.  The key is a pointer allocated by the module factory, so there
1319// is no chance of collisions even if tests are running in parallel with multiple contexts.  The
1320// contents should be short-lived, they are added during a module factory and removed immediately
1321// after the module factory returns.
1322var pendingHooks sync.Map
1323
1324func AddLoadHook(module Module, hook LoadHook) {
1325	// Only one goroutine can be processing a given module, so no additional locking is required
1326	// for the slice stored in the sync.Map.
1327	v, exists := pendingHooks.Load(module)
1328	if !exists {
1329		v, _ = pendingHooks.LoadOrStore(module, new([]LoadHook))
1330	}
1331	hooks := v.(*[]LoadHook)
1332	*hooks = append(*hooks, hook)
1333}
1334
1335func runAndRemoveLoadHooks(ctx *Context, config interface{}, module *moduleInfo,
1336	scopedModuleFactories *map[string]ModuleFactory) (newModules []*moduleInfo, deps []string, errs []error) {
1337
1338	if v, exists := pendingHooks.Load(module.logicModule); exists {
1339		hooks := v.(*[]LoadHook)
1340
1341		for _, hook := range *hooks {
1342			mctx := &loadHookContext{
1343				baseModuleContext: baseModuleContext{
1344					context: ctx,
1345					config:  config,
1346					module:  module,
1347				},
1348				scopedModuleFactories: scopedModuleFactories,
1349			}
1350			hook(mctx)
1351			newModules = append(newModules, mctx.newModules...)
1352			deps = append(deps, mctx.ninjaFileDeps...)
1353			errs = append(errs, mctx.errs...)
1354		}
1355		pendingHooks.Delete(module.logicModule)
1356
1357		return newModules, deps, errs
1358	}
1359
1360	return nil, nil, nil
1361}
1362
1363// Check the syntax of a generated blueprint file.
1364//
1365// This is intended to perform a quick syntactic check for generated blueprint
1366// code, where syntactically correct means:
1367// * No variable definitions.
1368// * Valid module types.
1369// * Valid property names.
1370// * Valid values for the property type.
1371//
1372// It does not perform any semantic checking of properties, existence of referenced
1373// files, or dependencies.
1374//
1375// At a low level it:
1376// * Parses the contents.
1377// * Invokes relevant factory to create Module instances.
1378// * Unpacks the properties into the Module.
1379// * Does not invoke load hooks or any mutators.
1380//
1381// The filename is only used for reporting errors.
1382func CheckBlueprintSyntax(moduleFactories map[string]ModuleFactory, filename string, contents string) []error {
1383	scope := parser.NewScope(nil)
1384	file, errs := parser.Parse(filename, strings.NewReader(contents), scope)
1385	if len(errs) != 0 {
1386		return errs
1387	}
1388
1389	for _, def := range file.Defs {
1390		switch def := def.(type) {
1391		case *parser.Module:
1392			_, moduleErrs := processModuleDef(def, filename, moduleFactories, nil, false)
1393			errs = append(errs, moduleErrs...)
1394
1395		default:
1396			panic(fmt.Errorf("unknown definition type: %T", def))
1397		}
1398	}
1399
1400	return errs
1401}
1402
1403func maybeLogicModule(module *moduleInfo) Module {
1404	if module != nil {
1405		return module.logicModule
1406	} else {
1407		return nil
1408	}
1409}
1410