blob: 7f5a69fa6197db0b79cda4ef7e88cbffcabbd137 [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 (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "errors"
20 "fmt"
21 "io"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070022 "path/filepath"
23 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070024 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080026 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070027 "strings"
Colin Cross23d7aa12015-06-30 16:05:22 -070028 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "text/scanner"
30 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070031
32 "github.com/google/blueprint/parser"
33 "github.com/google/blueprint/pathtools"
34 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070035)
36
37var ErrBuildActionsNotReady = errors.New("build actions are not ready")
38
39const maxErrors = 10
40
Jamie Gennisd4e10182014-06-12 20:06:50 -070041// A Context contains all the state needed to parse a set of Blueprints files
42// and generate a Ninja file. The process of generating a Ninja file proceeds
43// through a series of four phases. Each phase corresponds with a some methods
44// on the Context object
45//
46// Phase Methods
47// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070048// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070049//
50// 2. Parse ParseBlueprintsFiles, Parse
51//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070052// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070053//
54// 4. Write WriteBuildFile
55//
56// The registration phase prepares the context to process Blueprints files
57// containing various types of modules. The parse phase reads in one or more
58// Blueprints files and validates their contents against the module types that
59// have been registered. The generate phase then analyzes the parsed Blueprints
60// contents to create an internal representation for the build actions that must
61// be performed. This phase also performs validation of the module dependencies
62// and property values defined in the parsed Blueprints files. Finally, the
63// write phase generates the Ninja manifest text based on the generated build
64// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070065type Context struct {
66 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070067 moduleFactories map[string]ModuleFactory
Colin Cross0b7e83e2016-05-17 14:58:05 -070068 moduleNames map[string]*moduleGroup
69 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070070 moduleInfo map[Module]*moduleInfo
71 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070072 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070073 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070074 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070075 variantMutatorNames []string
76 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070077
Colin Cross3702ac72016-08-11 11:09:00 -070078 depsModified uint32 // positive if a mutator modified the dependencies
79
Jamie Gennis1bc967e2014-05-27 16:34:41 -070080 dependenciesReady bool // set to true on a successful ResolveDependencies
81 buildActionsReady bool // set to true on a successful PrepareBuildActions
82
83 // set by SetIgnoreUnknownModuleTypes
84 ignoreUnknownModuleTypes bool
85
Colin Cross036a1df2015-12-17 15:49:30 -080086 // set by SetAllowMissingDependencies
87 allowMissingDependencies bool
88
Jamie Gennis1bc967e2014-05-27 16:34:41 -070089 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080090 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070091 globalVariables map[Variable]*ninjaString
92 globalPools map[Pool]*poolDef
93 globalRules map[Rule]*ruleDef
94
95 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080096 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097 requiredNinjaMajor int // For the ninja_required_version variable
98 requiredNinjaMinor int // For the ninja_required_version variable
99 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700100
101 // set lazily by sortedModuleNames
102 cachedSortedModuleNames []string
Colin Crossd7b0f602016-06-02 15:30:20 -0700103
Colin Cross9cfd1982016-10-11 09:58:53 -0700104 // List of pending renames and replacements to apply after the mutator pass
105 renames []rename
106 replacements []replace
Colin Crossc4e5b812016-10-12 10:45:05 -0700107
Colin Crossd7b0f602016-06-02 15:30:20 -0700108 fs fileSystem
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109}
110
Jamie Gennisd4e10182014-06-12 20:06:50 -0700111// An Error describes a problem that was encountered that is related to a
112// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700113type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700114 Err error // the error that occurred
115 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116}
117
Colin Cross2c628442016-10-07 17:13:10 -0700118// A ModuleError describes a problem that was encountered that is related to a
119// particular module in a Blueprints file
120type ModuleError struct {
121 BlueprintError
122 module *moduleInfo
123}
124
125// A PropertyError describes a problem that was encountered that is related to a
126// particular property in a Blueprints file
127type PropertyError struct {
128 ModuleError
129 property string
130}
131
132func (e *BlueprintError) Error() string {
133 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
134}
135
136func (e *ModuleError) Error() string {
137 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
138}
139
140func (e *PropertyError) Error() string {
141 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
142}
143
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700144type localBuildActions struct {
145 variables []*localVariable
146 rules []*localRule
147 buildDefs []*buildDef
148}
149
Colin Crossbbfa51a2014-12-17 16:12:41 -0800150type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700151 name string
152 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700153
Colin Crossbbfa51a2014-12-17 16:12:41 -0800154 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700155}
156
Colin Crossbbfa51a2014-12-17 16:12:41 -0800157type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700158 // set during Parse
159 typeName string
160 relBlueprintsFile string
161 pos scanner.Position
162 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700163
Colin Crossf5e34b92015-03-13 16:02:36 -0700164 variantName string
165 variant variationMap
166 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700167
Colin Crossc9028482014-12-18 16:28:54 -0800168 logicModule Module
169 group *moduleGroup
170 moduleProperties []interface{}
171
172 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700173 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800174 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800175
Colin Cross7addea32015-03-11 15:43:52 -0700176 // set during updateDependencies
177 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700178 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700179
180 // used by parallelVisitAllBottomUp
181 waitingCount int
182
Colin Crossc9028482014-12-18 16:28:54 -0800183 // set during each runMutator
184 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700185
186 // set during PrepareBuildActions
187 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800188}
189
Colin Cross2c1f3d12016-04-11 15:47:28 -0700190type depInfo struct {
191 module *moduleInfo
192 tag DependencyTag
193}
194
Colin Cross0b7e83e2016-05-17 14:58:05 -0700195func (module *moduleInfo) Name() string {
196 return module.group.name
197}
198
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800199func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700200 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800201 if module.variantName != "" {
202 s += fmt.Sprintf(" variant %q", module.variantName)
203 }
204 return s
205}
206
Colin Crossf5e34b92015-03-13 16:02:36 -0700207// A Variation is a way that a variant of a module differs from other variants of the same module.
208// For example, two variants of the same module might have Variation{"arch","arm"} and
209// Variation{"arch","arm64"}
210type Variation struct {
211 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700212 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700213 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
214 // "shared" or "static" for link.
215 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700216}
217
Colin Crossf5e34b92015-03-13 16:02:36 -0700218// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
219type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700220
Colin Crossf5e34b92015-03-13 16:02:36 -0700221func (vm variationMap) clone() variationMap {
222 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700223 for k, v := range vm {
224 newVm[k] = v
225 }
226
227 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800228}
229
Colin Cross89486232015-05-08 11:14:54 -0700230// Compare this variationMap to another one. Returns true if the every entry in this map
231// is either the same in the other map or doesn't exist in the other map.
232func (vm variationMap) subset(other variationMap) bool {
233 for k, v1 := range vm {
234 if v2, ok := other[k]; ok && v1 != v2 {
235 return false
236 }
237 }
238 return true
239}
240
Colin Crossf5e34b92015-03-13 16:02:36 -0700241func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700242 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800243}
244
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700245type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700246 // set during RegisterSingletonType
247 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700248 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700249 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700250
251 // set during PrepareBuildActions
252 actionDefs localBuildActions
253}
254
Colin Crossc9028482014-12-18 16:28:54 -0800255type mutatorInfo struct {
256 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800257 topDownMutator TopDownMutator
258 bottomUpMutator BottomUpMutator
259 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700260 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800261}
262
Jamie Gennisd4e10182014-06-12 20:06:50 -0700263// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700264// no module or singleton factories registered, so the RegisterModuleFactory and
265// RegisterSingletonFactory methods must be called before it can do anything
266// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700267func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700268 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800269 moduleFactories: make(map[string]ModuleFactory),
Colin Cross0b7e83e2016-05-17 14:58:05 -0700270 moduleNames: make(map[string]*moduleGroup),
Colin Cross6134a5c2015-02-10 11:26:26 -0800271 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800272 moduleNinjaNames: make(map[string]*moduleGroup),
Colin Crossd7b0f602016-06-02 15:30:20 -0700273 fs: fs,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700274 }
Colin Cross763b6f12015-10-29 15:32:56 -0700275
276 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
277
278 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700279}
280
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700281// A ModuleFactory function creates a new Module object. See the
282// Context.RegisterModuleType method for details about how a registered
283// ModuleFactory is used by a Context.
284type ModuleFactory func() (m Module, propertyStructs []interface{})
285
Jamie Gennisd4e10182014-06-12 20:06:50 -0700286// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700287// Blueprints file) with a Module factory function. When the given module type
288// name is encountered in a Blueprints file during parsing, the Module factory
289// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800290// generation for the module. If a Mutator splits a module into multiple variants,
291// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700292//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700293// The module type names given here must be unique for the context. The factory
294// function should be a named function so that its package and name can be
295// included in the generated Ninja file for debugging purposes.
296//
297// The factory function returns two values. The first is the newly created
298// Module object. The second is a slice of pointers to that Module object's
299// properties structs. Each properties struct is examined when parsing a module
300// definition of this type in a Blueprints file. Exported fields of the
301// properties structs are automatically set to the property values specified in
302// the Blueprints file. The properties struct field names determine the name of
303// the Blueprints file properties that are used - the Blueprints property name
304// matches that of the properties struct field name with the first letter
305// converted to lower-case.
306//
307// The fields of the properties struct must be either []string, a string, or
308// bool. The Context will panic if a Module gets instantiated with a properties
309// struct containing a field that is not one these supported types.
310//
311// Any properties that appear in the Blueprints files that are not built-in
312// module properties (such as "name" and "deps") and do not have a corresponding
313// field in the returned module properties struct result in an error during the
314// Context's parse phase.
315//
316// As an example, the follow code:
317//
318// type myModule struct {
319// properties struct {
320// Foo string
321// Bar []string
322// }
323// }
324//
325// func NewMyModule() (blueprint.Module, []interface{}) {
326// module := new(myModule)
327// properties := &module.properties
328// return module, []interface{}{properties}
329// }
330//
331// func main() {
332// ctx := blueprint.NewContext()
333// ctx.RegisterModuleType("my_module", NewMyModule)
334// // ...
335// }
336//
337// would support parsing a module defined in a Blueprints file as follows:
338//
339// my_module {
340// name: "myName",
341// foo: "my foo string",
342// bar: ["my", "bar", "strings"],
343// }
344//
Colin Cross7ad621c2015-01-07 16:22:45 -0800345// The factory function may be called from multiple goroutines. Any accesses
346// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700347func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
348 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700349 panic(errors.New("module type name is already registered"))
350 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700351 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700352}
353
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700354// A SingletonFactory function creates a new Singleton object. See the
355// Context.RegisterSingletonType method for details about how a registered
356// SingletonFactory is used by a Context.
357type SingletonFactory func() Singleton
358
359// RegisterSingletonType registers a singleton type that will be invoked to
360// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700361// and invoked exactly once as part of the generate phase. Each registered
362// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700363//
364// The singleton type names given here must be unique for the context. The
365// factory function should be a named function so that its package and name can
366// be included in the generated Ninja file for debugging purposes.
367func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700368 for _, s := range c.singletonInfo {
369 if s.name == name {
370 panic(errors.New("singleton name is already registered"))
371 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700372 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700373
Yuchen Wub9103ef2015-08-25 17:58:17 -0700374 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700375 factory: factory,
376 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700377 name: name,
378 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700379}
380
381func singletonPkgPath(singleton Singleton) string {
382 typ := reflect.TypeOf(singleton)
383 for typ.Kind() == reflect.Ptr {
384 typ = typ.Elem()
385 }
386 return typ.PkgPath()
387}
388
389func singletonTypeName(singleton Singleton) string {
390 typ := reflect.TypeOf(singleton)
391 for typ.Kind() == reflect.Ptr {
392 typ = typ.Elem()
393 }
394 return typ.PkgPath() + "." + typ.Name()
395}
396
Colin Cross3702ac72016-08-11 11:09:00 -0700397// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
398// top-down between Modules. Each registered mutator is invoked in registration order (mixing
399// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
400// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800401//
Colin Cross65569e42015-03-10 20:08:19 -0700402// The mutator type names given here must be unique to all top down mutators in
403// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700404//
405// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
406// parallel while maintaining ordering.
407func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800408 for _, m := range c.mutatorInfo {
409 if m.name == name && m.topDownMutator != nil {
410 panic(fmt.Errorf("mutator name %s is already registered", name))
411 }
412 }
413
Colin Cross3702ac72016-08-11 11:09:00 -0700414 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800415 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800416 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700417 }
418
419 c.mutatorInfo = append(c.mutatorInfo, info)
420
421 return info
Colin Crossc9028482014-12-18 16:28:54 -0800422}
423
Colin Cross3702ac72016-08-11 11:09:00 -0700424// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
425// Each registered mutator is invoked in registration order (mixing TopDownMutators and
426// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
427// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800428//
Colin Cross65569e42015-03-10 20:08:19 -0700429// The mutator type names given here must be unique to all bottom up or early
430// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700431//
Colin Cross3702ac72016-08-11 11:09:00 -0700432// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
433// parallel while maintaining ordering.
434func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700435 for _, m := range c.variantMutatorNames {
436 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800437 panic(fmt.Errorf("mutator name %s is already registered", name))
438 }
439 }
440
Colin Cross49c279a2016-08-05 22:30:44 -0700441 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800442 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800443 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700444 }
445 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700446
447 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700448
449 return info
450}
451
Colin Cross3702ac72016-08-11 11:09:00 -0700452type MutatorHandle interface {
453 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
454 // method on the mutator context is thread-safe, but the mutator must handle synchronization
455 // for any modifications to global state or any modules outside the one it was invoked on.
456 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700457}
458
Colin Cross3702ac72016-08-11 11:09:00 -0700459func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700460 mutator.parallel = true
461 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700462}
463
464// RegisterEarlyMutator registers a mutator that will be invoked to split
465// Modules into multiple variant Modules before any dependencies have been
466// created. Each registered mutator is invoked in registration order once
467// per Module (including each variant from previous early mutators). Module
468// order is unpredictable.
469//
470// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700471// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700472//
473// The mutator type names given here must be unique to all bottom up or early
474// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700475//
476// Deprecated, use a BottomUpMutator instead. The only difference between
477// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
478// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700479func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
480 for _, m := range c.variantMutatorNames {
481 if m == name {
482 panic(fmt.Errorf("mutator name %s is already registered", name))
483 }
484 }
485
Colin Crossf8b50422016-08-10 12:56:40 -0700486 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
487 bottomUpMutator: func(mctx BottomUpMutatorContext) {
488 mutator(mctx)
489 },
490 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700491 })
492
493 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800494}
495
Jamie Gennisd4e10182014-06-12 20:06:50 -0700496// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
497// where it encounters an unknown module type while parsing Blueprints files. By
498// default, the context will report unknown module types as an error. If this
499// method is called with ignoreUnknownModuleTypes set to true then the context
500// will silently ignore unknown module types.
501//
502// This method should generally not be used. It exists to facilitate the
503// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700504func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
505 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
506}
507
Colin Cross036a1df2015-12-17 15:49:30 -0800508// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
509// unresolved dependencies. If the module's GenerateBuildActions calls
510// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
511// for missing dependencies.
512func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
513 c.allowMissingDependencies = allowMissingDependencies
514}
515
Jamie Gennisd4e10182014-06-12 20:06:50 -0700516// Parse parses a single Blueprints file from r, creating Module objects for
517// each of the module definitions encountered. If the Blueprints file contains
518// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700519// searched for Blueprints files returned in the subBlueprints return value.
520// If the Blueprints file contains an assignment to the "build" variable, then
521// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700522//
523// rootDir specifies the path to the root directory of the source tree, while
524// filename specifies the path to the Blueprints file. These paths are used for
525// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800526func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700527 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700528 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700529
Jamie Gennisec701282014-06-12 20:06:31 -0700530 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700531 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700532 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700533 }
534
Colin Crossc0dbc552015-01-02 15:19:28 -0800535 scope = parser.NewScope(scope)
536 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800537 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700538 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700539 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700540 if len(errs) > 0 {
541 for i, err := range errs {
542 if parseErr, ok := err.(*parser.ParseError); ok {
Colin Cross2c628442016-10-07 17:13:10 -0700543 err = &BlueprintError{
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700544 Err: parseErr.Err,
545 Pos: parseErr.Pos,
546 }
547 errs[i] = err
548 }
549 }
550
551 // If there were any parse errors don't bother trying to interpret the
552 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700553 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700554 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700555 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700556
Colin Cross6d8780f2015-07-10 17:51:55 -0700557 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700558 if err != nil {
559 errs = append(errs, err)
560 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700561
Colin Cross7f507402015-12-16 13:03:41 -0800562 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
563 if err != nil {
564 errs = append(errs, err)
565 }
566
Colin Cross6d8780f2015-07-10 17:51:55 -0700567 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700568 if err != nil {
569 errs = append(errs, err)
570 }
571
Colin Cross29394222015-04-27 13:18:21 -0700572 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
573
Colin Cross7f507402015-12-16 13:03:41 -0800574 var blueprints []string
575
576 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
577 blueprints = append(blueprints, newBlueprints...)
578 deps = append(deps, newDeps...)
579 errs = append(errs, newErrs...)
580
581 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
582 subBlueprintsName, false)
583 blueprints = append(blueprints, newBlueprints...)
584 deps = append(deps, newDeps...)
585 errs = append(errs, newErrs...)
586
587 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
588 optionalSubdirsPos, subBlueprintsName, true)
589 blueprints = append(blueprints, newBlueprints...)
590 deps = append(deps, newDeps...)
591 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800592
Colin Cross1fef5362015-04-20 16:50:54 -0700593 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
594 for i, b := range blueprints {
595 subBlueprintsAndScope[i] = stringAndScope{b, scope}
596 }
597
Colin Cross23d7aa12015-06-30 16:05:22 -0700598 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800599}
600
Colin Cross7ad621c2015-01-07 16:22:45 -0800601type stringAndScope struct {
602 string
603 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700604}
605
Jamie Gennisd4e10182014-06-12 20:06:50 -0700606// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
607// at rootFile. When it encounters a Blueprints file with a set of subdirs
608// listed it recursively parses any Blueprints files found in those
609// subdirectories.
610//
611// If no errors are encountered while parsing the files, the list of paths on
612// which the future output will depend is returned. This list will include both
613// Blueprints file paths as well as directory paths for cases where wildcard
614// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700615func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
616 errs []error) {
617
Colin Cross7ad621c2015-01-07 16:22:45 -0800618 c.dependenciesReady = false
619
Colin Cross23d7aa12015-06-30 16:05:22 -0700620 moduleCh := make(chan *moduleInfo)
621 errsCh := make(chan []error)
622 doneCh := make(chan struct{})
623 var numErrs uint32
624 var numGoroutines int32
625
626 // handler must be reentrant
627 handler := func(file *parser.File) {
628 if atomic.LoadUint32(&numErrs) > maxErrors {
629 return
630 }
631
632 atomic.AddInt32(&numGoroutines, 1)
633 go func() {
634 for _, def := range file.Defs {
635 var module *moduleInfo
636 var errs []error
637 switch def := def.(type) {
638 case *parser.Module:
639 module, errs = c.processModuleDef(def, file.Name)
640 case *parser.Assignment:
641 // Already handled via Scope object
642 default:
643 panic("unknown definition type")
644 }
645
646 if len(errs) > 0 {
647 atomic.AddUint32(&numErrs, uint32(len(errs)))
648 errsCh <- errs
649 } else if module != nil {
650 moduleCh <- module
651 }
652 }
653 doneCh <- struct{}{}
654 }()
655 }
656
657 atomic.AddInt32(&numGoroutines, 1)
658 go func() {
659 var errs []error
660 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
661 if len(errs) > 0 {
662 errsCh <- errs
663 }
664 doneCh <- struct{}{}
665 }()
666
667loop:
668 for {
669 select {
670 case newErrs := <-errsCh:
671 errs = append(errs, newErrs...)
672 case module := <-moduleCh:
673 newErrs := c.addModule(module)
674 if len(newErrs) > 0 {
675 errs = append(errs, newErrs...)
676 }
677 case <-doneCh:
678 n := atomic.AddInt32(&numGoroutines, -1)
679 if n == 0 {
680 break loop
681 }
682 }
683 }
684
685 return deps, errs
686}
687
688type FileHandler func(*parser.File)
689
690// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
691// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
692// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
693// it must be reentrant.
694//
695// If no errors are encountered while parsing the files, the list of paths on
696// which the future output will depend is returned. This list will include both
697// Blueprints file paths as well as directory paths for cases where wildcard
698// subdirs are found.
699func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
700 errs []error) {
701
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700702 rootDir := filepath.Dir(rootFile)
703
Colin Cross7ad621c2015-01-07 16:22:45 -0800704 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700705
Colin Cross7ad621c2015-01-07 16:22:45 -0800706 // Channels to receive data back from parseBlueprintsFile goroutines
707 blueprintsCh := make(chan stringAndScope)
708 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700709 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700711
Colin Cross7ad621c2015-01-07 16:22:45 -0800712 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
713 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700714
Colin Cross7ad621c2015-01-07 16:22:45 -0800715 // Number of outstanding goroutines to wait for
716 count := 0
717
718 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
719 count++
720 go func() {
721 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700722 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800723 doneCh <- struct{}{}
724 }()
725 }
726
727 tooManyErrors := false
728
729 startParseBlueprintsFile(rootFile, nil)
730
731loop:
732 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700733 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800734 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700735 }
736
Colin Cross7ad621c2015-01-07 16:22:45 -0800737 select {
738 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700739 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800740 case dep := <-depsCh:
741 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700742 case file := <-fileCh:
743 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800744 case blueprint := <-blueprintsCh:
745 if tooManyErrors {
746 continue
747 }
748 if blueprintsSet[blueprint.string] {
749 continue
750 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700751
Colin Cross7ad621c2015-01-07 16:22:45 -0800752 blueprintsSet[blueprint.string] = true
753 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
754 case <-doneCh:
755 count--
756 if count == 0 {
757 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700758 }
759 }
760 }
761
Colin Cross7ad621c2015-01-07 16:22:45 -0800762 return
763}
764
Colin Crossd7b0f602016-06-02 15:30:20 -0700765// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
766// filenames to contents stored as a byte slice.
767func (c *Context) MockFileSystem(files map[string][]byte) {
768 c.fs = &mockFS{
769 files: files,
770 }
771}
772
Colin Cross7ad621c2015-01-07 16:22:45 -0800773// parseBlueprintFile parses a single Blueprints file, returning any errors through
774// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
775// blueprintsCh, and any dependencies on Blueprints files or directories through
776// depsCh.
777func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700778 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800779 depsCh chan<- string) {
780
Colin Crossd7b0f602016-06-02 15:30:20 -0700781 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800782 if err != nil {
783 errsCh <- []error{err}
784 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700785 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700786 defer func() {
787 err = f.Close()
788 if err != nil {
789 errsCh <- []error{err}
790 }
791 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700792
Colin Cross23d7aa12015-06-30 16:05:22 -0700793 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800794 if len(errs) > 0 {
795 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700796 } else {
797 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800798 }
799
Colin Cross1fef5362015-04-20 16:50:54 -0700800 for _, b := range subBlueprints {
801 blueprintsCh <- b
802 }
803
804 for _, d := range deps {
805 depsCh <- d
806 }
Colin Cross1fef5362015-04-20 16:50:54 -0700807}
808
Colin Cross7f507402015-12-16 13:03:41 -0800809func (c *Context) findBuildBlueprints(dir string, build []string,
810 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
811
812 for _, file := range build {
813 globPattern := filepath.Join(dir, file)
814 matches, matchedDirs, err := pathtools.Glob(globPattern)
815 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700816 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800817 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
818 Pos: buildPos,
819 })
820 continue
821 }
822
823 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -0700824 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800825 Err: fmt.Errorf("%q: not found", globPattern),
826 Pos: buildPos,
827 })
828 }
829
830 // Depend on all searched directories so we pick up future changes.
831 deps = append(deps, matchedDirs...)
832
833 for _, foundBlueprints := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700834 exists, dir, err := c.fs.Exists(foundBlueprints)
835 if err != nil {
836 errs = append(errs, err)
837 } else if !exists {
Colin Cross2c628442016-10-07 17:13:10 -0700838 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800839 Err: fmt.Errorf("%q not found", foundBlueprints),
840 })
841 continue
Colin Crossd7b0f602016-06-02 15:30:20 -0700842 } else if dir {
Colin Cross2c628442016-10-07 17:13:10 -0700843 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800844 Err: fmt.Errorf("%q is a directory", foundBlueprints),
845 })
846 continue
847 }
848
849 blueprints = append(blueprints, foundBlueprints)
Colin Cross24587122016-10-11 10:01:29 -0700850 deps = append(deps, foundBlueprints)
Colin Cross7f507402015-12-16 13:03:41 -0800851 }
852 }
853
854 return blueprints, deps, errs
855}
856
857func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
858 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800859
860 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700861 globPattern := filepath.Join(dir, subdir)
862 matches, matchedDirs, err := pathtools.Glob(globPattern)
863 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700864 errs = append(errs, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700865 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
866 Pos: subdirsPos,
867 })
868 continue
869 }
870
Colin Cross7f507402015-12-16 13:03:41 -0800871 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -0700872 errs = append(errs, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700873 Err: fmt.Errorf("%q: not found", globPattern),
874 Pos: subdirsPos,
875 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700876 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800877
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700878 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700879 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800880
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700881 for _, foundSubdir := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700882 exists, dir, subdirStatErr := c.fs.Exists(foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700883 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700884 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700885 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800886 }
887
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700888 // Skip files
Colin Crossd7b0f602016-06-02 15:30:20 -0700889 if !dir {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700890 continue
891 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800892
Colin Cross29394222015-04-27 13:18:21 -0700893 var subBlueprints string
894 if subBlueprintsName != "" {
895 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
Colin Crossd7b0f602016-06-02 15:30:20 -0700896 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700897 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700898
Colin Crossd7b0f602016-06-02 15:30:20 -0700899 if err == nil && (!exists || subBlueprints == "") {
Colin Cross29394222015-04-27 13:18:21 -0700900 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
Colin Crossd7b0f602016-06-02 15:30:20 -0700901 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700902 }
903
Colin Crossd7b0f602016-06-02 15:30:20 -0700904 if err != nil {
905 errs = append(errs, err)
906 continue
907 }
908
909 if !exists {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700910 // There is no Blueprints file in this subdirectory. We
911 // need to add the directory to the list of dependencies
912 // so that if someone adds a Blueprints file in the
913 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700914 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700915 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700916 deps = append(deps, subBlueprints)
917 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800918 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800919 }
920 }
Colin Cross1fef5362015-04-20 16:50:54 -0700921
Colin Cross1fef5362015-04-20 16:50:54 -0700922 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700923}
924
Colin Cross6d8780f2015-07-10 17:51:55 -0700925func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
926 if assignment, local := scope.Get(v); assignment == nil || !local {
927 return nil, scanner.Position{}, nil
928 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700929 switch value := assignment.Value.Eval().(type) {
930 case *parser.List:
931 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700932
Colin Crosse32cc802016-06-07 12:28:16 -0700933 for _, listValue := range value.Values {
934 s, ok := listValue.(*parser.String)
935 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700936 // The parser should not produce this.
937 panic("non-string value found in list")
938 }
939
Colin Crosse32cc802016-06-07 12:28:16 -0700940 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700941 }
942
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700943 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700944 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -0700945 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700946 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700947 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700948 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700949 default:
950 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
951 }
952 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700953}
954
Colin Cross29394222015-04-27 13:18:21 -0700955func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700956 if assignment, _ := scope.Get(v); assignment == nil {
957 return "", scanner.Position{}, nil
958 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700959 switch value := assignment.Value.Eval().(type) {
960 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700961 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700962 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -0700963 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -0700964 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700965 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -0700966 }
967 default:
968 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
969 }
970 }
Colin Cross29394222015-04-27 13:18:21 -0700971}
972
Colin Cross910242b2016-04-11 15:41:52 -0700973// Clones a build logic module by calling the factory method for its module type, and then cloning
974// property values. Any values stored in the module object that are not stored in properties
975// structs will be lost.
976func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
977 typeName := origModule.typeName
978 factory, ok := c.moduleFactories[typeName]
979 if !ok {
980 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
981 }
982
Colin Cross910242b2016-04-11 15:41:52 -0700983 newLogicModule, newProperties := factory()
984
Colin Cross910242b2016-04-11 15:41:52 -0700985 if len(newProperties) != len(origModule.moduleProperties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700986 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -0700987 }
988
989 for i := range newProperties {
990 dst := reflect.ValueOf(newProperties[i]).Elem()
991 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
992
993 proptools.CopyProperties(dst, src)
994 }
995
996 return newLogicModule, newProperties
997}
998
Colin Crossf5e34b92015-03-13 16:02:36 -0700999func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
1000 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001001
Colin Crossf4d18a62015-03-18 17:43:15 -07001002 if len(variationNames) == 0 {
1003 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001004 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001005 }
1006
Colin Crossc9028482014-12-18 16:28:54 -08001007 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001008
Colin Cross174ae052015-03-03 17:37:03 -08001009 var errs []error
1010
Colin Crossf5e34b92015-03-13 16:02:36 -07001011 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001012 var newLogicModule Module
1013 var newProperties []interface{}
1014
1015 if i == 0 {
1016 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001017 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1018 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -07001019 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -08001020 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001021 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001022 }
1023
Colin Crossf5e34b92015-03-13 16:02:36 -07001024 newVariant := origModule.variant.clone()
1025 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001026
Colin Crossed342d92015-03-11 00:57:25 -07001027 m := *origModule
1028 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001029 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001030 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001031 newModule.variant = newVariant
1032 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -07001033 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001034
Colin Crossbadc8812016-08-11 17:01:46 -07001035 if variationName != "" {
1036 if newModule.variantName == "" {
1037 newModule.variantName = variationName
1038 } else {
1039 newModule.variantName += "_" + variationName
1040 }
Colin Crosse7daa222015-03-11 14:35:41 -07001041 }
1042
Colin Crossc9028482014-12-18 16:28:54 -08001043 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001044
Colin Crossf5e34b92015-03-13 16:02:36 -07001045 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001046 if len(newErrs) > 0 {
1047 errs = append(errs, newErrs...)
1048 }
Colin Crossc9028482014-12-18 16:28:54 -08001049 }
1050
1051 // Mark original variant as invalid. Modules that depend on this module will still
1052 // depend on origModule, but we'll fix it when the mutator is called on them.
1053 origModule.logicModule = nil
1054 origModule.splitModules = newModules
1055
Colin Cross3702ac72016-08-11 11:09:00 -07001056 atomic.AddUint32(&c.depsModified, 1)
1057
Colin Cross174ae052015-03-03 17:37:03 -08001058 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001059}
1060
Colin Crossf5e34b92015-03-13 16:02:36 -07001061func (c *Context) convertDepsToVariation(module *moduleInfo,
1062 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001063
Colin Crossc9028482014-12-18 16:28:54 -08001064 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001065 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001066 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001067 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001068 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001069 newDep = m
1070 break
1071 }
1072 }
1073 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001074 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001075 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001076 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001077 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001078 })
1079 continue
Colin Crossc9028482014-12-18 16:28:54 -08001080 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001081 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001082 }
1083 }
Colin Cross174ae052015-03-03 17:37:03 -08001084
1085 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001086}
1087
Colin Crossf5e34b92015-03-13 16:02:36 -07001088func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001089 names := make([]string, 0, len(variant))
1090 for _, m := range c.variantMutatorNames {
1091 if v, ok := variant[m]; ok {
1092 names = append(names, m+":"+v)
1093 }
1094 }
1095
1096 return strings.Join(names, ", ")
1097}
1098
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001099func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001100 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001101
Colin Crossc32c4792016-06-09 15:52:30 -07001102 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001103 if !ok {
1104 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001105 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001106 }
1107
Colin Cross7ad621c2015-01-07 16:22:45 -08001108 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001109 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001110 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1111 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001112 },
1113 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001114 }
1115
Colin Crossbbfa51a2014-12-17 16:12:41 -08001116 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001117
1118 module := &moduleInfo{
1119 logicModule: logicModule,
Colin Crossc32c4792016-06-09 15:52:30 -07001120 typeName: moduleDef.Type,
Jamie Gennisec701282014-06-12 20:06:31 -07001121 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001122 }
1123
Colin Crossed342d92015-03-11 00:57:25 -07001124 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001125
Jamie Gennis87622922014-09-30 11:38:25 -07001126 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001127 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001128 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001129 }
1130
Colin Crossc32c4792016-06-09 15:52:30 -07001131 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001132 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001133 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001134 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001135 }
1136
Colin Cross7ad621c2015-01-07 16:22:45 -08001137 return module, nil
1138}
1139
Colin Cross23d7aa12015-06-30 16:05:22 -07001140func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001141 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001142 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001143
Colin Cross0b7e83e2016-05-17 14:58:05 -07001144 if group, present := c.moduleNames[name]; present {
Colin Cross23d7aa12015-06-30 16:05:22 -07001145 return []error{
Colin Cross2c628442016-10-07 17:13:10 -07001146 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001147 Err: fmt.Errorf("module %q already defined", name),
1148 Pos: module.pos,
1149 },
Colin Cross2c628442016-10-07 17:13:10 -07001150 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001151 Err: fmt.Errorf("<-- previous definition here"),
1152 Pos: group.modules[0].pos,
1153 },
Colin Crossed342d92015-03-11 00:57:25 -07001154 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001155 }
1156
Colin Cross0b7e83e2016-05-17 14:58:05 -07001157 ninjaName := toNinjaName(name)
1158
1159 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1160 // already exists
1161 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1162 ninjaName = toNinjaName(name) + strconv.Itoa(i)
1163 }
1164
1165 group := &moduleGroup{
1166 name: name,
1167 ninjaName: ninjaName,
1168 modules: []*moduleInfo{module},
1169 }
1170 module.group = group
1171 c.moduleNames[name] = group
1172 c.moduleNinjaNames[ninjaName] = group
1173 c.moduleGroups = append(c.moduleGroups, group)
1174
Colin Cross23d7aa12015-06-30 16:05:22 -07001175 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001176}
1177
Jamie Gennisd4e10182014-06-12 20:06:50 -07001178// ResolveDependencies checks that the dependencies specified by all of the
1179// modules defined in the parsed Blueprints files are valid. This means that
1180// the modules depended upon are defined and that no circular dependencies
1181// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001182func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Crossf8b50422016-08-10 12:56:40 -07001183 errs := c.updateDependencies()
1184 if len(errs) > 0 {
1185 return errs
1186 }
1187
1188 errs = c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001189 if len(errs) > 0 {
1190 return errs
1191 }
1192
Colin Cross910242b2016-04-11 15:41:52 -07001193 c.cloneModules()
1194
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001195 c.dependenciesReady = true
1196 return nil
1197}
1198
Colin Cross763b6f12015-10-29 15:32:56 -07001199// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001200// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001201// module names returned by its DynamicDependencies method and those added by calling
1202// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001203func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001204 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001205 func() {
1206 defer func() {
1207 if r := recover(); r != nil {
1208 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1209 }
1210 }()
1211 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001212
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001213 if ctx.Failed() {
1214 return
1215 }
Colin Cross763b6f12015-10-29 15:32:56 -07001216
Colin Cross2c1f3d12016-04-11 15:47:28 -07001217 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001218 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001219 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001220}
1221
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001222// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1223// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001224func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1225 if len(possible) == 1 {
1226 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001227 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001228 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001229 if m.variant.equal(module.dependencyVariant) {
1230 return m
1231 }
1232 }
1233 }
1234
1235 return nil
1236}
1237
Colin Cross2c1f3d12016-04-11 15:47:28 -07001238func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001239 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001240 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001241 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001242 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001243 }}
1244 }
1245
Colin Cross0b7e83e2016-05-17 14:58:05 -07001246 possibleDeps := c.modulesFromName(depName)
1247 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001248 if c.allowMissingDependencies {
1249 module.missingDeps = append(module.missingDeps, depName)
1250 return nil
1251 }
Colin Cross2c628442016-10-07 17:13:10 -07001252 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001253 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001254 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001255 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001256 }}
1257 }
1258
Colin Cross0b7e83e2016-05-17 14:58:05 -07001259 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001260 for _, dep := range module.directDeps {
1261 if m == dep.module {
1262 // TODO(ccross): what if adding a dependency with a different tag?
1263 return nil
1264 }
Colin Cross65569e42015-03-10 20:08:19 -07001265 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001266 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001267 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001268 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001269 }
Colin Crossc9028482014-12-18 16:28:54 -08001270
Colin Cross2c628442016-10-07 17:13:10 -07001271 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001272 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001273 depName, module.Name(),
Colin Crossf5e34b92015-03-13 16:02:36 -07001274 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001275 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001276 }}
1277}
1278
Colin Cross8d8a7af2015-11-03 16:41:29 -08001279func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001280 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001281 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001282 Err: fmt.Errorf("%q depends on itself", destName),
1283 Pos: module.pos,
1284 }}
1285 }
1286
Colin Cross0b7e83e2016-05-17 14:58:05 -07001287 possibleDeps := c.modulesFromName(destName)
1288 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001289 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001290 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001291 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001292 Pos: module.pos,
1293 }}
1294 }
1295
Colin Cross0b7e83e2016-05-17 14:58:05 -07001296 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001297 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001298 }
1299
Colin Cross2c628442016-10-07 17:13:10 -07001300 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001301 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001302 destName, module.Name(),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001303 c.prettyPrintVariant(module.dependencyVariant)),
1304 Pos: module.pos,
1305 }}
1306}
1307
Colin Crossf5e34b92015-03-13 16:02:36 -07001308func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001309 tag DependencyTag, depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001310
Colin Cross0b7e83e2016-05-17 14:58:05 -07001311 possibleDeps := c.modulesFromName(depName)
1312 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001313 if c.allowMissingDependencies {
1314 module.missingDeps = append(module.missingDeps, depName)
1315 return nil
1316 }
Colin Cross2c628442016-10-07 17:13:10 -07001317 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001318 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001319 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001320 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001321 }}
1322 }
1323
1324 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1325 // compare the strings because the result won't be in mutator registration order.
1326 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001327 var newVariant variationMap
1328 if !far {
1329 newVariant = module.dependencyVariant.clone()
1330 } else {
1331 newVariant = make(variationMap)
1332 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001333 for _, v := range variations {
1334 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001335 }
1336
Colin Cross0b7e83e2016-05-17 14:58:05 -07001337 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001338 var found bool
1339 if far {
1340 found = m.variant.subset(newVariant)
1341 } else {
1342 found = m.variant.equal(newVariant)
1343 }
1344 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001345 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001346 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001347 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001348 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001349 }}
1350 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001351 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001352 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001353 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001354 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001355 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001356 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001357 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001358 }}
1359 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001360 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001361 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001362 return nil
1363 }
1364 }
1365
Colin Cross2c628442016-10-07 17:13:10 -07001366 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001367 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001368 depName, module.Name(),
Colin Crossf5e34b92015-03-13 16:02:36 -07001369 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001370 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001371 }}
Colin Crossc9028482014-12-18 16:28:54 -08001372}
1373
Colin Crossf1875462016-04-11 17:33:13 -07001374func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1375 from, to Module) {
1376
1377 var fromInfo, toInfo *moduleInfo
1378 for _, m := range origModule.splitModules {
1379 if m.logicModule == from {
1380 fromInfo = m
1381 }
1382 if m.logicModule == to {
1383 toInfo = m
1384 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001385 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001386 }
1387 }
1388 }
1389
1390 if fromInfo == nil || toInfo == nil {
1391 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001392 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001393 }
1394
1395 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001396 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001397}
1398
Colin Cross3702ac72016-08-11 11:09:00 -07001399type visitOrderer interface {
1400 // returns the number of modules that this module needs to wait for
1401 waitCount(module *moduleInfo) int
1402 // returns the list of modules that are waiting for this module
1403 propagate(module *moduleInfo) []*moduleInfo
1404 // visit modules in order
1405 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1406}
1407
1408type bottomUpVisitorImpl struct{}
1409
1410func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1411 return len(module.forwardDeps)
1412}
1413
1414func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1415 return module.reverseDeps
1416}
1417
1418func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1419 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001420 if visit(module) {
1421 return
1422 }
1423 }
1424}
1425
Colin Cross3702ac72016-08-11 11:09:00 -07001426type topDownVisitorImpl struct{}
1427
1428func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1429 return len(module.reverseDeps)
1430}
1431
1432func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1433 return module.forwardDeps
1434}
1435
1436func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1437 for i := 0; i < len(modules); i++ {
1438 module := modules[len(modules)-1-i]
1439 if visit(module) {
1440 return
1441 }
1442 }
1443}
1444
1445var (
1446 bottomUpVisitor bottomUpVisitorImpl
1447 topDownVisitor topDownVisitorImpl
1448)
1449
Colin Cross49c279a2016-08-05 22:30:44 -07001450// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1451// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001452func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001453 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001454 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001455 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001456 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001457
Colin Cross7addea32015-03-11 15:43:52 -07001458 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001459 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001460 }
1461
Colin Cross7addea32015-03-11 15:43:52 -07001462 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001463 count++
1464 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001465 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001466 if ret {
Colin Cross0fff7422016-08-11 15:37:45 -07001467 cancelCh <- true
Colin Cross8900e9b2015-03-02 14:03:01 -08001468 }
Colin Cross7addea32015-03-11 15:43:52 -07001469 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001470 }()
1471 }
1472
Colin Cross7addea32015-03-11 15:43:52 -07001473 for _, module := range c.modulesSorted {
1474 if module.waitingCount == 0 {
1475 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001476 }
1477 }
1478
Colin Cross11e3b0d2015-02-04 10:41:00 -08001479 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001480 select {
Colin Cross0fff7422016-08-11 15:37:45 -07001481 case cancel = <-cancelCh:
Colin Cross7addea32015-03-11 15:43:52 -07001482 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001483 if !cancel {
Colin Cross3702ac72016-08-11 11:09:00 -07001484 for _, module := range order.propagate(doneModule) {
1485 module.waitingCount--
1486 if module.waitingCount == 0 {
1487 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001488 }
Colin Cross691a60d2015-01-07 18:08:56 -08001489 }
1490 }
1491 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001492 }
1493 }
1494}
1495
1496// updateDependencies recursively walks the module dependency graph and updates
1497// additional fields based on the dependencies. It builds a sorted list of modules
1498// such that dependencies of a module always appear first, and populates reverse
1499// dependency links and counts of total dependencies. It also reports errors when
1500// it encounters dependency cycles. This should called after resolveDependencies,
1501// as well as after any mutator pass has called addDependency
1502func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001503 visited := make(map[*moduleInfo]bool) // modules that were already checked
1504 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001505
Colin Cross7addea32015-03-11 15:43:52 -07001506 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001507
Colin Cross7addea32015-03-11 15:43:52 -07001508 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001509
Colin Cross7addea32015-03-11 15:43:52 -07001510 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001511 // We are the "start" of the cycle, so we're responsible
1512 // for generating the errors. The cycle list is in
1513 // reverse order because all the 'check' calls append
1514 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001515 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001516 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001517 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001518 })
1519
1520 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001521 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001522 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001523 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001524 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001525 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001526 curModule.Name(),
1527 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001528 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001529 })
Colin Cross7addea32015-03-11 15:43:52 -07001530 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001531 }
1532 }
1533
Colin Cross7addea32015-03-11 15:43:52 -07001534 check = func(module *moduleInfo) []*moduleInfo {
1535 visited[module] = true
1536 checking[module] = true
1537 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001538
Colin Cross7addea32015-03-11 15:43:52 -07001539 deps := make(map[*moduleInfo]bool)
1540
1541 // Add an implicit dependency ordering on all earlier modules in the same module group
1542 for _, dep := range module.group.modules {
1543 if dep == module {
1544 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001545 }
Colin Cross7addea32015-03-11 15:43:52 -07001546 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001547 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001548
Colin Cross7addea32015-03-11 15:43:52 -07001549 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001550 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001551 }
1552
1553 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001554 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001555
Colin Crossbbfa51a2014-12-17 16:12:41 -08001556 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001557 if checking[dep] {
1558 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001559 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001560 }
1561
1562 if !visited[dep] {
1563 cycle := check(dep)
1564 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001565 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001566 // We are the "start" of the cycle, so we're responsible
1567 // for generating the errors. The cycle list is in
1568 // reverse order because all the 'check' calls append
1569 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001570 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001571
1572 // We can continue processing this module's children to
1573 // find more cycles. Since all the modules that were
1574 // part of the found cycle were marked as visited we
1575 // won't run into that cycle again.
1576 } else {
1577 // We're not the "start" of the cycle, so we just append
1578 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001579 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001580 }
1581 }
1582 }
Colin Cross691a60d2015-01-07 18:08:56 -08001583
Colin Cross3702ac72016-08-11 11:09:00 -07001584 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001585 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001586 }
1587
Colin Cross7addea32015-03-11 15:43:52 -07001588 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001589
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001590 return nil
1591 }
1592
Colin Cross7addea32015-03-11 15:43:52 -07001593 for _, module := range c.moduleInfo {
1594 if !visited[module] {
1595 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001596 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001597 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001598 panic("inconceivable!")
1599 }
1600 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001601 }
1602 }
1603 }
1604
Colin Cross7addea32015-03-11 15:43:52 -07001605 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001606
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001607 return
1608}
1609
Jamie Gennisd4e10182014-06-12 20:06:50 -07001610// PrepareBuildActions generates an internal representation of all the build
1611// actions that need to be performed. This process involves invoking the
1612// GenerateBuildActions method on each of the Module objects created during the
1613// parse phase and then on each of the registered Singleton objects.
1614//
1615// If the ResolveDependencies method has not already been called it is called
1616// automatically by this method.
1617//
1618// The config argument is made available to all of the Module and Singleton
1619// objects via the Config method on the ModuleContext and SingletonContext
1620// objects passed to GenerateBuildActions. It is also passed to the functions
1621// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1622// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001623//
1624// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001625// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1626// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1627// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001628func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001629 c.buildActionsReady = false
1630
1631 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001632 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001633 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001634 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635 }
1636 }
1637
1638 liveGlobals := newLiveTracker(config)
1639
1640 c.initSpecialVariables()
1641
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001642 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001643 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001644 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001645 }
1646
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001647 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001648 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001649 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001650 }
1651
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001652 deps = append(depsModules, depsSingletons...)
1653
Colin Crossa2599452015-11-18 16:01:01 -08001654 if c.ninjaBuildDir != nil {
1655 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001656 }
1657
Dan Willemsena481ae22015-12-18 15:18:03 -08001658 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1659
1660 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001661
1662 // This will panic if it finds a problem since it's a programming error.
1663 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1664
1665 c.pkgNames = pkgNames
1666 c.globalVariables = liveGlobals.variables
1667 c.globalPools = liveGlobals.pools
1668 c.globalRules = liveGlobals.rules
1669
1670 c.buildActionsReady = true
1671
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001672 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001673}
1674
Colin Crossc9028482014-12-18 16:28:54 -08001675func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001676 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001677
Colin Crossf8b50422016-08-10 12:56:40 -07001678 mutators = append(mutators, c.earlyMutatorInfo...)
1679 mutators = append(mutators, c.mutatorInfo...)
1680
1681 for _, mutator := range mutators {
Colin Crossc9028482014-12-18 16:28:54 -08001682 if mutator.topDownMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001683 errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001684 } else if mutator.bottomUpMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001685 errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001686 } else {
1687 panic("no mutator set on " + mutator.name)
1688 }
1689 if len(errs) > 0 {
1690 return errs
1691 }
1692 }
1693
1694 return nil
1695}
1696
Colin Cross3702ac72016-08-11 11:09:00 -07001697type mutatorDirection interface {
1698 run(mutator *mutatorInfo, ctx *mutatorContext)
1699 orderer() visitOrderer
1700 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001701}
1702
Colin Cross3702ac72016-08-11 11:09:00 -07001703type bottomUpMutatorImpl struct{}
1704
1705func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1706 mutator.bottomUpMutator(ctx)
1707}
1708
1709func (bottomUpMutatorImpl) orderer() visitOrderer {
1710 return bottomUpVisitor
1711}
1712
1713func (bottomUpMutatorImpl) String() string {
1714 return "bottom up mutator"
1715}
1716
1717type topDownMutatorImpl struct{}
1718
1719func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1720 mutator.topDownMutator(ctx)
1721}
1722
1723func (topDownMutatorImpl) orderer() visitOrderer {
1724 return topDownVisitor
1725}
1726
1727func (topDownMutatorImpl) String() string {
1728 return "top down mutator"
1729}
1730
1731var (
1732 topDownMutator topDownMutatorImpl
1733 bottomUpMutator bottomUpMutatorImpl
1734)
1735
Colin Cross49c279a2016-08-05 22:30:44 -07001736type reverseDep struct {
1737 module *moduleInfo
1738 dep depInfo
1739}
1740
Colin Cross3702ac72016-08-11 11:09:00 -07001741func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
1742 direction mutatorDirection) (errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001743
1744 newModuleInfo := make(map[Module]*moduleInfo)
1745 for k, v := range c.moduleInfo {
1746 newModuleInfo[k] = v
1747 }
Colin Crossc9028482014-12-18 16:28:54 -08001748
Colin Cross2c1f3d12016-04-11 15:47:28 -07001749 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross8d8a7af2015-11-03 16:41:29 -08001750
Colin Cross49c279a2016-08-05 22:30:44 -07001751 errsCh := make(chan []error)
1752 reverseDepsCh := make(chan []reverseDep)
1753 newModulesCh := make(chan []*moduleInfo)
1754 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001755
Colin Cross3702ac72016-08-11 11:09:00 -07001756 c.depsModified = 0
Colin Crossc4e5b812016-10-12 10:45:05 -07001757 c.renames = nil
Colin Cross9cfd1982016-10-11 09:58:53 -07001758 c.replacements = nil
Colin Cross3702ac72016-08-11 11:09:00 -07001759
Colin Cross49c279a2016-08-05 22:30:44 -07001760 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001761 if module.splitModules != nil {
1762 panic("split module found in sorted module list")
1763 }
1764
Colin Cross7addea32015-03-11 15:43:52 -07001765 mctx := &mutatorContext{
1766 baseModuleContext: baseModuleContext{
1767 context: c,
1768 config: config,
1769 module: module,
1770 },
Colin Cross49c279a2016-08-05 22:30:44 -07001771 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001772 }
Colin Crossc9028482014-12-18 16:28:54 -08001773
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001774 func() {
1775 defer func() {
1776 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001777 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001778 if err, ok := r.(panicError); ok {
1779 err.addIn(in)
1780 mctx.error(err)
1781 } else {
1782 mctx.error(newPanicErrorf(r, in))
1783 }
1784 }
1785 }()
Colin Cross3702ac72016-08-11 11:09:00 -07001786 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001787 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001788
Colin Cross7addea32015-03-11 15:43:52 -07001789 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07001790 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07001791 return true
Colin Cross7addea32015-03-11 15:43:52 -07001792 }
Colin Crossc9028482014-12-18 16:28:54 -08001793
Colin Cross49c279a2016-08-05 22:30:44 -07001794 if len(mctx.newModules) > 0 {
1795 newModulesCh <- mctx.newModules
1796 }
1797
1798 if len(mctx.reverseDeps) > 0 {
1799 reverseDepsCh <- mctx.reverseDeps
1800 }
1801
1802 return false
1803 }
1804
1805 // Process errs and reverseDeps in a single goroutine
1806 go func() {
1807 for {
1808 select {
1809 case newErrs := <-errsCh:
1810 errs = append(errs, newErrs...)
1811 case newReverseDeps := <-reverseDepsCh:
1812 for _, r := range newReverseDeps {
1813 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
1814 }
1815 case newModules := <-newModulesCh:
1816 for _, m := range newModules {
1817 newModuleInfo[m.logicModule] = m
1818 }
1819 case <-done:
1820 return
Colin Crossc9028482014-12-18 16:28:54 -08001821 }
1822 }
Colin Cross49c279a2016-08-05 22:30:44 -07001823 }()
Colin Crossc9028482014-12-18 16:28:54 -08001824
Colin Cross49c279a2016-08-05 22:30:44 -07001825 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07001826 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001827 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07001828 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001829 }
1830
1831 done <- true
1832
1833 if len(errs) > 0 {
1834 return errs
1835 }
1836
1837 c.moduleInfo = newModuleInfo
1838
1839 for _, group := range c.moduleGroups {
1840 for i := 0; i < len(group.modules); i++ {
1841 module := group.modules[i]
1842
1843 // Update module group to contain newly split variants
1844 if module.splitModules != nil {
1845 group.modules, i = spliceModules(group.modules, i, module.splitModules)
1846 }
1847
1848 // Fix up any remaining dependencies on modules that were split into variants
1849 // by replacing them with the first variant
1850 for j, dep := range module.directDeps {
1851 if dep.module.logicModule == nil {
1852 module.directDeps[j].module = dep.module.splitModules[0]
1853 }
1854 }
Colin Cross7addea32015-03-11 15:43:52 -07001855 }
Colin Crossc9028482014-12-18 16:28:54 -08001856 }
1857
Colin Cross8d8a7af2015-11-03 16:41:29 -08001858 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001859 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001860 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07001861 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08001862 }
1863
Colin Cross9cfd1982016-10-11 09:58:53 -07001864 errs = c.handleRenamesAndReplacements()
Colin Crossc4e5b812016-10-12 10:45:05 -07001865 if len(errs) > 0 {
1866 return errs
1867 }
1868
Colin Cross3702ac72016-08-11 11:09:00 -07001869 if c.depsModified > 0 {
1870 errs = c.updateDependencies()
1871 if len(errs) > 0 {
1872 return errs
1873 }
Colin Crossc9028482014-12-18 16:28:54 -08001874 }
1875
1876 return errs
1877}
1878
Colin Cross910242b2016-04-11 15:41:52 -07001879// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1880// a mutator sets a non-property member variable on a module, which works until a later mutator
1881// creates variants of that module.
1882func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07001883 type update struct {
1884 orig Module
1885 clone *moduleInfo
1886 }
1887 ch := make(chan update, 100)
1888
Colin Cross910242b2016-04-11 15:41:52 -07001889 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07001890 go func(m *moduleInfo) {
1891 origLogicModule := m.logicModule
1892 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1893 ch <- update{origLogicModule, m}
1894 }(m)
1895 }
1896
1897 for i := 0; i < len(c.modulesSorted); i++ {
1898 update := <-ch
1899 delete(c.moduleInfo, update.orig)
1900 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07001901 }
1902}
1903
Colin Cross49c279a2016-08-05 22:30:44 -07001904// Removes modules[i] from the list and inserts newModules... where it was located, returning
1905// the new slice and the index of the last inserted element
1906func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07001907 spliceSize := len(newModules)
1908 newLen := len(modules) + spliceSize - 1
1909 var dest []*moduleInfo
1910 if cap(modules) >= len(modules)-1+len(newModules) {
1911 // We can fit the splice in the existing capacity, do everything in place
1912 dest = modules[:newLen]
1913 } else {
1914 dest = make([]*moduleInfo, newLen)
1915 copy(dest, modules[:i])
1916 }
1917
1918 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001919 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001920
1921 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001922 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001923
Colin Cross49c279a2016-08-05 22:30:44 -07001924 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07001925}
1926
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001928 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001929 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001930 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001931 c.requiredNinjaMicro = 0
1932}
1933
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001934func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001935 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001936
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001937 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001938 var errs []error
1939
Colin Cross691a60d2015-01-07 18:08:56 -08001940 cancelCh := make(chan struct{})
1941 errsCh := make(chan []error)
1942 depsCh := make(chan []string)
1943
1944 go func() {
1945 for {
1946 select {
1947 case <-cancelCh:
1948 close(cancelCh)
1949 return
1950 case newErrs := <-errsCh:
1951 errs = append(errs, newErrs...)
1952 case newDeps := <-depsCh:
1953 deps = append(deps, newDeps...)
1954
1955 }
1956 }
1957 }()
1958
Colin Cross3702ac72016-08-11 11:09:00 -07001959 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Colin Cross7addea32015-03-11 15:43:52 -07001960 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1961 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1962 // just set it to nil.
1963 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1964 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001965
Colin Cross7addea32015-03-11 15:43:52 -07001966 mctx := &moduleContext{
1967 baseModuleContext: baseModuleContext{
1968 context: c,
1969 config: config,
1970 module: module,
1971 },
Colin Cross036a1df2015-12-17 15:49:30 -08001972 scope: scope,
1973 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001974 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001975
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001976 func() {
1977 defer func() {
1978 if r := recover(); r != nil {
1979 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1980 if err, ok := r.(panicError); ok {
1981 err.addIn(in)
1982 mctx.error(err)
1983 } else {
1984 mctx.error(newPanicErrorf(r, in))
1985 }
1986 }
1987 }()
1988 mctx.module.logicModule.GenerateBuildActions(mctx)
1989 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001990
Colin Cross7addea32015-03-11 15:43:52 -07001991 if len(mctx.errs) > 0 {
1992 errsCh <- mctx.errs
1993 return true
1994 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001995
Colin Cross036a1df2015-12-17 15:49:30 -08001996 if module.missingDeps != nil && !mctx.handledMissingDeps {
1997 var errs []error
1998 for _, depName := range module.missingDeps {
Colin Cross2c628442016-10-07 17:13:10 -07001999 errs = append(errs, &BlueprintError{
Colin Cross036a1df2015-12-17 15:49:30 -08002000 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07002001 module.Name(), depName),
Colin Cross036a1df2015-12-17 15:49:30 -08002002 Pos: module.pos,
2003 })
2004 }
2005 errsCh <- errs
2006 return true
2007 }
2008
Colin Cross7addea32015-03-11 15:43:52 -07002009 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002010
Colin Crossab6d7902015-03-11 16:17:52 -07002011 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002012 &mctx.actionDefs, liveGlobals)
2013 if len(newErrs) > 0 {
2014 errsCh <- newErrs
2015 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002016 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002017 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002018 })
2019
2020 cancelCh <- struct{}{}
2021 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002022
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002023 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002024}
2025
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002026func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002027 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002028
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002029 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002030 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002031
Yuchen Wub9103ef2015-08-25 17:58:17 -07002032 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002033 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2034 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2035 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002036 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002037
2038 sctx := &singletonContext{
2039 context: c,
2040 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002041 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002042 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002043 }
2044
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002045 func() {
2046 defer func() {
2047 if r := recover(); r != nil {
2048 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2049 if err, ok := r.(panicError); ok {
2050 err.addIn(in)
2051 sctx.error(err)
2052 } else {
2053 sctx.error(newPanicErrorf(r, in))
2054 }
2055 }
2056 }()
2057 info.singleton.GenerateBuildActions(sctx)
2058 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002059
2060 if len(sctx.errs) > 0 {
2061 errs = append(errs, sctx.errs...)
2062 if len(errs) > maxErrors {
2063 break
2064 }
2065 continue
2066 }
2067
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002068 deps = append(deps, sctx.ninjaFileDeps...)
2069
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002070 newErrs := c.processLocalBuildActions(&info.actionDefs,
2071 &sctx.actionDefs, liveGlobals)
2072 errs = append(errs, newErrs...)
2073 if len(errs) > maxErrors {
2074 break
2075 }
2076 }
2077
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002078 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002079}
2080
2081func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2082 liveGlobals *liveTracker) []error {
2083
2084 var errs []error
2085
2086 // First we go through and add everything referenced by the module's
2087 // buildDefs to the live globals set. This will end up adding the live
2088 // locals to the set as well, but we'll take them out after.
2089 for _, def := range in.buildDefs {
2090 err := liveGlobals.AddBuildDefDeps(def)
2091 if err != nil {
2092 errs = append(errs, err)
2093 }
2094 }
2095
2096 if len(errs) > 0 {
2097 return errs
2098 }
2099
Colin Crossc9028482014-12-18 16:28:54 -08002100 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002101
2102 // We use the now-incorrect set of live "globals" to determine which local
2103 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002104 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002105 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002106 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002107 if isLive {
2108 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002109 }
2110 }
2111
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002112 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002113 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002114 if isLive {
2115 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002116 }
2117 }
2118
2119 return nil
2120}
2121
Yuchen Wu222e2452015-10-06 14:03:27 -07002122func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002123 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002124
2125 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002126 var visiting *moduleInfo
2127
2128 defer func() {
2129 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002130 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2131 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002132 }
2133 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002134
2135 var walk func(module *moduleInfo)
2136 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002137 for _, dep := range module.directDeps {
2138 if !visited[dep.module] {
2139 visited[dep.module] = true
2140 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002141 recurse := true
2142 if visitDown != nil {
2143 recurse = visitDown(dep, module)
2144 }
2145 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002146 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002147 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002148 if visitUp != nil {
2149 visitUp(dep, module)
2150 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002151 }
2152 }
2153 }
2154
2155 walk(topModule)
2156}
2157
Colin Cross9cfd1982016-10-11 09:58:53 -07002158type replace struct {
2159 from, to *moduleInfo
2160}
2161
Colin Crossc4e5b812016-10-12 10:45:05 -07002162type rename struct {
2163 group *moduleGroup
2164 name string
2165}
2166
2167func (c *Context) rename(group *moduleGroup, name string) {
2168 c.renames = append(c.renames, rename{group, name})
2169}
2170
Colin Cross9cfd1982016-10-11 09:58:53 -07002171func (c *Context) replaceDependencies(module *moduleInfo, name string) {
2172 targets := c.modulesFromName(name)
2173
2174 if targets == nil {
2175 panic(fmt.Errorf("ReplaceDependencies called with non-existant name %q", name))
2176 }
2177
2178 var target *moduleInfo
2179 for _, m := range targets {
2180 if module.variantName == m.variantName {
2181 target = m
2182 break
2183 }
2184 }
2185
2186 if target == nil {
2187 panic(fmt.Errorf("ReplaceDependencies could not find identical variant %q for module %q",
2188 module.variantName, name))
2189 }
2190
2191 c.replacements = append(c.replacements, replace{target, module})
2192}
2193
2194func (c *Context) handleRenamesAndReplacements() []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002195 var errs []error
2196 for _, rename := range c.renames {
2197 group, name := rename.group, rename.name
2198 if name == group.name {
2199 continue
2200 }
2201
2202 existing := c.moduleNames[name]
2203 if existing != nil {
2204 errs = append(errs,
2205 &BlueprintError{
2206 Err: fmt.Errorf("renaming module %q to %q conflicts with existing module",
2207 group.name, name),
2208 Pos: group.modules[0].pos,
2209 },
2210 &BlueprintError{
2211 Err: fmt.Errorf("<-- existing module defined here"),
2212 Pos: existing.modules[0].pos,
2213 },
2214 )
2215 continue
2216 }
2217
2218 c.moduleNames[name] = group
2219 delete(c.moduleNames, group.name)
2220 group.name = name
2221 }
2222
Colin Cross9cfd1982016-10-11 09:58:53 -07002223 for _, replace := range c.replacements {
2224 for _, m := range replace.from.reverseDeps {
2225 for i, d := range m.directDeps {
2226 if d.module == replace.from {
2227 m.directDeps[i].module = replace.to
2228 }
2229 }
2230 }
2231
2232 atomic.AddUint32(&c.depsModified, 1)
2233 }
Colin Crossc4e5b812016-10-12 10:45:05 -07002234 return errs
2235}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002236
Colin Cross0b7e83e2016-05-17 14:58:05 -07002237func (c *Context) modulesFromName(name string) []*moduleInfo {
2238 if group := c.moduleNames[name]; group != nil {
2239 return group.modules
2240 }
2241 return nil
2242}
2243
Jamie Gennisc15544d2014-09-24 20:26:52 -07002244func (c *Context) sortedModuleNames() []string {
2245 if c.cachedSortedModuleNames == nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002246 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleNames))
2247 for moduleName := range c.moduleNames {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002248 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2249 moduleName)
2250 }
2251 sort.Strings(c.cachedSortedModuleNames)
2252 }
2253
2254 return c.cachedSortedModuleNames
2255}
2256
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002257func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002258 var module *moduleInfo
2259
2260 defer func() {
2261 if r := recover(); r != nil {
2262 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2263 funcName(visit), module))
2264 }
2265 }()
2266
Jamie Gennisc15544d2014-09-24 20:26:52 -07002267 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002268 modules := c.modulesFromName(moduleName)
2269 for _, module = range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002270 visit(module.logicModule)
2271 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002272 }
2273}
2274
2275func (c *Context) visitAllModulesIf(pred func(Module) bool,
2276 visit func(Module)) {
2277
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002278 var module *moduleInfo
2279
2280 defer func() {
2281 if r := recover(); r != nil {
2282 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2283 funcName(pred), funcName(visit), module))
2284 }
2285 }()
2286
Jamie Gennisc15544d2014-09-24 20:26:52 -07002287 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002288 modules := c.modulesFromName(moduleName)
2289 for _, module := range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002290 if pred(module.logicModule) {
2291 visit(module.logicModule)
2292 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002293 }
2294 }
2295}
2296
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002297func (c *Context) visitAllModuleVariants(module *moduleInfo,
2298 visit func(Module)) {
2299
2300 var variant *moduleInfo
2301
2302 defer func() {
2303 if r := recover(); r != nil {
2304 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2305 module, funcName(visit), variant))
2306 }
2307 }()
2308
2309 for _, variant = range module.group.modules {
2310 visit(variant.logicModule)
2311 }
2312}
2313
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002314func (c *Context) requireNinjaVersion(major, minor, micro int) {
2315 if major != 1 {
2316 panic("ninja version with major version != 1 not supported")
2317 }
2318 if c.requiredNinjaMinor < minor {
2319 c.requiredNinjaMinor = minor
2320 c.requiredNinjaMicro = micro
2321 }
2322 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2323 c.requiredNinjaMicro = micro
2324 }
2325}
2326
Colin Crossa2599452015-11-18 16:01:01 -08002327func (c *Context) setNinjaBuildDir(value *ninjaString) {
2328 if c.ninjaBuildDir == nil {
2329 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002330 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002331}
2332
2333func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002334 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002335
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002336 pkgs := make(map[string]*packageContext)
2337 pkgNames := make(map[*packageContext]string)
2338 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002339
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002340 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002341 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002342 // This is a built-in rule and has no package.
2343 return
2344 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002345 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002346 // We've already processed this package.
2347 return
2348 }
2349
Jamie Gennis2fb20952014-10-03 02:49:58 -07002350 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002351 if present {
2352 // Short name collision. Both this package and the one that's
2353 // already there need to use their full names. We leave the short
2354 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002355 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002356 longPkgNames[otherPkg] = true
2357 } else {
2358 // No collision so far. Tentatively set the package's name to be
2359 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002360 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002361 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002362 }
2363 }
2364
2365 // We try to give all packages their short name, but when we get collisions
2366 // we need to use the full unique package name.
2367 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002368 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002369 }
2370 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002371 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002372 }
2373 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002374 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002375 }
2376
2377 // Add the packages that had collisions using their full unique names. This
2378 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002379 for pctx := range longPkgNames {
2380 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002381 }
2382
Dan Willemsena481ae22015-12-18 15:18:03 -08002383 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2384 deps := []string{}
2385 for _, pkg := range pkgs {
2386 deps = append(deps, pkg.ninjaFileDeps...)
2387 }
2388
2389 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002390}
2391
2392func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002393 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002394
2395 visited := make(map[Variable]bool) // variables that were already checked
2396 checking := make(map[Variable]bool) // variables actively being checked
2397
2398 var check func(v Variable) []Variable
2399
2400 check = func(v Variable) []Variable {
2401 visited[v] = true
2402 checking[v] = true
2403 defer delete(checking, v)
2404
2405 value := variables[v]
2406 for _, dep := range value.variables {
2407 if checking[dep] {
2408 // This is a cycle.
2409 return []Variable{dep, v}
2410 }
2411
2412 if !visited[dep] {
2413 cycle := check(dep)
2414 if cycle != nil {
2415 if cycle[0] == v {
2416 // We are the "start" of the cycle, so we're responsible
2417 // for generating the errors. The cycle list is in
2418 // reverse order because all the 'check' calls append
2419 // their own module to the list.
2420 msgs := []string{"detected variable reference cycle:"}
2421
2422 // Iterate backwards through the cycle list.
2423 curName := v.fullName(pkgNames)
2424 curValue := value.Value(pkgNames)
2425 for i := len(cycle) - 1; i >= 0; i-- {
2426 next := cycle[i]
2427 nextName := next.fullName(pkgNames)
2428 nextValue := variables[next].Value(pkgNames)
2429
2430 msgs = append(msgs, fmt.Sprintf(
2431 " %q depends on %q", curName, nextName))
2432 msgs = append(msgs, fmt.Sprintf(
2433 " [%s = %s]", curName, curValue))
2434
2435 curName = nextName
2436 curValue = nextValue
2437 }
2438
2439 // Variable reference cycles are a programming error,
2440 // not the fault of the Blueprint file authors.
2441 panic(strings.Join(msgs, "\n"))
2442 } else {
2443 // We're not the "start" of the cycle, so we just append
2444 // our module to the list and return it.
2445 return append(cycle, v)
2446 }
2447 }
2448 }
2449 }
2450
2451 return nil
2452 }
2453
2454 for v := range variables {
2455 if !visited[v] {
2456 cycle := check(v)
2457 if cycle != nil {
2458 panic("inconceivable!")
2459 }
2460 }
2461 }
2462}
2463
Jamie Gennisaf435562014-10-27 22:34:56 -07002464// AllTargets returns a map all the build target names to the rule used to build
2465// them. This is the same information that is output by running 'ninja -t
2466// targets all'. If this is called before PrepareBuildActions successfully
2467// completes then ErrbuildActionsNotReady is returned.
2468func (c *Context) AllTargets() (map[string]string, error) {
2469 if !c.buildActionsReady {
2470 return nil, ErrBuildActionsNotReady
2471 }
2472
2473 targets := map[string]string{}
2474
2475 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002476 for _, module := range c.moduleInfo {
2477 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002478 ruleName := buildDef.Rule.fullName(c.pkgNames)
2479 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002480 outputValue, err := output.Eval(c.globalVariables)
2481 if err != nil {
2482 return nil, err
2483 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002484 targets[outputValue] = ruleName
2485 }
2486 }
2487 }
2488
2489 // Collect all the singleton build targets.
2490 for _, info := range c.singletonInfo {
2491 for _, buildDef := range info.actionDefs.buildDefs {
2492 ruleName := buildDef.Rule.fullName(c.pkgNames)
2493 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002494 outputValue, err := output.Eval(c.globalVariables)
2495 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002496 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002497 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002498 targets[outputValue] = ruleName
2499 }
2500 }
2501 }
2502
2503 return targets, nil
2504}
2505
Colin Crossa2599452015-11-18 16:01:01 -08002506func (c *Context) NinjaBuildDir() (string, error) {
2507 if c.ninjaBuildDir != nil {
2508 return c.ninjaBuildDir.Eval(c.globalVariables)
2509 } else {
2510 return "", nil
2511 }
2512}
2513
Colin Cross4572edd2015-05-13 14:36:24 -07002514// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2515// property structs returned by the factory for that module type.
2516func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2517 ret := make(map[string][]interface{})
2518 for moduleType, factory := range c.moduleFactories {
2519 _, ret[moduleType] = factory()
2520 }
2521
2522 return ret
2523}
2524
2525func (c *Context) ModuleName(logicModule Module) string {
2526 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002527 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002528}
2529
2530func (c *Context) ModuleDir(logicModule Module) string {
2531 module := c.moduleInfo[logicModule]
2532 return filepath.Dir(module.relBlueprintsFile)
2533}
2534
Colin Cross8c602f72015-12-17 18:02:11 -08002535func (c *Context) ModuleSubDir(logicModule Module) string {
2536 module := c.moduleInfo[logicModule]
2537 return module.variantName
2538}
2539
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002540func (c *Context) ModuleType(logicModule Module) string {
2541 module := c.moduleInfo[logicModule]
2542 return module.typeName
2543}
2544
Colin Cross4572edd2015-05-13 14:36:24 -07002545func (c *Context) BlueprintFile(logicModule Module) string {
2546 module := c.moduleInfo[logicModule]
2547 return module.relBlueprintsFile
2548}
2549
2550func (c *Context) ModuleErrorf(logicModule Module, format string,
2551 args ...interface{}) error {
2552
2553 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002554 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002555 Err: fmt.Errorf(format, args...),
2556 Pos: module.pos,
2557 }
2558}
2559
2560func (c *Context) VisitAllModules(visit func(Module)) {
2561 c.visitAllModules(visit)
2562}
2563
2564func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2565 visit func(Module)) {
2566
2567 c.visitAllModulesIf(pred, visit)
2568}
2569
2570func (c *Context) VisitDepsDepthFirst(module Module,
2571 visit func(Module)) {
2572
Colin Crossbafd5f52016-08-06 22:52:01 -07002573 topModule := c.moduleInfo[module]
2574
2575 var visiting *moduleInfo
2576
2577 defer func() {
2578 if r := recover(); r != nil {
2579 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2580 topModule, funcName(visit), visiting))
2581 }
2582 }()
2583
2584 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2585 visiting = dep.module
2586 visit(dep.module.logicModule)
2587 })
Colin Cross4572edd2015-05-13 14:36:24 -07002588}
2589
2590func (c *Context) VisitDepsDepthFirstIf(module Module,
2591 pred func(Module) bool, visit func(Module)) {
2592
Colin Crossbafd5f52016-08-06 22:52:01 -07002593 topModule := c.moduleInfo[module]
2594
2595 var visiting *moduleInfo
2596
2597 defer func() {
2598 if r := recover(); r != nil {
2599 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2600 topModule, funcName(pred), funcName(visit), visiting))
2601 }
2602 }()
2603
2604 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2605 if pred(dep.module.logicModule) {
2606 visiting = dep.module
2607 visit(dep.module.logicModule)
2608 }
2609 })
Colin Cross4572edd2015-05-13 14:36:24 -07002610}
2611
Colin Cross24ad5872015-11-17 16:22:29 -08002612func (c *Context) PrimaryModule(module Module) Module {
2613 return c.moduleInfo[module].group.modules[0].logicModule
2614}
2615
2616func (c *Context) FinalModule(module Module) Module {
2617 modules := c.moduleInfo[module].group.modules
2618 return modules[len(modules)-1].logicModule
2619}
2620
2621func (c *Context) VisitAllModuleVariants(module Module,
2622 visit func(Module)) {
2623
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002624 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002625}
2626
Jamie Gennisd4e10182014-06-12 20:06:50 -07002627// WriteBuildFile writes the Ninja manifeset text for the generated build
2628// actions to w. If this is called before PrepareBuildActions successfully
2629// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002630func (c *Context) WriteBuildFile(w io.Writer) error {
2631 if !c.buildActionsReady {
2632 return ErrBuildActionsNotReady
2633 }
2634
2635 nw := newNinjaWriter(w)
2636
2637 err := c.writeBuildFileHeader(nw)
2638 if err != nil {
2639 return err
2640 }
2641
2642 err = c.writeNinjaRequiredVersion(nw)
2643 if err != nil {
2644 return err
2645 }
2646
2647 // TODO: Group the globals by package.
2648
2649 err = c.writeGlobalVariables(nw)
2650 if err != nil {
2651 return err
2652 }
2653
2654 err = c.writeGlobalPools(nw)
2655 if err != nil {
2656 return err
2657 }
2658
2659 err = c.writeBuildDir(nw)
2660 if err != nil {
2661 return err
2662 }
2663
2664 err = c.writeGlobalRules(nw)
2665 if err != nil {
2666 return err
2667 }
2668
2669 err = c.writeAllModuleActions(nw)
2670 if err != nil {
2671 return err
2672 }
2673
2674 err = c.writeAllSingletonActions(nw)
2675 if err != nil {
2676 return err
2677 }
2678
2679 return nil
2680}
2681
Jamie Gennisc15544d2014-09-24 20:26:52 -07002682type pkgAssociation struct {
2683 PkgName string
2684 PkgPath string
2685}
2686
2687type pkgAssociationSorter struct {
2688 pkgs []pkgAssociation
2689}
2690
2691func (s *pkgAssociationSorter) Len() int {
2692 return len(s.pkgs)
2693}
2694
2695func (s *pkgAssociationSorter) Less(i, j int) bool {
2696 iName := s.pkgs[i].PkgName
2697 jName := s.pkgs[j].PkgName
2698 return iName < jName
2699}
2700
2701func (s *pkgAssociationSorter) Swap(i, j int) {
2702 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2703}
2704
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002705func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2706 headerTemplate := template.New("fileHeader")
2707 _, err := headerTemplate.Parse(fileHeaderTemplate)
2708 if err != nil {
2709 // This is a programming error.
2710 panic(err)
2711 }
2712
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002713 var pkgs []pkgAssociation
2714 maxNameLen := 0
2715 for pkg, name := range c.pkgNames {
2716 pkgs = append(pkgs, pkgAssociation{
2717 PkgName: name,
2718 PkgPath: pkg.pkgPath,
2719 })
2720 if len(name) > maxNameLen {
2721 maxNameLen = len(name)
2722 }
2723 }
2724
2725 for i := range pkgs {
2726 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2727 }
2728
Jamie Gennisc15544d2014-09-24 20:26:52 -07002729 sort.Sort(&pkgAssociationSorter{pkgs})
2730
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002731 params := map[string]interface{}{
2732 "Pkgs": pkgs,
2733 }
2734
2735 buf := bytes.NewBuffer(nil)
2736 err = headerTemplate.Execute(buf, params)
2737 if err != nil {
2738 return err
2739 }
2740
2741 return nw.Comment(buf.String())
2742}
2743
2744func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2745 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2746 c.requiredNinjaMicro)
2747
2748 err := nw.Assign("ninja_required_version", value)
2749 if err != nil {
2750 return err
2751 }
2752
2753 return nw.BlankLine()
2754}
2755
2756func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002757 if c.ninjaBuildDir != nil {
2758 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002759 if err != nil {
2760 return err
2761 }
2762
2763 err = nw.BlankLine()
2764 if err != nil {
2765 return err
2766 }
2767 }
2768 return nil
2769}
2770
Jamie Gennisc15544d2014-09-24 20:26:52 -07002771type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002772 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002773}
2774
Jamie Gennisc15544d2014-09-24 20:26:52 -07002775type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002776 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002777 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002778}
2779
Jamie Gennisc15544d2014-09-24 20:26:52 -07002780func (s *globalEntitySorter) Len() int {
2781 return len(s.entities)
2782}
2783
2784func (s *globalEntitySorter) Less(i, j int) bool {
2785 iName := s.entities[i].fullName(s.pkgNames)
2786 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002787 return iName < jName
2788}
2789
Jamie Gennisc15544d2014-09-24 20:26:52 -07002790func (s *globalEntitySorter) Swap(i, j int) {
2791 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002792}
2793
2794func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2795 visited := make(map[Variable]bool)
2796
2797 var walk func(v Variable) error
2798 walk = func(v Variable) error {
2799 visited[v] = true
2800
2801 // First visit variables on which this variable depends.
2802 value := c.globalVariables[v]
2803 for _, dep := range value.variables {
2804 if !visited[dep] {
2805 err := walk(dep)
2806 if err != nil {
2807 return err
2808 }
2809 }
2810 }
2811
2812 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2813 if err != nil {
2814 return err
2815 }
2816
2817 err = nw.BlankLine()
2818 if err != nil {
2819 return err
2820 }
2821
2822 return nil
2823 }
2824
Jamie Gennisc15544d2014-09-24 20:26:52 -07002825 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2826 for variable := range c.globalVariables {
2827 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002828 }
2829
Jamie Gennisc15544d2014-09-24 20:26:52 -07002830 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002831
Jamie Gennisc15544d2014-09-24 20:26:52 -07002832 for _, entity := range globalVariables {
2833 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002834 if !visited[v] {
2835 err := walk(v)
2836 if err != nil {
2837 return nil
2838 }
2839 }
2840 }
2841
2842 return nil
2843}
2844
2845func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002846 globalPools := make([]globalEntity, 0, len(c.globalPools))
2847 for pool := range c.globalPools {
2848 globalPools = append(globalPools, pool)
2849 }
2850
2851 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2852
2853 for _, entity := range globalPools {
2854 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002855 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002856 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002857 err := def.WriteTo(nw, name)
2858 if err != nil {
2859 return err
2860 }
2861
2862 err = nw.BlankLine()
2863 if err != nil {
2864 return err
2865 }
2866 }
2867
2868 return nil
2869}
2870
2871func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002872 globalRules := make([]globalEntity, 0, len(c.globalRules))
2873 for rule := range c.globalRules {
2874 globalRules = append(globalRules, rule)
2875 }
2876
2877 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2878
2879 for _, entity := range globalRules {
2880 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002881 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002882 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002883 err := def.WriteTo(nw, name, c.pkgNames)
2884 if err != nil {
2885 return err
2886 }
2887
2888 err = nw.BlankLine()
2889 if err != nil {
2890 return err
2891 }
2892 }
2893
2894 return nil
2895}
2896
Colin Cross2c1f3d12016-04-11 15:47:28 -07002897type depSorter []depInfo
2898
2899func (s depSorter) Len() int {
2900 return len(s)
2901}
2902
2903func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002904 iName := s[i].module.Name()
2905 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07002906 if iName == jName {
2907 iName = s[i].module.variantName
2908 jName = s[j].module.variantName
2909 }
2910 return iName < jName
2911}
2912
2913func (s depSorter) Swap(i, j int) {
2914 s[i], s[j] = s[j], s[i]
2915}
2916
Colin Crossab6d7902015-03-11 16:17:52 -07002917type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002918
Colin Crossab6d7902015-03-11 16:17:52 -07002919func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002920 return len(s)
2921}
2922
Colin Crossab6d7902015-03-11 16:17:52 -07002923func (s moduleSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002924 iName := s[i].Name()
2925 jName := s[j].Name()
Colin Crossab6d7902015-03-11 16:17:52 -07002926 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002927 iName = s[i].variantName
2928 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002929 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002930 return iName < jName
2931}
2932
Colin Crossab6d7902015-03-11 16:17:52 -07002933func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002934 s[i], s[j] = s[j], s[i]
2935}
2936
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002937func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2938 headerTemplate := template.New("moduleHeader")
2939 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2940 if err != nil {
2941 // This is a programming error.
2942 panic(err)
2943 }
2944
Colin Crossab6d7902015-03-11 16:17:52 -07002945 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2946 for _, module := range c.moduleInfo {
2947 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002948 }
Colin Crossab6d7902015-03-11 16:17:52 -07002949 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002950
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002951 buf := bytes.NewBuffer(nil)
2952
Colin Crossab6d7902015-03-11 16:17:52 -07002953 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002954 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2955 continue
2956 }
2957
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002958 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002959
2960 // In order to make the bootstrap build manifest independent of the
2961 // build dir we need to output the Blueprints file locations in the
2962 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002963 relPos := module.pos
2964 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002965
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002966 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002967 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002968 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2969 factoryName := factoryFunc.Name()
2970
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002971 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07002972 "name": module.Name(),
2973 "typeName": module.typeName,
2974 "goFactory": factoryName,
2975 "pos": relPos,
2976 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002977 }
2978 err = headerTemplate.Execute(buf, infoMap)
2979 if err != nil {
2980 return err
2981 }
2982
2983 err = nw.Comment(buf.String())
2984 if err != nil {
2985 return err
2986 }
2987
2988 err = nw.BlankLine()
2989 if err != nil {
2990 return err
2991 }
2992
Colin Crossab6d7902015-03-11 16:17:52 -07002993 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002994 if err != nil {
2995 return err
2996 }
2997
2998 err = nw.BlankLine()
2999 if err != nil {
3000 return err
3001 }
3002 }
3003
3004 return nil
3005}
3006
3007func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3008 headerTemplate := template.New("singletonHeader")
3009 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3010 if err != nil {
3011 // This is a programming error.
3012 panic(err)
3013 }
3014
3015 buf := bytes.NewBuffer(nil)
3016
Yuchen Wub9103ef2015-08-25 17:58:17 -07003017 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003018 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3019 continue
3020 }
3021
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003022 // Get the name of the factory function for the module.
3023 factory := info.factory
3024 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3025 factoryName := factoryFunc.Name()
3026
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003027 buf.Reset()
3028 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003029 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003030 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003031 }
3032 err = headerTemplate.Execute(buf, infoMap)
3033 if err != nil {
3034 return err
3035 }
3036
3037 err = nw.Comment(buf.String())
3038 if err != nil {
3039 return err
3040 }
3041
3042 err = nw.BlankLine()
3043 if err != nil {
3044 return err
3045 }
3046
3047 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3048 if err != nil {
3049 return err
3050 }
3051
3052 err = nw.BlankLine()
3053 if err != nil {
3054 return err
3055 }
3056 }
3057
3058 return nil
3059}
3060
3061func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3062 defs *localBuildActions) error {
3063
3064 // Write the local variable assignments.
3065 for _, v := range defs.variables {
3066 // A localVariable doesn't need the package names or config to
3067 // determine its name or value.
3068 name := v.fullName(nil)
3069 value, err := v.value(nil)
3070 if err != nil {
3071 panic(err)
3072 }
3073 err = nw.Assign(name, value.Value(c.pkgNames))
3074 if err != nil {
3075 return err
3076 }
3077 }
3078
3079 if len(defs.variables) > 0 {
3080 err := nw.BlankLine()
3081 if err != nil {
3082 return err
3083 }
3084 }
3085
3086 // Write the local rules.
3087 for _, r := range defs.rules {
3088 // A localRule doesn't need the package names or config to determine
3089 // its name or definition.
3090 name := r.fullName(nil)
3091 def, err := r.def(nil)
3092 if err != nil {
3093 panic(err)
3094 }
3095
3096 err = def.WriteTo(nw, name, c.pkgNames)
3097 if err != nil {
3098 return err
3099 }
3100
3101 err = nw.BlankLine()
3102 if err != nil {
3103 return err
3104 }
3105 }
3106
3107 // Write the build definitions.
3108 for _, buildDef := range defs.buildDefs {
3109 err := buildDef.WriteTo(nw, c.pkgNames)
3110 if err != nil {
3111 return err
3112 }
3113
3114 if len(buildDef.Args) > 0 {
3115 err = nw.BlankLine()
3116 if err != nil {
3117 return err
3118 }
3119 }
3120 }
3121
3122 return nil
3123}
3124
Colin Cross65569e42015-03-10 20:08:19 -07003125func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3126 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003127 if a == b {
3128 return false
3129 }
Colin Cross65569e42015-03-10 20:08:19 -07003130 for _, l := range list {
3131 if l == a {
3132 found = true
3133 } else if l == b {
3134 return found
3135 }
3136 }
3137
3138 missing := a
3139 if found {
3140 missing = b
3141 }
3142 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3143}
3144
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003145type panicError struct {
3146 panic interface{}
3147 stack []byte
3148 in string
3149}
3150
3151func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3152 buf := make([]byte, 4096)
3153 count := runtime.Stack(buf, false)
3154 return panicError{
3155 panic: panic,
3156 in: fmt.Sprintf(in, a...),
3157 stack: buf[:count],
3158 }
3159}
3160
3161func (p panicError) Error() string {
3162 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3163}
3164
3165func (p *panicError) addIn(in string) {
3166 p.in += " in " + in
3167}
3168
3169func funcName(f interface{}) string {
3170 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3171}
3172
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003173var fileHeaderTemplate = `******************************************************************************
3174*** This file is generated and should not be edited ***
3175******************************************************************************
3176{{if .Pkgs}}
3177This file contains variables, rules, and pools with name prefixes indicating
3178they were generated by the following Go packages:
3179{{range .Pkgs}}
3180 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3181
3182`
3183
3184var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003185Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003186Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003187Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003188Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003189Defined: {{.pos}}
3190`
3191
3192var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3193Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003194Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003195`