blob: 88bb7eb0bf0ddd315850b948c5fb20ce748f9f10 [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 Cross49c279a2016-08-05 22:30:44 -0700432 reverseDeps []reverseDep
433 newModules []*moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800434}
435
436type baseMutatorContext interface {
437 BaseModuleContext
438
439 Module() Module
440}
441
Colin Cross65569e42015-03-10 20:08:19 -0700442type EarlyMutatorContext interface {
443 baseMutatorContext
444
Colin Crossf5e34b92015-03-13 16:02:36 -0700445 CreateVariations(...string) []Module
446 CreateLocalVariations(...string) []Module
Colin Cross65569e42015-03-10 20:08:19 -0700447}
448
Colin Crossc9028482014-12-18 16:28:54 -0800449type TopDownMutatorContext interface {
450 baseMutatorContext
451
Colin Cross8d222332015-11-02 16:11:32 -0800452 OtherModuleName(m Module) string
453 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Colin Cross2c1f3d12016-04-11 15:47:28 -0700454 OtherModuleDependencyTag(m Module) DependencyTag
Colin Cross8d222332015-11-02 16:11:32 -0800455
Colin Crossc9028482014-12-18 16:28:54 -0800456 VisitDirectDeps(visit func(Module))
457 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
458 VisitDepsDepthFirst(visit func(Module))
459 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Yuchen Wu222e2452015-10-06 14:03:27 -0700460 WalkDeps(visit func(Module, Module) bool)
Colin Crossc9028482014-12-18 16:28:54 -0800461}
462
463type BottomUpMutatorContext interface {
Colin Cross93c4cf62016-08-06 22:54:17 -0700464 baseMutatorContext
Colin Crossc9028482014-12-18 16:28:54 -0800465
Colin Cross2c1f3d12016-04-11 15:47:28 -0700466 AddDependency(module Module, tag DependencyTag, name ...string)
467 AddReverseDependency(module Module, tag DependencyTag, name string)
Colin Crossf5e34b92015-03-13 16:02:36 -0700468 CreateVariations(...string) []Module
Jamie Gennis6a5825e2015-05-19 11:26:11 -0700469 CreateLocalVariations(...string) []Module
Colin Crossf5e34b92015-03-13 16:02:36 -0700470 SetDependencyVariation(string)
Colin Cross2c1f3d12016-04-11 15:47:28 -0700471 AddVariationDependencies([]Variation, DependencyTag, ...string)
472 AddFarVariationDependencies([]Variation, DependencyTag, ...string)
Colin Crossf1875462016-04-11 17:33:13 -0700473 AddInterVariantDependency(tag DependencyTag, from, to Module)
Colin Crossc9028482014-12-18 16:28:54 -0800474}
475
476// A Mutator function is called for each Module, and can use
Colin Crossf5e34b92015-03-13 16:02:36 -0700477// MutatorContext.CreateVariations to split a Module into multiple Modules,
Colin Crossc9028482014-12-18 16:28:54 -0800478// modifying properties on the new modules to differentiate them. It is called
479// after parsing all Blueprint files, but before generating any build rules,
480// and is always called on dependencies before being called on the depending module.
481//
482// The Mutator function should only modify members of properties structs, and not
483// members of the module struct itself, to ensure the modified values are copied
484// if a second Mutator chooses to split the module a second time.
485type TopDownMutator func(mctx TopDownMutatorContext)
486type BottomUpMutator func(mctx BottomUpMutatorContext)
Colin Cross65569e42015-03-10 20:08:19 -0700487type EarlyMutator func(mctx EarlyMutatorContext)
Colin Crossc9028482014-12-18 16:28:54 -0800488
Colin Cross2c1f3d12016-04-11 15:47:28 -0700489// DependencyTag is an interface to an arbitrary object that embeds BaseDependencyTag. It can be
490// used to transfer information on a dependency between the mutator that called AddDependency
491// and the GenerateBuildActions method. Variants created by CreateVariations have a copy of the
492// interface (pointing to the same concrete object) from their original module.
493type DependencyTag interface {
494 dependencyTag(DependencyTag)
495}
496
497type BaseDependencyTag struct {
498}
499
500func (BaseDependencyTag) dependencyTag(DependencyTag) {
501}
502
503var _ DependencyTag = BaseDependencyTag{}
504
Colin Crossf5e34b92015-03-13 16:02:36 -0700505// Split a module into mulitple variants, one for each name in the variationNames
506// parameter. It returns a list of new modules in the same order as the variationNames
Colin Crossc9028482014-12-18 16:28:54 -0800507// list.
508//
509// If any of the dependencies of the module being operated on were already split
Colin Crossf5e34b92015-03-13 16:02:36 -0700510// by calling CreateVariations with the same name, the dependency will automatically
Colin Crossc9028482014-12-18 16:28:54 -0800511// be updated to point the matching variant.
512//
513// If a module is split, and then a module depending on the first module is not split
514// when the Mutator is later called on it, the dependency of the depending module will
515// automatically be updated to point to the first variant.
Colin Crossf5e34b92015-03-13 16:02:36 -0700516func (mctx *mutatorContext) CreateVariations(variationNames ...string) []Module {
517 return mctx.createVariations(variationNames, false)
Colin Cross65569e42015-03-10 20:08:19 -0700518}
519
520// Split a module into mulitple variants, one for each name in the variantNames
521// parameter. It returns a list of new modules in the same order as the variantNames
522// list.
523//
Colin Crossf5e34b92015-03-13 16:02:36 -0700524// Local variations do not affect automatic dependency resolution - dependencies added
Colin Cross65569e42015-03-10 20:08:19 -0700525// to the split module via deps or DynamicDependerModule must exactly match a variant
Colin Crossf5e34b92015-03-13 16:02:36 -0700526// that contains all the non-local variations.
527func (mctx *mutatorContext) CreateLocalVariations(variationNames ...string) []Module {
528 return mctx.createVariations(variationNames, true)
Colin Cross65569e42015-03-10 20:08:19 -0700529}
530
Colin Crossf5e34b92015-03-13 16:02:36 -0700531func (mctx *mutatorContext) createVariations(variationNames []string, local bool) []Module {
Colin Crossc9028482014-12-18 16:28:54 -0800532 ret := []Module{}
Colin Crossf5e34b92015-03-13 16:02:36 -0700533 modules, errs := mctx.context.createVariations(mctx.module, mctx.name, variationNames)
Colin Cross174ae052015-03-03 17:37:03 -0800534 if len(errs) > 0 {
535 mctx.errs = append(mctx.errs, errs...)
536 }
Colin Crossc9028482014-12-18 16:28:54 -0800537
Colin Cross65569e42015-03-10 20:08:19 -0700538 for i, module := range modules {
Colin Crossc9028482014-12-18 16:28:54 -0800539 ret = append(ret, module.logicModule)
Colin Cross65569e42015-03-10 20:08:19 -0700540 if !local {
Colin Crossf5e34b92015-03-13 16:02:36 -0700541 module.dependencyVariant[mctx.name] = variationNames[i]
Colin Cross65569e42015-03-10 20:08:19 -0700542 }
Colin Crossc9028482014-12-18 16:28:54 -0800543 }
544
Colin Cross49c279a2016-08-05 22:30:44 -0700545 if mctx.newModules != nil {
546 panic("module already has variations from this mutator")
547 }
548 mctx.newModules = modules
549
Colin Crossf5e34b92015-03-13 16:02:36 -0700550 if len(ret) != len(variationNames) {
Colin Crossc9028482014-12-18 16:28:54 -0800551 panic("oops!")
552 }
553
554 return ret
555}
556
Colin Crossf5e34b92015-03-13 16:02:36 -0700557// Set all dangling dependencies on the current module to point to the variation
Colin Crossc9028482014-12-18 16:28:54 -0800558// with given name.
Colin Crossf5e34b92015-03-13 16:02:36 -0700559func (mctx *mutatorContext) SetDependencyVariation(variationName string) {
560 mctx.context.convertDepsToVariation(mctx.module, mctx.name, variationName)
Colin Crossc9028482014-12-18 16:28:54 -0800561}
562
563func (mctx *mutatorContext) Module() Module {
564 return mctx.module.logicModule
565}
566
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700567// Add a dependency to the given module.
Colin Crossc9028482014-12-18 16:28:54 -0800568// Does not affect the ordering of the current mutator pass, but will be ordered
569// correctly for all future mutator passes.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700570func (mctx *mutatorContext) AddDependency(module Module, tag DependencyTag, deps ...string) {
Colin Cross763b6f12015-10-29 15:32:56 -0700571 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700572 errs := mctx.context.addDependency(mctx.context.moduleInfo[module], tag, dep)
Colin Cross763b6f12015-10-29 15:32:56 -0700573 if len(errs) > 0 {
574 mctx.errs = append(mctx.errs, errs...)
575 }
Colin Cross65569e42015-03-10 20:08:19 -0700576 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700577}
578
579// Add a dependency from the destination to the given module.
580// Does not affect the ordering of the current mutator pass, but will be ordered
Colin Cross8d8a7af2015-11-03 16:41:29 -0800581// correctly for all future mutator passes. All reverse dependencies for a destination module are
582// collected until the end of the mutator pass, sorted by name, and then appended to the destination
583// module's dependency list.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700584func (mctx *mutatorContext) AddReverseDependency(module Module, tag DependencyTag, destName string) {
Colin Cross8d8a7af2015-11-03 16:41:29 -0800585 destModule, errs := mctx.context.findReverseDependency(mctx.context.moduleInfo[module], destName)
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700586 if len(errs) > 0 {
587 mctx.errs = append(mctx.errs, errs...)
Colin Cross8d8a7af2015-11-03 16:41:29 -0800588 return
Dan Willemsenfdeb7242015-07-24 16:53:27 -0700589 }
Colin Cross8d8a7af2015-11-03 16:41:29 -0800590
Colin Cross49c279a2016-08-05 22:30:44 -0700591 mctx.reverseDeps = append(mctx.reverseDeps, reverseDep{
592 destModule,
593 depInfo{mctx.context.moduleInfo[module], tag},
594 })
Colin Crossc9028482014-12-18 16:28:54 -0800595}
596
Colin Cross763b6f12015-10-29 15:32:56 -0700597// AddVariationDependencies adds deps as dependencies of the current module, but uses the variations
598// argument to select which variant of the dependency to use. A variant of the dependency must
599// exist that matches the all of the non-local variations of the current module, plus the variations
600// argument.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700601func (mctx *mutatorContext) AddVariationDependencies(variations []Variation, tag DependencyTag,
Colin Cross763b6f12015-10-29 15:32:56 -0700602 deps ...string) {
603
604 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700605 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, false)
Colin Cross763b6f12015-10-29 15:32:56 -0700606 if len(errs) > 0 {
607 mctx.errs = append(mctx.errs, errs...)
608 }
609 }
610}
611
612// AddFarVariationDependencies adds deps as dependencies of the current module, but uses the
613// variations argument to select which variant of the dependency to use. A variant of the
614// dependency must exist that matches the variations argument, but may also have other variations.
615// For any unspecified variation the first variant will be used.
616//
617// Unlike AddVariationDependencies, the variations of the current module are ignored - the
618// depdendency only needs to match the supplied variations.
Colin Cross2c1f3d12016-04-11 15:47:28 -0700619func (mctx *mutatorContext) AddFarVariationDependencies(variations []Variation, tag DependencyTag,
Colin Cross763b6f12015-10-29 15:32:56 -0700620 deps ...string) {
621
622 for _, dep := range deps {
Colin Cross2c1f3d12016-04-11 15:47:28 -0700623 errs := mctx.context.addVariationDependency(mctx.module, variations, tag, dep, true)
Colin Cross763b6f12015-10-29 15:32:56 -0700624 if len(errs) > 0 {
625 mctx.errs = append(mctx.errs, errs...)
626 }
627 }
628}
Colin Crossf1875462016-04-11 17:33:13 -0700629
630func (mctx *mutatorContext) AddInterVariantDependency(tag DependencyTag, from, to Module) {
631 mctx.context.addInterVariantDependency(mctx.module, tag, from, to)
632}