blob: 5cc25c9994033b67db7d8a8475e742a3fe2d77c3 [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 Cross0aa6a5f2016-01-07 13:43:09 -0800196 d.error(&Error{
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 Cross0aa6a5f2016-01-07 13:43:09 -0800205 d.error(&Error{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700206 Err: fmt.Errorf(format, args...),
Colin Crossed342d92015-03-11 00:57:25 -0700207 Pos: d.module.pos,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700208 })
209}
210
Colin Crossbe1a9a12014-12-18 11:05:45 -0800211func (d *baseModuleContext) PropertyErrorf(property, format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700212 args ...interface{}) {
213
Colin Crossa2ca92c2015-11-02 16:10:23 -0800214 pos := d.module.propertyPos[property]
215
216 if !pos.IsValid() {
217 pos = d.module.pos
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700218 }
219
Colin Crossa2ca92c2015-11-02 16:10:23 -0800220 format = property + ": " + format
221
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800222 d.error(&Error{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700223 Err: fmt.Errorf(format, args...),
224 Pos: pos,
225 })
226}
227
Colin Crossbe1a9a12014-12-18 11:05:45 -0800228func (d *baseModuleContext) Failed() bool {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700229 return len(d.errs) > 0
230}
231
Colin Cross1455a0f2014-12-17 13:23:56 -0800232var _ ModuleContext = (*moduleContext)(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700233
Colin Cross1455a0f2014-12-17 13:23:56 -0800234type moduleContext struct {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800235 baseModuleContext
Colin Cross036a1df2015-12-17 15:49:30 -0800236 scope *localScope
237 ninjaFileDeps []string
238 actionDefs localBuildActions
239 handledMissingDeps bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700240}
241
Colin Cross2c1f3d12016-04-11 15:47:28 -0700242func (m *baseModuleContext) OtherModuleName(logicModule Module) string {
Colin Crossed342d92015-03-11 00:57:25 -0700243 module := m.context.moduleInfo[logicModule]
244 return module.properties.Name
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700245}
246
Colin Cross2c1f3d12016-04-11 15:47:28 -0700247func (m *baseModuleContext) OtherModuleErrorf(logicModule Module, format string,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700248 args ...interface{}) {
249
Colin Crossed342d92015-03-11 00:57:25 -0700250 module := m.context.moduleInfo[logicModule]
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700251 m.errs = append(m.errs, &Error{
252 Err: fmt.Errorf(format, args...),
Colin Crossed342d92015-03-11 00:57:25 -0700253 Pos: module.pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700254 })
255}
256
Colin Cross2c1f3d12016-04-11 15:47:28 -0700257func (m *baseModuleContext) OtherModuleDependencyTag(logicModule Module) DependencyTag {
258 // fast path for calling OtherModuleDependencyTag from inside VisitDirectDeps
Colin Crossbafd5f52016-08-06 22:52:01 -0700259 if logicModule == m.visitingDep.module.logicModule {
260 return m.visitingDep.tag
Colin Cross2c1f3d12016-04-11 15:47:28 -0700261 }
262
Colin Crossbafd5f52016-08-06 22:52:01 -0700263 for _, dep := range m.visitingParent.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700264 if dep.module.logicModule == logicModule {
265 return dep.tag
266 }
267 }
268
269 return nil
Colin Crossc7ffa302015-02-10 11:24:52 -0800270}
271
Colin Cross2c1f3d12016-04-11 15:47:28 -0700272func (m *baseModuleContext) VisitDirectDeps(visit func(Module)) {
273 defer func() {
274 if r := recover(); r != nil {
275 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
Colin Crossbafd5f52016-08-06 22:52:01 -0700276 m.module, funcName(visit), m.visitingDep.module))
Colin Cross2c1f3d12016-04-11 15:47:28 -0700277 }
278 }()
279
Colin Crossbafd5f52016-08-06 22:52:01 -0700280 m.visitingParent = m.module
281
Colin Cross2c1f3d12016-04-11 15:47:28 -0700282 for _, dep := range m.module.directDeps {
Colin Crossbafd5f52016-08-06 22:52:01 -0700283 m.visitingDep = dep
Colin Cross2c1f3d12016-04-11 15:47:28 -0700284 visit(dep.module.logicModule)
285 }
Colin Crossbafd5f52016-08-06 22:52:01 -0700286
287 m.visitingParent = nil
288 m.visitingDep = depInfo{}
Colin Crossc7ffa302015-02-10 11:24:52 -0800289}
290
Colin Cross2c1f3d12016-04-11 15:47:28 -0700291func (m *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
292 defer func() {
293 if r := recover(); r != nil {
294 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
Colin Crossbafd5f52016-08-06 22:52:01 -0700295 m.module, funcName(pred), funcName(visit), m.visitingDep.module))
Colin Cross2c1f3d12016-04-11 15:47:28 -0700296 }
297 }()
298
Colin Crossbafd5f52016-08-06 22:52:01 -0700299 m.visitingParent = m.module
300
Colin Cross2c1f3d12016-04-11 15:47:28 -0700301 for _, dep := range m.module.directDeps {
Colin Crossbafd5f52016-08-06 22:52:01 -0700302 m.visitingDep = dep
Colin Cross2c1f3d12016-04-11 15:47:28 -0700303 if pred(dep.module.logicModule) {
304 visit(dep.module.logicModule)
305 }
306 }
Colin Crossbafd5f52016-08-06 22:52:01 -0700307
308 m.visitingParent = nil
309 m.visitingDep = depInfo{}
Colin Cross2c1f3d12016-04-11 15:47:28 -0700310}
311
312func (m *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -0700313 defer func() {
314 if r := recover(); r != nil {
315 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
316 m.module, funcName(visit), m.visitingDep.module))
317 }
318 }()
319
320 m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
321 m.visitingParent = parent
322 m.visitingDep = dep
323 visit(dep.module.logicModule)
324 })
325
326 m.visitingParent = nil
327 m.visitingDep = depInfo{}
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800328}
329
Colin Cross2c1f3d12016-04-11 15:47:28 -0700330func (m *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800331 visit func(Module)) {
332
Colin Crossbafd5f52016-08-06 22:52:01 -0700333 defer func() {
334 if r := recover(); r != nil {
335 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
336 m.module, funcName(pred), funcName(visit), m.visitingDep.module))
337 }
338 }()
339
340 m.context.walkDeps(m.module, nil, func(dep depInfo, parent *moduleInfo) {
341 if pred(dep.module.logicModule) {
342 m.visitingParent = parent
343 m.visitingDep = dep
344 visit(dep.module.logicModule)
345 }
346 })
347
348 m.visitingParent = nil
349 m.visitingDep = depInfo{}
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800350}
351
Colin Cross2c1f3d12016-04-11 15:47:28 -0700352func (m *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
Colin Crossbafd5f52016-08-06 22:52:01 -0700353 m.context.walkDeps(m.module, func(dep depInfo, parent *moduleInfo) bool {
354 m.visitingParent = parent
355 m.visitingDep = dep
356 return visit(dep.module.logicModule, parent.logicModule)
357 }, nil)
358
359 m.visitingParent = nil
360 m.visitingDep = depInfo{}
Yuchen Wu222e2452015-10-06 14:03:27 -0700361}
362
Colin Crossc9028482014-12-18 16:28:54 -0800363func (m *moduleContext) ModuleSubDir() string {
Colin Crosse7daa222015-03-11 14:35:41 -0700364 return m.module.variantName
Colin Crossc9028482014-12-18 16:28:54 -0800365}
366
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800367func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700368 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700369
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700370 v, err := m.scope.AddLocalVariable(name, value)
371 if err != nil {
372 panic(err)
373 }
374
375 m.actionDefs.variables = append(m.actionDefs.variables, v)
376}
377
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800378func (m *moduleContext) Rule(pctx PackageContext, name string,
Jamie Gennis2fb20952014-10-03 02:49:58 -0700379 params RuleParams, argNames ...string) Rule {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700380
Jamie Gennis2fb20952014-10-03 02:49:58 -0700381 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700382
Jamie Genniscbc6f862014-06-05 20:00:22 -0700383 r, err := m.scope.AddLocalRule(name, &params, argNames...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700384 if err != nil {
385 panic(err)
386 }
387
388 m.actionDefs.rules = append(m.actionDefs.rules, r)
389
390 return r
391}
392
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800393func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
Jamie Gennis2fb20952014-10-03 02:49:58 -0700394 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700395
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700396 def, err := parseBuildParams(m.scope, &params)
397 if err != nil {
398 panic(err)
399 }
400
401 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
402}
403
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700404func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
405 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
406}
Colin Crossc9028482014-12-18 16:28:54 -0800407
408func (m *moduleContext) PrimaryModule() Module {
Colin Cross80ad04d2015-01-06 16:19:59 -0800409 return m.module.group.modules[0].logicModule
410}
411
412func (m *moduleContext) FinalModule() Module {
413 return m.module.group.modules[len(m.module.group.modules)-1].logicModule
414}
415
416func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800417 m.context.visitAllModuleVariants(m.module, visit)
Colin Crossc9028482014-12-18 16:28:54 -0800418}
419
Colin Cross036a1df2015-12-17 15:49:30 -0800420func (m *moduleContext) GetMissingDependencies() []string {
421 m.handledMissingDeps = true
422 return m.module.missingDeps
423}
424
Colin Crossc9028482014-12-18 16:28:54 -0800425//
426// MutatorContext
427//
428
429type mutatorContext struct {
430 baseModuleContext
Colin Cross8d8a7af2015-11-03 16:41:29 -0800431 name string
Colin Cross2c1f3d12016-04-11 15:47:28 -0700432 reverseDeps map[*moduleInfo][]depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800433}
434
435type baseMutatorContext interface {
436 BaseModuleContext
437
438 Module() Module
439}
440
Colin Cross65569e42015-03-10 20:08:19 -0700441type EarlyMutatorContext interface {
442 baseMutatorContext
443
Colin Crossf5e34b92015-03-13 16:02:36 -0700444 CreateVariations(...string) []Module
445 CreateLocalVariations(...string) []Module
Colin Cross65569e42015-03-10 20:08:19 -0700446}
447
Colin Crossc9028482014-12-18 16:28:54 -0800448type TopDownMutatorContext interface {
449 baseMutatorContext
450
Colin Cross8d222332015-11-02 16:11:32 -0800451 OtherModuleName(m Module) string
452 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Colin Cross2c1f3d12016-04-11 15:47:28 -0700453 OtherModuleDependencyTag(m Module) DependencyTag
Colin Cross8d222332015-11-02 16:11:32 -0800454
Colin Crossc9028482014-12-18 16:28:54 -0800455 VisitDirectDeps(visit func(Module))
456 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
457 VisitDepsDepthFirst(visit func(Module))
458 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Yuchen Wu222e2452015-10-06 14:03:27 -0700459 WalkDeps(visit func(Module, Module) bool)
Colin Crossc9028482014-12-18 16:28:54 -0800460}
461
462type BottomUpMutatorContext interface {
Colin Cross93c4cf62016-08-06 22:54:17 -0700463 baseMutatorContext
Colin Crossc9028482014-12-18 16:28:54 -0800464
Colin Cross2c1f3d12016-04-11 15:47:28 -0700465 AddDependency(module Module, tag DependencyTag, name ...string)
466 AddReverseDependency(module Module, tag DependencyTag, name string)
Colin Crossf5e34b92015-03-13 16:02:36 -0700467 CreateVariations(...string) []Module
Jamie Gennis6a5825e2015-05-19 11:26:11 -0700468 CreateLocalVariations(...string) []Module
Colin Crossf5e34b92015-03-13 16:02:36 -0700469 SetDependencyVariation(string)
Colin Cross2c1f3d12016-04-11 15:47:28 -0700470 AddVariationDependencies([]Variation, DependencyTag, ...string)
471 AddFarVariationDependencies([]Variation, DependencyTag, ...string)
Colin Crossf1875462016-04-11 17:33:13 -0700472 AddInterVariantDependency(tag DependencyTag, from, to Module)
Colin Crossc9028482014-12-18 16:28:54 -0800473}
474
475// A Mutator function is called for each Module, and can use
Colin Crossf5e34b92015-03-13 16:02:36 -0700476// MutatorContext.CreateVariations to split a Module into multiple Modules,
Colin Crossc9028482014-12-18 16:28:54 -0800477// modifying properties on the new modules to differentiate them. It is called
478// after parsing all Blueprint files, but before generating any build rules,
479// and is always called on dependencies before being called on the depending module.
480//
481// The Mutator function should only modify members of properties structs, and not
482// members of the module struct itself, to ensure the modified values are copied
483// if a second Mutator chooses to split the module a second time.
484type TopDownMutator func(mctx TopDownMutatorContext)
485type BottomUpMutator func(mctx BottomUpMutatorContext)
Colin Cross65569e42015-03-10 20:08:19 -0700486type EarlyMutator func(mctx EarlyMutatorContext)
Colin Crossc9028482014-12-18 16:28:54 -0800487
Colin Cross2c1f3d12016-04-11 15:47:28 -0700488// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be
489// used to transfer information on a dependency between the mutator that called AddDependency
490// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the
491// interface (pointing to the same concrete object) from their original module.
492type DependencyTag interface {
493 dependencyTag(DependencyTag)
494}
495
496type BaseDependencyTag struct {
497}
498
499func (BaseDependencyTag) dependencyTag(DependencyTag) {
500}
501
502var _ DependencyTag = BaseDependencyTag{}
503
Colin Crossf5e34b92015-03-13 16:02:36 -0700504// Split a module into mulitple variants, one for each name in the variationNames
505// parameter. It returns a list of new modules in the same order as the variationNames
Colin Crossc9028482014-12-18 16:28:54 -0800506// list.
507//
508// If any of the dependencies of the module being operated on were already split
Colin Crossf5e34b92015-03-13 16:02:36 -0700509// by calling CreateVariations with the same name, the dependency will automatically
Colin Crossc9028482014-12-18 16:28:54 -0800510// be updated to point the matching variant.
511//
512// If a module is split, and then a module depending on the first module is not split
513// when the Mutator is later called on it, the dependency of the depending module will
514// automatically be updated to point to the first variant.
Colin Crossf5e34b92015-03-13 16:02:36 -0700515func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
516 return mctx.createVariations(variationNames, false)
Colin Cross65569e42015-03-10 20:08:19 -0700517}
518
519// Split a module into mulitple variants, one for each name in the variantNames
520// parameter. It returns a list of new modules in the same order as the variantNames
521// list.
522//
Colin Crossf5e34b92015-03-13 16:02:36 -0700523// Local variations do not affect automatic dependency resolution - dependencies added
Colin Cross65569e42015-03-10 20:08:19 -0700524// to the split module via deps or DynamicDependerModule must exactly match a variant
Colin Crossf5e34b92015-03-13 16:02:36 -0700525// that contains all the non-local variations.
526func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
527 return mctx.createVariations(variationNames, true)
Colin Cross65569e42015-03-10 20:08:19 -0700528}
529
Colin Crossf5e34b92015-03-13 16:02:36 -0700530func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
Colin Crossc9028482014-12-18 16:28:54 -0800531 ret := []Module{}
Colin Crossf5e34b92015-03-13 16:02:36 -0700532 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames)
Colin Cross174ae052015-03-03 17:37:03 -0800533 if len(errs) > 0 {
534 mctx.errs = append(mctx.errs, errs...)
535 }
Colin Crossc9028482014-12-18 16:28:54 -0800536
Colin Cross65569e42015-03-10 20:08:19 -0700537 for i, module := range modules {
Colin Crossc9028482014-12-18 16:28:54 -0800538 ret = append(ret, module.logicModule)
Colin Cross65569e42015-03-10 20:08:19 -0700539 if !local {
Colin Crossf5e34b92015-03-13 16:02:36 -0700540 module.dependencyVariant[mctx.name] = variationNames[i]
Colin Cross65569e42015-03-10 20:08:19 -0700541 }
Colin Crossc9028482014-12-18 16:28:54 -0800542 }
543
Colin Crossf5e34b92015-03-13 16:02:36 -0700544 if len(ret) != len(variationNames) {
Colin Crossc9028482014-12-18 16:28:54 -0800545 panic("oops!")
546 }
547
548 return ret
549}
550
Colin Crossf5e34b92015-03-13 16:02:36 -0700551// Set all dangling dependencies on the current module to point to the variation
Colin Crossc9028482014-12-18 16:28:54 -0800552// with given name.
Colin Crossf5e34b92015-03-13 16:02:36 -0700553func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
554 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
Colin Crossc9028482014-12-18 16:28:54 -0800555}
556
557func (mctx *mutatorContext) Module() Module {
558 return mctx.module.logicModule
559}
560
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700561// Add a dependency to the given module.
Colin Crossc9028482014-12-18 16:28:54 -0800562// Does not affect the ordering of the current mutator pass, but will be ordered
563// correctly for all future mutator passes.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700564func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
Colin Cross763b6f12015-10-29 15:32:56 -0700565 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700566 errs := mctx.context.addDependency(mctx.context.moduleInfo[module], tag, dep)
Colin Cross763b6f12015-10-29 15:32:56 -0700567 if len(errs) > 0 {
568 mctx.errs = append(mctx.errs, errs...)
569 }
Colin Cross65569e42015-03-10 20:08:19 -0700570 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700571}
572
573// Add a dependency from the destination to the given module.
574// Does not affect the ordering of the current mutator pass, but will be ordered
Colin Cross8d8a7af2015-11-03 16:41:29 -0800575// correctly for all future mutator passes. All reverse dependencies for a destination module are
576// collected until the end of the mutator pass, sorted by name, and then appended to the destination
577// module's dependency list.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700578func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
Colin Cross8d8a7af2015-11-03 16:41:29 -0800579 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700580 if len(errs) > 0 {
581 mctx.errs = append(mctx.errs, errs...)
Colin Cross8d8a7af2015-11-03 16:41:29 -0800582 return
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700583 }
Colin Cross8d8a7af2015-11-03 16:41:29 -0800584
585 mctx.reverseDeps[destModule] = append(mctx.reverseDeps[destModule],
Colin Cross2c1f3d12016-04-11 15:47:28 -0700586 depInfo{mctx.context.moduleInfo[module], tag})
Colin Crossc9028482014-12-18 16:28:54 -0800587}
588
Colin Cross763b6f12015-10-29 15:32:56 -0700589// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
590// argument to select which variant of the dependency to use. A variant of the dependency must
591// exist that matches the all of the non-local variations of the current module, plus the variations
592// argument.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700593func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
Colin Cross763b6f12015-10-29 15:32:56 -0700594 deps ...string) {
595
596 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700597 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
Colin Cross763b6f12015-10-29 15:32:56 -0700598 if len(errs) > 0 {
599 mctx.errs = append(mctx.errs, errs...)
600 }
601 }
602}
603
604// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
605// variations argument to select which variant of the dependency to use. A variant of the
606// dependency must exist that matches the variations argument, but may also have other variations.
607// For any unspecified variation the first variant will be used.
608//
609// Unlike AddVariationDependencies, the variations of the current module are ignored - the
610// depdendency only needs to match the supplied variations.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700611func (mctx *mutatorContext) AddFarVariationDependencies(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, true)
Colin Cross763b6f12015-10-29 15:32:56 -0700616 if len(errs) > 0 {
617 mctx.errs = append(mctx.errs, errs...)
618 }
619 }
620}
Colin Crossf1875462016-04-11 17:33:13 -0700621
622func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
623 mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
624}