blob: e38d1ec33ace7117956134c735d809c7ca3e7c44 [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 Crossc4e5b812016-10-12 10:45:05 -0700104 renames []rename // List of pending renames to apply after the mutator pass
105
Colin Crossd7b0f602016-06-02 15:30:20 -0700106 fs fileSystem
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700107}
108
Jamie Gennisd4e10182014-06-12 20:06:50 -0700109// An Error describes a problem that was encountered that is related to a
110// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700111type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700112 Err error // the error that occurred
113 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700114}
115
Colin Cross2c628442016-10-07 17:13:10 -0700116// A ModuleError describes a problem that was encountered that is related to a
117// particular module in a Blueprints file
118type ModuleError struct {
119 BlueprintError
120 module *moduleInfo
121}
122
123// A PropertyError describes a problem that was encountered that is related to a
124// particular property in a Blueprints file
125type PropertyError struct {
126 ModuleError
127 property string
128}
129
130func (e *BlueprintError) Error() string {
131 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
132}
133
134func (e *ModuleError) Error() string {
135 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
136}
137
138func (e *PropertyError) Error() string {
139 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
140}
141
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700142type localBuildActions struct {
143 variables []*localVariable
144 rules []*localRule
145 buildDefs []*buildDef
146}
147
Colin Crossbbfa51a2014-12-17 16:12:41 -0800148type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700149 name string
150 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700151
Colin Crossbbfa51a2014-12-17 16:12:41 -0800152 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700153}
154
Colin Crossbbfa51a2014-12-17 16:12:41 -0800155type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700156 // set during Parse
157 typeName string
158 relBlueprintsFile string
159 pos scanner.Position
160 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700161
Colin Crossf5e34b92015-03-13 16:02:36 -0700162 variantName string
163 variant variationMap
164 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700165
Colin Crossc9028482014-12-18 16:28:54 -0800166 logicModule Module
167 group *moduleGroup
168 moduleProperties []interface{}
169
170 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700171 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800172 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800173
Colin Cross7addea32015-03-11 15:43:52 -0700174 // set during updateDependencies
175 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700176 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700177
178 // used by parallelVisitAllBottomUp
179 waitingCount int
180
Colin Crossc9028482014-12-18 16:28:54 -0800181 // set during each runMutator
182 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700183
184 // set during PrepareBuildActions
185 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800186}
187
Colin Cross2c1f3d12016-04-11 15:47:28 -0700188type depInfo struct {
189 module *moduleInfo
190 tag DependencyTag
191}
192
Colin Cross0b7e83e2016-05-17 14:58:05 -0700193func (module *moduleInfo) Name() string {
194 return module.group.name
195}
196
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800197func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700198 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800199 if module.variantName != "" {
200 s += fmt.Sprintf(" variant %q", module.variantName)
201 }
202 return s
203}
204
Colin Crossf5e34b92015-03-13 16:02:36 -0700205// A Variation is a way that a variant of a module differs from other variants of the same module.
206// For example, two variants of the same module might have Variation{"arch","arm"} and
207// Variation{"arch","arm64"}
208type Variation struct {
209 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700210 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700211 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
212 // "shared" or "static" for link.
213 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700214}
215
Colin Crossf5e34b92015-03-13 16:02:36 -0700216// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
217type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700218
Colin Crossf5e34b92015-03-13 16:02:36 -0700219func (vm variationMap) clone() variationMap {
220 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700221 for k, v := range vm {
222 newVm[k] = v
223 }
224
225 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800226}
227
Colin Cross89486232015-05-08 11:14:54 -0700228// Compare this variationMap to another one. Returns true if the every entry in this map
229// is either the same in the other map or doesn't exist in the other map.
230func (vm variationMap) subset(other variationMap) bool {
231 for k, v1 := range vm {
232 if v2, ok := other[k]; ok && v1 != v2 {
233 return false
234 }
235 }
236 return true
237}
238
Colin Crossf5e34b92015-03-13 16:02:36 -0700239func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700240 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800241}
242
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700243type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700244 // set during RegisterSingletonType
245 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700246 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700247 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700248
249 // set during PrepareBuildActions
250 actionDefs localBuildActions
251}
252
Colin Crossc9028482014-12-18 16:28:54 -0800253type mutatorInfo struct {
254 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800255 topDownMutator TopDownMutator
256 bottomUpMutator BottomUpMutator
257 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700258 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800259}
260
Jamie Gennisd4e10182014-06-12 20:06:50 -0700261// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700262// no module or singleton factories registered, so the RegisterModuleFactory and
263// RegisterSingletonFactory methods must be called before it can do anything
264// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700265func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700266 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800267 moduleFactories: make(map[string]ModuleFactory),
Colin Cross0b7e83e2016-05-17 14:58:05 -0700268 moduleNames: make(map[string]*moduleGroup),
Colin Cross6134a5c2015-02-10 11:26:26 -0800269 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800270 moduleNinjaNames: make(map[string]*moduleGroup),
Colin Crossd7b0f602016-06-02 15:30:20 -0700271 fs: fs,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700272 }
Colin Cross763b6f12015-10-29 15:32:56 -0700273
274 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
275
276 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700277}
278
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700279// A ModuleFactory function creates a new Module object. See the
280// Context.RegisterModuleType method for details about how a registered
281// ModuleFactory is used by a Context.
282type ModuleFactory func() (m Module, propertyStructs []interface{})
283
Jamie Gennisd4e10182014-06-12 20:06:50 -0700284// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700285// Blueprints file) with a Module factory function. When the given module type
286// name is encountered in a Blueprints file during parsing, the Module factory
287// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800288// generation for the module. If a Mutator splits a module into multiple variants,
289// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700290//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700291// The module type names given here must be unique for the context. The factory
292// function should be a named function so that its package and name can be
293// included in the generated Ninja file for debugging purposes.
294//
295// The factory function returns two values. The first is the newly created
296// Module object. The second is a slice of pointers to that Module object's
297// properties structs. Each properties struct is examined when parsing a module
298// definition of this type in a Blueprints file. Exported fields of the
299// properties structs are automatically set to the property values specified in
300// the Blueprints file. The properties struct field names determine the name of
301// the Blueprints file properties that are used - the Blueprints property name
302// matches that of the properties struct field name with the first letter
303// converted to lower-case.
304//
305// The fields of the properties struct must be either []string, a string, or
306// bool. The Context will panic if a Module gets instantiated with a properties
307// struct containing a field that is not one these supported types.
308//
309// Any properties that appear in the Blueprints files that are not built-in
310// module properties (such as "name" and "deps") and do not have a corresponding
311// field in the returned module properties struct result in an error during the
312// Context's parse phase.
313//
314// As an example, the follow code:
315//
316// type myModule struct {
317// properties struct {
318// Foo string
319// Bar []string
320// }
321// }
322//
323// func NewMyModule() (blueprint.Module, []interface{}) {
324// module := new(myModule)
325// properties := &module.properties
326// return module, []interface{}{properties}
327// }
328//
329// func main() {
330// ctx := blueprint.NewContext()
331// ctx.RegisterModuleType("my_module", NewMyModule)
332// // ...
333// }
334//
335// would support parsing a module defined in a Blueprints file as follows:
336//
337// my_module {
338// name: "myName",
339// foo: "my foo string",
340// bar: ["my", "bar", "strings"],
341// }
342//
Colin Cross7ad621c2015-01-07 16:22:45 -0800343// The factory function may be called from multiple goroutines. Any accesses
344// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700345func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
346 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700347 panic(errors.New("module type name is already registered"))
348 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700349 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700350}
351
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700352// A SingletonFactory function creates a new Singleton object. See the
353// Context.RegisterSingletonType method for details about how a registered
354// SingletonFactory is used by a Context.
355type SingletonFactory func() Singleton
356
357// RegisterSingletonType registers a singleton type that will be invoked to
358// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700359// and invoked exactly once as part of the generate phase. Each registered
360// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700361//
362// The singleton type names given here must be unique for the context. The
363// factory function should be a named function so that its package and name can
364// be included in the generated Ninja file for debugging purposes.
365func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700366 for _, s := range c.singletonInfo {
367 if s.name == name {
368 panic(errors.New("singleton name is already registered"))
369 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700370 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700371
Yuchen Wub9103ef2015-08-25 17:58:17 -0700372 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700373 factory: factory,
374 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700375 name: name,
376 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700377}
378
379func singletonPkgPath(singleton Singleton) string {
380 typ := reflect.TypeOf(singleton)
381 for typ.Kind() == reflect.Ptr {
382 typ = typ.Elem()
383 }
384 return typ.PkgPath()
385}
386
387func singletonTypeName(singleton Singleton) string {
388 typ := reflect.TypeOf(singleton)
389 for typ.Kind() == reflect.Ptr {
390 typ = typ.Elem()
391 }
392 return typ.PkgPath() + "." + typ.Name()
393}
394
Colin Cross3702ac72016-08-11 11:09:00 -0700395// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
396// top-down between Modules. Each registered mutator is invoked in registration order (mixing
397// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
398// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800399//
Colin Cross65569e42015-03-10 20:08:19 -0700400// The mutator type names given here must be unique to all top down mutators in
401// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700402//
403// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
404// parallel while maintaining ordering.
405func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800406 for _, m := range c.mutatorInfo {
407 if m.name == name && m.topDownMutator != nil {
408 panic(fmt.Errorf("mutator name %s is already registered", name))
409 }
410 }
411
Colin Cross3702ac72016-08-11 11:09:00 -0700412 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800413 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800414 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700415 }
416
417 c.mutatorInfo = append(c.mutatorInfo, info)
418
419 return info
Colin Crossc9028482014-12-18 16:28:54 -0800420}
421
Colin Cross3702ac72016-08-11 11:09:00 -0700422// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
423// Each registered mutator is invoked in registration order (mixing TopDownMutators and
424// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
425// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800426//
Colin Cross65569e42015-03-10 20:08:19 -0700427// The mutator type names given here must be unique to all bottom up or early
428// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700429//
Colin Cross3702ac72016-08-11 11:09:00 -0700430// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
431// parallel while maintaining ordering.
432func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700433 for _, m := range c.variantMutatorNames {
434 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800435 panic(fmt.Errorf("mutator name %s is already registered", name))
436 }
437 }
438
Colin Cross49c279a2016-08-05 22:30:44 -0700439 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800440 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800441 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700442 }
443 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700444
445 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700446
447 return info
448}
449
Colin Cross3702ac72016-08-11 11:09:00 -0700450type MutatorHandle interface {
451 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
452 // method on the mutator context is thread-safe, but the mutator must handle synchronization
453 // for any modifications to global state or any modules outside the one it was invoked on.
454 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700455}
456
Colin Cross3702ac72016-08-11 11:09:00 -0700457func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700458 mutator.parallel = true
459 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700460}
461
462// RegisterEarlyMutator registers a mutator that will be invoked to split
463// Modules into multiple variant Modules before any dependencies have been
464// created. Each registered mutator is invoked in registration order once
465// per Module (including each variant from previous early mutators). Module
466// order is unpredictable.
467//
468// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700469// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700470//
471// The mutator type names given here must be unique to all bottom up or early
472// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700473//
474// Deprecated, use a BottomUpMutator instead. The only difference between
475// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
476// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700477func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
478 for _, m := range c.variantMutatorNames {
479 if m == name {
480 panic(fmt.Errorf("mutator name %s is already registered", name))
481 }
482 }
483
Colin Crossf8b50422016-08-10 12:56:40 -0700484 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
485 bottomUpMutator: func(mctx BottomUpMutatorContext) {
486 mutator(mctx)
487 },
488 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700489 })
490
491 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800492}
493
Jamie Gennisd4e10182014-06-12 20:06:50 -0700494// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
495// where it encounters an unknown module type while parsing Blueprints files. By
496// default, the context will report unknown module types as an error. If this
497// method is called with ignoreUnknownModuleTypes set to true then the context
498// will silently ignore unknown module types.
499//
500// This method should generally not be used. It exists to facilitate the
501// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700502func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
503 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
504}
505
Colin Cross036a1df2015-12-17 15:49:30 -0800506// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
507// unresolved dependencies. If the module's GenerateBuildActions calls
508// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
509// for missing dependencies.
510func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
511 c.allowMissingDependencies = allowMissingDependencies
512}
513
Jamie Gennisd4e10182014-06-12 20:06:50 -0700514// Parse parses a single Blueprints file from r, creating Module objects for
515// each of the module definitions encountered. If the Blueprints file contains
516// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700517// searched for Blueprints files returned in the subBlueprints return value.
518// If the Blueprints file contains an assignment to the "build" variable, then
519// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700520//
521// rootDir specifies the path to the root directory of the source tree, while
522// filename specifies the path to the Blueprints file. These paths are used for
523// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800524func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700525 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700526 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700527
Jamie Gennisec701282014-06-12 20:06:31 -0700528 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700529 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700530 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700531 }
532
Colin Crossc0dbc552015-01-02 15:19:28 -0800533 scope = parser.NewScope(scope)
534 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800535 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700536 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700537 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700538 if len(errs) > 0 {
539 for i, err := range errs {
540 if parseErr, ok := err.(*parser.ParseError); ok {
Colin Cross2c628442016-10-07 17:13:10 -0700541 err = &BlueprintError{
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700542 Err: parseErr.Err,
543 Pos: parseErr.Pos,
544 }
545 errs[i] = err
546 }
547 }
548
549 // If there were any parse errors don't bother trying to interpret the
550 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700551 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700552 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700553 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700554
Colin Cross6d8780f2015-07-10 17:51:55 -0700555 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700556 if err != nil {
557 errs = append(errs, err)
558 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700559
Colin Cross7f507402015-12-16 13:03:41 -0800560 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
561 if err != nil {
562 errs = append(errs, err)
563 }
564
Colin Cross6d8780f2015-07-10 17:51:55 -0700565 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700566 if err != nil {
567 errs = append(errs, err)
568 }
569
Colin Cross29394222015-04-27 13:18:21 -0700570 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
571
Colin Cross7f507402015-12-16 13:03:41 -0800572 var blueprints []string
573
574 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
575 blueprints = append(blueprints, newBlueprints...)
576 deps = append(deps, newDeps...)
577 errs = append(errs, newErrs...)
578
579 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
580 subBlueprintsName, false)
581 blueprints = append(blueprints, newBlueprints...)
582 deps = append(deps, newDeps...)
583 errs = append(errs, newErrs...)
584
585 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
586 optionalSubdirsPos, subBlueprintsName, true)
587 blueprints = append(blueprints, newBlueprints...)
588 deps = append(deps, newDeps...)
589 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800590
Colin Cross1fef5362015-04-20 16:50:54 -0700591 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
592 for i, b := range blueprints {
593 subBlueprintsAndScope[i] = stringAndScope{b, scope}
594 }
595
Colin Cross23d7aa12015-06-30 16:05:22 -0700596 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800597}
598
Colin Cross7ad621c2015-01-07 16:22:45 -0800599type stringAndScope struct {
600 string
601 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700602}
603
Jamie Gennisd4e10182014-06-12 20:06:50 -0700604// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
605// at rootFile. When it encounters a Blueprints file with a set of subdirs
606// listed it recursively parses any Blueprints files found in those
607// subdirectories.
608//
609// If no errors are encountered while parsing the files, the list of paths on
610// which the future output will depend is returned. This list will include both
611// Blueprints file paths as well as directory paths for cases where wildcard
612// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700613func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
614 errs []error) {
615
Colin Cross7ad621c2015-01-07 16:22:45 -0800616 c.dependenciesReady = false
617
Colin Cross23d7aa12015-06-30 16:05:22 -0700618 moduleCh := make(chan *moduleInfo)
619 errsCh := make(chan []error)
620 doneCh := make(chan struct{})
621 var numErrs uint32
622 var numGoroutines int32
623
624 // handler must be reentrant
625 handler := func(file *parser.File) {
626 if atomic.LoadUint32(&numErrs) > maxErrors {
627 return
628 }
629
630 atomic.AddInt32(&numGoroutines, 1)
631 go func() {
632 for _, def := range file.Defs {
633 var module *moduleInfo
634 var errs []error
635 switch def := def.(type) {
636 case *parser.Module:
637 module, errs = c.processModuleDef(def, file.Name)
638 case *parser.Assignment:
639 // Already handled via Scope object
640 default:
641 panic("unknown definition type")
642 }
643
644 if len(errs) > 0 {
645 atomic.AddUint32(&numErrs, uint32(len(errs)))
646 errsCh <- errs
647 } else if module != nil {
648 moduleCh <- module
649 }
650 }
651 doneCh <- struct{}{}
652 }()
653 }
654
655 atomic.AddInt32(&numGoroutines, 1)
656 go func() {
657 var errs []error
658 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
659 if len(errs) > 0 {
660 errsCh <- errs
661 }
662 doneCh <- struct{}{}
663 }()
664
665loop:
666 for {
667 select {
668 case newErrs := <-errsCh:
669 errs = append(errs, newErrs...)
670 case module := <-moduleCh:
671 newErrs := c.addModule(module)
672 if len(newErrs) > 0 {
673 errs = append(errs, newErrs...)
674 }
675 case <-doneCh:
676 n := atomic.AddInt32(&numGoroutines, -1)
677 if n == 0 {
678 break loop
679 }
680 }
681 }
682
683 return deps, errs
684}
685
686type FileHandler func(*parser.File)
687
688// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
689// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
690// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
691// it must be reentrant.
692//
693// If no errors are encountered while parsing the files, the list of paths on
694// which the future output will depend is returned. This list will include both
695// Blueprints file paths as well as directory paths for cases where wildcard
696// subdirs are found.
697func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
698 errs []error) {
699
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700700 rootDir := filepath.Dir(rootFile)
701
Colin Cross7ad621c2015-01-07 16:22:45 -0800702 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700703
Colin Cross7ad621c2015-01-07 16:22:45 -0800704 // Channels to receive data back from parseBlueprintsFile goroutines
705 blueprintsCh := make(chan stringAndScope)
706 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700707 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800708 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700709
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
711 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700712
Colin Cross7ad621c2015-01-07 16:22:45 -0800713 // Number of outstanding goroutines to wait for
714 count := 0
715
716 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
717 count++
718 go func() {
719 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700720 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800721 doneCh <- struct{}{}
722 }()
723 }
724
725 tooManyErrors := false
726
727 startParseBlueprintsFile(rootFile, nil)
728
729loop:
730 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700731 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800732 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700733 }
734
Colin Cross7ad621c2015-01-07 16:22:45 -0800735 select {
736 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700737 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800738 case dep := <-depsCh:
739 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700740 case file := <-fileCh:
741 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800742 case blueprint := <-blueprintsCh:
743 if tooManyErrors {
744 continue
745 }
746 if blueprintsSet[blueprint.string] {
747 continue
748 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700749
Colin Cross7ad621c2015-01-07 16:22:45 -0800750 blueprintsSet[blueprint.string] = true
751 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
752 case <-doneCh:
753 count--
754 if count == 0 {
755 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700756 }
757 }
758 }
759
Colin Cross7ad621c2015-01-07 16:22:45 -0800760 return
761}
762
Colin Crossd7b0f602016-06-02 15:30:20 -0700763// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
764// filenames to contents stored as a byte slice.
765func (c *Context) MockFileSystem(files map[string][]byte) {
766 c.fs = &mockFS{
767 files: files,
768 }
769}
770
Colin Cross7ad621c2015-01-07 16:22:45 -0800771// parseBlueprintFile parses a single Blueprints file, returning any errors through
772// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
773// blueprintsCh, and any dependencies on Blueprints files or directories through
774// depsCh.
775func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700776 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800777 depsCh chan<- string) {
778
Colin Crossd7b0f602016-06-02 15:30:20 -0700779 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800780 if err != nil {
781 errsCh <- []error{err}
782 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700783 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700784 defer func() {
785 err = f.Close()
786 if err != nil {
787 errsCh <- []error{err}
788 }
789 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700790
Colin Cross23d7aa12015-06-30 16:05:22 -0700791 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800792 if len(errs) > 0 {
793 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700794 } else {
795 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800796 }
797
Colin Cross1fef5362015-04-20 16:50:54 -0700798 for _, b := range subBlueprints {
799 blueprintsCh <- b
800 }
801
802 for _, d := range deps {
803 depsCh <- d
804 }
Colin Cross1fef5362015-04-20 16:50:54 -0700805}
806
Colin Cross7f507402015-12-16 13:03:41 -0800807func (c *Context) findBuildBlueprints(dir string, build []string,
808 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
809
810 for _, file := range build {
811 globPattern := filepath.Join(dir, file)
812 matches, matchedDirs, err := pathtools.Glob(globPattern)
813 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700814 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800815 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
816 Pos: buildPos,
817 })
818 continue
819 }
820
821 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -0700822 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800823 Err: fmt.Errorf("%q: not found", globPattern),
824 Pos: buildPos,
825 })
826 }
827
828 // Depend on all searched directories so we pick up future changes.
829 deps = append(deps, matchedDirs...)
830
831 for _, foundBlueprints := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700832 exists, dir, err := c.fs.Exists(foundBlueprints)
833 if err != nil {
834 errs = append(errs, err)
835 } else if !exists {
Colin Cross2c628442016-10-07 17:13:10 -0700836 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800837 Err: fmt.Errorf("%q not found", foundBlueprints),
838 })
839 continue
Colin Crossd7b0f602016-06-02 15:30:20 -0700840 } else if dir {
Colin Cross2c628442016-10-07 17:13:10 -0700841 errs = append(errs, &BlueprintError{
Colin Cross7f507402015-12-16 13:03:41 -0800842 Err: fmt.Errorf("%q is a directory", foundBlueprints),
843 })
844 continue
845 }
846
847 blueprints = append(blueprints, foundBlueprints)
Colin Cross24587122016-10-11 10:01:29 -0700848 deps = append(deps, foundBlueprints)
Colin Cross7f507402015-12-16 13:03:41 -0800849 }
850 }
851
852 return blueprints, deps, errs
853}
854
855func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
856 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800857
858 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700859 globPattern := filepath.Join(dir, subdir)
860 matches, matchedDirs, err := pathtools.Glob(globPattern)
861 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700862 errs = append(errs, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700863 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
864 Pos: subdirsPos,
865 })
866 continue
867 }
868
Colin Cross7f507402015-12-16 13:03:41 -0800869 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -0700870 errs = append(errs, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700871 Err: fmt.Errorf("%q: not found", globPattern),
872 Pos: subdirsPos,
873 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700874 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800875
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700876 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700877 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800878
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700879 for _, foundSubdir := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700880 exists, dir, subdirStatErr := c.fs.Exists(foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700881 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700882 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700883 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800884 }
885
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700886 // Skip files
Colin Crossd7b0f602016-06-02 15:30:20 -0700887 if !dir {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700888 continue
889 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800890
Colin Cross29394222015-04-27 13:18:21 -0700891 var subBlueprints string
892 if subBlueprintsName != "" {
893 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
Colin Crossd7b0f602016-06-02 15:30:20 -0700894 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700895 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700896
Colin Crossd7b0f602016-06-02 15:30:20 -0700897 if err == nil && (!exists || subBlueprints == "") {
Colin Cross29394222015-04-27 13:18:21 -0700898 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
Colin Crossd7b0f602016-06-02 15:30:20 -0700899 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700900 }
901
Colin Crossd7b0f602016-06-02 15:30:20 -0700902 if err != nil {
903 errs = append(errs, err)
904 continue
905 }
906
907 if !exists {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700908 // There is no Blueprints file in this subdirectory. We
909 // need to add the directory to the list of dependencies
910 // so that if someone adds a Blueprints file in the
911 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700912 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700913 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700914 deps = append(deps, subBlueprints)
915 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800916 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800917 }
918 }
Colin Cross1fef5362015-04-20 16:50:54 -0700919
Colin Cross1fef5362015-04-20 16:50:54 -0700920 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700921}
922
Colin Cross6d8780f2015-07-10 17:51:55 -0700923func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
924 if assignment, local := scope.Get(v); assignment == nil || !local {
925 return nil, scanner.Position{}, nil
926 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700927 switch value := assignment.Value.Eval().(type) {
928 case *parser.List:
929 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700930
Colin Crosse32cc802016-06-07 12:28:16 -0700931 for _, listValue := range value.Values {
932 s, ok := listValue.(*parser.String)
933 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700934 // The parser should not produce this.
935 panic("non-string value found in list")
936 }
937
Colin Crosse32cc802016-06-07 12:28:16 -0700938 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700939 }
940
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700941 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700942 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -0700943 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700944 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700945 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700946 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700947 default:
948 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
949 }
950 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700951}
952
Colin Cross29394222015-04-27 13:18:21 -0700953func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700954 if assignment, _ := scope.Get(v); assignment == nil {
955 return "", scanner.Position{}, nil
956 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700957 switch value := assignment.Value.Eval().(type) {
958 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700959 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700960 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -0700961 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -0700962 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700963 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -0700964 }
965 default:
966 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
967 }
968 }
Colin Cross29394222015-04-27 13:18:21 -0700969}
970
Colin Cross910242b2016-04-11 15:41:52 -0700971// Clones a build logic module by calling the factory method for its module type, and then cloning
972// property values. Any values stored in the module object that are not stored in properties
973// structs will be lost.
974func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
975 typeName := origModule.typeName
976 factory, ok := c.moduleFactories[typeName]
977 if !ok {
978 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
979 }
980
Colin Cross910242b2016-04-11 15:41:52 -0700981 newLogicModule, newProperties := factory()
982
Colin Cross910242b2016-04-11 15:41:52 -0700983 if len(newProperties) != len(origModule.moduleProperties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700984 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -0700985 }
986
987 for i := range newProperties {
988 dst := reflect.ValueOf(newProperties[i]).Elem()
989 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
990
991 proptools.CopyProperties(dst, src)
992 }
993
994 return newLogicModule, newProperties
995}
996
Colin Crossf5e34b92015-03-13 16:02:36 -0700997func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
998 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800999
Colin Crossf4d18a62015-03-18 17:43:15 -07001000 if len(variationNames) == 0 {
1001 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001002 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001003 }
1004
Colin Crossc9028482014-12-18 16:28:54 -08001005 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001006
Colin Cross174ae052015-03-03 17:37:03 -08001007 var errs []error
1008
Colin Crossf5e34b92015-03-13 16:02:36 -07001009 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001010 var newLogicModule Module
1011 var newProperties []interface{}
1012
1013 if i == 0 {
1014 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001015 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1016 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -07001017 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -08001018 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001019 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001020 }
1021
Colin Crossf5e34b92015-03-13 16:02:36 -07001022 newVariant := origModule.variant.clone()
1023 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001024
Colin Crossed342d92015-03-11 00:57:25 -07001025 m := *origModule
1026 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001027 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001028 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001029 newModule.variant = newVariant
1030 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -07001031 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001032
Colin Crossbadc8812016-08-11 17:01:46 -07001033 if variationName != "" {
1034 if newModule.variantName == "" {
1035 newModule.variantName = variationName
1036 } else {
1037 newModule.variantName += "_" + variationName
1038 }
Colin Crosse7daa222015-03-11 14:35:41 -07001039 }
1040
Colin Crossc9028482014-12-18 16:28:54 -08001041 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001042
Colin Crossf5e34b92015-03-13 16:02:36 -07001043 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001044 if len(newErrs) > 0 {
1045 errs = append(errs, newErrs...)
1046 }
Colin Crossc9028482014-12-18 16:28:54 -08001047 }
1048
1049 // Mark original variant as invalid. Modules that depend on this module will still
1050 // depend on origModule, but we'll fix it when the mutator is called on them.
1051 origModule.logicModule = nil
1052 origModule.splitModules = newModules
1053
Colin Cross3702ac72016-08-11 11:09:00 -07001054 atomic.AddUint32(&c.depsModified, 1)
1055
Colin Cross174ae052015-03-03 17:37:03 -08001056 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001057}
1058
Colin Crossf5e34b92015-03-13 16:02:36 -07001059func (c *Context) convertDepsToVariation(module *moduleInfo,
1060 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001061
Colin Crossc9028482014-12-18 16:28:54 -08001062 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001063 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001064 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001065 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001066 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001067 newDep = m
1068 break
1069 }
1070 }
1071 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001072 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001073 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001074 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001075 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001076 })
1077 continue
Colin Crossc9028482014-12-18 16:28:54 -08001078 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001079 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001080 }
1081 }
Colin Cross174ae052015-03-03 17:37:03 -08001082
1083 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001084}
1085
Colin Crossf5e34b92015-03-13 16:02:36 -07001086func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001087 names := make([]string, 0, len(variant))
1088 for _, m := range c.variantMutatorNames {
1089 if v, ok := variant[m]; ok {
1090 names = append(names, m+":"+v)
1091 }
1092 }
1093
1094 return strings.Join(names, ", ")
1095}
1096
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001097func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001098 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001099
Colin Crossc32c4792016-06-09 15:52:30 -07001100 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001101 if !ok {
1102 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001103 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001104 }
1105
Colin Cross7ad621c2015-01-07 16:22:45 -08001106 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001107 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001108 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1109 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001110 },
1111 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001112 }
1113
Colin Crossbbfa51a2014-12-17 16:12:41 -08001114 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001115
1116 module := &moduleInfo{
1117 logicModule: logicModule,
Colin Crossc32c4792016-06-09 15:52:30 -07001118 typeName: moduleDef.Type,
Jamie Gennisec701282014-06-12 20:06:31 -07001119 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001120 }
1121
Colin Crossed342d92015-03-11 00:57:25 -07001122 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001123
Jamie Gennis87622922014-09-30 11:38:25 -07001124 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001125 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001126 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001127 }
1128
Colin Crossc32c4792016-06-09 15:52:30 -07001129 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001130 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001131 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001132 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001133 }
1134
Colin Cross7ad621c2015-01-07 16:22:45 -08001135 return module, nil
1136}
1137
Colin Cross23d7aa12015-06-30 16:05:22 -07001138func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001139 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001140 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001141
Colin Cross0b7e83e2016-05-17 14:58:05 -07001142 if group, present := c.moduleNames[name]; present {
Colin Cross23d7aa12015-06-30 16:05:22 -07001143 return []error{
Colin Cross2c628442016-10-07 17:13:10 -07001144 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001145 Err: fmt.Errorf("module %q already defined", name),
1146 Pos: module.pos,
1147 },
Colin Cross2c628442016-10-07 17:13:10 -07001148 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001149 Err: fmt.Errorf("<-- previous definition here"),
1150 Pos: group.modules[0].pos,
1151 },
Colin Crossed342d92015-03-11 00:57:25 -07001152 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001153 }
1154
Colin Cross0b7e83e2016-05-17 14:58:05 -07001155 ninjaName := toNinjaName(name)
1156
1157 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1158 // already exists
1159 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1160 ninjaName = toNinjaName(name) + strconv.Itoa(i)
1161 }
1162
1163 group := &moduleGroup{
1164 name: name,
1165 ninjaName: ninjaName,
1166 modules: []*moduleInfo{module},
1167 }
1168 module.group = group
1169 c.moduleNames[name] = group
1170 c.moduleNinjaNames[ninjaName] = group
1171 c.moduleGroups = append(c.moduleGroups, group)
1172
Colin Cross23d7aa12015-06-30 16:05:22 -07001173 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001174}
1175
Jamie Gennisd4e10182014-06-12 20:06:50 -07001176// ResolveDependencies checks that the dependencies specified by all of the
1177// modules defined in the parsed Blueprints files are valid. This means that
1178// the modules depended upon are defined and that no circular dependencies
1179// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001180func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Crossf8b50422016-08-10 12:56:40 -07001181 errs := c.updateDependencies()
1182 if len(errs) > 0 {
1183 return errs
1184 }
1185
1186 errs = c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001187 if len(errs) > 0 {
1188 return errs
1189 }
1190
Colin Cross910242b2016-04-11 15:41:52 -07001191 c.cloneModules()
1192
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001193 c.dependenciesReady = true
1194 return nil
1195}
1196
Colin Cross763b6f12015-10-29 15:32:56 -07001197// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001198// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001199// module names returned by its DynamicDependencies method and those added by calling
1200// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001201func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001202 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001203 func() {
1204 defer func() {
1205 if r := recover(); r != nil {
1206 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1207 }
1208 }()
1209 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001210
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001211 if ctx.Failed() {
1212 return
1213 }
Colin Cross763b6f12015-10-29 15:32:56 -07001214
Colin Cross2c1f3d12016-04-11 15:47:28 -07001215 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001216 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001217 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001218}
1219
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001220// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1221// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001222func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1223 if len(possible) == 1 {
1224 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001225 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001226 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001227 if m.variant.equal(module.dependencyVariant) {
1228 return m
1229 }
1230 }
1231 }
1232
1233 return nil
1234}
1235
Colin Cross2c1f3d12016-04-11 15:47:28 -07001236func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001237 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001238 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001239 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001240 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001241 }}
1242 }
1243
Colin Cross0b7e83e2016-05-17 14:58:05 -07001244 possibleDeps := c.modulesFromName(depName)
1245 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001246 if c.allowMissingDependencies {
1247 module.missingDeps = append(module.missingDeps, depName)
1248 return nil
1249 }
Colin Cross2c628442016-10-07 17:13:10 -07001250 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001251 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001252 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001253 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001254 }}
1255 }
1256
Colin Cross0b7e83e2016-05-17 14:58:05 -07001257 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001258 for _, dep := range module.directDeps {
1259 if m == dep.module {
1260 // TODO(ccross): what if adding a dependency with a different tag?
1261 return nil
1262 }
Colin Cross65569e42015-03-10 20:08:19 -07001263 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001264 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001265 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001266 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001267 }
Colin Crossc9028482014-12-18 16:28:54 -08001268
Colin Cross2c628442016-10-07 17:13:10 -07001269 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001270 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001271 depName, module.Name(),
Colin Crossf5e34b92015-03-13 16:02:36 -07001272 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001273 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001274 }}
1275}
1276
Colin Cross8d8a7af2015-11-03 16:41:29 -08001277func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001278 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001279 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001280 Err: fmt.Errorf("%q depends on itself", destName),
1281 Pos: module.pos,
1282 }}
1283 }
1284
Colin Cross0b7e83e2016-05-17 14:58:05 -07001285 possibleDeps := c.modulesFromName(destName)
1286 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001287 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001288 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001289 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001290 Pos: module.pos,
1291 }}
1292 }
1293
Colin Cross0b7e83e2016-05-17 14:58:05 -07001294 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001295 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001296 }
1297
Colin Cross2c628442016-10-07 17:13:10 -07001298 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001299 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001300 destName, module.Name(),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001301 c.prettyPrintVariant(module.dependencyVariant)),
1302 Pos: module.pos,
1303 }}
1304}
1305
Colin Crossf5e34b92015-03-13 16:02:36 -07001306func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001307 tag DependencyTag, depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001308
Colin Cross0b7e83e2016-05-17 14:58:05 -07001309 possibleDeps := c.modulesFromName(depName)
1310 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001311 if c.allowMissingDependencies {
1312 module.missingDeps = append(module.missingDeps, depName)
1313 return nil
1314 }
Colin Cross2c628442016-10-07 17:13:10 -07001315 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001316 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001317 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001318 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001319 }}
1320 }
1321
1322 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1323 // compare the strings because the result won't be in mutator registration order.
1324 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001325 var newVariant variationMap
1326 if !far {
1327 newVariant = module.dependencyVariant.clone()
1328 } else {
1329 newVariant = make(variationMap)
1330 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001331 for _, v := range variations {
1332 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001333 }
1334
Colin Cross0b7e83e2016-05-17 14:58:05 -07001335 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001336 var found bool
1337 if far {
1338 found = m.variant.subset(newVariant)
1339 } else {
1340 found = m.variant.equal(newVariant)
1341 }
1342 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001343 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001344 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001345 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001346 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001347 }}
1348 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001349 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001350 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001351 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001352 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001353 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001354 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001355 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001356 }}
1357 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001358 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001359 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001360 return nil
1361 }
1362 }
1363
Colin Cross2c628442016-10-07 17:13:10 -07001364 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001365 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001366 depName, module.Name(),
Colin Crossf5e34b92015-03-13 16:02:36 -07001367 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001368 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001369 }}
Colin Crossc9028482014-12-18 16:28:54 -08001370}
1371
Colin Crossf1875462016-04-11 17:33:13 -07001372func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1373 from, to Module) {
1374
1375 var fromInfo, toInfo *moduleInfo
1376 for _, m := range origModule.splitModules {
1377 if m.logicModule == from {
1378 fromInfo = m
1379 }
1380 if m.logicModule == to {
1381 toInfo = m
1382 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001383 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001384 }
1385 }
1386 }
1387
1388 if fromInfo == nil || toInfo == nil {
1389 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001390 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001391 }
1392
1393 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001394 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001395}
1396
Colin Cross3702ac72016-08-11 11:09:00 -07001397type visitOrderer interface {
1398 // returns the number of modules that this module needs to wait for
1399 waitCount(module *moduleInfo) int
1400 // returns the list of modules that are waiting for this module
1401 propagate(module *moduleInfo) []*moduleInfo
1402 // visit modules in order
1403 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1404}
1405
1406type bottomUpVisitorImpl struct{}
1407
1408func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1409 return len(module.forwardDeps)
1410}
1411
1412func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1413 return module.reverseDeps
1414}
1415
1416func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1417 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001418 if visit(module) {
1419 return
1420 }
1421 }
1422}
1423
Colin Cross3702ac72016-08-11 11:09:00 -07001424type topDownVisitorImpl struct{}
1425
1426func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1427 return len(module.reverseDeps)
1428}
1429
1430func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1431 return module.forwardDeps
1432}
1433
1434func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1435 for i := 0; i < len(modules); i++ {
1436 module := modules[len(modules)-1-i]
1437 if visit(module) {
1438 return
1439 }
1440 }
1441}
1442
1443var (
1444 bottomUpVisitor bottomUpVisitorImpl
1445 topDownVisitor topDownVisitorImpl
1446)
1447
Colin Cross49c279a2016-08-05 22:30:44 -07001448// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1449// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001450func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001451 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001452 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001453 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001454 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001455
Colin Cross7addea32015-03-11 15:43:52 -07001456 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001457 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001458 }
1459
Colin Cross7addea32015-03-11 15:43:52 -07001460 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001461 count++
1462 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001463 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001464 if ret {
Colin Cross0fff7422016-08-11 15:37:45 -07001465 cancelCh <- true
Colin Cross8900e9b2015-03-02 14:03:01 -08001466 }
Colin Cross7addea32015-03-11 15:43:52 -07001467 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001468 }()
1469 }
1470
Colin Cross7addea32015-03-11 15:43:52 -07001471 for _, module := range c.modulesSorted {
1472 if module.waitingCount == 0 {
1473 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001474 }
1475 }
1476
Colin Cross11e3b0d2015-02-04 10:41:00 -08001477 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001478 select {
Colin Cross0fff7422016-08-11 15:37:45 -07001479 case cancel = <-cancelCh:
Colin Cross7addea32015-03-11 15:43:52 -07001480 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001481 if !cancel {
Colin Cross3702ac72016-08-11 11:09:00 -07001482 for _, module := range order.propagate(doneModule) {
1483 module.waitingCount--
1484 if module.waitingCount == 0 {
1485 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001486 }
Colin Cross691a60d2015-01-07 18:08:56 -08001487 }
1488 }
1489 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001490 }
1491 }
1492}
1493
1494// updateDependencies recursively walks the module dependency graph and updates
1495// additional fields based on the dependencies. It builds a sorted list of modules
1496// such that dependencies of a module always appear first, and populates reverse
1497// dependency links and counts of total dependencies. It also reports errors when
1498// it encounters dependency cycles. This should called after resolveDependencies,
1499// as well as after any mutator pass has called addDependency
1500func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001501 visited := make(map[*moduleInfo]bool) // modules that were already checked
1502 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001503
Colin Cross7addea32015-03-11 15:43:52 -07001504 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001505
Colin Cross7addea32015-03-11 15:43:52 -07001506 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001507
Colin Cross7addea32015-03-11 15:43:52 -07001508 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001509 // We are the "start" of the cycle, so we're responsible
1510 // for generating the errors. The cycle list is in
1511 // reverse order because all the 'check' calls append
1512 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001513 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001514 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001515 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001516 })
1517
1518 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001519 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001520 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001521 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001522 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001523 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001524 curModule.Name(),
1525 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001526 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001527 })
Colin Cross7addea32015-03-11 15:43:52 -07001528 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001529 }
1530 }
1531
Colin Cross7addea32015-03-11 15:43:52 -07001532 check = func(module *moduleInfo) []*moduleInfo {
1533 visited[module] = true
1534 checking[module] = true
1535 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001536
Colin Cross7addea32015-03-11 15:43:52 -07001537 deps := make(map[*moduleInfo]bool)
1538
1539 // Add an implicit dependency ordering on all earlier modules in the same module group
1540 for _, dep := range module.group.modules {
1541 if dep == module {
1542 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001543 }
Colin Cross7addea32015-03-11 15:43:52 -07001544 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001545 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001546
Colin Cross7addea32015-03-11 15:43:52 -07001547 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001548 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001549 }
1550
1551 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001552 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001553
Colin Crossbbfa51a2014-12-17 16:12:41 -08001554 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001555 if checking[dep] {
1556 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001557 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001558 }
1559
1560 if !visited[dep] {
1561 cycle := check(dep)
1562 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001563 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001564 // We are the "start" of the cycle, so we're responsible
1565 // for generating the errors. The cycle list is in
1566 // reverse order because all the 'check' calls append
1567 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001568 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001569
1570 // We can continue processing this module's children to
1571 // find more cycles. Since all the modules that were
1572 // part of the found cycle were marked as visited we
1573 // won't run into that cycle again.
1574 } else {
1575 // We're not the "start" of the cycle, so we just append
1576 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001577 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001578 }
1579 }
1580 }
Colin Cross691a60d2015-01-07 18:08:56 -08001581
Colin Cross3702ac72016-08-11 11:09:00 -07001582 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001583 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001584 }
1585
Colin Cross7addea32015-03-11 15:43:52 -07001586 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001587
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001588 return nil
1589 }
1590
Colin Cross7addea32015-03-11 15:43:52 -07001591 for _, module := range c.moduleInfo {
1592 if !visited[module] {
1593 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001594 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001595 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001596 panic("inconceivable!")
1597 }
1598 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001599 }
1600 }
1601 }
1602
Colin Cross7addea32015-03-11 15:43:52 -07001603 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001604
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001605 return
1606}
1607
Jamie Gennisd4e10182014-06-12 20:06:50 -07001608// PrepareBuildActions generates an internal representation of all the build
1609// actions that need to be performed. This process involves invoking the
1610// GenerateBuildActions method on each of the Module objects created during the
1611// parse phase and then on each of the registered Singleton objects.
1612//
1613// If the ResolveDependencies method has not already been called it is called
1614// automatically by this method.
1615//
1616// The config argument is made available to all of the Module and Singleton
1617// objects via the Config method on the ModuleContext and SingletonContext
1618// objects passed to GenerateBuildActions. It is also passed to the functions
1619// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1620// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001621//
1622// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001623// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1624// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1625// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001626func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001627 c.buildActionsReady = false
1628
1629 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001630 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001631 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001632 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001633 }
1634 }
1635
1636 liveGlobals := newLiveTracker(config)
1637
1638 c.initSpecialVariables()
1639
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001640 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001641 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001642 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001643 }
1644
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001645 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001646 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001647 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001648 }
1649
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001650 deps = append(depsModules, depsSingletons...)
1651
Colin Crossa2599452015-11-18 16:01:01 -08001652 if c.ninjaBuildDir != nil {
1653 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001654 }
1655
Dan Willemsena481ae22015-12-18 15:18:03 -08001656 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1657
1658 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001659
1660 // This will panic if it finds a problem since it's a programming error.
1661 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1662
1663 c.pkgNames = pkgNames
1664 c.globalVariables = liveGlobals.variables
1665 c.globalPools = liveGlobals.pools
1666 c.globalRules = liveGlobals.rules
1667
1668 c.buildActionsReady = true
1669
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001670 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001671}
1672
Colin Crossc9028482014-12-18 16:28:54 -08001673func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001674 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001675
Colin Crossf8b50422016-08-10 12:56:40 -07001676 mutators = append(mutators, c.earlyMutatorInfo...)
1677 mutators = append(mutators, c.mutatorInfo...)
1678
1679 for _, mutator := range mutators {
Colin Crossc9028482014-12-18 16:28:54 -08001680 if mutator.topDownMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001681 errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001682 } else if mutator.bottomUpMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001683 errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001684 } else {
1685 panic("no mutator set on " + mutator.name)
1686 }
1687 if len(errs) > 0 {
1688 return errs
1689 }
1690 }
1691
1692 return nil
1693}
1694
Colin Cross3702ac72016-08-11 11:09:00 -07001695type mutatorDirection interface {
1696 run(mutator *mutatorInfo, ctx *mutatorContext)
1697 orderer() visitOrderer
1698 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001699}
1700
Colin Cross3702ac72016-08-11 11:09:00 -07001701type bottomUpMutatorImpl struct{}
1702
1703func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1704 mutator.bottomUpMutator(ctx)
1705}
1706
1707func (bottomUpMutatorImpl) orderer() visitOrderer {
1708 return bottomUpVisitor
1709}
1710
1711func (bottomUpMutatorImpl) String() string {
1712 return "bottom up mutator"
1713}
1714
1715type topDownMutatorImpl struct{}
1716
1717func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1718 mutator.topDownMutator(ctx)
1719}
1720
1721func (topDownMutatorImpl) orderer() visitOrderer {
1722 return topDownVisitor
1723}
1724
1725func (topDownMutatorImpl) String() string {
1726 return "top down mutator"
1727}
1728
1729var (
1730 topDownMutator topDownMutatorImpl
1731 bottomUpMutator bottomUpMutatorImpl
1732)
1733
Colin Cross49c279a2016-08-05 22:30:44 -07001734type reverseDep struct {
1735 module *moduleInfo
1736 dep depInfo
1737}
1738
Colin Cross3702ac72016-08-11 11:09:00 -07001739func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
1740 direction mutatorDirection) (errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001741
1742 newModuleInfo := make(map[Module]*moduleInfo)
1743 for k, v := range c.moduleInfo {
1744 newModuleInfo[k] = v
1745 }
Colin Crossc9028482014-12-18 16:28:54 -08001746
Colin Cross2c1f3d12016-04-11 15:47:28 -07001747 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross8d8a7af2015-11-03 16:41:29 -08001748
Colin Cross49c279a2016-08-05 22:30:44 -07001749 errsCh := make(chan []error)
1750 reverseDepsCh := make(chan []reverseDep)
1751 newModulesCh := make(chan []*moduleInfo)
1752 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001753
Colin Cross3702ac72016-08-11 11:09:00 -07001754 c.depsModified = 0
Colin Crossc4e5b812016-10-12 10:45:05 -07001755 c.renames = nil
Colin Cross3702ac72016-08-11 11:09:00 -07001756
Colin Cross49c279a2016-08-05 22:30:44 -07001757 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001758 if module.splitModules != nil {
1759 panic("split module found in sorted module list")
1760 }
1761
Colin Cross7addea32015-03-11 15:43:52 -07001762 mctx := &mutatorContext{
1763 baseModuleContext: baseModuleContext{
1764 context: c,
1765 config: config,
1766 module: module,
1767 },
Colin Cross49c279a2016-08-05 22:30:44 -07001768 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001769 }
Colin Crossc9028482014-12-18 16:28:54 -08001770
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001771 func() {
1772 defer func() {
1773 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001774 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001775 if err, ok := r.(panicError); ok {
1776 err.addIn(in)
1777 mctx.error(err)
1778 } else {
1779 mctx.error(newPanicErrorf(r, in))
1780 }
1781 }
1782 }()
Colin Cross3702ac72016-08-11 11:09:00 -07001783 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001784 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001785
Colin Cross7addea32015-03-11 15:43:52 -07001786 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07001787 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07001788 return true
Colin Cross7addea32015-03-11 15:43:52 -07001789 }
Colin Crossc9028482014-12-18 16:28:54 -08001790
Colin Cross49c279a2016-08-05 22:30:44 -07001791 if len(mctx.newModules) > 0 {
1792 newModulesCh <- mctx.newModules
1793 }
1794
1795 if len(mctx.reverseDeps) > 0 {
1796 reverseDepsCh <- mctx.reverseDeps
1797 }
1798
1799 return false
1800 }
1801
1802 // Process errs and reverseDeps in a single goroutine
1803 go func() {
1804 for {
1805 select {
1806 case newErrs := <-errsCh:
1807 errs = append(errs, newErrs...)
1808 case newReverseDeps := <-reverseDepsCh:
1809 for _, r := range newReverseDeps {
1810 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
1811 }
1812 case newModules := <-newModulesCh:
1813 for _, m := range newModules {
1814 newModuleInfo[m.logicModule] = m
1815 }
1816 case <-done:
1817 return
Colin Crossc9028482014-12-18 16:28:54 -08001818 }
1819 }
Colin Cross49c279a2016-08-05 22:30:44 -07001820 }()
Colin Crossc9028482014-12-18 16:28:54 -08001821
Colin Cross49c279a2016-08-05 22:30:44 -07001822 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07001823 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001824 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07001825 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001826 }
1827
1828 done <- true
1829
1830 if len(errs) > 0 {
1831 return errs
1832 }
1833
1834 c.moduleInfo = newModuleInfo
1835
1836 for _, group := range c.moduleGroups {
1837 for i := 0; i < len(group.modules); i++ {
1838 module := group.modules[i]
1839
1840 // Update module group to contain newly split variants
1841 if module.splitModules != nil {
1842 group.modules, i = spliceModules(group.modules, i, module.splitModules)
1843 }
1844
1845 // Fix up any remaining dependencies on modules that were split into variants
1846 // by replacing them with the first variant
1847 for j, dep := range module.directDeps {
1848 if dep.module.logicModule == nil {
1849 module.directDeps[j].module = dep.module.splitModules[0]
1850 }
1851 }
Colin Cross7addea32015-03-11 15:43:52 -07001852 }
Colin Crossc9028482014-12-18 16:28:54 -08001853 }
1854
Colin Cross8d8a7af2015-11-03 16:41:29 -08001855 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001856 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001857 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07001858 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08001859 }
1860
Colin Crossc4e5b812016-10-12 10:45:05 -07001861 errs = c.handleRenames()
1862 if len(errs) > 0 {
1863 return errs
1864 }
1865
Colin Cross3702ac72016-08-11 11:09:00 -07001866 if c.depsModified > 0 {
1867 errs = c.updateDependencies()
1868 if len(errs) > 0 {
1869 return errs
1870 }
Colin Crossc9028482014-12-18 16:28:54 -08001871 }
1872
1873 return errs
1874}
1875
Colin Cross910242b2016-04-11 15:41:52 -07001876// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1877// a mutator sets a non-property member variable on a module, which works until a later mutator
1878// creates variants of that module.
1879func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07001880 type update struct {
1881 orig Module
1882 clone *moduleInfo
1883 }
1884 ch := make(chan update, 100)
1885
Colin Cross910242b2016-04-11 15:41:52 -07001886 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07001887 go func(m *moduleInfo) {
1888 origLogicModule := m.logicModule
1889 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1890 ch <- update{origLogicModule, m}
1891 }(m)
1892 }
1893
1894 for i := 0; i < len(c.modulesSorted); i++ {
1895 update := <-ch
1896 delete(c.moduleInfo, update.orig)
1897 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07001898 }
1899}
1900
Colin Cross49c279a2016-08-05 22:30:44 -07001901// Removes modules[i] from the list and inserts newModules... where it was located, returning
1902// the new slice and the index of the last inserted element
1903func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07001904 spliceSize := len(newModules)
1905 newLen := len(modules) + spliceSize - 1
1906 var dest []*moduleInfo
1907 if cap(modules) >= len(modules)-1+len(newModules) {
1908 // We can fit the splice in the existing capacity, do everything in place
1909 dest = modules[:newLen]
1910 } else {
1911 dest = make([]*moduleInfo, newLen)
1912 copy(dest, modules[:i])
1913 }
1914
1915 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001916 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001917
1918 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001919 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001920
Colin Cross49c279a2016-08-05 22:30:44 -07001921 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07001922}
1923
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001924func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001925 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001926 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001927 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001928 c.requiredNinjaMicro = 0
1929}
1930
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001931func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001932 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001933
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001934 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001935 var errs []error
1936
Colin Cross691a60d2015-01-07 18:08:56 -08001937 cancelCh := make(chan struct{})
1938 errsCh := make(chan []error)
1939 depsCh := make(chan []string)
1940
1941 go func() {
1942 for {
1943 select {
1944 case <-cancelCh:
1945 close(cancelCh)
1946 return
1947 case newErrs := <-errsCh:
1948 errs = append(errs, newErrs...)
1949 case newDeps := <-depsCh:
1950 deps = append(deps, newDeps...)
1951
1952 }
1953 }
1954 }()
1955
Colin Cross3702ac72016-08-11 11:09:00 -07001956 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Colin Cross7addea32015-03-11 15:43:52 -07001957 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1958 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1959 // just set it to nil.
1960 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1961 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001962
Colin Cross7addea32015-03-11 15:43:52 -07001963 mctx := &moduleContext{
1964 baseModuleContext: baseModuleContext{
1965 context: c,
1966 config: config,
1967 module: module,
1968 },
Colin Cross036a1df2015-12-17 15:49:30 -08001969 scope: scope,
1970 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001971 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001972
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001973 func() {
1974 defer func() {
1975 if r := recover(); r != nil {
1976 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1977 if err, ok := r.(panicError); ok {
1978 err.addIn(in)
1979 mctx.error(err)
1980 } else {
1981 mctx.error(newPanicErrorf(r, in))
1982 }
1983 }
1984 }()
1985 mctx.module.logicModule.GenerateBuildActions(mctx)
1986 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001987
Colin Cross7addea32015-03-11 15:43:52 -07001988 if len(mctx.errs) > 0 {
1989 errsCh <- mctx.errs
1990 return true
1991 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001992
Colin Cross036a1df2015-12-17 15:49:30 -08001993 if module.missingDeps != nil && !mctx.handledMissingDeps {
1994 var errs []error
1995 for _, depName := range module.missingDeps {
Colin Cross2c628442016-10-07 17:13:10 -07001996 errs = append(errs, &BlueprintError{
Colin Cross036a1df2015-12-17 15:49:30 -08001997 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001998 module.Name(), depName),
Colin Cross036a1df2015-12-17 15:49:30 -08001999 Pos: module.pos,
2000 })
2001 }
2002 errsCh <- errs
2003 return true
2004 }
2005
Colin Cross7addea32015-03-11 15:43:52 -07002006 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002007
Colin Crossab6d7902015-03-11 16:17:52 -07002008 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002009 &mctx.actionDefs, liveGlobals)
2010 if len(newErrs) > 0 {
2011 errsCh <- newErrs
2012 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002013 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002014 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002015 })
2016
2017 cancelCh <- struct{}{}
2018 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002019
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002020 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002021}
2022
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002023func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002024 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002025
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002026 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002027 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002028
Yuchen Wub9103ef2015-08-25 17:58:17 -07002029 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002030 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2031 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2032 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002033 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002034
2035 sctx := &singletonContext{
2036 context: c,
2037 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002038 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002039 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002040 }
2041
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002042 func() {
2043 defer func() {
2044 if r := recover(); r != nil {
2045 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2046 if err, ok := r.(panicError); ok {
2047 err.addIn(in)
2048 sctx.error(err)
2049 } else {
2050 sctx.error(newPanicErrorf(r, in))
2051 }
2052 }
2053 }()
2054 info.singleton.GenerateBuildActions(sctx)
2055 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002056
2057 if len(sctx.errs) > 0 {
2058 errs = append(errs, sctx.errs...)
2059 if len(errs) > maxErrors {
2060 break
2061 }
2062 continue
2063 }
2064
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002065 deps = append(deps, sctx.ninjaFileDeps...)
2066
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002067 newErrs := c.processLocalBuildActions(&info.actionDefs,
2068 &sctx.actionDefs, liveGlobals)
2069 errs = append(errs, newErrs...)
2070 if len(errs) > maxErrors {
2071 break
2072 }
2073 }
2074
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002075 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002076}
2077
2078func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2079 liveGlobals *liveTracker) []error {
2080
2081 var errs []error
2082
2083 // First we go through and add everything referenced by the module's
2084 // buildDefs to the live globals set. This will end up adding the live
2085 // locals to the set as well, but we'll take them out after.
2086 for _, def := range in.buildDefs {
2087 err := liveGlobals.AddBuildDefDeps(def)
2088 if err != nil {
2089 errs = append(errs, err)
2090 }
2091 }
2092
2093 if len(errs) > 0 {
2094 return errs
2095 }
2096
Colin Crossc9028482014-12-18 16:28:54 -08002097 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002098
2099 // We use the now-incorrect set of live "globals" to determine which local
2100 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002101 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002102 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002103 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002104 if isLive {
2105 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002106 }
2107 }
2108
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002109 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002110 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002111 if isLive {
2112 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002113 }
2114 }
2115
2116 return nil
2117}
2118
Yuchen Wu222e2452015-10-06 14:03:27 -07002119func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002120 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002121
2122 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002123 var visiting *moduleInfo
2124
2125 defer func() {
2126 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002127 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2128 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002129 }
2130 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002131
2132 var walk func(module *moduleInfo)
2133 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002134 for _, dep := range module.directDeps {
2135 if !visited[dep.module] {
2136 visited[dep.module] = true
2137 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002138 recurse := true
2139 if visitDown != nil {
2140 recurse = visitDown(dep, module)
2141 }
2142 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002143 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002144 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002145 if visitUp != nil {
2146 visitUp(dep, module)
2147 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002148 }
2149 }
2150 }
2151
2152 walk(topModule)
2153}
2154
Colin Crossc4e5b812016-10-12 10:45:05 -07002155type rename struct {
2156 group *moduleGroup
2157 name string
2158}
2159
2160func (c *Context) rename(group *moduleGroup, name string) {
2161 c.renames = append(c.renames, rename{group, name})
2162}
2163
2164func (c *Context) handleRenames() []error {
2165 var errs []error
2166 for _, rename := range c.renames {
2167 group, name := rename.group, rename.name
2168 if name == group.name {
2169 continue
2170 }
2171
2172 existing := c.moduleNames[name]
2173 if existing != nil {
2174 errs = append(errs,
2175 &BlueprintError{
2176 Err: fmt.Errorf("renaming module %q to %q conflicts with existing module",
2177 group.name, name),
2178 Pos: group.modules[0].pos,
2179 },
2180 &BlueprintError{
2181 Err: fmt.Errorf("<-- existing module defined here"),
2182 Pos: existing.modules[0].pos,
2183 },
2184 )
2185 continue
2186 }
2187
2188 c.moduleNames[name] = group
2189 delete(c.moduleNames, group.name)
2190 group.name = name
2191 }
2192
2193 return errs
2194}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002195
Colin Cross0b7e83e2016-05-17 14:58:05 -07002196func (c *Context) modulesFromName(name string) []*moduleInfo {
2197 if group := c.moduleNames[name]; group != nil {
2198 return group.modules
2199 }
2200 return nil
2201}
2202
Jamie Gennisc15544d2014-09-24 20:26:52 -07002203func (c *Context) sortedModuleNames() []string {
2204 if c.cachedSortedModuleNames == nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002205 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleNames))
2206 for moduleName := range c.moduleNames {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002207 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2208 moduleName)
2209 }
2210 sort.Strings(c.cachedSortedModuleNames)
2211 }
2212
2213 return c.cachedSortedModuleNames
2214}
2215
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002216func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002217 var module *moduleInfo
2218
2219 defer func() {
2220 if r := recover(); r != nil {
2221 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2222 funcName(visit), module))
2223 }
2224 }()
2225
Jamie Gennisc15544d2014-09-24 20:26:52 -07002226 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002227 modules := c.modulesFromName(moduleName)
2228 for _, module = range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002229 visit(module.logicModule)
2230 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002231 }
2232}
2233
2234func (c *Context) visitAllModulesIf(pred func(Module) bool,
2235 visit func(Module)) {
2236
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002237 var module *moduleInfo
2238
2239 defer func() {
2240 if r := recover(); r != nil {
2241 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2242 funcName(pred), funcName(visit), module))
2243 }
2244 }()
2245
Jamie Gennisc15544d2014-09-24 20:26:52 -07002246 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002247 modules := c.modulesFromName(moduleName)
2248 for _, module := range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002249 if pred(module.logicModule) {
2250 visit(module.logicModule)
2251 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002252 }
2253 }
2254}
2255
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002256func (c *Context) visitAllModuleVariants(module *moduleInfo,
2257 visit func(Module)) {
2258
2259 var variant *moduleInfo
2260
2261 defer func() {
2262 if r := recover(); r != nil {
2263 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2264 module, funcName(visit), variant))
2265 }
2266 }()
2267
2268 for _, variant = range module.group.modules {
2269 visit(variant.logicModule)
2270 }
2271}
2272
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002273func (c *Context) requireNinjaVersion(major, minor, micro int) {
2274 if major != 1 {
2275 panic("ninja version with major version != 1 not supported")
2276 }
2277 if c.requiredNinjaMinor < minor {
2278 c.requiredNinjaMinor = minor
2279 c.requiredNinjaMicro = micro
2280 }
2281 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2282 c.requiredNinjaMicro = micro
2283 }
2284}
2285
Colin Crossa2599452015-11-18 16:01:01 -08002286func (c *Context) setNinjaBuildDir(value *ninjaString) {
2287 if c.ninjaBuildDir == nil {
2288 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002289 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002290}
2291
2292func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002293 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002294
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002295 pkgs := make(map[string]*packageContext)
2296 pkgNames := make(map[*packageContext]string)
2297 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002298
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002299 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002300 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002301 // This is a built-in rule and has no package.
2302 return
2303 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002304 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002305 // We've already processed this package.
2306 return
2307 }
2308
Jamie Gennis2fb20952014-10-03 02:49:58 -07002309 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002310 if present {
2311 // Short name collision. Both this package and the one that's
2312 // already there need to use their full names. We leave the short
2313 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002314 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002315 longPkgNames[otherPkg] = true
2316 } else {
2317 // No collision so far. Tentatively set the package's name to be
2318 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002319 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002320 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002321 }
2322 }
2323
2324 // We try to give all packages their short name, but when we get collisions
2325 // we need to use the full unique package name.
2326 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002327 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002328 }
2329 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002330 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002331 }
2332 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002333 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002334 }
2335
2336 // Add the packages that had collisions using their full unique names. This
2337 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002338 for pctx := range longPkgNames {
2339 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002340 }
2341
Dan Willemsena481ae22015-12-18 15:18:03 -08002342 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2343 deps := []string{}
2344 for _, pkg := range pkgs {
2345 deps = append(deps, pkg.ninjaFileDeps...)
2346 }
2347
2348 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002349}
2350
2351func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002352 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002353
2354 visited := make(map[Variable]bool) // variables that were already checked
2355 checking := make(map[Variable]bool) // variables actively being checked
2356
2357 var check func(v Variable) []Variable
2358
2359 check = func(v Variable) []Variable {
2360 visited[v] = true
2361 checking[v] = true
2362 defer delete(checking, v)
2363
2364 value := variables[v]
2365 for _, dep := range value.variables {
2366 if checking[dep] {
2367 // This is a cycle.
2368 return []Variable{dep, v}
2369 }
2370
2371 if !visited[dep] {
2372 cycle := check(dep)
2373 if cycle != nil {
2374 if cycle[0] == v {
2375 // We are the "start" of the cycle, so we're responsible
2376 // for generating the errors. The cycle list is in
2377 // reverse order because all the 'check' calls append
2378 // their own module to the list.
2379 msgs := []string{"detected variable reference cycle:"}
2380
2381 // Iterate backwards through the cycle list.
2382 curName := v.fullName(pkgNames)
2383 curValue := value.Value(pkgNames)
2384 for i := len(cycle) - 1; i >= 0; i-- {
2385 next := cycle[i]
2386 nextName := next.fullName(pkgNames)
2387 nextValue := variables[next].Value(pkgNames)
2388
2389 msgs = append(msgs, fmt.Sprintf(
2390 " %q depends on %q", curName, nextName))
2391 msgs = append(msgs, fmt.Sprintf(
2392 " [%s = %s]", curName, curValue))
2393
2394 curName = nextName
2395 curValue = nextValue
2396 }
2397
2398 // Variable reference cycles are a programming error,
2399 // not the fault of the Blueprint file authors.
2400 panic(strings.Join(msgs, "\n"))
2401 } else {
2402 // We're not the "start" of the cycle, so we just append
2403 // our module to the list and return it.
2404 return append(cycle, v)
2405 }
2406 }
2407 }
2408 }
2409
2410 return nil
2411 }
2412
2413 for v := range variables {
2414 if !visited[v] {
2415 cycle := check(v)
2416 if cycle != nil {
2417 panic("inconceivable!")
2418 }
2419 }
2420 }
2421}
2422
Jamie Gennisaf435562014-10-27 22:34:56 -07002423// AllTargets returns a map all the build target names to the rule used to build
2424// them. This is the same information that is output by running 'ninja -t
2425// targets all'. If this is called before PrepareBuildActions successfully
2426// completes then ErrbuildActionsNotReady is returned.
2427func (c *Context) AllTargets() (map[string]string, error) {
2428 if !c.buildActionsReady {
2429 return nil, ErrBuildActionsNotReady
2430 }
2431
2432 targets := map[string]string{}
2433
2434 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002435 for _, module := range c.moduleInfo {
2436 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002437 ruleName := buildDef.Rule.fullName(c.pkgNames)
2438 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002439 outputValue, err := output.Eval(c.globalVariables)
2440 if err != nil {
2441 return nil, err
2442 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002443 targets[outputValue] = ruleName
2444 }
2445 }
2446 }
2447
2448 // Collect all the singleton build targets.
2449 for _, info := range c.singletonInfo {
2450 for _, buildDef := range info.actionDefs.buildDefs {
2451 ruleName := buildDef.Rule.fullName(c.pkgNames)
2452 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002453 outputValue, err := output.Eval(c.globalVariables)
2454 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002455 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002456 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002457 targets[outputValue] = ruleName
2458 }
2459 }
2460 }
2461
2462 return targets, nil
2463}
2464
Colin Crossa2599452015-11-18 16:01:01 -08002465func (c *Context) NinjaBuildDir() (string, error) {
2466 if c.ninjaBuildDir != nil {
2467 return c.ninjaBuildDir.Eval(c.globalVariables)
2468 } else {
2469 return "", nil
2470 }
2471}
2472
Colin Cross4572edd2015-05-13 14:36:24 -07002473// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2474// property structs returned by the factory for that module type.
2475func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2476 ret := make(map[string][]interface{})
2477 for moduleType, factory := range c.moduleFactories {
2478 _, ret[moduleType] = factory()
2479 }
2480
2481 return ret
2482}
2483
2484func (c *Context) ModuleName(logicModule Module) string {
2485 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002486 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002487}
2488
2489func (c *Context) ModuleDir(logicModule Module) string {
2490 module := c.moduleInfo[logicModule]
2491 return filepath.Dir(module.relBlueprintsFile)
2492}
2493
Colin Cross8c602f72015-12-17 18:02:11 -08002494func (c *Context) ModuleSubDir(logicModule Module) string {
2495 module := c.moduleInfo[logicModule]
2496 return module.variantName
2497}
2498
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002499func (c *Context) ModuleType(logicModule Module) string {
2500 module := c.moduleInfo[logicModule]
2501 return module.typeName
2502}
2503
Colin Cross4572edd2015-05-13 14:36:24 -07002504func (c *Context) BlueprintFile(logicModule Module) string {
2505 module := c.moduleInfo[logicModule]
2506 return module.relBlueprintsFile
2507}
2508
2509func (c *Context) ModuleErrorf(logicModule Module, format string,
2510 args ...interface{}) error {
2511
2512 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002513 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002514 Err: fmt.Errorf(format, args...),
2515 Pos: module.pos,
2516 }
2517}
2518
2519func (c *Context) VisitAllModules(visit func(Module)) {
2520 c.visitAllModules(visit)
2521}
2522
2523func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2524 visit func(Module)) {
2525
2526 c.visitAllModulesIf(pred, visit)
2527}
2528
2529func (c *Context) VisitDepsDepthFirst(module Module,
2530 visit func(Module)) {
2531
Colin Crossbafd5f52016-08-06 22:52:01 -07002532 topModule := c.moduleInfo[module]
2533
2534 var visiting *moduleInfo
2535
2536 defer func() {
2537 if r := recover(); r != nil {
2538 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2539 topModule, funcName(visit), visiting))
2540 }
2541 }()
2542
2543 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2544 visiting = dep.module
2545 visit(dep.module.logicModule)
2546 })
Colin Cross4572edd2015-05-13 14:36:24 -07002547}
2548
2549func (c *Context) VisitDepsDepthFirstIf(module Module,
2550 pred func(Module) bool, visit func(Module)) {
2551
Colin Crossbafd5f52016-08-06 22:52:01 -07002552 topModule := c.moduleInfo[module]
2553
2554 var visiting *moduleInfo
2555
2556 defer func() {
2557 if r := recover(); r != nil {
2558 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2559 topModule, funcName(pred), funcName(visit), visiting))
2560 }
2561 }()
2562
2563 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2564 if pred(dep.module.logicModule) {
2565 visiting = dep.module
2566 visit(dep.module.logicModule)
2567 }
2568 })
Colin Cross4572edd2015-05-13 14:36:24 -07002569}
2570
Colin Cross24ad5872015-11-17 16:22:29 -08002571func (c *Context) PrimaryModule(module Module) Module {
2572 return c.moduleInfo[module].group.modules[0].logicModule
2573}
2574
2575func (c *Context) FinalModule(module Module) Module {
2576 modules := c.moduleInfo[module].group.modules
2577 return modules[len(modules)-1].logicModule
2578}
2579
2580func (c *Context) VisitAllModuleVariants(module Module,
2581 visit func(Module)) {
2582
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002583 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002584}
2585
Jamie Gennisd4e10182014-06-12 20:06:50 -07002586// WriteBuildFile writes the Ninja manifeset text for the generated build
2587// actions to w. If this is called before PrepareBuildActions successfully
2588// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002589func (c *Context) WriteBuildFile(w io.Writer) error {
2590 if !c.buildActionsReady {
2591 return ErrBuildActionsNotReady
2592 }
2593
2594 nw := newNinjaWriter(w)
2595
2596 err := c.writeBuildFileHeader(nw)
2597 if err != nil {
2598 return err
2599 }
2600
2601 err = c.writeNinjaRequiredVersion(nw)
2602 if err != nil {
2603 return err
2604 }
2605
2606 // TODO: Group the globals by package.
2607
2608 err = c.writeGlobalVariables(nw)
2609 if err != nil {
2610 return err
2611 }
2612
2613 err = c.writeGlobalPools(nw)
2614 if err != nil {
2615 return err
2616 }
2617
2618 err = c.writeBuildDir(nw)
2619 if err != nil {
2620 return err
2621 }
2622
2623 err = c.writeGlobalRules(nw)
2624 if err != nil {
2625 return err
2626 }
2627
2628 err = c.writeAllModuleActions(nw)
2629 if err != nil {
2630 return err
2631 }
2632
2633 err = c.writeAllSingletonActions(nw)
2634 if err != nil {
2635 return err
2636 }
2637
2638 return nil
2639}
2640
Jamie Gennisc15544d2014-09-24 20:26:52 -07002641type pkgAssociation struct {
2642 PkgName string
2643 PkgPath string
2644}
2645
2646type pkgAssociationSorter struct {
2647 pkgs []pkgAssociation
2648}
2649
2650func (s *pkgAssociationSorter) Len() int {
2651 return len(s.pkgs)
2652}
2653
2654func (s *pkgAssociationSorter) Less(i, j int) bool {
2655 iName := s.pkgs[i].PkgName
2656 jName := s.pkgs[j].PkgName
2657 return iName < jName
2658}
2659
2660func (s *pkgAssociationSorter) Swap(i, j int) {
2661 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2662}
2663
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002664func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2665 headerTemplate := template.New("fileHeader")
2666 _, err := headerTemplate.Parse(fileHeaderTemplate)
2667 if err != nil {
2668 // This is a programming error.
2669 panic(err)
2670 }
2671
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002672 var pkgs []pkgAssociation
2673 maxNameLen := 0
2674 for pkg, name := range c.pkgNames {
2675 pkgs = append(pkgs, pkgAssociation{
2676 PkgName: name,
2677 PkgPath: pkg.pkgPath,
2678 })
2679 if len(name) > maxNameLen {
2680 maxNameLen = len(name)
2681 }
2682 }
2683
2684 for i := range pkgs {
2685 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2686 }
2687
Jamie Gennisc15544d2014-09-24 20:26:52 -07002688 sort.Sort(&pkgAssociationSorter{pkgs})
2689
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002690 params := map[string]interface{}{
2691 "Pkgs": pkgs,
2692 }
2693
2694 buf := bytes.NewBuffer(nil)
2695 err = headerTemplate.Execute(buf, params)
2696 if err != nil {
2697 return err
2698 }
2699
2700 return nw.Comment(buf.String())
2701}
2702
2703func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2704 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2705 c.requiredNinjaMicro)
2706
2707 err := nw.Assign("ninja_required_version", value)
2708 if err != nil {
2709 return err
2710 }
2711
2712 return nw.BlankLine()
2713}
2714
2715func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002716 if c.ninjaBuildDir != nil {
2717 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002718 if err != nil {
2719 return err
2720 }
2721
2722 err = nw.BlankLine()
2723 if err != nil {
2724 return err
2725 }
2726 }
2727 return nil
2728}
2729
Jamie Gennisc15544d2014-09-24 20:26:52 -07002730type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002731 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002732}
2733
Jamie Gennisc15544d2014-09-24 20:26:52 -07002734type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002735 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002736 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002737}
2738
Jamie Gennisc15544d2014-09-24 20:26:52 -07002739func (s *globalEntitySorter) Len() int {
2740 return len(s.entities)
2741}
2742
2743func (s *globalEntitySorter) Less(i, j int) bool {
2744 iName := s.entities[i].fullName(s.pkgNames)
2745 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002746 return iName < jName
2747}
2748
Jamie Gennisc15544d2014-09-24 20:26:52 -07002749func (s *globalEntitySorter) Swap(i, j int) {
2750 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002751}
2752
2753func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2754 visited := make(map[Variable]bool)
2755
2756 var walk func(v Variable) error
2757 walk = func(v Variable) error {
2758 visited[v] = true
2759
2760 // First visit variables on which this variable depends.
2761 value := c.globalVariables[v]
2762 for _, dep := range value.variables {
2763 if !visited[dep] {
2764 err := walk(dep)
2765 if err != nil {
2766 return err
2767 }
2768 }
2769 }
2770
2771 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2772 if err != nil {
2773 return err
2774 }
2775
2776 err = nw.BlankLine()
2777 if err != nil {
2778 return err
2779 }
2780
2781 return nil
2782 }
2783
Jamie Gennisc15544d2014-09-24 20:26:52 -07002784 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2785 for variable := range c.globalVariables {
2786 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002787 }
2788
Jamie Gennisc15544d2014-09-24 20:26:52 -07002789 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002790
Jamie Gennisc15544d2014-09-24 20:26:52 -07002791 for _, entity := range globalVariables {
2792 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002793 if !visited[v] {
2794 err := walk(v)
2795 if err != nil {
2796 return nil
2797 }
2798 }
2799 }
2800
2801 return nil
2802}
2803
2804func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002805 globalPools := make([]globalEntity, 0, len(c.globalPools))
2806 for pool := range c.globalPools {
2807 globalPools = append(globalPools, pool)
2808 }
2809
2810 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2811
2812 for _, entity := range globalPools {
2813 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002814 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002815 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002816 err := def.WriteTo(nw, name)
2817 if err != nil {
2818 return err
2819 }
2820
2821 err = nw.BlankLine()
2822 if err != nil {
2823 return err
2824 }
2825 }
2826
2827 return nil
2828}
2829
2830func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002831 globalRules := make([]globalEntity, 0, len(c.globalRules))
2832 for rule := range c.globalRules {
2833 globalRules = append(globalRules, rule)
2834 }
2835
2836 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2837
2838 for _, entity := range globalRules {
2839 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002840 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002841 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002842 err := def.WriteTo(nw, name, c.pkgNames)
2843 if err != nil {
2844 return err
2845 }
2846
2847 err = nw.BlankLine()
2848 if err != nil {
2849 return err
2850 }
2851 }
2852
2853 return nil
2854}
2855
Colin Cross2c1f3d12016-04-11 15:47:28 -07002856type depSorter []depInfo
2857
2858func (s depSorter) Len() int {
2859 return len(s)
2860}
2861
2862func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002863 iName := s[i].module.Name()
2864 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07002865 if iName == jName {
2866 iName = s[i].module.variantName
2867 jName = s[j].module.variantName
2868 }
2869 return iName < jName
2870}
2871
2872func (s depSorter) Swap(i, j int) {
2873 s[i], s[j] = s[j], s[i]
2874}
2875
Colin Crossab6d7902015-03-11 16:17:52 -07002876type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002877
Colin Crossab6d7902015-03-11 16:17:52 -07002878func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002879 return len(s)
2880}
2881
Colin Crossab6d7902015-03-11 16:17:52 -07002882func (s moduleSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002883 iName := s[i].Name()
2884 jName := s[j].Name()
Colin Crossab6d7902015-03-11 16:17:52 -07002885 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002886 iName = s[i].variantName
2887 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002888 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002889 return iName < jName
2890}
2891
Colin Crossab6d7902015-03-11 16:17:52 -07002892func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002893 s[i], s[j] = s[j], s[i]
2894}
2895
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002896func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2897 headerTemplate := template.New("moduleHeader")
2898 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2899 if err != nil {
2900 // This is a programming error.
2901 panic(err)
2902 }
2903
Colin Crossab6d7902015-03-11 16:17:52 -07002904 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2905 for _, module := range c.moduleInfo {
2906 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002907 }
Colin Crossab6d7902015-03-11 16:17:52 -07002908 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002909
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002910 buf := bytes.NewBuffer(nil)
2911
Colin Crossab6d7902015-03-11 16:17:52 -07002912 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002913 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2914 continue
2915 }
2916
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002917 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002918
2919 // In order to make the bootstrap build manifest independent of the
2920 // build dir we need to output the Blueprints file locations in the
2921 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002922 relPos := module.pos
2923 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002924
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002925 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002926 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002927 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2928 factoryName := factoryFunc.Name()
2929
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002930 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07002931 "name": module.Name(),
2932 "typeName": module.typeName,
2933 "goFactory": factoryName,
2934 "pos": relPos,
2935 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002936 }
2937 err = headerTemplate.Execute(buf, infoMap)
2938 if err != nil {
2939 return err
2940 }
2941
2942 err = nw.Comment(buf.String())
2943 if err != nil {
2944 return err
2945 }
2946
2947 err = nw.BlankLine()
2948 if err != nil {
2949 return err
2950 }
2951
Colin Crossab6d7902015-03-11 16:17:52 -07002952 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002953 if err != nil {
2954 return err
2955 }
2956
2957 err = nw.BlankLine()
2958 if err != nil {
2959 return err
2960 }
2961 }
2962
2963 return nil
2964}
2965
2966func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2967 headerTemplate := template.New("singletonHeader")
2968 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2969 if err != nil {
2970 // This is a programming error.
2971 panic(err)
2972 }
2973
2974 buf := bytes.NewBuffer(nil)
2975
Yuchen Wub9103ef2015-08-25 17:58:17 -07002976 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002977 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2978 continue
2979 }
2980
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002981 // Get the name of the factory function for the module.
2982 factory := info.factory
2983 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2984 factoryName := factoryFunc.Name()
2985
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002986 buf.Reset()
2987 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002988 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002989 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002990 }
2991 err = headerTemplate.Execute(buf, infoMap)
2992 if err != nil {
2993 return err
2994 }
2995
2996 err = nw.Comment(buf.String())
2997 if err != nil {
2998 return err
2999 }
3000
3001 err = nw.BlankLine()
3002 if err != nil {
3003 return err
3004 }
3005
3006 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3007 if err != nil {
3008 return err
3009 }
3010
3011 err = nw.BlankLine()
3012 if err != nil {
3013 return err
3014 }
3015 }
3016
3017 return nil
3018}
3019
3020func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3021 defs *localBuildActions) error {
3022
3023 // Write the local variable assignments.
3024 for _, v := range defs.variables {
3025 // A localVariable doesn't need the package names or config to
3026 // determine its name or value.
3027 name := v.fullName(nil)
3028 value, err := v.value(nil)
3029 if err != nil {
3030 panic(err)
3031 }
3032 err = nw.Assign(name, value.Value(c.pkgNames))
3033 if err != nil {
3034 return err
3035 }
3036 }
3037
3038 if len(defs.variables) > 0 {
3039 err := nw.BlankLine()
3040 if err != nil {
3041 return err
3042 }
3043 }
3044
3045 // Write the local rules.
3046 for _, r := range defs.rules {
3047 // A localRule doesn't need the package names or config to determine
3048 // its name or definition.
3049 name := r.fullName(nil)
3050 def, err := r.def(nil)
3051 if err != nil {
3052 panic(err)
3053 }
3054
3055 err = def.WriteTo(nw, name, c.pkgNames)
3056 if err != nil {
3057 return err
3058 }
3059
3060 err = nw.BlankLine()
3061 if err != nil {
3062 return err
3063 }
3064 }
3065
3066 // Write the build definitions.
3067 for _, buildDef := range defs.buildDefs {
3068 err := buildDef.WriteTo(nw, c.pkgNames)
3069 if err != nil {
3070 return err
3071 }
3072
3073 if len(buildDef.Args) > 0 {
3074 err = nw.BlankLine()
3075 if err != nil {
3076 return err
3077 }
3078 }
3079 }
3080
3081 return nil
3082}
3083
Colin Cross65569e42015-03-10 20:08:19 -07003084func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3085 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003086 if a == b {
3087 return false
3088 }
Colin Cross65569e42015-03-10 20:08:19 -07003089 for _, l := range list {
3090 if l == a {
3091 found = true
3092 } else if l == b {
3093 return found
3094 }
3095 }
3096
3097 missing := a
3098 if found {
3099 missing = b
3100 }
3101 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3102}
3103
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003104type panicError struct {
3105 panic interface{}
3106 stack []byte
3107 in string
3108}
3109
3110func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3111 buf := make([]byte, 4096)
3112 count := runtime.Stack(buf, false)
3113 return panicError{
3114 panic: panic,
3115 in: fmt.Sprintf(in, a...),
3116 stack: buf[:count],
3117 }
3118}
3119
3120func (p panicError) Error() string {
3121 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3122}
3123
3124func (p *panicError) addIn(in string) {
3125 p.in += " in " + in
3126}
3127
3128func funcName(f interface{}) string {
3129 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3130}
3131
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003132var fileHeaderTemplate = `******************************************************************************
3133*** This file is generated and should not be edited ***
3134******************************************************************************
3135{{if .Pkgs}}
3136This file contains variables, rules, and pools with name prefixes indicating
3137they were generated by the following Go packages:
3138{{range .Pkgs}}
3139 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3140
3141`
3142
3143var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003144Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003145Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003146Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003147Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003148Defined: {{.pos}}
3149`
3150
3151var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3152Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003153Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003154`