blob: a2b089022d2605a1063309f30705802723741797 [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
68 moduleGroups map[string]*moduleGroup
69 moduleInfo map[Module]*moduleInfo
70 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070071 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070072 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070073 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070074 variantMutatorNames []string
75 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070076
77 dependenciesReady bool // set to true on a successful ResolveDependencies
78 buildActionsReady bool // set to true on a successful PrepareBuildActions
79
80 // set by SetIgnoreUnknownModuleTypes
81 ignoreUnknownModuleTypes bool
82
Colin Cross036a1df2015-12-17 15:49:30 -080083 // set by SetAllowMissingDependencies
84 allowMissingDependencies bool
85
Jamie Gennis1bc967e2014-05-27 16:34:41 -070086 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080087 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070088 globalVariables map[Variable]*ninjaString
89 globalPools map[Pool]*poolDef
90 globalRules map[Rule]*ruleDef
91
92 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080093 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070094 requiredNinjaMajor int // For the ninja_required_version variable
95 requiredNinjaMinor int // For the ninja_required_version variable
96 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070097
98 // set lazily by sortedModuleNames
99 cachedSortedModuleNames []string
Colin Crossd7b0f602016-06-02 15:30:20 -0700100
101 fs fileSystem
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102}
103
Jamie Gennisd4e10182014-06-12 20:06:50 -0700104// An Error describes a problem that was encountered that is related to a
105// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700106type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700107 Err error // the error that occurred
108 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109}
110
111type localBuildActions struct {
112 variables []*localVariable
113 rules []*localRule
114 buildDefs []*buildDef
115}
116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700118 name string
119 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700120
Colin Crossbbfa51a2014-12-17 16:12:41 -0800121 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122}
123
Colin Crossbbfa51a2014-12-17 16:12:41 -0800124type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700125 // set during Parse
126 typeName string
127 relBlueprintsFile string
128 pos scanner.Position
129 propertyPos map[string]scanner.Position
130 properties struct {
131 Name string
132 Deps []string
133 }
134
Colin Crossf5e34b92015-03-13 16:02:36 -0700135 variantName string
136 variant variationMap
137 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700138
Colin Crossc9028482014-12-18 16:28:54 -0800139 logicModule Module
140 group *moduleGroup
141 moduleProperties []interface{}
142
143 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700144 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800145 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800146
Colin Cross7addea32015-03-11 15:43:52 -0700147 // set during updateDependencies
148 reverseDeps []*moduleInfo
149 depsCount int
150
151 // used by parallelVisitAllBottomUp
152 waitingCount int
153
Colin Crossc9028482014-12-18 16:28:54 -0800154 // set during each runMutator
155 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700156
157 // set during PrepareBuildActions
158 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800159}
160
Colin Cross2c1f3d12016-04-11 15:47:28 -0700161type depInfo struct {
162 module *moduleInfo
163 tag DependencyTag
164}
165
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800166func (module *moduleInfo) String() string {
167 s := fmt.Sprintf("module %q", module.properties.Name)
168 if module.variantName != "" {
169 s += fmt.Sprintf(" variant %q", module.variantName)
170 }
171 return s
172}
173
Colin Crossf5e34b92015-03-13 16:02:36 -0700174// A Variation is a way that a variant of a module differs from other variants of the same module.
175// For example, two variants of the same module might have Variation{"arch","arm"} and
176// Variation{"arch","arm64"}
177type Variation struct {
178 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700179 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700180 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
181 // "shared" or "static" for link.
182 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700183}
184
Colin Crossf5e34b92015-03-13 16:02:36 -0700185// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
186type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700187
Colin Crossf5e34b92015-03-13 16:02:36 -0700188func (vm variationMap) clone() variationMap {
189 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700190 for k, v := range vm {
191 newVm[k] = v
192 }
193
194 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800195}
196
Colin Cross89486232015-05-08 11:14:54 -0700197// Compare this variationMap to another one. Returns true if the every entry in this map
198// is either the same in the other map or doesn't exist in the other map.
199func (vm variationMap) subset(other variationMap) bool {
200 for k, v1 := range vm {
201 if v2, ok := other[k]; ok && v1 != v2 {
202 return false
203 }
204 }
205 return true
206}
207
Colin Crossf5e34b92015-03-13 16:02:36 -0700208func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700209 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800210}
211
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700212type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700213 // set during RegisterSingletonType
214 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700215 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700216 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700217
218 // set during PrepareBuildActions
219 actionDefs localBuildActions
220}
221
Colin Crossc9028482014-12-18 16:28:54 -0800222type mutatorInfo struct {
223 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800224 topDownMutator TopDownMutator
225 bottomUpMutator BottomUpMutator
226 name string
Colin Crossc9028482014-12-18 16:28:54 -0800227}
228
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700229func (e *Error) Error() string {
230
231 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
232}
233
Jamie Gennisd4e10182014-06-12 20:06:50 -0700234// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700235// no module or singleton factories registered, so the RegisterModuleFactory and
236// RegisterSingletonFactory methods must be called before it can do anything
237// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700238func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700239 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800240 moduleFactories: make(map[string]ModuleFactory),
241 moduleGroups: make(map[string]*moduleGroup),
242 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800243 moduleNinjaNames: make(map[string]*moduleGroup),
Colin Crossd7b0f602016-06-02 15:30:20 -0700244 fs: fs,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700245 }
Colin Cross763b6f12015-10-29 15:32:56 -0700246
247 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
248
249 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700250}
251
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700252// A ModuleFactory function creates a new Module object. See the
253// Context.RegisterModuleType method for details about how a registered
254// ModuleFactory is used by a Context.
255type ModuleFactory func() (m Module, propertyStructs []interface{})
256
Jamie Gennisd4e10182014-06-12 20:06:50 -0700257// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700258// Blueprints file) with a Module factory function. When the given module type
259// name is encountered in a Blueprints file during parsing, the Module factory
260// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800261// generation for the module. If a Mutator splits a module into multiple variants,
262// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700263//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700264// The module type names given here must be unique for the context. The factory
265// function should be a named function so that its package and name can be
266// included in the generated Ninja file for debugging purposes.
267//
268// The factory function returns two values. The first is the newly created
269// Module object. The second is a slice of pointers to that Module object's
270// properties structs. Each properties struct is examined when parsing a module
271// definition of this type in a Blueprints file. Exported fields of the
272// properties structs are automatically set to the property values specified in
273// the Blueprints file. The properties struct field names determine the name of
274// the Blueprints file properties that are used - the Blueprints property name
275// matches that of the properties struct field name with the first letter
276// converted to lower-case.
277//
278// The fields of the properties struct must be either []string, a string, or
279// bool. The Context will panic if a Module gets instantiated with a properties
280// struct containing a field that is not one these supported types.
281//
282// Any properties that appear in the Blueprints files that are not built-in
283// module properties (such as "name" and "deps") and do not have a corresponding
284// field in the returned module properties struct result in an error during the
285// Context's parse phase.
286//
287// As an example, the follow code:
288//
289// type myModule struct {
290// properties struct {
291// Foo string
292// Bar []string
293// }
294// }
295//
296// func NewMyModule() (blueprint.Module, []interface{}) {
297// module := new(myModule)
298// properties := &module.properties
299// return module, []interface{}{properties}
300// }
301//
302// func main() {
303// ctx := blueprint.NewContext()
304// ctx.RegisterModuleType("my_module", NewMyModule)
305// // ...
306// }
307//
308// would support parsing a module defined in a Blueprints file as follows:
309//
310// my_module {
311// name: "myName",
312// foo: "my foo string",
313// bar: ["my", "bar", "strings"],
314// }
315//
Colin Cross7ad621c2015-01-07 16:22:45 -0800316// The factory function may be called from multiple goroutines. Any accesses
317// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700318func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
319 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700320 panic(errors.New("module type name is already registered"))
321 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700322 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700323}
324
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700325// A SingletonFactory function creates a new Singleton object. See the
326// Context.RegisterSingletonType method for details about how a registered
327// SingletonFactory is used by a Context.
328type SingletonFactory func() Singleton
329
330// RegisterSingletonType registers a singleton type that will be invoked to
331// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700332// and invoked exactly once as part of the generate phase. Each registered
333// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700334//
335// The singleton type names given here must be unique for the context. The
336// factory function should be a named function so that its package and name can
337// be included in the generated Ninja file for debugging purposes.
338func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700339 for _, s := range c.singletonInfo {
340 if s.name == name {
341 panic(errors.New("singleton name is already registered"))
342 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700343 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700344
Yuchen Wub9103ef2015-08-25 17:58:17 -0700345 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700346 factory: factory,
347 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700348 name: name,
349 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700350}
351
352func singletonPkgPath(singleton Singleton) string {
353 typ := reflect.TypeOf(singleton)
354 for typ.Kind() == reflect.Ptr {
355 typ = typ.Elem()
356 }
357 return typ.PkgPath()
358}
359
360func singletonTypeName(singleton Singleton) string {
361 typ := reflect.TypeOf(singleton)
362 for typ.Kind() == reflect.Ptr {
363 typ = typ.Elem()
364 }
365 return typ.PkgPath() + "." + typ.Name()
366}
367
Colin Crossc9028482014-12-18 16:28:54 -0800368// RegisterTopDownMutator registers a mutator that will be invoked to propagate
369// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700370// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
371// once per Module, and is invoked on a module before being invoked on any of its
372// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800373//
Colin Cross65569e42015-03-10 20:08:19 -0700374// The mutator type names given here must be unique to all top down mutators in
375// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800376func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
377 for _, m := range c.mutatorInfo {
378 if m.name == name && m.topDownMutator != nil {
379 panic(fmt.Errorf("mutator name %s is already registered", name))
380 }
381 }
382
383 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
384 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800385 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800386 })
387}
388
389// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700390// Modules into variants. Each registered mutator is invoked in registration
391// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
392// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800393//
Colin Cross65569e42015-03-10 20:08:19 -0700394// The mutator type names given here must be unique to all bottom up or early
395// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800396func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700397 for _, m := range c.variantMutatorNames {
398 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800399 panic(fmt.Errorf("mutator name %s is already registered", name))
400 }
401 }
402
403 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
404 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800405 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800406 })
Colin Cross65569e42015-03-10 20:08:19 -0700407
408 c.variantMutatorNames = append(c.variantMutatorNames, name)
409}
410
411// RegisterEarlyMutator registers a mutator that will be invoked to split
412// Modules into multiple variant Modules before any dependencies have been
413// created. Each registered mutator is invoked in registration order once
414// per Module (including each variant from previous early mutators). Module
415// order is unpredictable.
416//
417// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700418// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700419//
420// The mutator type names given here must be unique to all bottom up or early
421// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700422//
423// Deprecated, use a BottomUpMutator instead. The only difference between
424// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
425// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700426func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
427 for _, m := range c.variantMutatorNames {
428 if m == name {
429 panic(fmt.Errorf("mutator name %s is already registered", name))
430 }
431 }
432
Colin Crossf8b50422016-08-10 12:56:40 -0700433 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
434 bottomUpMutator: func(mctx BottomUpMutatorContext) {
435 mutator(mctx)
436 },
437 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700438 })
439
440 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800441}
442
Jamie Gennisd4e10182014-06-12 20:06:50 -0700443// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
444// where it encounters an unknown module type while parsing Blueprints files. By
445// default, the context will report unknown module types as an error. If this
446// method is called with ignoreUnknownModuleTypes set to true then the context
447// will silently ignore unknown module types.
448//
449// This method should generally not be used. It exists to facilitate the
450// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700451func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
452 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
453}
454
Colin Cross036a1df2015-12-17 15:49:30 -0800455// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
456// unresolved dependencies. If the module's GenerateBuildActions calls
457// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
458// for missing dependencies.
459func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
460 c.allowMissingDependencies = allowMissingDependencies
461}
462
Jamie Gennisd4e10182014-06-12 20:06:50 -0700463// Parse parses a single Blueprints file from r, creating Module objects for
464// each of the module definitions encountered. If the Blueprints file contains
465// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700466// searched for Blueprints files returned in the subBlueprints return value.
467// If the Blueprints file contains an assignment to the "build" variable, then
468// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700469//
470// rootDir specifies the path to the root directory of the source tree, while
471// filename specifies the path to the Blueprints file. These paths are used for
472// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800473func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700474 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700475 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700476
Jamie Gennisec701282014-06-12 20:06:31 -0700477 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700479 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700480 }
481
Colin Crossc0dbc552015-01-02 15:19:28 -0800482 scope = parser.NewScope(scope)
483 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800484 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700485 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700486 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700487 if len(errs) > 0 {
488 for i, err := range errs {
489 if parseErr, ok := err.(*parser.ParseError); ok {
490 err = &Error{
491 Err: parseErr.Err,
492 Pos: parseErr.Pos,
493 }
494 errs[i] = err
495 }
496 }
497
498 // If there were any parse errors don't bother trying to interpret the
499 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700500 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700501 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700502 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700503
Colin Cross6d8780f2015-07-10 17:51:55 -0700504 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700505 if err != nil {
506 errs = append(errs, err)
507 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700508
Colin Cross7f507402015-12-16 13:03:41 -0800509 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
510 if err != nil {
511 errs = append(errs, err)
512 }
513
Colin Cross6d8780f2015-07-10 17:51:55 -0700514 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700515 if err != nil {
516 errs = append(errs, err)
517 }
518
Colin Cross29394222015-04-27 13:18:21 -0700519 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
520
Colin Cross7f507402015-12-16 13:03:41 -0800521 var blueprints []string
522
523 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
524 blueprints = append(blueprints, newBlueprints...)
525 deps = append(deps, newDeps...)
526 errs = append(errs, newErrs...)
527
528 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
529 subBlueprintsName, false)
530 blueprints = append(blueprints, newBlueprints...)
531 deps = append(deps, newDeps...)
532 errs = append(errs, newErrs...)
533
534 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
535 optionalSubdirsPos, subBlueprintsName, true)
536 blueprints = append(blueprints, newBlueprints...)
537 deps = append(deps, newDeps...)
538 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800539
Colin Cross1fef5362015-04-20 16:50:54 -0700540 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
541 for i, b := range blueprints {
542 subBlueprintsAndScope[i] = stringAndScope{b, scope}
543 }
544
Colin Cross23d7aa12015-06-30 16:05:22 -0700545 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800546}
547
Colin Cross7ad621c2015-01-07 16:22:45 -0800548type stringAndScope struct {
549 string
550 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700551}
552
Jamie Gennisd4e10182014-06-12 20:06:50 -0700553// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
554// at rootFile. When it encounters a Blueprints file with a set of subdirs
555// listed it recursively parses any Blueprints files found in those
556// subdirectories.
557//
558// If no errors are encountered while parsing the files, the list of paths on
559// which the future output will depend is returned. This list will include both
560// Blueprints file paths as well as directory paths for cases where wildcard
561// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700562func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
563 errs []error) {
564
Colin Cross7ad621c2015-01-07 16:22:45 -0800565 c.dependenciesReady = false
566
Colin Cross23d7aa12015-06-30 16:05:22 -0700567 moduleCh := make(chan *moduleInfo)
568 errsCh := make(chan []error)
569 doneCh := make(chan struct{})
570 var numErrs uint32
571 var numGoroutines int32
572
573 // handler must be reentrant
574 handler := func(file *parser.File) {
575 if atomic.LoadUint32(&numErrs) > maxErrors {
576 return
577 }
578
579 atomic.AddInt32(&numGoroutines, 1)
580 go func() {
581 for _, def := range file.Defs {
582 var module *moduleInfo
583 var errs []error
584 switch def := def.(type) {
585 case *parser.Module:
586 module, errs = c.processModuleDef(def, file.Name)
587 case *parser.Assignment:
588 // Already handled via Scope object
589 default:
590 panic("unknown definition type")
591 }
592
593 if len(errs) > 0 {
594 atomic.AddUint32(&numErrs, uint32(len(errs)))
595 errsCh <- errs
596 } else if module != nil {
597 moduleCh <- module
598 }
599 }
600 doneCh <- struct{}{}
601 }()
602 }
603
604 atomic.AddInt32(&numGoroutines, 1)
605 go func() {
606 var errs []error
607 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
608 if len(errs) > 0 {
609 errsCh <- errs
610 }
611 doneCh <- struct{}{}
612 }()
613
614loop:
615 for {
616 select {
617 case newErrs := <-errsCh:
618 errs = append(errs, newErrs...)
619 case module := <-moduleCh:
620 newErrs := c.addModule(module)
621 if len(newErrs) > 0 {
622 errs = append(errs, newErrs...)
623 }
624 case <-doneCh:
625 n := atomic.AddInt32(&numGoroutines, -1)
626 if n == 0 {
627 break loop
628 }
629 }
630 }
631
632 return deps, errs
633}
634
635type FileHandler func(*parser.File)
636
637// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
638// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
639// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
640// it must be reentrant.
641//
642// If no errors are encountered while parsing the files, the list of paths on
643// which the future output will depend is returned. This list will include both
644// Blueprints file paths as well as directory paths for cases where wildcard
645// subdirs are found.
646func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
647 errs []error) {
648
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700649 rootDir := filepath.Dir(rootFile)
650
Colin Cross7ad621c2015-01-07 16:22:45 -0800651 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700652
Colin Cross7ad621c2015-01-07 16:22:45 -0800653 // Channels to receive data back from parseBlueprintsFile goroutines
654 blueprintsCh := make(chan stringAndScope)
655 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700656 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800657 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700658
Colin Cross7ad621c2015-01-07 16:22:45 -0800659 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
660 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700661
Colin Cross7ad621c2015-01-07 16:22:45 -0800662 // Number of outstanding goroutines to wait for
663 count := 0
664
665 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
666 count++
667 go func() {
668 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700669 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800670 doneCh <- struct{}{}
671 }()
672 }
673
674 tooManyErrors := false
675
676 startParseBlueprintsFile(rootFile, nil)
677
678loop:
679 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700680 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800681 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700682 }
683
Colin Cross7ad621c2015-01-07 16:22:45 -0800684 select {
685 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700686 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800687 case dep := <-depsCh:
688 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700689 case file := <-fileCh:
690 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800691 case blueprint := <-blueprintsCh:
692 if tooManyErrors {
693 continue
694 }
695 if blueprintsSet[blueprint.string] {
696 continue
697 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700698
Colin Cross7ad621c2015-01-07 16:22:45 -0800699 blueprintsSet[blueprint.string] = true
700 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
701 case <-doneCh:
702 count--
703 if count == 0 {
704 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700705 }
706 }
707 }
708
Colin Cross7ad621c2015-01-07 16:22:45 -0800709 return
710}
711
Colin Crossd7b0f602016-06-02 15:30:20 -0700712// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
713// filenames to contents stored as a byte slice.
714func (c *Context) MockFileSystem(files map[string][]byte) {
715 c.fs = &mockFS{
716 files: files,
717 }
718}
719
Colin Cross7ad621c2015-01-07 16:22:45 -0800720// parseBlueprintFile parses a single Blueprints file, returning any errors through
721// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
722// blueprintsCh, and any dependencies on Blueprints files or directories through
723// depsCh.
724func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700725 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800726 depsCh chan<- string) {
727
Colin Crossd7b0f602016-06-02 15:30:20 -0700728 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800729 if err != nil {
730 errsCh <- []error{err}
731 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700732 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700733 defer func() {
734 err = f.Close()
735 if err != nil {
736 errsCh <- []error{err}
737 }
738 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700739
Colin Cross23d7aa12015-06-30 16:05:22 -0700740 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800741 if len(errs) > 0 {
742 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700743 } else {
744 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800745 }
746
Colin Cross1fef5362015-04-20 16:50:54 -0700747 for _, b := range subBlueprints {
748 blueprintsCh <- b
749 }
750
751 for _, d := range deps {
752 depsCh <- d
753 }
Colin Cross1fef5362015-04-20 16:50:54 -0700754}
755
Colin Cross7f507402015-12-16 13:03:41 -0800756func (c *Context) findBuildBlueprints(dir string, build []string,
757 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
758
759 for _, file := range build {
760 globPattern := filepath.Join(dir, file)
761 matches, matchedDirs, err := pathtools.Glob(globPattern)
762 if err != nil {
763 errs = append(errs, &Error{
764 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
765 Pos: buildPos,
766 })
767 continue
768 }
769
770 if len(matches) == 0 {
771 errs = append(errs, &Error{
772 Err: fmt.Errorf("%q: not found", globPattern),
773 Pos: buildPos,
774 })
775 }
776
777 // Depend on all searched directories so we pick up future changes.
778 deps = append(deps, matchedDirs...)
779
780 for _, foundBlueprints := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700781 exists, dir, err := c.fs.Exists(foundBlueprints)
782 if err != nil {
783 errs = append(errs, err)
784 } else if !exists {
Colin Cross7f507402015-12-16 13:03:41 -0800785 errs = append(errs, &Error{
786 Err: fmt.Errorf("%q not found", foundBlueprints),
787 })
788 continue
Colin Crossd7b0f602016-06-02 15:30:20 -0700789 } else if dir {
Colin Cross7f507402015-12-16 13:03:41 -0800790 errs = append(errs, &Error{
791 Err: fmt.Errorf("%q is a directory", foundBlueprints),
792 })
793 continue
794 }
795
796 blueprints = append(blueprints, foundBlueprints)
797 }
798 }
799
800 return blueprints, deps, errs
801}
802
803func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
804 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800805
806 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700807 globPattern := filepath.Join(dir, subdir)
808 matches, matchedDirs, err := pathtools.Glob(globPattern)
809 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700810 errs = append(errs, &Error{
811 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
812 Pos: subdirsPos,
813 })
814 continue
815 }
816
Colin Cross7f507402015-12-16 13:03:41 -0800817 if len(matches) == 0 && !optional {
Colin Cross1fef5362015-04-20 16:50:54 -0700818 errs = append(errs, &Error{
819 Err: fmt.Errorf("%q: not found", globPattern),
820 Pos: subdirsPos,
821 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700822 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800823
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700824 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700825 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800826
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700827 for _, foundSubdir := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700828 exists, dir, subdirStatErr := c.fs.Exists(foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700829 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700830 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700831 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800832 }
833
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700834 // Skip files
Colin Crossd7b0f602016-06-02 15:30:20 -0700835 if !dir {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700836 continue
837 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800838
Colin Cross29394222015-04-27 13:18:21 -0700839 var subBlueprints string
840 if subBlueprintsName != "" {
841 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
Colin Crossd7b0f602016-06-02 15:30:20 -0700842 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700843 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700844
Colin Crossd7b0f602016-06-02 15:30:20 -0700845 if err == nil && (!exists || subBlueprints == "") {
Colin Cross29394222015-04-27 13:18:21 -0700846 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
Colin Crossd7b0f602016-06-02 15:30:20 -0700847 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700848 }
849
Colin Crossd7b0f602016-06-02 15:30:20 -0700850 if err != nil {
851 errs = append(errs, err)
852 continue
853 }
854
855 if !exists {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700856 // There is no Blueprints file in this subdirectory. We
857 // need to add the directory to the list of dependencies
858 // so that if someone adds a Blueprints file in the
859 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700860 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700861 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700862 deps = append(deps, subBlueprints)
863 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800864 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800865 }
866 }
Colin Cross1fef5362015-04-20 16:50:54 -0700867
Colin Cross1fef5362015-04-20 16:50:54 -0700868 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700869}
870
Colin Cross6d8780f2015-07-10 17:51:55 -0700871func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
872 if assignment, local := scope.Get(v); assignment == nil || !local {
873 return nil, scanner.Position{}, nil
874 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700875 switch value := assignment.Value.Eval().(type) {
876 case *parser.List:
877 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700878
Colin Crosse32cc802016-06-07 12:28:16 -0700879 for _, listValue := range value.Values {
880 s, ok := listValue.(*parser.String)
881 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700882 // The parser should not produce this.
883 panic("non-string value found in list")
884 }
885
Colin Crosse32cc802016-06-07 12:28:16 -0700886 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700887 }
888
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700889 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700890 case *parser.Bool, *parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700891 return nil, scanner.Position{}, &Error{
892 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700893 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700894 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700895 default:
896 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
897 }
898 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700899}
900
Colin Cross29394222015-04-27 13:18:21 -0700901func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700902 if assignment, _ := scope.Get(v); assignment == nil {
903 return "", scanner.Position{}, nil
904 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700905 switch value := assignment.Value.Eval().(type) {
906 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700907 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700908 case *parser.Bool, *parser.List:
Colin Cross29394222015-04-27 13:18:21 -0700909 return "", scanner.Position{}, &Error{
910 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700911 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -0700912 }
913 default:
914 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
915 }
916 }
Colin Cross29394222015-04-27 13:18:21 -0700917}
918
Colin Cross910242b2016-04-11 15:41:52 -0700919// Clones a build logic module by calling the factory method for its module type, and then cloning
920// property values. Any values stored in the module object that are not stored in properties
921// structs will be lost.
922func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
923 typeName := origModule.typeName
924 factory, ok := c.moduleFactories[typeName]
925 if !ok {
926 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
927 }
928
929 props := []interface{}{
930 &origModule.properties,
931 }
932 newLogicModule, newProperties := factory()
933
934 newProperties = append(props, newProperties...)
935
936 if len(newProperties) != len(origModule.moduleProperties) {
937 panic("mismatched properties array length in " + origModule.properties.Name)
938 }
939
940 for i := range newProperties {
941 dst := reflect.ValueOf(newProperties[i]).Elem()
942 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
943
944 proptools.CopyProperties(dst, src)
945 }
946
947 return newLogicModule, newProperties
948}
949
Colin Crossf5e34b92015-03-13 16:02:36 -0700950func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
951 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800952
Colin Crossf4d18a62015-03-18 17:43:15 -0700953 if len(variationNames) == 0 {
954 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400955 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700956 }
957
Colin Crossc9028482014-12-18 16:28:54 -0800958 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800959
Colin Cross174ae052015-03-03 17:37:03 -0800960 var errs []error
961
Colin Crossf5e34b92015-03-13 16:02:36 -0700962 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -0800963 var newLogicModule Module
964 var newProperties []interface{}
965
966 if i == 0 {
967 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700968 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
969 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -0700970 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -0800971 } else {
Colin Cross910242b2016-04-11 15:41:52 -0700972 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -0800973 }
974
Colin Crossf5e34b92015-03-13 16:02:36 -0700975 newVariant := origModule.variant.clone()
976 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800977
Colin Crossed342d92015-03-11 00:57:25 -0700978 m := *origModule
979 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -0700980 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -0700981 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700982 newModule.variant = newVariant
983 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700984 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800985
Colin Crosse7daa222015-03-11 14:35:41 -0700986 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700987 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700988 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700989 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700990 }
991
Colin Crossc9028482014-12-18 16:28:54 -0800992 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700993
994 // Insert the new variant into the global module map. If this is the first variant then
995 // it reuses logicModule from the original module, which causes this to replace the
996 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800997 c.moduleInfo[newModule.logicModule] = newModule
998
Colin Crossf5e34b92015-03-13 16:02:36 -0700999 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001000 if len(newErrs) > 0 {
1001 errs = append(errs, newErrs...)
1002 }
Colin Crossc9028482014-12-18 16:28:54 -08001003 }
1004
1005 // Mark original variant as invalid. Modules that depend on this module will still
1006 // depend on origModule, but we'll fix it when the mutator is called on them.
1007 origModule.logicModule = nil
1008 origModule.splitModules = newModules
1009
Colin Cross174ae052015-03-03 17:37:03 -08001010 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001011}
1012
Colin Crossf5e34b92015-03-13 16:02:36 -07001013func (c *Context) convertDepsToVariation(module *moduleInfo,
1014 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001015
Colin Crossc9028482014-12-18 16:28:54 -08001016 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001017 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001018 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001019 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001020 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001021 newDep = m
1022 break
1023 }
1024 }
1025 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -08001026 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -07001027 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001028 variationName, dep.module.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -07001029 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001030 })
1031 continue
Colin Crossc9028482014-12-18 16:28:54 -08001032 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001033 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001034 }
1035 }
Colin Cross174ae052015-03-03 17:37:03 -08001036
1037 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001038}
1039
Colin Crossf5e34b92015-03-13 16:02:36 -07001040func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001041 names := make([]string, 0, len(variant))
1042 for _, m := range c.variantMutatorNames {
1043 if v, ok := variant[m]; ok {
1044 names = append(names, m+":"+v)
1045 }
1046 }
1047
1048 return strings.Join(names, ", ")
1049}
1050
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001051func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001052 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001053
Colin Crossc32c4792016-06-09 15:52:30 -07001054 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001055 if !ok {
1056 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001057 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001058 }
1059
Colin Cross7ad621c2015-01-07 16:22:45 -08001060 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001061 &Error{
Colin Crossc32c4792016-06-09 15:52:30 -07001062 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1063 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001064 },
1065 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001066 }
1067
Colin Crossbbfa51a2014-12-17 16:12:41 -08001068 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001069
1070 module := &moduleInfo{
1071 logicModule: logicModule,
Colin Crossc32c4792016-06-09 15:52:30 -07001072 typeName: moduleDef.Type,
Jamie Gennisec701282014-06-12 20:06:31 -07001073 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001074 }
1075
Jamie Gennis87622922014-09-30 11:38:25 -07001076 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001077 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001078 }
1079 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001080 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001081
Jamie Gennis87622922014-09-30 11:38:25 -07001082 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001083 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001084 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001085 }
1086
Colin Crossc32c4792016-06-09 15:52:30 -07001087 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001088 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001089 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001090 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001091 }
1092
Colin Cross7ad621c2015-01-07 16:22:45 -08001093 return module, nil
1094}
1095
Colin Cross23d7aa12015-06-30 16:05:22 -07001096func (c *Context) addModule(module *moduleInfo) []error {
1097 name := module.properties.Name
1098 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001099
Colin Cross23d7aa12015-06-30 16:05:22 -07001100 if group, present := c.moduleGroups[name]; present {
1101 return []error{
1102 &Error{
1103 Err: fmt.Errorf("module %q already defined", name),
1104 Pos: module.pos,
1105 },
1106 &Error{
1107 Err: fmt.Errorf("<-- previous definition here"),
1108 Pos: group.modules[0].pos,
1109 },
Colin Crossed342d92015-03-11 00:57:25 -07001110 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001111 } else {
1112 ninjaName := toNinjaName(module.properties.Name)
1113
1114 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1115 // already exists
1116 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1117 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1118 }
1119
1120 group := &moduleGroup{
1121 name: module.properties.Name,
1122 ninjaName: ninjaName,
1123 modules: []*moduleInfo{module},
1124 }
1125 module.group = group
1126 c.moduleGroups[name] = group
1127 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001128 }
1129
Colin Cross23d7aa12015-06-30 16:05:22 -07001130 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001131}
1132
Jamie Gennisd4e10182014-06-12 20:06:50 -07001133// ResolveDependencies checks that the dependencies specified by all of the
1134// modules defined in the parsed Blueprints files are valid. This means that
1135// the modules depended upon are defined and that no circular dependencies
1136// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001137func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Crossf8b50422016-08-10 12:56:40 -07001138 errs := c.updateDependencies()
1139 if len(errs) > 0 {
1140 return errs
1141 }
1142
1143 errs = c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001144 if len(errs) > 0 {
1145 return errs
1146 }
1147
Colin Cross910242b2016-04-11 15:41:52 -07001148 c.cloneModules()
1149
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001150 c.dependenciesReady = true
1151 return nil
1152}
1153
Colin Cross763b6f12015-10-29 15:32:56 -07001154// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001155// DynamicDependerModule interface then this set consists of the union of those
1156// module names listed in its "deps" property, those returned by its
1157// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001158// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001159// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001160func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001161 ctx.AddDependency(ctx.Module(), nil, ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001162
Colin Cross763b6f12015-10-29 15:32:56 -07001163 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001164 func() {
1165 defer func() {
1166 if r := recover(); r != nil {
1167 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1168 }
1169 }()
1170 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001171
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001172 if ctx.Failed() {
1173 return
1174 }
Colin Cross763b6f12015-10-29 15:32:56 -07001175
Colin Cross2c1f3d12016-04-11 15:47:28 -07001176 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001177 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001178 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001179}
1180
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001181// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1182// and returns the matching module, or nil if one is not found.
1183func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1184 if len(group.modules) == 1 {
1185 return group.modules[0]
1186 } else {
1187 for _, m := range group.modules {
1188 if m.variant.equal(module.dependencyVariant) {
1189 return m
1190 }
1191 }
1192 }
1193
1194 return nil
1195}
1196
Colin Cross2c1f3d12016-04-11 15:47:28 -07001197func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001198 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001199 return []error{&Error{
1200 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001201 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001202 }}
1203 }
1204
Colin Cross2c1f3d12016-04-11 15:47:28 -07001205 depGroup, ok := c.moduleGroups[depName]
Colin Crossc9028482014-12-18 16:28:54 -08001206 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001207 if c.allowMissingDependencies {
1208 module.missingDeps = append(module.missingDeps, depName)
1209 return nil
1210 }
Colin Crossc9028482014-12-18 16:28:54 -08001211 return []error{&Error{
1212 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001213 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001214 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001215 }}
1216 }
1217
Colin Cross2c1f3d12016-04-11 15:47:28 -07001218 if m := c.findMatchingVariant(module, depGroup); m != nil {
1219 for _, dep := range module.directDeps {
1220 if m == dep.module {
1221 // TODO(ccross): what if adding a dependency with a different tag?
1222 return nil
1223 }
Colin Cross65569e42015-03-10 20:08:19 -07001224 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001225 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001226 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001227 }
Colin Crossc9028482014-12-18 16:28:54 -08001228
Colin Cross65569e42015-03-10 20:08:19 -07001229 return []error{&Error{
1230 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001231 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001232 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001233 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001234 }}
1235}
1236
Colin Cross8d8a7af2015-11-03 16:41:29 -08001237func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001238 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001239 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001240 Err: fmt.Errorf("%q depends on itself", destName),
1241 Pos: module.pos,
1242 }}
1243 }
1244
1245 destInfo, ok := c.moduleGroups[destName]
1246 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001247 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001248 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1249 module.properties.Name, destName),
1250 Pos: module.pos,
1251 }}
1252 }
1253
1254 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001255 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001256 }
1257
Colin Cross8d8a7af2015-11-03 16:41:29 -08001258 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001259 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1260 destName, module.properties.Name,
1261 c.prettyPrintVariant(module.dependencyVariant)),
1262 Pos: module.pos,
1263 }}
1264}
1265
Colin Crossf5e34b92015-03-13 16:02:36 -07001266func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001267 tag DependencyTag, depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001268
Colin Cross2c1f3d12016-04-11 15:47:28 -07001269 depGroup, ok := c.moduleGroups[depName]
Colin Cross65569e42015-03-10 20:08:19 -07001270 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001271 if c.allowMissingDependencies {
1272 module.missingDeps = append(module.missingDeps, depName)
1273 return nil
1274 }
Colin Cross65569e42015-03-10 20:08:19 -07001275 return []error{&Error{
1276 Err: fmt.Errorf("%q depends on undefined module %q",
1277 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001278 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001279 }}
1280 }
1281
1282 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1283 // compare the strings because the result won't be in mutator registration order.
1284 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001285 var newVariant variationMap
1286 if !far {
1287 newVariant = module.dependencyVariant.clone()
1288 } else {
1289 newVariant = make(variationMap)
1290 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001291 for _, v := range variations {
1292 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001293 }
1294
Colin Cross2c1f3d12016-04-11 15:47:28 -07001295 for _, m := range depGroup.modules {
Colin Cross89486232015-05-08 11:14:54 -07001296 var found bool
1297 if far {
1298 found = m.variant.subset(newVariant)
1299 } else {
1300 found = m.variant.equal(newVariant)
1301 }
1302 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001303 if module == m {
1304 return []error{&Error{
1305 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001306 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001307 }}
1308 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001309 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001310 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001311 // run GenerateBuildActions in order for the variants of a module
Colin Cross2c1f3d12016-04-11 15:47:28 -07001312 if depGroup == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross65569e42015-03-10 20:08:19 -07001313 return []error{&Error{
1314 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001315 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001316 }}
1317 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001318 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001319 return nil
1320 }
1321 }
1322
1323 return []error{&Error{
1324 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001325 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001326 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001327 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001328 }}
Colin Crossc9028482014-12-18 16:28:54 -08001329}
1330
Colin Crossf1875462016-04-11 17:33:13 -07001331func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1332 from, to Module) {
1333
1334 var fromInfo, toInfo *moduleInfo
1335 for _, m := range origModule.splitModules {
1336 if m.logicModule == from {
1337 fromInfo = m
1338 }
1339 if m.logicModule == to {
1340 toInfo = m
1341 if fromInfo != nil {
1342 panic(fmt.Errorf("%q depends on later version of itself", origModule.properties.Name))
1343 }
1344 }
1345 }
1346
1347 if fromInfo == nil || toInfo == nil {
1348 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
1349 origModule.properties.Name))
1350 }
1351
1352 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
1353}
1354
Colin Cross7addea32015-03-11 15:43:52 -07001355func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1356 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001357 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001358 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001359
Colin Cross7addea32015-03-11 15:43:52 -07001360 for _, module := range c.modulesSorted {
1361 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001362 }
1363
Colin Cross7addea32015-03-11 15:43:52 -07001364 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001365 count++
1366 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001367 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001368 if ret {
1369 cancel = true
1370 }
Colin Cross7addea32015-03-11 15:43:52 -07001371 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001372 }()
1373 }
1374
Colin Cross7addea32015-03-11 15:43:52 -07001375 for _, module := range c.modulesSorted {
1376 if module.waitingCount == 0 {
1377 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001378 }
1379 }
1380
Colin Cross11e3b0d2015-02-04 10:41:00 -08001381 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001382 select {
Colin Cross7addea32015-03-11 15:43:52 -07001383 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001384 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001385 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001386 parent.waitingCount--
1387 if parent.waitingCount == 0 {
1388 visitOne(parent)
1389 }
Colin Cross691a60d2015-01-07 18:08:56 -08001390 }
1391 }
1392 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001393 }
1394 }
1395}
1396
1397// updateDependencies recursively walks the module dependency graph and updates
1398// additional fields based on the dependencies. It builds a sorted list of modules
1399// such that dependencies of a module always appear first, and populates reverse
1400// dependency links and counts of total dependencies. It also reports errors when
1401// it encounters dependency cycles. This should called after resolveDependencies,
1402// as well as after any mutator pass has called addDependency
1403func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001404 visited := make(map[*moduleInfo]bool) // modules that were already checked
1405 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001406
Colin Cross7addea32015-03-11 15:43:52 -07001407 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001408
Colin Cross7addea32015-03-11 15:43:52 -07001409 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001410
Colin Cross7addea32015-03-11 15:43:52 -07001411 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001412 // We are the "start" of the cycle, so we're responsible
1413 // for generating the errors. The cycle list is in
1414 // reverse order because all the 'check' calls append
1415 // their own module to the list.
1416 errs = append(errs, &Error{
1417 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001418 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001419 })
1420
1421 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001422 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001423 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001424 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001425 errs = append(errs, &Error{
1426 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001427 curModule.properties.Name,
1428 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001429 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001430 })
Colin Cross7addea32015-03-11 15:43:52 -07001431 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001432 }
1433 }
1434
Colin Cross7addea32015-03-11 15:43:52 -07001435 check = func(module *moduleInfo) []*moduleInfo {
1436 visited[module] = true
1437 checking[module] = true
1438 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001439
Colin Cross7addea32015-03-11 15:43:52 -07001440 deps := make(map[*moduleInfo]bool)
1441
1442 // Add an implicit dependency ordering on all earlier modules in the same module group
1443 for _, dep := range module.group.modules {
1444 if dep == module {
1445 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001446 }
Colin Cross7addea32015-03-11 15:43:52 -07001447 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001448 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001449
Colin Cross7addea32015-03-11 15:43:52 -07001450 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001451 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001452 }
1453
1454 module.reverseDeps = []*moduleInfo{}
1455 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001456
Colin Crossbbfa51a2014-12-17 16:12:41 -08001457 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001458 if checking[dep] {
1459 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001460 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001461 }
1462
1463 if !visited[dep] {
1464 cycle := check(dep)
1465 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001466 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001467 // We are the "start" of the cycle, so we're responsible
1468 // for generating the errors. The cycle list is in
1469 // reverse order because all the 'check' calls append
1470 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001471 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001472
1473 // We can continue processing this module's children to
1474 // find more cycles. Since all the modules that were
1475 // part of the found cycle were marked as visited we
1476 // won't run into that cycle again.
1477 } else {
1478 // We're not the "start" of the cycle, so we just append
1479 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001480 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001481 }
1482 }
1483 }
Colin Cross691a60d2015-01-07 18:08:56 -08001484
Colin Cross7addea32015-03-11 15:43:52 -07001485 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001486 }
1487
Colin Cross7addea32015-03-11 15:43:52 -07001488 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001489
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001490 return nil
1491 }
1492
Colin Cross7addea32015-03-11 15:43:52 -07001493 for _, module := range c.moduleInfo {
1494 if !visited[module] {
1495 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001496 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001497 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001498 panic("inconceivable!")
1499 }
1500 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001501 }
1502 }
1503 }
1504
Colin Cross7addea32015-03-11 15:43:52 -07001505 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001506
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001507 return
1508}
1509
Jamie Gennisd4e10182014-06-12 20:06:50 -07001510// PrepareBuildActions generates an internal representation of all the build
1511// actions that need to be performed. This process involves invoking the
1512// GenerateBuildActions method on each of the Module objects created during the
1513// parse phase and then on each of the registered Singleton objects.
1514//
1515// If the ResolveDependencies method has not already been called it is called
1516// automatically by this method.
1517//
1518// The config argument is made available to all of the Module and Singleton
1519// objects via the Config method on the ModuleContext and SingletonContext
1520// objects passed to GenerateBuildActions. It is also passed to the functions
1521// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1522// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001523//
1524// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001525// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1526// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1527// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001528func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001529 c.buildActionsReady = false
1530
1531 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001532 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001533 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001534 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001535 }
1536 }
1537
1538 liveGlobals := newLiveTracker(config)
1539
1540 c.initSpecialVariables()
1541
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001542 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001543 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001544 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001545 }
1546
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001547 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001548 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001549 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001550 }
1551
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001552 deps = append(depsModules, depsSingletons...)
1553
Colin Crossa2599452015-11-18 16:01:01 -08001554 if c.ninjaBuildDir != nil {
1555 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001556 }
1557
Dan Willemsena481ae22015-12-18 15:18:03 -08001558 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1559
1560 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001561
1562 // This will panic if it finds a problem since it's a programming error.
1563 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1564
1565 c.pkgNames = pkgNames
1566 c.globalVariables = liveGlobals.variables
1567 c.globalPools = liveGlobals.pools
1568 c.globalRules = liveGlobals.rules
1569
1570 c.buildActionsReady = true
1571
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001572 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001573}
1574
Colin Crossc9028482014-12-18 16:28:54 -08001575func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001576 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001577
Colin Crossf8b50422016-08-10 12:56:40 -07001578 mutators = append(mutators, c.earlyMutatorInfo...)
1579 mutators = append(mutators, c.mutatorInfo...)
1580
1581 for _, mutator := range mutators {
Colin Crossc9028482014-12-18 16:28:54 -08001582 if mutator.topDownMutator != nil {
1583 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1584 } else if mutator.bottomUpMutator != nil {
1585 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1586 } else {
1587 panic("no mutator set on " + mutator.name)
1588 }
1589 if len(errs) > 0 {
1590 return errs
1591 }
1592 }
1593
1594 return nil
1595}
1596
1597func (c *Context) runTopDownMutator(config interface{},
1598 name string, mutator TopDownMutator) (errs []error) {
1599
Colin Cross7addea32015-03-11 15:43:52 -07001600 for i := 0; i < len(c.modulesSorted); i++ {
1601 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1602 mctx := &mutatorContext{
1603 baseModuleContext: baseModuleContext{
1604 context: c,
1605 config: config,
1606 module: module,
1607 },
1608 name: name,
1609 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001610 func() {
1611 defer func() {
1612 if r := recover(); r != nil {
1613 in := fmt.Sprintf("top down mutator %q for %s", name, module)
1614 if err, ok := r.(panicError); ok {
1615 err.addIn(in)
1616 mctx.error(err)
1617 } else {
1618 mctx.error(newPanicErrorf(r, in))
1619 }
1620 }
1621 }()
1622 mutator(mctx)
1623 }()
Colin Crossc9028482014-12-18 16:28:54 -08001624
Colin Cross7addea32015-03-11 15:43:52 -07001625 if len(mctx.errs) > 0 {
1626 errs = append(errs, mctx.errs...)
1627 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001628 }
1629 }
1630
1631 return errs
1632}
1633
1634func (c *Context) runBottomUpMutator(config interface{},
1635 name string, mutator BottomUpMutator) (errs []error) {
1636
Colin Cross2c1f3d12016-04-11 15:47:28 -07001637 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross8d8a7af2015-11-03 16:41:29 -08001638
Colin Cross7addea32015-03-11 15:43:52 -07001639 for _, module := range c.modulesSorted {
1640 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001641
Jamie Gennisc7988252015-04-14 23:28:10 -04001642 if module.splitModules != nil {
1643 panic("split module found in sorted module list")
1644 }
1645
Colin Cross7addea32015-03-11 15:43:52 -07001646 mctx := &mutatorContext{
1647 baseModuleContext: baseModuleContext{
1648 context: c,
1649 config: config,
1650 module: module,
1651 },
Colin Cross8d8a7af2015-11-03 16:41:29 -08001652 name: name,
1653 reverseDeps: reverseDeps,
Colin Cross7addea32015-03-11 15:43:52 -07001654 }
Colin Crossc9028482014-12-18 16:28:54 -08001655
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001656 func() {
1657 defer func() {
1658 if r := recover(); r != nil {
1659 in := fmt.Sprintf("bottom up mutator %q for %s", name, module)
1660 if err, ok := r.(panicError); ok {
1661 err.addIn(in)
1662 mctx.error(err)
1663 } else {
1664 mctx.error(newPanicErrorf(r, in))
1665 }
1666 }
1667 }()
1668 mutator(mctx)
1669 }()
Colin Cross7addea32015-03-11 15:43:52 -07001670 if len(mctx.errs) > 0 {
1671 errs = append(errs, mctx.errs...)
1672 return errs
1673 }
Colin Crossc9028482014-12-18 16:28:54 -08001674
Colin Cross7addea32015-03-11 15:43:52 -07001675 // Fix up any remaining dependencies on modules that were split into variants
1676 // by replacing them with the first variant
1677 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001678 if dep.module.logicModule == nil {
1679 module.directDeps[i].module = dep.module.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001680 }
1681 }
1682
Colin Cross7addea32015-03-11 15:43:52 -07001683 if module.splitModules != nil {
1684 newModules = append(newModules, module.splitModules...)
1685 } else {
1686 newModules = append(newModules, module)
1687 }
1688
1689 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001690 }
1691
Colin Cross8d8a7af2015-11-03 16:41:29 -08001692 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001693 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001694 module.directDeps = append(module.directDeps, deps...)
1695 }
1696
Jamie Gennisc7988252015-04-14 23:28:10 -04001697 errs = c.updateDependencies()
1698 if len(errs) > 0 {
1699 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001700 }
1701
1702 return errs
1703}
1704
Colin Cross910242b2016-04-11 15:41:52 -07001705// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1706// a mutator sets a non-property member variable on a module, which works until a later mutator
1707// creates variants of that module.
1708func (c *Context) cloneModules() {
1709 for _, m := range c.modulesSorted {
1710 origLogicModule := m.logicModule
1711 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1712 delete(c.moduleInfo, origLogicModule)
1713 c.moduleInfo[m.logicModule] = m
1714 }
1715}
1716
Colin Cross7addea32015-03-11 15:43:52 -07001717func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1718 newModules []*moduleInfo) []*moduleInfo {
1719 for i, m := range modules {
1720 if m == origModule {
1721 return spliceModulesAtIndex(modules, i, newModules)
1722 }
1723 }
1724
1725 panic("failed to find original module to splice")
1726}
1727
1728func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1729 spliceSize := len(newModules)
1730 newLen := len(modules) + spliceSize - 1
1731 var dest []*moduleInfo
1732 if cap(modules) >= len(modules)-1+len(newModules) {
1733 // We can fit the splice in the existing capacity, do everything in place
1734 dest = modules[:newLen]
1735 } else {
1736 dest = make([]*moduleInfo, newLen)
1737 copy(dest, modules[:i])
1738 }
1739
1740 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001741 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001742
1743 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001744 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001745
Colin Cross72bd1932015-03-16 00:13:59 -07001746 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001747}
1748
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001749func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001750 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001751 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001752 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001753 c.requiredNinjaMicro = 0
1754}
1755
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001756func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001757 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001758
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001759 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001760 var errs []error
1761
Colin Cross691a60d2015-01-07 18:08:56 -08001762 cancelCh := make(chan struct{})
1763 errsCh := make(chan []error)
1764 depsCh := make(chan []string)
1765
1766 go func() {
1767 for {
1768 select {
1769 case <-cancelCh:
1770 close(cancelCh)
1771 return
1772 case newErrs := <-errsCh:
1773 errs = append(errs, newErrs...)
1774 case newDeps := <-depsCh:
1775 deps = append(deps, newDeps...)
1776
1777 }
1778 }
1779 }()
1780
Colin Cross7addea32015-03-11 15:43:52 -07001781 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1782 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1783 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1784 // just set it to nil.
1785 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1786 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001787
Colin Cross7addea32015-03-11 15:43:52 -07001788 mctx := &moduleContext{
1789 baseModuleContext: baseModuleContext{
1790 context: c,
1791 config: config,
1792 module: module,
1793 },
Colin Cross036a1df2015-12-17 15:49:30 -08001794 scope: scope,
1795 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001796 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001797
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001798 func() {
1799 defer func() {
1800 if r := recover(); r != nil {
1801 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1802 if err, ok := r.(panicError); ok {
1803 err.addIn(in)
1804 mctx.error(err)
1805 } else {
1806 mctx.error(newPanicErrorf(r, in))
1807 }
1808 }
1809 }()
1810 mctx.module.logicModule.GenerateBuildActions(mctx)
1811 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001812
Colin Cross7addea32015-03-11 15:43:52 -07001813 if len(mctx.errs) > 0 {
1814 errsCh <- mctx.errs
1815 return true
1816 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001817
Colin Cross036a1df2015-12-17 15:49:30 -08001818 if module.missingDeps != nil && !mctx.handledMissingDeps {
1819 var errs []error
1820 for _, depName := range module.missingDeps {
1821 errs = append(errs, &Error{
1822 Err: fmt.Errorf("%q depends on undefined module %q",
1823 module.properties.Name, depName),
1824 Pos: module.pos,
1825 })
1826 }
1827 errsCh <- errs
1828 return true
1829 }
1830
Colin Cross7addea32015-03-11 15:43:52 -07001831 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001832
Colin Crossab6d7902015-03-11 16:17:52 -07001833 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001834 &mctx.actionDefs, liveGlobals)
1835 if len(newErrs) > 0 {
1836 errsCh <- newErrs
1837 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001838 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001839 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001840 })
1841
1842 cancelCh <- struct{}{}
1843 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001845 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001846}
1847
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001848func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001849 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001850
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001851 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001852 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001853
Yuchen Wub9103ef2015-08-25 17:58:17 -07001854 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001855 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1856 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1857 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001858 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001859
1860 sctx := &singletonContext{
1861 context: c,
1862 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001863 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08001864 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001865 }
1866
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001867 func() {
1868 defer func() {
1869 if r := recover(); r != nil {
1870 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
1871 if err, ok := r.(panicError); ok {
1872 err.addIn(in)
1873 sctx.error(err)
1874 } else {
1875 sctx.error(newPanicErrorf(r, in))
1876 }
1877 }
1878 }()
1879 info.singleton.GenerateBuildActions(sctx)
1880 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001881
1882 if len(sctx.errs) > 0 {
1883 errs = append(errs, sctx.errs...)
1884 if len(errs) > maxErrors {
1885 break
1886 }
1887 continue
1888 }
1889
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001890 deps = append(deps, sctx.ninjaFileDeps...)
1891
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001892 newErrs := c.processLocalBuildActions(&info.actionDefs,
1893 &sctx.actionDefs, liveGlobals)
1894 errs = append(errs, newErrs...)
1895 if len(errs) > maxErrors {
1896 break
1897 }
1898 }
1899
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001900 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001901}
1902
1903func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1904 liveGlobals *liveTracker) []error {
1905
1906 var errs []error
1907
1908 // First we go through and add everything referenced by the module's
1909 // buildDefs to the live globals set. This will end up adding the live
1910 // locals to the set as well, but we'll take them out after.
1911 for _, def := range in.buildDefs {
1912 err := liveGlobals.AddBuildDefDeps(def)
1913 if err != nil {
1914 errs = append(errs, err)
1915 }
1916 }
1917
1918 if len(errs) > 0 {
1919 return errs
1920 }
1921
Colin Crossc9028482014-12-18 16:28:54 -08001922 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001923
1924 // We use the now-incorrect set of live "globals" to determine which local
1925 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001926 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001928 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001929 if isLive {
1930 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001931 }
1932 }
1933
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001934 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001935 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001936 if isLive {
1937 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001938 }
1939 }
1940
1941 return nil
1942}
1943
Yuchen Wu222e2452015-10-06 14:03:27 -07001944func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07001945 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07001946
1947 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001948 var visiting *moduleInfo
1949
1950 defer func() {
1951 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07001952 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
1953 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001954 }
1955 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07001956
1957 var walk func(module *moduleInfo)
1958 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001959 for _, dep := range module.directDeps {
1960 if !visited[dep.module] {
1961 visited[dep.module] = true
1962 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07001963 recurse := true
1964 if visitDown != nil {
1965 recurse = visitDown(dep, module)
1966 }
1967 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001968 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07001969 }
Colin Crossbafd5f52016-08-06 22:52:01 -07001970 if visitUp != nil {
1971 visitUp(dep, module)
1972 }
Yuchen Wu222e2452015-10-06 14:03:27 -07001973 }
1974 }
1975 }
1976
1977 walk(topModule)
1978}
1979
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001980type innerPanicError error
1981
Jamie Gennisc15544d2014-09-24 20:26:52 -07001982func (c *Context) sortedModuleNames() []string {
1983 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001984 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1985 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001986 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1987 moduleName)
1988 }
1989 sort.Strings(c.cachedSortedModuleNames)
1990 }
1991
1992 return c.cachedSortedModuleNames
1993}
1994
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001995func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001996 var module *moduleInfo
1997
1998 defer func() {
1999 if r := recover(); r != nil {
2000 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2001 funcName(visit), module))
2002 }
2003 }()
2004
Jamie Gennisc15544d2014-09-24 20:26:52 -07002005 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002006 group := c.moduleGroups[moduleName]
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002007 for _, module = range group.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002008 visit(module.logicModule)
2009 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002010 }
2011}
2012
2013func (c *Context) visitAllModulesIf(pred func(Module) bool,
2014 visit func(Module)) {
2015
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002016 var module *moduleInfo
2017
2018 defer func() {
2019 if r := recover(); r != nil {
2020 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2021 funcName(pred), funcName(visit), module))
2022 }
2023 }()
2024
Jamie Gennisc15544d2014-09-24 20:26:52 -07002025 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002026 group := c.moduleGroups[moduleName]
2027 for _, module := range group.modules {
2028 if pred(module.logicModule) {
2029 visit(module.logicModule)
2030 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002031 }
2032 }
2033}
2034
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002035func (c *Context) visitAllModuleVariants(module *moduleInfo,
2036 visit func(Module)) {
2037
2038 var variant *moduleInfo
2039
2040 defer func() {
2041 if r := recover(); r != nil {
2042 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2043 module, funcName(visit), variant))
2044 }
2045 }()
2046
2047 for _, variant = range module.group.modules {
2048 visit(variant.logicModule)
2049 }
2050}
2051
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002052func (c *Context) requireNinjaVersion(major, minor, micro int) {
2053 if major != 1 {
2054 panic("ninja version with major version != 1 not supported")
2055 }
2056 if c.requiredNinjaMinor < minor {
2057 c.requiredNinjaMinor = minor
2058 c.requiredNinjaMicro = micro
2059 }
2060 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2061 c.requiredNinjaMicro = micro
2062 }
2063}
2064
Colin Crossa2599452015-11-18 16:01:01 -08002065func (c *Context) setNinjaBuildDir(value *ninjaString) {
2066 if c.ninjaBuildDir == nil {
2067 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002068 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002069}
2070
2071func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002072 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002073
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002074 pkgs := make(map[string]*packageContext)
2075 pkgNames := make(map[*packageContext]string)
2076 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002077
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002078 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002079 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002080 // This is a built-in rule and has no package.
2081 return
2082 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002083 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002084 // We've already processed this package.
2085 return
2086 }
2087
Jamie Gennis2fb20952014-10-03 02:49:58 -07002088 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002089 if present {
2090 // Short name collision. Both this package and the one that's
2091 // already there need to use their full names. We leave the short
2092 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002093 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002094 longPkgNames[otherPkg] = true
2095 } else {
2096 // No collision so far. Tentatively set the package's name to be
2097 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002098 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002099 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002100 }
2101 }
2102
2103 // We try to give all packages their short name, but when we get collisions
2104 // we need to use the full unique package name.
2105 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002106 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002107 }
2108 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002109 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002110 }
2111 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002112 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002113 }
2114
2115 // Add the packages that had collisions using their full unique names. This
2116 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002117 for pctx := range longPkgNames {
2118 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002119 }
2120
Dan Willemsena481ae22015-12-18 15:18:03 -08002121 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2122 deps := []string{}
2123 for _, pkg := range pkgs {
2124 deps = append(deps, pkg.ninjaFileDeps...)
2125 }
2126
2127 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002128}
2129
2130func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002131 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002132
2133 visited := make(map[Variable]bool) // variables that were already checked
2134 checking := make(map[Variable]bool) // variables actively being checked
2135
2136 var check func(v Variable) []Variable
2137
2138 check = func(v Variable) []Variable {
2139 visited[v] = true
2140 checking[v] = true
2141 defer delete(checking, v)
2142
2143 value := variables[v]
2144 for _, dep := range value.variables {
2145 if checking[dep] {
2146 // This is a cycle.
2147 return []Variable{dep, v}
2148 }
2149
2150 if !visited[dep] {
2151 cycle := check(dep)
2152 if cycle != nil {
2153 if cycle[0] == v {
2154 // We are the "start" of the cycle, so we're responsible
2155 // for generating the errors. The cycle list is in
2156 // reverse order because all the 'check' calls append
2157 // their own module to the list.
2158 msgs := []string{"detected variable reference cycle:"}
2159
2160 // Iterate backwards through the cycle list.
2161 curName := v.fullName(pkgNames)
2162 curValue := value.Value(pkgNames)
2163 for i := len(cycle) - 1; i >= 0; i-- {
2164 next := cycle[i]
2165 nextName := next.fullName(pkgNames)
2166 nextValue := variables[next].Value(pkgNames)
2167
2168 msgs = append(msgs, fmt.Sprintf(
2169 " %q depends on %q", curName, nextName))
2170 msgs = append(msgs, fmt.Sprintf(
2171 " [%s = %s]", curName, curValue))
2172
2173 curName = nextName
2174 curValue = nextValue
2175 }
2176
2177 // Variable reference cycles are a programming error,
2178 // not the fault of the Blueprint file authors.
2179 panic(strings.Join(msgs, "\n"))
2180 } else {
2181 // We're not the "start" of the cycle, so we just append
2182 // our module to the list and return it.
2183 return append(cycle, v)
2184 }
2185 }
2186 }
2187 }
2188
2189 return nil
2190 }
2191
2192 for v := range variables {
2193 if !visited[v] {
2194 cycle := check(v)
2195 if cycle != nil {
2196 panic("inconceivable!")
2197 }
2198 }
2199 }
2200}
2201
Jamie Gennisaf435562014-10-27 22:34:56 -07002202// AllTargets returns a map all the build target names to the rule used to build
2203// them. This is the same information that is output by running 'ninja -t
2204// targets all'. If this is called before PrepareBuildActions successfully
2205// completes then ErrbuildActionsNotReady is returned.
2206func (c *Context) AllTargets() (map[string]string, error) {
2207 if !c.buildActionsReady {
2208 return nil, ErrBuildActionsNotReady
2209 }
2210
2211 targets := map[string]string{}
2212
2213 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002214 for _, module := range c.moduleInfo {
2215 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002216 ruleName := buildDef.Rule.fullName(c.pkgNames)
2217 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002218 outputValue, err := output.Eval(c.globalVariables)
2219 if err != nil {
2220 return nil, err
2221 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002222 targets[outputValue] = ruleName
2223 }
2224 }
2225 }
2226
2227 // Collect all the singleton build targets.
2228 for _, info := range c.singletonInfo {
2229 for _, buildDef := range info.actionDefs.buildDefs {
2230 ruleName := buildDef.Rule.fullName(c.pkgNames)
2231 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002232 outputValue, err := output.Eval(c.globalVariables)
2233 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002234 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002235 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002236 targets[outputValue] = ruleName
2237 }
2238 }
2239 }
2240
2241 return targets, nil
2242}
2243
Colin Crossa2599452015-11-18 16:01:01 -08002244func (c *Context) NinjaBuildDir() (string, error) {
2245 if c.ninjaBuildDir != nil {
2246 return c.ninjaBuildDir.Eval(c.globalVariables)
2247 } else {
2248 return "", nil
2249 }
2250}
2251
Colin Cross4572edd2015-05-13 14:36:24 -07002252// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2253// property structs returned by the factory for that module type.
2254func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2255 ret := make(map[string][]interface{})
2256 for moduleType, factory := range c.moduleFactories {
2257 _, ret[moduleType] = factory()
2258 }
2259
2260 return ret
2261}
2262
2263func (c *Context) ModuleName(logicModule Module) string {
2264 module := c.moduleInfo[logicModule]
2265 return module.properties.Name
2266}
2267
2268func (c *Context) ModuleDir(logicModule Module) string {
2269 module := c.moduleInfo[logicModule]
2270 return filepath.Dir(module.relBlueprintsFile)
2271}
2272
Colin Cross8c602f72015-12-17 18:02:11 -08002273func (c *Context) ModuleSubDir(logicModule Module) string {
2274 module := c.moduleInfo[logicModule]
2275 return module.variantName
2276}
2277
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002278func (c *Context) ModuleType(logicModule Module) string {
2279 module := c.moduleInfo[logicModule]
2280 return module.typeName
2281}
2282
Colin Cross4572edd2015-05-13 14:36:24 -07002283func (c *Context) BlueprintFile(logicModule Module) string {
2284 module := c.moduleInfo[logicModule]
2285 return module.relBlueprintsFile
2286}
2287
2288func (c *Context) ModuleErrorf(logicModule Module, format string,
2289 args ...interface{}) error {
2290
2291 module := c.moduleInfo[logicModule]
2292 return &Error{
2293 Err: fmt.Errorf(format, args...),
2294 Pos: module.pos,
2295 }
2296}
2297
2298func (c *Context) VisitAllModules(visit func(Module)) {
2299 c.visitAllModules(visit)
2300}
2301
2302func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2303 visit func(Module)) {
2304
2305 c.visitAllModulesIf(pred, visit)
2306}
2307
2308func (c *Context) VisitDepsDepthFirst(module Module,
2309 visit func(Module)) {
2310
Colin Crossbafd5f52016-08-06 22:52:01 -07002311 topModule := c.moduleInfo[module]
2312
2313 var visiting *moduleInfo
2314
2315 defer func() {
2316 if r := recover(); r != nil {
2317 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2318 topModule, funcName(visit), visiting))
2319 }
2320 }()
2321
2322 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2323 visiting = dep.module
2324 visit(dep.module.logicModule)
2325 })
Colin Cross4572edd2015-05-13 14:36:24 -07002326}
2327
2328func (c *Context) VisitDepsDepthFirstIf(module Module,
2329 pred func(Module) bool, visit func(Module)) {
2330
Colin Crossbafd5f52016-08-06 22:52:01 -07002331 topModule := c.moduleInfo[module]
2332
2333 var visiting *moduleInfo
2334
2335 defer func() {
2336 if r := recover(); r != nil {
2337 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2338 topModule, funcName(pred), funcName(visit), visiting))
2339 }
2340 }()
2341
2342 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2343 if pred(dep.module.logicModule) {
2344 visiting = dep.module
2345 visit(dep.module.logicModule)
2346 }
2347 })
Colin Cross4572edd2015-05-13 14:36:24 -07002348}
2349
Colin Cross24ad5872015-11-17 16:22:29 -08002350func (c *Context) PrimaryModule(module Module) Module {
2351 return c.moduleInfo[module].group.modules[0].logicModule
2352}
2353
2354func (c *Context) FinalModule(module Module) Module {
2355 modules := c.moduleInfo[module].group.modules
2356 return modules[len(modules)-1].logicModule
2357}
2358
2359func (c *Context) VisitAllModuleVariants(module Module,
2360 visit func(Module)) {
2361
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002362 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002363}
2364
Jamie Gennisd4e10182014-06-12 20:06:50 -07002365// WriteBuildFile writes the Ninja manifeset text for the generated build
2366// actions to w. If this is called before PrepareBuildActions successfully
2367// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002368func (c *Context) WriteBuildFile(w io.Writer) error {
2369 if !c.buildActionsReady {
2370 return ErrBuildActionsNotReady
2371 }
2372
2373 nw := newNinjaWriter(w)
2374
2375 err := c.writeBuildFileHeader(nw)
2376 if err != nil {
2377 return err
2378 }
2379
2380 err = c.writeNinjaRequiredVersion(nw)
2381 if err != nil {
2382 return err
2383 }
2384
2385 // TODO: Group the globals by package.
2386
2387 err = c.writeGlobalVariables(nw)
2388 if err != nil {
2389 return err
2390 }
2391
2392 err = c.writeGlobalPools(nw)
2393 if err != nil {
2394 return err
2395 }
2396
2397 err = c.writeBuildDir(nw)
2398 if err != nil {
2399 return err
2400 }
2401
2402 err = c.writeGlobalRules(nw)
2403 if err != nil {
2404 return err
2405 }
2406
2407 err = c.writeAllModuleActions(nw)
2408 if err != nil {
2409 return err
2410 }
2411
2412 err = c.writeAllSingletonActions(nw)
2413 if err != nil {
2414 return err
2415 }
2416
2417 return nil
2418}
2419
Jamie Gennisc15544d2014-09-24 20:26:52 -07002420type pkgAssociation struct {
2421 PkgName string
2422 PkgPath string
2423}
2424
2425type pkgAssociationSorter struct {
2426 pkgs []pkgAssociation
2427}
2428
2429func (s *pkgAssociationSorter) Len() int {
2430 return len(s.pkgs)
2431}
2432
2433func (s *pkgAssociationSorter) Less(i, j int) bool {
2434 iName := s.pkgs[i].PkgName
2435 jName := s.pkgs[j].PkgName
2436 return iName < jName
2437}
2438
2439func (s *pkgAssociationSorter) Swap(i, j int) {
2440 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2441}
2442
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002443func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2444 headerTemplate := template.New("fileHeader")
2445 _, err := headerTemplate.Parse(fileHeaderTemplate)
2446 if err != nil {
2447 // This is a programming error.
2448 panic(err)
2449 }
2450
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002451 var pkgs []pkgAssociation
2452 maxNameLen := 0
2453 for pkg, name := range c.pkgNames {
2454 pkgs = append(pkgs, pkgAssociation{
2455 PkgName: name,
2456 PkgPath: pkg.pkgPath,
2457 })
2458 if len(name) > maxNameLen {
2459 maxNameLen = len(name)
2460 }
2461 }
2462
2463 for i := range pkgs {
2464 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2465 }
2466
Jamie Gennisc15544d2014-09-24 20:26:52 -07002467 sort.Sort(&pkgAssociationSorter{pkgs})
2468
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002469 params := map[string]interface{}{
2470 "Pkgs": pkgs,
2471 }
2472
2473 buf := bytes.NewBuffer(nil)
2474 err = headerTemplate.Execute(buf, params)
2475 if err != nil {
2476 return err
2477 }
2478
2479 return nw.Comment(buf.String())
2480}
2481
2482func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2483 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2484 c.requiredNinjaMicro)
2485
2486 err := nw.Assign("ninja_required_version", value)
2487 if err != nil {
2488 return err
2489 }
2490
2491 return nw.BlankLine()
2492}
2493
2494func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002495 if c.ninjaBuildDir != nil {
2496 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002497 if err != nil {
2498 return err
2499 }
2500
2501 err = nw.BlankLine()
2502 if err != nil {
2503 return err
2504 }
2505 }
2506 return nil
2507}
2508
Jamie Gennisc15544d2014-09-24 20:26:52 -07002509type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002510 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002511}
2512
Jamie Gennisc15544d2014-09-24 20:26:52 -07002513type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002514 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002515 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002516}
2517
Jamie Gennisc15544d2014-09-24 20:26:52 -07002518func (s *globalEntitySorter) Len() int {
2519 return len(s.entities)
2520}
2521
2522func (s *globalEntitySorter) Less(i, j int) bool {
2523 iName := s.entities[i].fullName(s.pkgNames)
2524 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002525 return iName < jName
2526}
2527
Jamie Gennisc15544d2014-09-24 20:26:52 -07002528func (s *globalEntitySorter) Swap(i, j int) {
2529 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002530}
2531
2532func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2533 visited := make(map[Variable]bool)
2534
2535 var walk func(v Variable) error
2536 walk = func(v Variable) error {
2537 visited[v] = true
2538
2539 // First visit variables on which this variable depends.
2540 value := c.globalVariables[v]
2541 for _, dep := range value.variables {
2542 if !visited[dep] {
2543 err := walk(dep)
2544 if err != nil {
2545 return err
2546 }
2547 }
2548 }
2549
2550 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2551 if err != nil {
2552 return err
2553 }
2554
2555 err = nw.BlankLine()
2556 if err != nil {
2557 return err
2558 }
2559
2560 return nil
2561 }
2562
Jamie Gennisc15544d2014-09-24 20:26:52 -07002563 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2564 for variable := range c.globalVariables {
2565 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002566 }
2567
Jamie Gennisc15544d2014-09-24 20:26:52 -07002568 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002569
Jamie Gennisc15544d2014-09-24 20:26:52 -07002570 for _, entity := range globalVariables {
2571 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002572 if !visited[v] {
2573 err := walk(v)
2574 if err != nil {
2575 return nil
2576 }
2577 }
2578 }
2579
2580 return nil
2581}
2582
2583func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002584 globalPools := make([]globalEntity, 0, len(c.globalPools))
2585 for pool := range c.globalPools {
2586 globalPools = append(globalPools, pool)
2587 }
2588
2589 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2590
2591 for _, entity := range globalPools {
2592 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002593 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002594 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002595 err := def.WriteTo(nw, name)
2596 if err != nil {
2597 return err
2598 }
2599
2600 err = nw.BlankLine()
2601 if err != nil {
2602 return err
2603 }
2604 }
2605
2606 return nil
2607}
2608
2609func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002610 globalRules := make([]globalEntity, 0, len(c.globalRules))
2611 for rule := range c.globalRules {
2612 globalRules = append(globalRules, rule)
2613 }
2614
2615 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2616
2617 for _, entity := range globalRules {
2618 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002619 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002620 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002621 err := def.WriteTo(nw, name, c.pkgNames)
2622 if err != nil {
2623 return err
2624 }
2625
2626 err = nw.BlankLine()
2627 if err != nil {
2628 return err
2629 }
2630 }
2631
2632 return nil
2633}
2634
Colin Cross2c1f3d12016-04-11 15:47:28 -07002635type depSorter []depInfo
2636
2637func (s depSorter) Len() int {
2638 return len(s)
2639}
2640
2641func (s depSorter) Less(i, j int) bool {
2642 iName := s[i].module.properties.Name
2643 jName := s[j].module.properties.Name
2644 if iName == jName {
2645 iName = s[i].module.variantName
2646 jName = s[j].module.variantName
2647 }
2648 return iName < jName
2649}
2650
2651func (s depSorter) Swap(i, j int) {
2652 s[i], s[j] = s[j], s[i]
2653}
2654
Colin Crossab6d7902015-03-11 16:17:52 -07002655type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002656
Colin Crossab6d7902015-03-11 16:17:52 -07002657func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002658 return len(s)
2659}
2660
Colin Crossab6d7902015-03-11 16:17:52 -07002661func (s moduleSorter) Less(i, j int) bool {
2662 iName := s[i].properties.Name
2663 jName := s[j].properties.Name
2664 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002665 iName = s[i].variantName
2666 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002667 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002668 return iName < jName
2669}
2670
Colin Crossab6d7902015-03-11 16:17:52 -07002671func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002672 s[i], s[j] = s[j], s[i]
2673}
2674
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002675func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2676 headerTemplate := template.New("moduleHeader")
2677 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2678 if err != nil {
2679 // This is a programming error.
2680 panic(err)
2681 }
2682
Colin Crossab6d7902015-03-11 16:17:52 -07002683 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2684 for _, module := range c.moduleInfo {
2685 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002686 }
Colin Crossab6d7902015-03-11 16:17:52 -07002687 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002688
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002689 buf := bytes.NewBuffer(nil)
2690
Colin Crossab6d7902015-03-11 16:17:52 -07002691 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002692 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2693 continue
2694 }
2695
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002696 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002697
2698 // In order to make the bootstrap build manifest independent of the
2699 // build dir we need to output the Blueprints file locations in the
2700 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002701 relPos := module.pos
2702 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002703
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002704 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002705 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002706 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2707 factoryName := factoryFunc.Name()
2708
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002709 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002710 "properties": module.properties,
2711 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002712 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002713 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002714 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002715 }
2716 err = headerTemplate.Execute(buf, infoMap)
2717 if err != nil {
2718 return err
2719 }
2720
2721 err = nw.Comment(buf.String())
2722 if err != nil {
2723 return err
2724 }
2725
2726 err = nw.BlankLine()
2727 if err != nil {
2728 return err
2729 }
2730
Colin Crossab6d7902015-03-11 16:17:52 -07002731 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002732 if err != nil {
2733 return err
2734 }
2735
2736 err = nw.BlankLine()
2737 if err != nil {
2738 return err
2739 }
2740 }
2741
2742 return nil
2743}
2744
2745func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2746 headerTemplate := template.New("singletonHeader")
2747 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2748 if err != nil {
2749 // This is a programming error.
2750 panic(err)
2751 }
2752
2753 buf := bytes.NewBuffer(nil)
2754
Yuchen Wub9103ef2015-08-25 17:58:17 -07002755 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002756 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2757 continue
2758 }
2759
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002760 // Get the name of the factory function for the module.
2761 factory := info.factory
2762 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2763 factoryName := factoryFunc.Name()
2764
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002765 buf.Reset()
2766 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002767 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002768 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002769 }
2770 err = headerTemplate.Execute(buf, infoMap)
2771 if err != nil {
2772 return err
2773 }
2774
2775 err = nw.Comment(buf.String())
2776 if err != nil {
2777 return err
2778 }
2779
2780 err = nw.BlankLine()
2781 if err != nil {
2782 return err
2783 }
2784
2785 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2786 if err != nil {
2787 return err
2788 }
2789
2790 err = nw.BlankLine()
2791 if err != nil {
2792 return err
2793 }
2794 }
2795
2796 return nil
2797}
2798
2799func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2800 defs *localBuildActions) error {
2801
2802 // Write the local variable assignments.
2803 for _, v := range defs.variables {
2804 // A localVariable doesn't need the package names or config to
2805 // determine its name or value.
2806 name := v.fullName(nil)
2807 value, err := v.value(nil)
2808 if err != nil {
2809 panic(err)
2810 }
2811 err = nw.Assign(name, value.Value(c.pkgNames))
2812 if err != nil {
2813 return err
2814 }
2815 }
2816
2817 if len(defs.variables) > 0 {
2818 err := nw.BlankLine()
2819 if err != nil {
2820 return err
2821 }
2822 }
2823
2824 // Write the local rules.
2825 for _, r := range defs.rules {
2826 // A localRule doesn't need the package names or config to determine
2827 // its name or definition.
2828 name := r.fullName(nil)
2829 def, err := r.def(nil)
2830 if err != nil {
2831 panic(err)
2832 }
2833
2834 err = def.WriteTo(nw, name, c.pkgNames)
2835 if err != nil {
2836 return err
2837 }
2838
2839 err = nw.BlankLine()
2840 if err != nil {
2841 return err
2842 }
2843 }
2844
2845 // Write the build definitions.
2846 for _, buildDef := range defs.buildDefs {
2847 err := buildDef.WriteTo(nw, c.pkgNames)
2848 if err != nil {
2849 return err
2850 }
2851
2852 if len(buildDef.Args) > 0 {
2853 err = nw.BlankLine()
2854 if err != nil {
2855 return err
2856 }
2857 }
2858 }
2859
2860 return nil
2861}
2862
Colin Cross65569e42015-03-10 20:08:19 -07002863func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2864 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002865 if a == b {
2866 return false
2867 }
Colin Cross65569e42015-03-10 20:08:19 -07002868 for _, l := range list {
2869 if l == a {
2870 found = true
2871 } else if l == b {
2872 return found
2873 }
2874 }
2875
2876 missing := a
2877 if found {
2878 missing = b
2879 }
2880 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2881}
2882
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002883type panicError struct {
2884 panic interface{}
2885 stack []byte
2886 in string
2887}
2888
2889func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
2890 buf := make([]byte, 4096)
2891 count := runtime.Stack(buf, false)
2892 return panicError{
2893 panic: panic,
2894 in: fmt.Sprintf(in, a...),
2895 stack: buf[:count],
2896 }
2897}
2898
2899func (p panicError) Error() string {
2900 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
2901}
2902
2903func (p *panicError) addIn(in string) {
2904 p.in += " in " + in
2905}
2906
2907func funcName(f interface{}) string {
2908 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
2909}
2910
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002911var fileHeaderTemplate = `******************************************************************************
2912*** This file is generated and should not be edited ***
2913******************************************************************************
2914{{if .Pkgs}}
2915This file contains variables, rules, and pools with name prefixes indicating
2916they were generated by the following Go packages:
2917{{range .Pkgs}}
2918 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2919
2920`
2921
2922var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2923Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002924Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002925Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002926Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002927Defined: {{.pos}}
2928`
2929
2930var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2931Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002932Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002933`