blob: ec6252fa5401e63f8f873c5d8f7da21105f6d7f5 [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
10// single module that is defined in a Blueprints file. Module objects are
11// created during the parse phase of a Context using one of the registered
12// module types (and the associated ModuleFactory function). The Module's
13// properties struct is automatically filled in with the property values
14// specified in the Blueprints file (see Context.RegisterModuleType for more
15// information on this).
16//
17// The Module implementation can access the build configuration as well as any
18// modules on which on which it depends (as defined by the "deps" property
19// specified in the Blueprints file or dynamically added by implementing the
20// DynamicDependerModule interface) using the ModuleContext passed to
21// GenerateBuildActions. This ModuleContext is also used to create Ninja build
22// actions and to report errors to the user.
23//
24// In addition to implementing the GenerateBuildActions method, a Module should
25// implement methods that provide dependant modules and singletons information
26// they need to generate their build actions. These methods will only be called
27// after GenerateBuildActions is called because the Context calls
28// GenerateBuildActions in dependency-order (and singletons are invoked after
29// all the Modules). The set of methods a Module supports will determine how
30// dependant Modules interact with it.
31//
32// For example, consider a Module that is responsible for generating a library
33// that other modules can link against. The library Module might implement the
34// following interface:
35//
36// type LibraryProducer interface {
37// LibraryFileName() string
38// }
39//
40// func IsLibraryProducer(module blueprint.Module) {
41// _, ok := module.(LibraryProducer)
42// return ok
43// }
44//
45// A binary-producing Module that depends on the library Module could then do:
46//
47// func (m *myBinaryModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
48// ...
49// var libraryFiles []string
50// ctx.VisitDepsDepthFirstIf(IsLibraryProducer,
51// func(module blueprint.Module) {
52// libProducer := module.(LibraryProducer)
53// libraryFiles = append(libraryFiles, libProducer.LibraryFileName())
54// })
55// ...
56// }
57//
58// to build the list of library file names that should be included in its link
59// command.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070060type Module interface {
Jamie Gennisb9e87f62014-09-24 20:28:11 -070061 // GenerateBuildActions is called by the Context that created the Module
62 // during its generate phase. This call should generate all Ninja build
63 // actions (rules, pools, and build statements) needed to build the module.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064 GenerateBuildActions(ModuleContext)
65}
66
Jamie Gennisb9e87f62014-09-24 20:28:11 -070067// A DynamicDependerModule is a Module that may add dependencies that do not
68// appear in its "deps" property. Any Module that implements this interface
69// will have its DynamicDependencies method called by the Context that created
70// it during generate phase.
71type DynamicDependerModule interface {
72 Module
73
74 // DynamicDependencies is called by the Context that created the
75 // DynamicDependerModule during its generate phase. This call should return
76 // the list of module names that the DynamicDependerModule depends on
77 // dynamically. Module names that already appear in the "deps" property may
78 // but do not need to be included in the returned list.
79 DynamicDependencies(DynamicDependerModuleContext) []string
80}
81
82type DynamicDependerModuleContext interface {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070083 ModuleName() string
84 ModuleDir() string
Jamie Gennis6eb4d242014-06-11 18:31:16 -070085 Config() interface{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070086
David Allison701fbad2014-10-29 14:51:13 -070087 ContainsProperty(name string) bool
Jamie Gennis6a40c192014-07-02 16:40:31 -070088 Errorf(pos scanner.Position, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -070089 ModuleErrorf(fmt string, args ...interface{})
90 PropertyErrorf(property, fmt string, args ...interface{})
Jamie Gennis6a40c192014-07-02 16:40:31 -070091 Failed() bool
Jamie Gennisb9e87f62014-09-24 20:28:11 -070092}
93
94type ModuleContext interface {
95 DynamicDependerModuleContext
96
97 OtherModuleName(m Module) string
98 OtherModuleErrorf(m Module, fmt string, args ...interface{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099
Jamie Gennis2fb20952014-10-03 02:49:58 -0700100 Variable(pctx *PackageContext, name, value string)
101 Rule(pctx *PackageContext, name string, params RuleParams, argNames ...string) Rule
102 Build(pctx *PackageContext, params BuildParams)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700103
104 VisitDepsDepthFirst(visit func(Module))
105 VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700106
107 AddNinjaFileDeps(deps ...string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700108}
109
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700110var _ DynamicDependerModuleContext = (*dynamicDependerModuleContext)(nil)
111
112type dynamicDependerModuleContext struct {
113 context *Context
114 config interface{}
115 info *moduleInfo
116 errs []error
117}
118
119func (d *dynamicDependerModuleContext) ModuleName() string {
120 return d.info.properties.Name
121}
122
David Allison701fbad2014-10-29 14:51:13 -0700123func (d *dynamicDependerModuleContext) ContainsProperty(name string) bool {
124 _, ok := d.info.propertyPos[name]
125 return ok
126}
127
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700128func (d *dynamicDependerModuleContext) ModuleDir() string {
129 return filepath.Dir(d.info.relBlueprintsFile)
130}
131
132func (d *dynamicDependerModuleContext) Config() interface{} {
133 return d.config
134}
135
136func (d *dynamicDependerModuleContext) Errorf(pos scanner.Position,
137 format string, args ...interface{}) {
138
139 d.errs = append(d.errs, &Error{
140 Err: fmt.Errorf(format, args...),
141 Pos: pos,
142 })
143}
144
145func (d *dynamicDependerModuleContext) ModuleErrorf(format string,
146 args ...interface{}) {
147
148 d.errs = append(d.errs, &Error{
149 Err: fmt.Errorf(format, args...),
150 Pos: d.info.pos,
151 })
152}
153
154func (d *dynamicDependerModuleContext) PropertyErrorf(property, format string,
155 args ...interface{}) {
156
157 pos, ok := d.info.propertyPos[property]
158 if !ok {
159 panic(fmt.Errorf("property %q was not set for this module", property))
160 }
161
162 d.errs = append(d.errs, &Error{
163 Err: fmt.Errorf(format, args...),
164 Pos: pos,
165 })
166}
167
168func (d *dynamicDependerModuleContext) Failed() bool {
169 return len(d.errs) > 0
170}
171
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700172var _ ModuleContext = (*moduleContext)(nil)
173
174type moduleContext struct {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700175 dynamicDependerModuleContext
176 module Module
177 scope *localScope
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700178 ninjaFileDeps []string
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700179 actionDefs localBuildActions
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700180}
181
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700182func (m *moduleContext) OtherModuleName(module Module) string {
183 info := m.context.moduleInfo[module]
184 return info.properties.Name
185}
186
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700187func (m *moduleContext) OtherModuleErrorf(module Module, format string,
188 args ...interface{}) {
189
190 info := m.context.moduleInfo[module]
191 m.errs = append(m.errs, &Error{
192 Err: fmt.Errorf(format, args...),
193 Pos: info.pos,
194 })
195}
196
Jamie Gennis2fb20952014-10-03 02:49:58 -0700197func (m *moduleContext) Variable(pctx *PackageContext, name, value string) {
198 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700199
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700200 v, err := m.scope.AddLocalVariable(name, value)
201 if err != nil {
202 panic(err)
203 }
204
205 m.actionDefs.variables = append(m.actionDefs.variables, v)
206}
207
Jamie Gennis2fb20952014-10-03 02:49:58 -0700208func (m *moduleContext) Rule(pctx *PackageContext, name string,
209 params RuleParams, argNames ...string) Rule {
Jamie Genniscbc6f862014-06-05 20:00:22 -0700210
Jamie Gennis2fb20952014-10-03 02:49:58 -0700211 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700212
Jamie Genniscbc6f862014-06-05 20:00:22 -0700213 r, err := m.scope.AddLocalRule(name, &params, argNames...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700214 if err != nil {
215 panic(err)
216 }
217
218 m.actionDefs.rules = append(m.actionDefs.rules, r)
219
220 return r
221}
222
Jamie Gennis2fb20952014-10-03 02:49:58 -0700223func (m *moduleContext) Build(pctx *PackageContext, params BuildParams) {
224 m.scope.ReparentTo(pctx)
Jamie Gennis0ed63ef2014-06-30 18:07:17 -0700225
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226 def, err := parseBuildParams(m.scope, &params)
227 if err != nil {
228 panic(err)
229 }
230
231 m.actionDefs.buildDefs = append(m.actionDefs.buildDefs, def)
232}
233
234func (m *moduleContext) VisitDepsDepthFirst(visit func(Module)) {
235 m.context.visitDepsDepthFirst(m.module, visit)
236}
237
238func (m *moduleContext) VisitDepsDepthFirstIf(pred func(Module) bool,
239 visit func(Module)) {
240
241 m.context.visitDepsDepthFirstIf(m.module, pred, visit)
242}
Mathias Agopian5b8477d2014-06-25 17:21:54 -0700243
244func (m *moduleContext) AddNinjaFileDeps(deps ...string) {
245 m.ninjaFileDeps = append(m.ninjaFileDeps, deps...)
246}