blob: fd89a8674774769f94a5f70935e10c9ef7725fad [file] [log] [blame]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001package blueprint
2
3import (
4 "fmt"
5 "path/filepath"
Jamie Gennis6a40c192014-07-02 16:40:31 -07006 "text/scanner"
Jamie Gennis1bc967e2014-05-27 16:34:41 -07007)
8
Jamie Gennisb9e87f62014-09-24 20:28:11 -07009// A Module handles generating all of the Ninja build actions needed to build a
Colin Crossc9028482014-12-18 16:28:54 -080010// single module based on properties defined in a Blueprints file. Module
11// objects are initially created during the parse phase of a Context using one
12// of the registered module types (and the associated ModuleFactory function).
13// The Module's properties struct is automatically filled in with the property
14// values specified in the Blueprints file (see Context.RegisterModuleType for more
Jamie Gennisb9e87f62014-09-24 20:28:11 -070015// information on this).
16//
Colin Crossc9028482014-12-18 16:28:54 -080017// A Module can be split into multiple Modules by a Mutator. All existing
18// properties set on the module will be duplicated to the new Module, and then
19// modified as necessary by the Mutator.
20//
Jamie Gennisb9e87f62014-09-24 20:28:11 -070021// The Module implementation can access the build configuration as well as any
22// modules on which on which it depends (as defined by the "deps" property
23// specified in the Blueprints file or dynamically added by implementing the
24// DynamicDependerModule interface) using the ModuleContext passed to
25// GenerateBuildActions. This ModuleContext is also used to create Ninja build
26// actions and to report errors to the user.
27//
28// In addition to implementing the GenerateBuildActions method, a Module should
29// implement methods that provide dependant modules and singletons information
30// they need to generate their build actions. These methods will only be called
31// after GenerateBuildActions is called because the Context calls
32// GenerateBuildActions in dependency-order (and singletons are invoked after
33// all the Modules). The set of methods a Module supports will determine how
34// dependant Modules interact with it.
35//
36// For example, consider a Module that is responsible for generating a library
37// that other modules can link against. The library Module might implement the
38// following interface:
39//
40// type LibraryProducer interface {
41// LibraryFileName() string
42// }
43//
44// func IsLibraryProducer(module blueprint.Module) {
45// _, ok := module.(LibraryProducer)
46// return ok
47// }
48//
49// A binary-producing Module that depends on the library Module could then do:
50//
51// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
52// ...
53// var libraryFiles []string
54// ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
55// func(module blueprint.Module) {
56// libProducer := module.(LibraryProducer)
57// libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
58// })
59// ...
60// }
61//
62// to build the list of library file names that should be included in its link
63// command.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064type Module interface {
Jamie Gennisb9e87f62014-09-24 20:28:11 -070065 // GenerateBuildActions is called by the Context that created the Module
66 // during its generate phase. This call should generate all Ninja build
67 // actions (rules, pools, and build statements) needed to build the module.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070068 GenerateBuildActions(ModuleContext)
69}
70
Colin Crossb2e7b5d2014-11-11 14:18:53 -080071type preGenerateModule interface {
72 // PreGenerateBuildActions is called by the Context that created the Module
73 // during its generate phase, before calling GenerateBuildActions on
74 // any module. It should not touch any Ninja build actions.
75 PreGenerateBuildActions(PreModuleContext)
76}
77
Jamie Gennisb9e87f62014-09-24 20:28:11 -070078// A DynamicDependerModule is a Module that may add dependencies that do not
79// appear in its "deps" property. Any Module that implements this interface
80// will have its DynamicDependencies method called by the Context that created
81// it during generate phase.
82type DynamicDependerModule interface {
83 Module
84
85 // DynamicDependencies is called by the Context that created the
86 // DynamicDependerModule during its generate phase. This call should return
87 // the list of module names that the DynamicDependerModule depends on
88 // dynamically. Module names that already appear in the "deps" property may
89 // but do not need to be included in the returned list.
90 DynamicDependencies(DynamicDependerModuleContext) []string
91}
92
Colin Crossbe1a9a12014-12-18 11:05:45 -080093type BaseModuleContext interface {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070094 ModuleName() string
95 ModuleDir() string
Jamie Gennis6eb4d242014-06-11 18:31:16 -070096 Config() interface{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097
David Allison701fbad2014-10-29 14:51:13 -070098 ContainsProperty(name string) bool
Jamie Gennis6a40c192014-07-02 16:40:31 -070099 Errorf(pos scanner.Position, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100 ModuleErrorf(fmt string, args ...interface{})
101 PropertyErrorf(property, fmt string, args ...interface{})
Jamie Gennis6a40c192014-07-02 16:40:31 -0700102 Failed() bool
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700103}
104
Colin Crossbe1a9a12014-12-18 11:05:45 -0800105type DynamicDependerModuleContext interface {
106 BaseModuleContext
107}
108
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800109type PreModuleContext interface {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800110 BaseModuleContext
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700111
112 OtherModuleName(m Module) string
113 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700114
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800115 VisitDepsDepthFirst(visit func(Module))
116 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
117}
118
119type ModuleContext interface {
120 PreModuleContext
121
Colin Crossc9028482014-12-18 16:28:54 -0800122 ModuleSubDir() string
123
Jamie Gennis2fb20952014-10-03 02:49:58 -0700124 Variable(pctx *PackageContext, name, value string)
125 Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule
126 Build(pctx *PackageContext, params BuildParams)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700127
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700128 AddNinjaFileDeps(deps ...string)
Colin Crossc9028482014-12-18 16:28:54 -0800129
130 PrimaryModule() Module
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700131}
132
Colin Crossbe1a9a12014-12-18 11:05:45 -0800133var _ BaseModuleContext = (*baseModuleContext)(nil)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700134
Colin Crossbe1a9a12014-12-18 11:05:45 -0800135type baseModuleContext struct {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700136 context *Context
137 config interface{}
Colin Crossbbfa51a2014-12-17 16:12:41 -0800138 group *moduleGroup
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700139 errs []error
140}
141
Colin Crossbe1a9a12014-12-18 11:05:45 -0800142func (d *baseModuleContext) ModuleName() string {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800143 return d.group.properties.Name
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700144}
145
Colin Crossbe1a9a12014-12-18 11:05:45 -0800146func (d *baseModuleContext) ContainsProperty(name string) bool {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800147 _, ok := d.group.propertyPos[name]
David Allison701fbad2014-10-29 14:51:13 -0700148 return ok
149}
150
Colin Crossbe1a9a12014-12-18 11:05:45 -0800151func (d *baseModuleContext) ModuleDir() string {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800152 return filepath.Dir(d.group.relBlueprintsFile)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700153}
154
Colin Crossbe1a9a12014-12-18 11:05:45 -0800155func (d *baseModuleContext) Config() interface{} {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700156 return d.config
157}
158
Colin Crossbe1a9a12014-12-18 11:05:45 -0800159func (d *baseModuleContext) Errorf(pos scanner.Position,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700160 format string, args ...interface{}) {
161
162 d.errs = append(d.errs, &Error{
163 Err: fmt.Errorf(format, args...),
164 Pos: pos,
165 })
166}
167
Colin Crossbe1a9a12014-12-18 11:05:45 -0800168func (d *baseModuleContext) ModuleErrorf(format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700169 args ...interface{}) {
170
171 d.errs = append(d.errs, &Error{
172 Err: fmt.Errorf(format, args...),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800173 Pos: d.group.pos,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700174 })
175}
176
Colin Crossbe1a9a12014-12-18 11:05:45 -0800177func (d *baseModuleContext) PropertyErrorf(property, format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700178 args ...interface{}) {
179
Colin Crossbbfa51a2014-12-17 16:12:41 -0800180 pos, ok := d.group.propertyPos[property]
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700181 if !ok {
182 panic(fmt.Errorf("property %q was not set for this module", property))
183 }
184
185 d.errs = append(d.errs, &Error{
186 Err: fmt.Errorf(format, args...),
187 Pos: pos,
188 })
189}
190
Colin Crossbe1a9a12014-12-18 11:05:45 -0800191func (d *baseModuleContext) Failed() bool {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700192 return len(d.errs) > 0
193}
194
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800195var _ PreModuleContext = (*preModuleContext)(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700196
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800197type preModuleContext struct {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800198 baseModuleContext
Colin Crossc9028482014-12-18 16:28:54 -0800199 module *moduleInfo
200 primaryModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700201}
202
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800203func (m *preModuleContext) OtherModuleName(module Module) string {
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700204 info := m.context.moduleInfo[module]
Colin Crossbbfa51a2014-12-17 16:12:41 -0800205 return info.group.properties.Name
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700206}
207
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800208func (m *preModuleContext) OtherModuleErrorf(module Module, format string,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700209 args ...interface{}) {
210
211 info := m.context.moduleInfo[module]
212 m.errs = append(m.errs, &Error{
213 Err: fmt.Errorf(format, args...),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800214 Pos: info.group.pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700215 })
216}
217
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800218func (m *preModuleContext) VisitDepsDepthFirst(visit func(Module)) {
219 m.context.visitDepsDepthFirst(m.module, visit)
220}
221
222func (m *preModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
223 visit func(Module)) {
224
225 m.context.visitDepsDepthFirstIf(m.module, pred, visit)
226}
227
228var _ ModuleContext = (*moduleContext)(nil)
229
230type moduleContext struct {
231 preModuleContext
232 scope *localScope
233 ninjaFileDeps []string
234 actionDefs localBuildActions
235}
236
Colin Crossc9028482014-12-18 16:28:54 -0800237func (m *moduleContext) ModuleSubDir() string {
238 return m.module.subName()
239}
240
Jamie Gennis2fb20952014-10-03 02:49:58 -0700241func (m *moduleContext) Variable(pctx *PackageContext, name, value string) {
242 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700243
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700244 v, err := m.scope.AddLocalVariable(name, value)
245 if err != nil {
246 panic(err)
247 }
248
249 m.actionDefs.variables = append(m.actionDefs.variables, v)
250}
251
Jamie Gennis2fb20952014-10-03 02:49:58 -0700252func (m *moduleContext) Rule(pctx *PackageContext, name string,
253 params RuleParams, argNames ...string) Rule {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700254
Jamie Gennis2fb20952014-10-03 02:49:58 -0700255 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700256
Jamie Genniscbc6f862014-06-05 20:00:22 -0700257 r, err := m.scope.AddLocalRule(name, &params, argNames...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700258 if err != nil {
259 panic(err)
260 }
261
262 m.actionDefs.rules = append(m.actionDefs.rules, r)
263
264 return r
265}
266
Jamie Gennis2fb20952014-10-03 02:49:58 -0700267func (m *moduleContext) Build(pctx *PackageContext, params BuildParams) {
268 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700269
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700270 def, err := parseBuildParams(m.scope, &params)
271 if err != nil {
272 panic(err)
273 }
274
275 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
276}
277
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700278func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
279 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
280}
Colin Crossc9028482014-12-18 16:28:54 -0800281
282func (m *moduleContext) PrimaryModule() Module {
283 return m.primaryModule.logicModule
284}
285
286//
287// MutatorContext
288//
289
290type mutatorContext struct {
291 baseModuleContext
292 module *moduleInfo
293 name string
294 dependenciesModified bool
295}
296
297type baseMutatorContext interface {
298 BaseModuleContext
299
300 Module() Module
301}
302
303type TopDownMutatorContext interface {
304 baseMutatorContext
305
306 VisitDirectDeps(visit func(Module))
307 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
308 VisitDepsDepthFirst(visit func(Module))
309 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
310}
311
312type BottomUpMutatorContext interface {
313 baseMutatorContext
314
315 AddDependency(module Module, name string)
316 CreateVariants(...string) []Module
317 SetDependencyVariant(string)
318}
319
320// A Mutator function is called for each Module, and can use
321// MutatorContext.CreateSubVariants to split a Module into multiple Modules,
322// modifying properties on the new modules to differentiate them. It is called
323// after parsing all Blueprint files, but before generating any build rules,
324// and is always called on dependencies before being called on the depending module.
325//
326// The Mutator function should only modify members of properties structs, and not
327// members of the module struct itself, to ensure the modified values are copied
328// if a second Mutator chooses to split the module a second time.
329type TopDownMutator func(mctx TopDownMutatorContext)
330type BottomUpMutator func(mctx BottomUpMutatorContext)
331
332// Split a module into mulitple variants, one for each name in the variantNames
333// parameter. It returns a list of new modules in the same order as the variantNames
334// list.
335//
336// If any of the dependencies of the module being operated on were already split
337// by calling CreateVariants with the same name, the dependency will automatically
338// be updated to point the matching variant.
339//
340// If a module is split, and then a module depending on the first module is not split
341// when the Mutator is later called on it, the dependency of the depending module will
342// automatically be updated to point to the first variant.
343func (mctx *mutatorContext) CreateVariants(variantNames ...string) []Module {
344 ret := []Module{}
345 modules := mctx.context.createVariants(mctx.module, mctx.name, variantNames)
346
347 for _, module := range modules {
348 ret = append(ret, module.logicModule)
349 }
350
351 if len(ret) != len(variantNames) {
352 panic("oops!")
353 }
354
355 return ret
356}
357
358// Set all dangling dependencies on the current module to point to the variant
359// with given name.
360func (mctx *mutatorContext) SetDependencyVariant(variantName string) {
361 subName := subName{
362 mutatorName: mctx.name,
363 variantName: variantName,
364 }
365 mctx.context.convertDepsToVariant(mctx.module, subName)
366}
367
368func (mctx *mutatorContext) Module() Module {
369 return mctx.module.logicModule
370}
371
372// Add a dependency to the given module. The depender can be a specific variant
373// of a module, but the dependee must be a module that only has a single variant.
374// Does not affect the ordering of the current mutator pass, but will be ordered
375// correctly for all future mutator passes.
376func (mctx *mutatorContext) AddDependency(module Module, depName string) {
377 mctx.context.addDependency(mctx.context.moduleInfo[module], depName)
378 mctx.dependenciesModified = true
379}
380
381func (mctx *mutatorContext) VisitDirectDeps(visit func(Module)) {
382 mctx.context.visitDirectDeps(mctx.module, visit)
383}
384
385func (mctx *mutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
386 mctx.context.visitDirectDepsIf(mctx.module, pred, visit)
387}
388
389func (mctx *mutatorContext) VisitDepsDepthFirst(visit func(Module)) {
390 mctx.context.visitDepsDepthFirst(mctx.module, visit)
391}
392
393func (mctx *mutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool,
394 visit func(Module)) {
395
396 mctx.context.visitDepsDepthFirstIf(mctx.module, pred, visit)
397}