blob: e2c68f25b08d8378e0513f7d6fc1b95393b6df1f [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
Jamie Gennisb9e87f62014-09-24 20:28:11 -070071// A DynamicDependerModule is a Module that may add dependencies that do not
72// appear in its "deps" property. Any Module that implements this interface
73// will have its DynamicDependencies method called by the Context that created
74// it during generate phase.
75type DynamicDependerModule interface {
76 Module
77
78 // DynamicDependencies is called by the Context that created the
79 // DynamicDependerModule during its generate phase. This call should return
80 // the list of module names that the DynamicDependerModule depends on
81 // dynamically. Module names that already appear in the "deps" property may
82 // but do not need to be included in the returned list.
83 DynamicDependencies(DynamicDependerModuleContext) []string
84}
85
Colin Crossbe1a9a12014-12-18 11:05:45 -080086type BaseModuleContext interface {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 ModuleName() string
88 ModuleDir() string
Jamie Gennis6eb4d242014-06-11 18:31:16 -070089 Config() interface{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070090
David Allison701fbad2014-10-29 14:51:13 -070091 ContainsProperty(name string) bool
Jamie Gennis6a40c192014-07-02 16:40:31 -070092 Errorf(pos scanner.Position, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -070093 ModuleErrorf(fmt string, args ...interface{})
94 PropertyErrorf(property, fmt string, args ...interface{})
Jamie Gennis6a40c192014-07-02 16:40:31 -070095 Failed() bool
Jamie Gennisb9e87f62014-09-24 20:28:11 -070096}
97
Colin Crossbe1a9a12014-12-18 11:05:45 -080098type DynamicDependerModuleContext interface {
99 BaseModuleContext
100}
101
Colin Cross1455a0f2014-12-17 13:23:56 -0800102type ModuleContext interface {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800103 BaseModuleContext
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700104
105 OtherModuleName(m Module) string
106 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700107
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800108 VisitDepsDepthFirst(visit func(Module))
109 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800110
Colin Crossc9028482014-12-18 16:28:54 -0800111 ModuleSubDir() string
112
Jamie Gennis2fb20952014-10-03 02:49:58 -0700113 Variable(pctx *PackageContext, name, value string)
114 Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule
115 Build(pctx *PackageContext, params BuildParams)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700117 AddNinjaFileDeps(deps ...string)
Colin Crossc9028482014-12-18 16:28:54 -0800118
119 PrimaryModule() Module
Colin Cross80ad04d2015-01-06 16:19:59 -0800120 FinalModule() Module
121 VisitAllModuleVariants(visit func(Module))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122}
123
Colin Crossbe1a9a12014-12-18 11:05:45 -0800124var _ BaseModuleContext = (*baseModuleContext)(nil)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700125
Colin Crossbe1a9a12014-12-18 11:05:45 -0800126type baseModuleContext struct {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700127 context *Context
128 config interface{}
Colin Crossbbfa51a2014-12-17 16:12:41 -0800129 group *moduleGroup
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700130 errs []error
131}
132
Colin Crossbe1a9a12014-12-18 11:05:45 -0800133func (d *baseModuleContext) ModuleName() string {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800134 return d.group.properties.Name
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700135}
136
Colin Crossbe1a9a12014-12-18 11:05:45 -0800137func (d *baseModuleContext) ContainsProperty(name string) bool {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800138 _, ok := d.group.propertyPos[name]
David Allison701fbad2014-10-29 14:51:13 -0700139 return ok
140}
141
Colin Crossbe1a9a12014-12-18 11:05:45 -0800142func (d *baseModuleContext) ModuleDir() string {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800143 return filepath.Dir(d.group.relBlueprintsFile)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700144}
145
Colin Crossbe1a9a12014-12-18 11:05:45 -0800146func (d *baseModuleContext) Config() interface{} {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700147 return d.config
148}
149
Colin Crossbe1a9a12014-12-18 11:05:45 -0800150func (d *baseModuleContext) Errorf(pos scanner.Position,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700151 format string, args ...interface{}) {
152
153 d.errs = append(d.errs, &Error{
154 Err: fmt.Errorf(format, args...),
155 Pos: pos,
156 })
157}
158
Colin Crossbe1a9a12014-12-18 11:05:45 -0800159func (d *baseModuleContext) ModuleErrorf(format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700160 args ...interface{}) {
161
162 d.errs = append(d.errs, &Error{
163 Err: fmt.Errorf(format, args...),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800164 Pos: d.group.pos,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700165 })
166}
167
Colin Crossbe1a9a12014-12-18 11:05:45 -0800168func (d *baseModuleContext) PropertyErrorf(property, format string,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700169 args ...interface{}) {
170
Colin Crossbbfa51a2014-12-17 16:12:41 -0800171 pos, ok := d.group.propertyPos[property]
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700172 if !ok {
173 panic(fmt.Errorf("property %q was not set for this module", property))
174 }
175
176 d.errs = append(d.errs, &Error{
177 Err: fmt.Errorf(format, args...),
178 Pos: pos,
179 })
180}
181
Colin Crossbe1a9a12014-12-18 11:05:45 -0800182func (d *baseModuleContext) Failed() bool {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700183 return len(d.errs) > 0
184}
185
Colin Cross1455a0f2014-12-17 13:23:56 -0800186var _ ModuleContext = (*moduleContext)(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700187
Colin Cross1455a0f2014-12-17 13:23:56 -0800188type moduleContext struct {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800189 baseModuleContext
Colin Cross1455a0f2014-12-17 13:23:56 -0800190 module *moduleInfo
191 scope *localScope
192 ninjaFileDeps []string
193 actionDefs localBuildActions
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700194}
195
Colin Cross1455a0f2014-12-17 13:23:56 -0800196func (m *moduleContext) OtherModuleName(module Module) string {
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700197 info := m.context.moduleInfo[module]
Colin Crossbbfa51a2014-12-17 16:12:41 -0800198 return info.group.properties.Name
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700199}
200
Colin Cross1455a0f2014-12-17 13:23:56 -0800201func (m *moduleContext) OtherModuleErrorf(module Module, format string,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700202 args ...interface{}) {
203
204 info := m.context.moduleInfo[module]
205 m.errs = append(m.errs, &Error{
206 Err: fmt.Errorf(format, args...),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800207 Pos: info.group.pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700208 })
209}
210
Colin Cross1455a0f2014-12-17 13:23:56 -0800211func (m *moduleContext) VisitDepsDepthFirst(visit func(Module)) {
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800212 m.context.visitDepsDepthFirst(m.module, visit)
213}
214
Colin Cross1455a0f2014-12-17 13:23:56 -0800215func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
Colin Crossb2e7b5d2014-11-11 14:18:53 -0800216 visit func(Module)) {
217
218 m.context.visitDepsDepthFirstIf(m.module, pred, visit)
219}
220
Colin Crossc9028482014-12-18 16:28:54 -0800221func (m *moduleContext) ModuleSubDir() string {
222 return m.module.subName()
223}
224
Jamie Gennis2fb20952014-10-03 02:49:58 -0700225func (m *moduleContext) Variable(pctx *PackageContext, name, value string) {
226 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700227
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700228 v, err := m.scope.AddLocalVariable(name, value)
229 if err != nil {
230 panic(err)
231 }
232
233 m.actionDefs.variables = append(m.actionDefs.variables, v)
234}
235
Jamie Gennis2fb20952014-10-03 02:49:58 -0700236func (m *moduleContext) Rule(pctx *PackageContext, name string,
237 params RuleParams, argNames ...string) Rule {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700238
Jamie Gennis2fb20952014-10-03 02:49:58 -0700239 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700240
Jamie Genniscbc6f862014-06-05 20:00:22 -0700241 r, err := m.scope.AddLocalRule(name, &params, argNames...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700242 if err != nil {
243 panic(err)
244 }
245
246 m.actionDefs.rules = append(m.actionDefs.rules, r)
247
248 return r
249}
250
Jamie Gennis2fb20952014-10-03 02:49:58 -0700251func (m *moduleContext) Build(pctx *PackageContext, params BuildParams) {
252 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700253
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700254 def, err := parseBuildParams(m.scope, &params)
255 if err != nil {
256 panic(err)
257 }
258
259 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
260}
261
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700262func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
263 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
264}
Colin Crossc9028482014-12-18 16:28:54 -0800265
266func (m *moduleContext) PrimaryModule() Module {
Colin Cross80ad04d2015-01-06 16:19:59 -0800267 return m.module.group.modules[0].logicModule
268}
269
270func (m *moduleContext) FinalModule() Module {
271 return m.module.group.modules[len(m.module.group.modules)-1].logicModule
272}
273
274func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
275 for _, module := range m.module.group.modules {
276 visit(module.logicModule)
277 }
Colin Crossc9028482014-12-18 16:28:54 -0800278}
279
280//
281// MutatorContext
282//
283
284type mutatorContext struct {
285 baseModuleContext
286 module *moduleInfo
287 name string
288 dependenciesModified bool
289}
290
291type baseMutatorContext interface {
292 BaseModuleContext
293
294 Module() Module
295}
296
297type TopDownMutatorContext interface {
298 baseMutatorContext
299
300 VisitDirectDeps(visit func(Module))
301 VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
302 VisitDepsDepthFirst(visit func(Module))
303 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
304}
305
306type BottomUpMutatorContext interface {
307 baseMutatorContext
308
309 AddDependency(module Module, name string)
310 CreateVariants(...string) []Module
311 SetDependencyVariant(string)
312}
313
314// A Mutator function is called for each Module, and can use
315// MutatorContext.CreateSubVariants to split a Module into multiple Modules,
316// modifying properties on the new modules to differentiate them. It is called
317// after parsing all Blueprint files, but before generating any build rules,
318// and is always called on dependencies before being called on the depending module.
319//
320// The Mutator function should only modify members of properties structs, and not
321// members of the module struct itself, to ensure the modified values are copied
322// if a second Mutator chooses to split the module a second time.
323type TopDownMutator func(mctx TopDownMutatorContext)
324type BottomUpMutator func(mctx BottomUpMutatorContext)
325
326// Split a module into mulitple variants, one for each name in the variantNames
327// parameter. It returns a list of new modules in the same order as the variantNames
328// list.
329//
330// If any of the dependencies of the module being operated on were already split
331// by calling CreateVariants with the same name, the dependency will automatically
332// be updated to point the matching variant.
333//
334// If a module is split, and then a module depending on the first module is not split
335// when the Mutator is later called on it, the dependency of the depending module will
336// automatically be updated to point to the first variant.
337func (mctx *mutatorContext) CreateVariants(variantNames ...string) []Module {
338 ret := []Module{}
339 modules := mctx.context.createVariants(mctx.module, mctx.name, variantNames)
340
341 for _, module := range modules {
342 ret = append(ret, module.logicModule)
343 }
344
345 if len(ret) != len(variantNames) {
346 panic("oops!")
347 }
348
349 return ret
350}
351
352// Set all dangling dependencies on the current module to point to the variant
353// with given name.
354func (mctx *mutatorContext) SetDependencyVariant(variantName string) {
355 subName := subName{
356 mutatorName: mctx.name,
357 variantName: variantName,
358 }
359 mctx.context.convertDepsToVariant(mctx.module, subName)
360}
361
362func (mctx *mutatorContext) Module() Module {
363 return mctx.module.logicModule
364}
365
366// Add a dependency to the given module. The depender can be a specific variant
367// of a module, but the dependee must be a module that only has a single variant.
368// Does not affect the ordering of the current mutator pass, but will be ordered
369// correctly for all future mutator passes.
370func (mctx *mutatorContext) AddDependency(module Module, depName string) {
371 mctx.context.addDependency(mctx.context.moduleInfo[module], depName)
372 mctx.dependenciesModified = true
373}
374
375func (mctx *mutatorContext) VisitDirectDeps(visit func(Module)) {
376 mctx.context.visitDirectDeps(mctx.module, visit)
377}
378
379func (mctx *mutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
380 mctx.context.visitDirectDepsIf(mctx.module, pred, visit)
381}
382
383func (mctx *mutatorContext) VisitDepsDepthFirst(visit func(Module)) {
384 mctx.context.visitDepsDepthFirst(mctx.module, visit)
385}
386
387func (mctx *mutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool,
388 visit func(Module)) {
389
390 mctx.context.visitDepsDepthFirstIf(mctx.module, pred, visit)
391}