blob: 22896c203ce6ccb8c5700df1ecb024cd33f9736a [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// 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
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
18 "fmt"
19 "path/filepath"
Jamie Gennis6a40c192014-07-02 16:40:31 -070020 "text/scanner"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070021)
22
Jamie Gennisb9e87f62014-09-24 20:28:11 -070023// A Module handles generating all of the Ninja build actions needed to build a
Colin Crossc9028482014-12-18 16:28:54 -080024// single module based on properties defined in a Blueprints file. Module
25// objects are initially created during the parse phase of a Context using one
26// of the registered module types (and the associated ModuleFactory function).
27// The Module's properties struct is automatically filled in with the property
28// values specified in the Blueprints file (see Context.RegisterModuleType for more
Jamie Gennisb9e87f62014-09-24 20:28:11 -070029// information on this).
30//
Colin Crossc9028482014-12-18 16:28:54 -080031// A Module can be split into multiple Modules by a Mutator. All existing
32// properties set on the module will be duplicated to the new Module, and then
33// modified as necessary by the Mutator.
34//
Jamie Gennisb9e87f62014-09-24 20:28:11 -070035// The Module implementation can access the build configuration as well as any
36// modules on which on which it depends (as defined by the "deps" property
Colin Cross763b6f12015-10-29 15:32:56 -070037// specified in the Blueprints file, dynamically added by implementing the
38// (deprecated) DynamicDependerModule interface, or dynamically added by a
39// BottomUpMutator) using the ModuleContext passed to GenerateBuildActions.
40// This ModuleContext is also used to create Ninja build actions and to report
41// errors to the user.
Jamie Gennisb9e87f62014-09-24 20:28:11 -070042//
43// In addition to implementing the GenerateBuildActions method, a Module should
44// implement methods that provide dependant modules and singletons information
45// they need to generate their build actions. These methods will only be called
46// after GenerateBuildActions is called because the Context calls
47// GenerateBuildActions in dependency-order (and singletons are invoked after
48// all the Modules). The set of methods a Module supports will determine how
49// dependant Modules interact with it.
50//
51// For example, consider a Module that is responsible for generating a library
52// that other modules can link against. The library Module might implement the
53// following interface:
54//
55// type LibraryProducer interface {
56// LibraryFileName() string
57// }
58//
59// func IsLibraryProducer(module blueprint.Module) {
60// _, ok := module.(LibraryProducer)
61// return ok
62// }
63//
64// A binary-producing Module that depends on the library Module could then do:
65//
66// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
67// ...
68// var libraryFiles []string
69// ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
70// func(module blueprint.Module) {
71// libProducer := module.(LibraryProducer)
72// libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
73// })
74// ...
75// }
76//
77// to build the list of library file names that should be included in its link
78// command.
Colin Cross691a60d2015-01-07 18:08:56 -080079//
80// GenerateBuildActions may be called from multiple threads. It is guaranteed to
81// be called after it has finished being called on all dependencies and on all
82// variants of that appear earlier in the ModuleContext.VisitAllModuleVariants list.
83// Any accesses to global variables or to Module objects that are not dependencies
84// or variants of the current Module must be synchronized by the implementation of
85// GenerateBuildActions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070086type Module interface {
Jamie Gennisb9e87f62014-09-24 20:28:11 -070087 // GenerateBuildActions is called by the Context that created the Module
88 // during its generate phase. This call should generate all Ninja build
89 // actions (rules, pools, and build statements) needed to build the module.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070090 GenerateBuildActions(ModuleContext)
91}
92
Jamie Gennisb9e87f62014-09-24 20:28:11 -070093// A DynamicDependerModule is a Module that may add dependencies that do not
94// appear in its "deps" property. Any Module that implements this interface
95// will have its DynamicDependencies method called by the Context that created
96// it during generate phase.
Colin Cross763b6f12015-10-29 15:32:56 -070097//
98// Deprecated, use a BottomUpMutator instead
Jamie Gennisb9e87f62014-09-24 20:28:11 -070099type DynamicDependerModule interface {
100 Module
101
102 // DynamicDependencies is called by the Context that created the
103 // DynamicDependerModule during its generate phase. This call should return
104 // the list of module names that the DynamicDependerModule depends on
105 // dynamically. Module names that already appear in the "deps" property may
106 // but do not need to be included in the returned list.
107 DynamicDependencies(DynamicDependerModuleContext) []string
108}
109
Colin Crossbe1a9a12014-12-18 11:05:45 -0800110type BaseModuleContext interface {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700111 ModuleName() string
112 ModuleDir() string
Jamie Gennis6eb4d242014-06-11 18:31:16 -0700113 Config() interface{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700114
David Allison701fbad2014-10-29 14:51:13 -0700115 ContainsProperty(name string) bool
Jamie Gennis6a40c192014-07-02 16:40:31 -0700116 Errorf(pos scanner.Position, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700117 ModuleErrorf(fmt string, args ...interface{})
118 PropertyErrorf(property, fmt string, args ...interface{})
Jamie Gennis6a40c192014-07-02 16:40:31 -0700119 Failed() bool
Colin Cross763b6f12015-10-29 15:32:56 -0700120
121 moduleInfo() *moduleInfo
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800122 error(err error)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700123}
124
Colin Cross763b6f12015-10-29 15:32:56 -0700125type DynamicDependerModuleContext BottomUpMutatorContext
Colin Crossbe1a9a12014-12-18 11:05:45 -0800126
Colin Cross1455a0f2014-12-17 13:23:56 -0800127type ModuleContext interface {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800128 BaseModuleContext
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700129
130 OtherModuleName(m Module) string
131 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Colin Cross2c1f3d12016-04-11 15:47:28 -0700132 OtherModuleDependencyTag(m Module) DependencyTag
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700133
Colin Crossc7ffa302015-02-10 11:24:52 -0800134 VisitDirectDeps(visit func(Module))
135 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800136 VisitDepsDepthFirst(visit func(Module))
137 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Yuchen Wu222e2452015-10-06 14:03:27 -0700138 WalkDeps(visit func(Module, Module) bool)
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800139
Colin Crossc9028482014-12-18 16:28:54 -0800140 ModuleSubDir() string
141
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800142 Variable(pctx PackageContext, name, value string)
143 Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
144 Build(pctx PackageContext, params BuildParams)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700145
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700146 AddNinjaFileDeps(deps ...string)
Colin Crossc9028482014-12-18 16:28:54 -0800147
148 PrimaryModule() Module
Colin Cross80ad04d2015-01-06 16:19:59 -0800149 FinalModule() Module
150 VisitAllModuleVariants(visit func(Module))
Colin Cross036a1df2015-12-17 15:49:30 -0800151
152 GetMissingDependencies() []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700153}
154
Colin Crossbe1a9a12014-12-18 11:05:45 -0800155var _ BaseModuleContext = (*baseModuleContext)(nil)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700156
Colin Crossbe1a9a12014-12-18 11:05:45 -0800157type baseModuleContext struct {
Colin Crossbafd5f52016-08-06 22:52:01 -0700158 context *Context
159 config interface{}
160 module *moduleInfo
161 errs []error
162 visitingParent *moduleInfo
163 visitingDep depInfo
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700164}
165
Colin Cross763b6f12015-10-29 15:32:56 -0700166func (d *baseModuleContext) moduleInfo() *moduleInfo {
167 return d.module
168}
169
Colin Crossbe1a9a12014-12-18 11:05:45 -0800170func (d *baseModuleContext) ModuleName() string {
Colin Crossed342d92015-03-11 00:57:25 -0700171 return d.module.properties.Name
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700172}
173
Colin Crossbe1a9a12014-12-18 11:05:45 -0800174func (d *baseModuleContext) ContainsProperty(name string) bool {
Colin Crossed342d92015-03-11 00:57:25 -0700175 _, ok := d.module.propertyPos[name]
David Allison701fbad2014-10-29 14:51:13 -0700176 return ok
177}
178
Colin Crossbe1a9a12014-12-18 11:05:45 -0800179func (d *baseModuleContext) ModuleDir() string {
Colin Crossed342d92015-03-11 00:57:25 -0700180 return filepath.Dir(d.module.relBlueprintsFile)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700181}
182
Colin Crossbe1a9a12014-12-18 11:05:45 -0800183func (d *baseModuleContext) Config() interface{} {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700184 return d.config
185}
186
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800187func (d *baseModuleContext) error(err error) {
188 if err != nil {
189 d.errs = append(d.errs, err)
190 }
191}
192
Colin Crossbe1a9a12014-12-18 11:05:45 -0800193func (d *baseModuleContext) Errorf(pos scanner.Position,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700194 format string, args ...interface{}) {
195
Colin Cross2c628442016-10-07 17:13:10 -0700196 d.error(&BlueprintError{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700197 Err: fmt.Errorf(format, args...),
198 Pos: pos,
199 })
200}
201
Colin Crossbe1a9a12014-12-18 11:05:45 -0800202func (d *baseModuleContext) ModuleErrorf(format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700203 args ...interface{}) {
204
Colin Cross2c628442016-10-07 17:13:10 -0700205 d.error(&ModuleError{
206 BlueprintError: BlueprintError{
207 Err: fmt.Errorf(format, args...),
208 Pos: d.module.pos,
209 },
210 module: d.module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700211 })
212}
213
Colin Crossbe1a9a12014-12-18 11:05:45 -0800214func (d *baseModuleContext) PropertyErrorf(property, format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700215 args ...interface{}) {
216
Colin Crossa2ca92c2015-11-02 16:10:23 -0800217 pos := d.module.propertyPos[property]
218
219 if !pos.IsValid() {
220 pos = d.module.pos
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700221 }
222
Colin Cross2c628442016-10-07 17:13:10 -0700223 d.error(&PropertyError{
224 ModuleError: ModuleError{
225 BlueprintError: BlueprintError{
226 Err: fmt.Errorf(format, args...),
227 Pos: pos,
228 },
229 module: d.module,
230 },
231 property: property,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700232 })
233}
234
Colin Crossbe1a9a12014-12-18 11:05:45 -0800235func (d *baseModuleContext) Failed() bool {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700236 return len(d.errs) > 0
237}
238
Colin Cross1455a0f2014-12-17 13:23:56 -0800239var _ ModuleContext = (*moduleContext)(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700240
Colin Cross1455a0f2014-12-17 13:23:56 -0800241type moduleContext struct {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800242 baseModuleContext
Colin Cross036a1df2015-12-17 15:49:30 -0800243 scope *localScope
244 ninjaFileDeps []string
245 actionDefs localBuildActions
246 handledMissingDeps bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700247}
248
Colin Cross2c1f3d12016-04-11 15:47:28 -0700249func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
Colin Crossed342d92015-03-11 00:57:25 -0700250 module := m.context.moduleInfo[logicModule]
251 return module.properties.Name
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700252}
253
Colin Cross2c1f3d12016-04-11 15:47:28 -0700254func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700255 args ...interface{}) {
256
Colin Crossed342d92015-03-11 00:57:25 -0700257 module := m.context.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -0700258 m.errs = append(m.errs, &ModuleError{
259 BlueprintError: BlueprintError{
260 Err: fmt.Errorf(format, args...),
261 Pos: module.pos,
262 },
263 module: module,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700264 })
265}
266
Colin Cross2c1f3d12016-04-11 15:47:28 -0700267func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
268 // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
Colin Crossbafd5f52016-08-06 22:52:01 -0700269 if logicModule == m.visitingDep.module.logicModule {
270 return m.visitingDep.tag
Colin Cross2c1f3d12016-04-11 15:47:28 -0700271 }
272
Colin Crossbafd5f52016-08-06 22:52:01 -0700273 for _, dep := range m.visitingParent.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700274 if dep.module.logicModule == logicModule {
275 return dep.tag
276 }
277 }
278
279 return nil
Colin Crossc7ffa302015-02-10 11:24:52 -0800280}
281
Colin Cross2c1f3d12016-04-11 15:47:28 -0700282func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
283 defer func() {
284 if r := recover(); r != nil {
285 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
Colin Crossbafd5f52016-08-06 22:52:01 -0700286 m.module, funcName(visit), m.visitingDep.module))
Colin Cross2c1f3d12016-04-11 15:47:28 -0700287 }
288 }()
289
Colin Crossbafd5f52016-08-06 22:52:01 -0700290 m.visitingParent = m.module
291
Colin Cross2c1f3d12016-04-11 15:47:28 -0700292 for _, dep := range m.module.directDeps {
Colin Crossbafd5f52016-08-06 22:52:01 -0700293 m.visitingDep = dep
Colin Cross2c1f3d12016-04-11 15:47:28 -0700294 visit(dep.module.logicModule)
295 }
Colin Crossbafd5f52016-08-06 22:52:01 -0700296
297 m.visitingParent = nil
298 m.visitingDep = depInfo{}
Colin Crossc7ffa302015-02-10 11:24:52 -0800299}
300
Colin Cross2c1f3d12016-04-11 15:47:28 -0700301func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
302 defer func() {
303 if r := recover(); r != nil {
304 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
Colin Crossbafd5f52016-08-06 22:52:01 -0700305 m.module, funcName(pred), funcName(visit), m.visitingDep.module))
Colin Cross2c1f3d12016-04-11 15:47:28 -0700306 }
307 }()
308
Colin Crossbafd5f52016-08-06 22:52:01 -0700309 m.visitingParent = m.module
310
Colin Cross2c1f3d12016-04-11 15:47:28 -0700311 for _, dep := range m.module.directDeps {
Colin Crossbafd5f52016-08-06 22:52:01 -0700312 m.visitingDep = dep
Colin Cross2c1f3d12016-04-11 15:47:28 -0700313 if pred(dep.module.logicModule) {
314 visit(dep.module.logicModule)
315 }
316 }
Colin Crossbafd5f52016-08-06 22:52:01 -0700317
318 m.visitingParent = nil
319 m.visitingDep = depInfo{}
Colin Cross2c1f3d12016-04-11 15:47:28 -0700320}
321
322func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -0700323 defer func() {
324 if r := recover(); r != nil {
325 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
326 m.module, funcName(visit), m.visitingDep.module))
327 }
328 }()
329
330 m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
331 m.visitingParent = parent
332 m.visitingDep = dep
333 visit(dep.module.logicModule)
334 })
335
336 m.visitingParent = nil
337 m.visitingDep = depInfo{}
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800338}
339
Colin Cross2c1f3d12016-04-11 15:47:28 -0700340func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800341 visit func(Module)) {
342
Colin Crossbafd5f52016-08-06 22:52:01 -0700343 defer func() {
344 if r := recover(); r != nil {
345 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
346 m.module, funcName(pred), funcName(visit), m.visitingDep.module))
347 }
348 }()
349
350 m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
351 if pred(dep.module.logicModule) {
352 m.visitingParent = parent
353 m.visitingDep = dep
354 visit(dep.module.logicModule)
355 }
356 })
357
358 m.visitingParent = nil
359 m.visitingDep = depInfo{}
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800360}
361
Colin Cross2c1f3d12016-04-11 15:47:28 -0700362func (m *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
Colin Crossbafd5f52016-08-06 22:52:01 -0700363 m.context.walkDeps(m.module, func(dep depInfo, parent *moduleInfo) bool {
364 m.visitingParent = parent
365 m.visitingDep = dep
366 return visit(dep.module.logicModule, parent.logicModule)
367 }, nil)
368
369 m.visitingParent = nil
370 m.visitingDep = depInfo{}
Yuchen Wu222e2452015-10-06 14:03:27 -0700371}
372
Colin Crossc9028482014-12-18 16:28:54 -0800373func (m *moduleContext) ModuleSubDir() string {
Colin Crosse7daa222015-03-11 14:35:41 -0700374 return m.module.variantName
Colin Crossc9028482014-12-18 16:28:54 -0800375}
376
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800377func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700378 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700379
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700380 v, err := m.scope.AddLocalVariable(name, value)
381 if err != nil {
382 panic(err)
383 }
384
385 m.actionDefs.variables = append(m.actionDefs.variables, v)
386}
387
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800388func (m *moduleContext) Rule(pctx PackageContext, name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700389 params RuleParams, argNames ...string) Rule {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700390
Jamie Gennis2fb20952014-10-03 02:49:58 -0700391 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700392
Jamie Genniscbc6f862014-06-05 20:00:22 -0700393 r, err := m.scope.AddLocalRule(name, &params, argNames...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700394 if err != nil {
395 panic(err)
396 }
397
398 m.actionDefs.rules = append(m.actionDefs.rules, r)
399
400 return r
401}
402
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800403func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700404 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700405
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700406 def, err := parseBuildParams(m.scope, &params)
407 if err != nil {
408 panic(err)
409 }
410
411 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
412}
413
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700414func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
415 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
416}
Colin Crossc9028482014-12-18 16:28:54 -0800417
418func (m *moduleContext) PrimaryModule() Module {
Colin Cross80ad04d2015-01-06 16:19:59 -0800419 return m.module.group.modules[0].logicModule
420}
421
422func (m *moduleContext) FinalModule() Module {
423 return m.module.group.modules[len(m.module.group.modules)-1].logicModule
424}
425
426func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800427 m.context.visitAllModuleVariants(m.module, visit)
Colin Crossc9028482014-12-18 16:28:54 -0800428}
429
Colin Cross036a1df2015-12-17 15:49:30 -0800430func (m *moduleContext) GetMissingDependencies() []string {
431 m.handledMissingDeps = true
432 return m.module.missingDeps
433}
434
Colin Crossc9028482014-12-18 16:28:54 -0800435//
436// MutatorContext
437//
438
439type mutatorContext struct {
440 baseModuleContext
Colin Cross8d8a7af2015-11-03 16:41:29 -0800441 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700442 reverseDeps []reverseDep
443 newModules []*moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800444}
445
446type baseMutatorContext interface {
447 BaseModuleContext
448
449 Module() Module
450}
451
Colin Cross65569e42015-03-10 20:08:19 -0700452type EarlyMutatorContext interface {
453 baseMutatorContext
454
Colin Crossf5e34b92015-03-13 16:02:36 -0700455 CreateVariations(...string) []Module
456 CreateLocalVariations(...string) []Module
Colin Cross65569e42015-03-10 20:08:19 -0700457}
458
Colin Crossc9028482014-12-18 16:28:54 -0800459type TopDownMutatorContext interface {
460 baseMutatorContext
461
Colin Cross8d222332015-11-02 16:11:32 -0800462 OtherModuleName(m Module) string
463 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Colin Cross2c1f3d12016-04-11 15:47:28 -0700464 OtherModuleDependencyTag(m Module) DependencyTag
Colin Cross8d222332015-11-02 16:11:32 -0800465
Colin Crossc9028482014-12-18 16:28:54 -0800466 VisitDirectDeps(visit func(Module))
467 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
468 VisitDepsDepthFirst(visit func(Module))
469 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Yuchen Wu222e2452015-10-06 14:03:27 -0700470 WalkDeps(visit func(Module, Module) bool)
Colin Crossc9028482014-12-18 16:28:54 -0800471}
472
473type BottomUpMutatorContext interface {
Colin Cross93c4cf62016-08-06 22:54:17 -0700474 baseMutatorContext
Colin Crossc9028482014-12-18 16:28:54 -0800475
Colin Cross2c1f3d12016-04-11 15:47:28 -0700476 AddDependency(module Module, tag DependencyTag, name ...string)
477 AddReverseDependency(module Module, tag DependencyTag, name string)
Colin Crossf5e34b92015-03-13 16:02:36 -0700478 CreateVariations(...string) []Module
Jamie Gennis6a5825e2015-05-19 11:26:11 -0700479 CreateLocalVariations(...string) []Module
Colin Crossf5e34b92015-03-13 16:02:36 -0700480 SetDependencyVariation(string)
Colin Cross2c1f3d12016-04-11 15:47:28 -0700481 AddVariationDependencies([]Variation, DependencyTag, ...string)
482 AddFarVariationDependencies([]Variation, DependencyTag, ...string)
Colin Crossf1875462016-04-11 17:33:13 -0700483 AddInterVariantDependency(tag DependencyTag, from, to Module)
Colin Crossc9028482014-12-18 16:28:54 -0800484}
485
486// A Mutator function is called for each Module, and can use
Colin Crossf5e34b92015-03-13 16:02:36 -0700487// MutatorContext.CreateVariations to split a Module into multiple Modules,
Colin Crossc9028482014-12-18 16:28:54 -0800488// modifying properties on the new modules to differentiate them. It is called
489// after parsing all Blueprint files, but before generating any build rules,
490// and is always called on dependencies before being called on the depending module.
491//
492// The Mutator function should only modify members of properties structs, and not
493// members of the module struct itself, to ensure the modified values are copied
494// if a second Mutator chooses to split the module a second time.
495type TopDownMutator func(mctx TopDownMutatorContext)
496type BottomUpMutator func(mctx BottomUpMutatorContext)
Colin Cross65569e42015-03-10 20:08:19 -0700497type EarlyMutator func(mctx EarlyMutatorContext)
Colin Crossc9028482014-12-18 16:28:54 -0800498
Colin Cross2c1f3d12016-04-11 15:47:28 -0700499// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be
500// used to transfer information on a dependency between the mutator that called AddDependency
501// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the
502// interface (pointing to the same concrete object) from their original module.
503type DependencyTag interface {
504 dependencyTag(DependencyTag)
505}
506
507type BaseDependencyTag struct {
508}
509
510func (BaseDependencyTag) dependencyTag(DependencyTag) {
511}
512
513var _ DependencyTag = BaseDependencyTag{}
514
Colin Crossf5e34b92015-03-13 16:02:36 -0700515// Split a module into mulitple variants, one for each name in the variationNames
516// parameter. It returns a list of new modules in the same order as the variationNames
Colin Crossc9028482014-12-18 16:28:54 -0800517// list.
518//
519// If any of the dependencies of the module being operated on were already split
Colin Crossf5e34b92015-03-13 16:02:36 -0700520// by calling CreateVariations with the same name, the dependency will automatically
Colin Crossc9028482014-12-18 16:28:54 -0800521// be updated to point the matching variant.
522//
523// If a module is split, and then a module depending on the first module is not split
524// when the Mutator is later called on it, the dependency of the depending module will
525// automatically be updated to point to the first variant.
Colin Crossf5e34b92015-03-13 16:02:36 -0700526func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
527 return mctx.createVariations(variationNames, false)
Colin Cross65569e42015-03-10 20:08:19 -0700528}
529
530// Split a module into mulitple variants, one for each name in the variantNames
531// parameter. It returns a list of new modules in the same order as the variantNames
532// list.
533//
Colin Crossf5e34b92015-03-13 16:02:36 -0700534// Local variations do not affect automatic dependency resolution - dependencies added
Colin Cross65569e42015-03-10 20:08:19 -0700535// to the split module via deps or DynamicDependerModule must exactly match a variant
Colin Crossf5e34b92015-03-13 16:02:36 -0700536// that contains all the non-local variations.
537func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
538 return mctx.createVariations(variationNames, true)
Colin Cross65569e42015-03-10 20:08:19 -0700539}
540
Colin Crossf5e34b92015-03-13 16:02:36 -0700541func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
Colin Crossc9028482014-12-18 16:28:54 -0800542 ret := []Module{}
Colin Crossf5e34b92015-03-13 16:02:36 -0700543 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames)
Colin Cross174ae052015-03-03 17:37:03 -0800544 if len(errs) > 0 {
545 mctx.errs = append(mctx.errs, errs...)
546 }
Colin Crossc9028482014-12-18 16:28:54 -0800547
Colin Cross65569e42015-03-10 20:08:19 -0700548 for i, module := range modules {
Colin Crossc9028482014-12-18 16:28:54 -0800549 ret = append(ret, module.logicModule)
Colin Cross65569e42015-03-10 20:08:19 -0700550 if !local {
Colin Crossf5e34b92015-03-13 16:02:36 -0700551 module.dependencyVariant[mctx.name] = variationNames[i]
Colin Cross65569e42015-03-10 20:08:19 -0700552 }
Colin Crossc9028482014-12-18 16:28:54 -0800553 }
554
Colin Cross49c279a2016-08-05 22:30:44 -0700555 if mctx.newModules != nil {
556 panic("module already has variations from this mutator")
557 }
558 mctx.newModules = modules
559
Colin Crossf5e34b92015-03-13 16:02:36 -0700560 if len(ret) != len(variationNames) {
Colin Crossc9028482014-12-18 16:28:54 -0800561 panic("oops!")
562 }
563
564 return ret
565}
566
Colin Crossf5e34b92015-03-13 16:02:36 -0700567// Set all dangling dependencies on the current module to point to the variation
Colin Crossc9028482014-12-18 16:28:54 -0800568// with given name.
Colin Crossf5e34b92015-03-13 16:02:36 -0700569func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
570 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
Colin Crossc9028482014-12-18 16:28:54 -0800571}
572
573func (mctx *mutatorContext) Module() Module {
574 return mctx.module.logicModule
575}
576
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700577// Add a dependency to the given module.
Colin Crossc9028482014-12-18 16:28:54 -0800578// Does not affect the ordering of the current mutator pass, but will be ordered
579// correctly for all future mutator passes.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700580func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
Colin Cross763b6f12015-10-29 15:32:56 -0700581 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700582 errs := mctx.context.addDependency(mctx.context.moduleInfo[module], tag, dep)
Colin Cross763b6f12015-10-29 15:32:56 -0700583 if len(errs) > 0 {
584 mctx.errs = append(mctx.errs, errs...)
585 }
Colin Cross65569e42015-03-10 20:08:19 -0700586 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700587}
588
589// Add a dependency from the destination to the given module.
590// Does not affect the ordering of the current mutator pass, but will be ordered
Colin Cross8d8a7af2015-11-03 16:41:29 -0800591// correctly for all future mutator passes. All reverse dependencies for a destination module are
592// collected until the end of the mutator pass, sorted by name, and then appended to the destination
593// module's dependency list.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700594func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
Colin Cross8d8a7af2015-11-03 16:41:29 -0800595 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700596 if len(errs) > 0 {
597 mctx.errs = append(mctx.errs, errs...)
Colin Cross8d8a7af2015-11-03 16:41:29 -0800598 return
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700599 }
Colin Cross8d8a7af2015-11-03 16:41:29 -0800600
Colin Cross49c279a2016-08-05 22:30:44 -0700601 mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
602 destModule,
603 depInfo{mctx.context.moduleInfo[module], tag},
604 })
Colin Crossc9028482014-12-18 16:28:54 -0800605}
606
Colin Cross763b6f12015-10-29 15:32:56 -0700607// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
608// argument to select which variant of the dependency to use. A variant of the dependency must
609// exist that matches the all of the non-local variations of the current module, plus the variations
610// argument.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700611func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
Colin Cross763b6f12015-10-29 15:32:56 -0700612 deps ...string) {
613
614 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700615 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
Colin Cross763b6f12015-10-29 15:32:56 -0700616 if len(errs) > 0 {
617 mctx.errs = append(mctx.errs, errs...)
618 }
619 }
620}
621
622// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
623// variations argument to select which variant of the dependency to use. A variant of the
624// dependency must exist that matches the variations argument, but may also have other variations.
625// For any unspecified variation the first variant will be used.
626//
627// Unlike AddVariationDependencies, the variations of the current module are ignored - the
628// depdendency only needs to match the supplied variations.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700629func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
Colin Cross763b6f12015-10-29 15:32:56 -0700630 deps ...string) {
631
632 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700633 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
Colin Cross763b6f12015-10-29 15:32:56 -0700634 if len(errs) > 0 {
635 mctx.errs = append(mctx.errs, errs...)
636 }
637 }
638}
Colin Crossf1875462016-04-11 17:33:13 -0700639
640func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
641 mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
642}