blob: b644ac54c71f8582e5e2b2f3579e0a4ab31e47a9 [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"
22 "os"
23 "path/filepath"
24 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070025 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070026 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080027 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "strings"
Colin Cross23d7aa12015-06-30 16:05:22 -070029 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "text/scanner"
31 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070032
33 "github.com/google/blueprint/parser"
34 "github.com/google/blueprint/pathtools"
35 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070036)
37
38var ErrBuildActionsNotReady = errors.New("build actions are not ready")
39
40const maxErrors = 10
41
Jamie Gennisd4e10182014-06-12 20:06:50 -070042// A Context contains all the state needed to parse a set of Blueprints files
43// and generate a Ninja file. The process of generating a Ninja file proceeds
44// through a series of four phases. Each phase corresponds with a some methods
45// on the Context object
46//
47// Phase Methods
48// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070049// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070050//
51// 2. Parse ParseBlueprintsFiles, Parse
52//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 4. Write WriteBuildFile
56//
57// The registration phase prepares the context to process Blueprints files
58// containing various types of modules. The parse phase reads in one or more
59// Blueprints files and validates their contents against the module types that
60// have been registered. The generate phase then analyzes the parsed Blueprints
61// contents to create an internal representation for the build actions that must
62// be performed. This phase also performs validation of the module dependencies
63// and property values defined in the parsed Blueprints files. Finally, the
64// write phase generates the Ninja manifest text based on the generated build
65// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066type Context struct {
67 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070068 moduleFactories map[string]ModuleFactory
69 moduleGroups map[string]*moduleGroup
70 moduleInfo map[Module]*moduleInfo
71 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070072 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070073 mutatorInfo []*mutatorInfo
74 earlyMutatorInfo []*earlyMutatorInfo
75 variantMutatorNames []string
76 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070077
78 dependenciesReady bool // set to true on a successful ResolveDependencies
79 buildActionsReady bool // set to true on a successful PrepareBuildActions
80
81 // set by SetIgnoreUnknownModuleTypes
82 ignoreUnknownModuleTypes bool
83
Colin Cross036a1df2015-12-17 15:49:30 -080084 // set by SetAllowMissingDependencies
85 allowMissingDependencies bool
86
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080088 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070089 globalVariables map[Variable]*ninjaString
90 globalPools map[Pool]*poolDef
91 globalRules map[Rule]*ruleDef
92
93 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080094 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095 requiredNinjaMajor int // For the ninja_required_version variable
96 requiredNinjaMinor int // For the ninja_required_version variable
97 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070098
99 // set lazily by sortedModuleNames
100 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101}
102
Jamie Gennisd4e10182014-06-12 20:06:50 -0700103// An Error describes a problem that was encountered that is related to a
104// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700106 Err error // the error that occurred
107 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700108}
109
110type localBuildActions struct {
111 variables []*localVariable
112 rules []*localRule
113 buildDefs []*buildDef
114}
115
Colin Crossbbfa51a2014-12-17 16:12:41 -0800116type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700117 name string
118 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119
Colin Crossbbfa51a2014-12-17 16:12:41 -0800120 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700121}
122
Colin Crossbbfa51a2014-12-17 16:12:41 -0800123type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700124 // set during Parse
125 typeName string
126 relBlueprintsFile string
127 pos scanner.Position
128 propertyPos map[string]scanner.Position
129 properties struct {
130 Name string
131 Deps []string
132 }
133
Colin Crossf5e34b92015-03-13 16:02:36 -0700134 variantName string
135 variant variationMap
136 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700137
Colin Crossc9028482014-12-18 16:28:54 -0800138 logicModule Module
139 group *moduleGroup
140 moduleProperties []interface{}
141
142 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700143 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800144 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800145
Colin Cross7addea32015-03-11 15:43:52 -0700146 // set during updateDependencies
147 reverseDeps []*moduleInfo
148 depsCount int
149
150 // used by parallelVisitAllBottomUp
151 waitingCount int
152
Colin Crossc9028482014-12-18 16:28:54 -0800153 // set during each runMutator
154 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700155
156 // set during PrepareBuildActions
157 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800158}
159
Colin Cross2c1f3d12016-04-11 15:47:28 -0700160type depInfo struct {
161 module *moduleInfo
162 tag DependencyTag
163}
164
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800165func (module *moduleInfo) String() string {
166 s := fmt.Sprintf("module %q", module.properties.Name)
167 if module.variantName != "" {
168 s += fmt.Sprintf(" variant %q", module.variantName)
169 }
170 return s
171}
172
Colin Crossf5e34b92015-03-13 16:02:36 -0700173// A Variation is a way that a variant of a module differs from other variants of the same module.
174// For example, two variants of the same module might have Variation{"arch","arm"} and
175// Variation{"arch","arm64"}
176type Variation struct {
177 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700178 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700179 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
180 // "shared" or "static" for link.
181 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700182}
183
Colin Crossf5e34b92015-03-13 16:02:36 -0700184// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
185type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700186
Colin Crossf5e34b92015-03-13 16:02:36 -0700187func (vm variationMap) clone() variationMap {
188 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700189 for k, v := range vm {
190 newVm[k] = v
191 }
192
193 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800194}
195
Colin Cross89486232015-05-08 11:14:54 -0700196// Compare this variationMap to another one. Returns true if the every entry in this map
197// is either the same in the other map or doesn't exist in the other map.
198func (vm variationMap) subset(other variationMap) bool {
199 for k, v1 := range vm {
200 if v2, ok := other[k]; ok && v1 != v2 {
201 return false
202 }
203 }
204 return true
205}
206
Colin Crossf5e34b92015-03-13 16:02:36 -0700207func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700208 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800209}
210
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700211type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700212 // set during RegisterSingletonType
213 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700214 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700215 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700216
217 // set during PrepareBuildActions
218 actionDefs localBuildActions
219}
220
Colin Crossc9028482014-12-18 16:28:54 -0800221type mutatorInfo struct {
222 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800223 topDownMutator TopDownMutator
224 bottomUpMutator BottomUpMutator
225 name string
Colin Crossc9028482014-12-18 16:28:54 -0800226}
227
Colin Cross65569e42015-03-10 20:08:19 -0700228type earlyMutatorInfo struct {
229 // set during RegisterEarlyMutator
230 mutator EarlyMutator
231 name string
232}
233
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700234func (e *Error) Error() string {
235
236 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
237}
238
Jamie Gennisd4e10182014-06-12 20:06:50 -0700239// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700240// no module or singleton factories registered, so the RegisterModuleFactory and
241// RegisterSingletonFactory methods must be called before it can do anything
242// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700243func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700244 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800245 moduleFactories: make(map[string]ModuleFactory),
246 moduleGroups: make(map[string]*moduleGroup),
247 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800248 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700249 }
Colin Cross763b6f12015-10-29 15:32:56 -0700250
251 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
252
253 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700254}
255
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700256// A ModuleFactory function creates a new Module object. See the
257// Context.RegisterModuleType method for details about how a registered
258// ModuleFactory is used by a Context.
259type ModuleFactory func() (m Module, propertyStructs []interface{})
260
Jamie Gennisd4e10182014-06-12 20:06:50 -0700261// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700262// Blueprints file) with a Module factory function. When the given module type
263// name is encountered in a Blueprints file during parsing, the Module factory
264// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800265// generation for the module. If a Mutator splits a module into multiple variants,
266// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700267//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700268// The module type names given here must be unique for the context. The factory
269// function should be a named function so that its package and name can be
270// included in the generated Ninja file for debugging purposes.
271//
272// The factory function returns two values. The first is the newly created
273// Module object. The second is a slice of pointers to that Module object's
274// properties structs. Each properties struct is examined when parsing a module
275// definition of this type in a Blueprints file. Exported fields of the
276// properties structs are automatically set to the property values specified in
277// the Blueprints file. The properties struct field names determine the name of
278// the Blueprints file properties that are used - the Blueprints property name
279// matches that of the properties struct field name with the first letter
280// converted to lower-case.
281//
282// The fields of the properties struct must be either []string, a string, or
283// bool. The Context will panic if a Module gets instantiated with a properties
284// struct containing a field that is not one these supported types.
285//
286// Any properties that appear in the Blueprints files that are not built-in
287// module properties (such as "name" and "deps") and do not have a corresponding
288// field in the returned module properties struct result in an error during the
289// Context's parse phase.
290//
291// As an example, the follow code:
292//
293// type myModule struct {
294// properties struct {
295// Foo string
296// Bar []string
297// }
298// }
299//
300// func NewMyModule() (blueprint.Module, []interface{}) {
301// module := new(myModule)
302// properties := &module.properties
303// return module, []interface{}{properties}
304// }
305//
306// func main() {
307// ctx := blueprint.NewContext()
308// ctx.RegisterModuleType("my_module", NewMyModule)
309// // ...
310// }
311//
312// would support parsing a module defined in a Blueprints file as follows:
313//
314// my_module {
315// name: "myName",
316// foo: "my foo string",
317// bar: ["my", "bar", "strings"],
318// }
319//
Colin Cross7ad621c2015-01-07 16:22:45 -0800320// The factory function may be called from multiple goroutines. Any accesses
321// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700322func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
323 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700324 panic(errors.New("module type name is already registered"))
325 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700326 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700327}
328
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700329// A SingletonFactory function creates a new Singleton object. See the
330// Context.RegisterSingletonType method for details about how a registered
331// SingletonFactory is used by a Context.
332type SingletonFactory func() Singleton
333
334// RegisterSingletonType registers a singleton type that will be invoked to
335// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700336// and invoked exactly once as part of the generate phase. Each registered
337// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700338//
339// The singleton type names given here must be unique for the context. The
340// factory function should be a named function so that its package and name can
341// be included in the generated Ninja file for debugging purposes.
342func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700343 for _, s := range c.singletonInfo {
344 if s.name == name {
345 panic(errors.New("singleton name is already registered"))
346 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700347 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700348
Yuchen Wub9103ef2015-08-25 17:58:17 -0700349 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700350 factory: factory,
351 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700352 name: name,
353 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700354}
355
356func singletonPkgPath(singleton Singleton) string {
357 typ := reflect.TypeOf(singleton)
358 for typ.Kind() == reflect.Ptr {
359 typ = typ.Elem()
360 }
361 return typ.PkgPath()
362}
363
364func singletonTypeName(singleton Singleton) string {
365 typ := reflect.TypeOf(singleton)
366 for typ.Kind() == reflect.Ptr {
367 typ = typ.Elem()
368 }
369 return typ.PkgPath() + "." + typ.Name()
370}
371
Colin Crossc9028482014-12-18 16:28:54 -0800372// RegisterTopDownMutator registers a mutator that will be invoked to propagate
373// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700374// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
375// once per Module, and is invoked on a module before being invoked on any of its
376// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800377//
Colin Cross65569e42015-03-10 20:08:19 -0700378// The mutator type names given here must be unique to all top down mutators in
379// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800380func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
381 for _, m := range c.mutatorInfo {
382 if m.name == name && m.topDownMutator != nil {
383 panic(fmt.Errorf("mutator name %s is already registered", name))
384 }
385 }
386
387 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
388 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800389 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800390 })
391}
392
393// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700394// Modules into variants. Each registered mutator is invoked in registration
395// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
396// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800397//
Colin Cross65569e42015-03-10 20:08:19 -0700398// The mutator type names given here must be unique to all bottom up or early
399// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800400func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700401 for _, m := range c.variantMutatorNames {
402 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800403 panic(fmt.Errorf("mutator name %s is already registered", name))
404 }
405 }
406
407 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
408 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800409 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800410 })
Colin Cross65569e42015-03-10 20:08:19 -0700411
412 c.variantMutatorNames = append(c.variantMutatorNames, name)
413}
414
415// RegisterEarlyMutator registers a mutator that will be invoked to split
416// Modules into multiple variant Modules before any dependencies have been
417// created. Each registered mutator is invoked in registration order once
418// per Module (including each variant from previous early mutators). Module
419// order is unpredictable.
420//
421// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700422// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700423//
424// The mutator type names given here must be unique to all bottom up or early
425// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700426//
427// Deprecated, use a BottomUpMutator instead. The only difference between
428// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
429// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700430func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
431 for _, m := range c.variantMutatorNames {
432 if m == name {
433 panic(fmt.Errorf("mutator name %s is already registered", name))
434 }
435 }
436
437 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
438 mutator: mutator,
439 name: name,
440 })
441
442 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800443}
444
Jamie Gennisd4e10182014-06-12 20:06:50 -0700445// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
446// where it encounters an unknown module type while parsing Blueprints files. By
447// default, the context will report unknown module types as an error. If this
448// method is called with ignoreUnknownModuleTypes set to true then the context
449// will silently ignore unknown module types.
450//
451// This method should generally not be used. It exists to facilitate the
452// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700453func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
454 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
455}
456
Colin Cross036a1df2015-12-17 15:49:30 -0800457// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
458// unresolved dependencies. If the module's GenerateBuildActions calls
459// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
460// for missing dependencies.
461func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
462 c.allowMissingDependencies = allowMissingDependencies
463}
464
Jamie Gennisd4e10182014-06-12 20:06:50 -0700465// Parse parses a single Blueprints file from r, creating Module objects for
466// each of the module definitions encountered. If the Blueprints file contains
467// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700468// searched for Blueprints files returned in the subBlueprints return value.
469// If the Blueprints file contains an assignment to the "build" variable, then
470// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700471//
472// rootDir specifies the path to the root directory of the source tree, while
473// filename specifies the path to the Blueprints file. These paths are used for
474// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800475func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700476 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700477 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478
Jamie Gennisec701282014-06-12 20:06:31 -0700479 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700480 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700481 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700482 }
483
Colin Crossc0dbc552015-01-02 15:19:28 -0800484 scope = parser.NewScope(scope)
485 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800486 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700487 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700488 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700489 if len(errs) > 0 {
490 for i, err := range errs {
491 if parseErr, ok := err.(*parser.ParseError); ok {
492 err = &Error{
493 Err: parseErr.Err,
494 Pos: parseErr.Pos,
495 }
496 errs[i] = err
497 }
498 }
499
500 // If there were any parse errors don't bother trying to interpret the
501 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700502 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700503 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700504 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700505
Colin Cross6d8780f2015-07-10 17:51:55 -0700506 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700507 if err != nil {
508 errs = append(errs, err)
509 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700510
Colin Cross7f507402015-12-16 13:03:41 -0800511 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
512 if err != nil {
513 errs = append(errs, err)
514 }
515
Colin Cross6d8780f2015-07-10 17:51:55 -0700516 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700517 if err != nil {
518 errs = append(errs, err)
519 }
520
Colin Cross29394222015-04-27 13:18:21 -0700521 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
522
Colin Cross7f507402015-12-16 13:03:41 -0800523 var blueprints []string
524
525 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
526 blueprints = append(blueprints, newBlueprints...)
527 deps = append(deps, newDeps...)
528 errs = append(errs, newErrs...)
529
530 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
531 subBlueprintsName, false)
532 blueprints = append(blueprints, newBlueprints...)
533 deps = append(deps, newDeps...)
534 errs = append(errs, newErrs...)
535
536 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
537 optionalSubdirsPos, subBlueprintsName, true)
538 blueprints = append(blueprints, newBlueprints...)
539 deps = append(deps, newDeps...)
540 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800541
Colin Cross1fef5362015-04-20 16:50:54 -0700542 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
543 for i, b := range blueprints {
544 subBlueprintsAndScope[i] = stringAndScope{b, scope}
545 }
546
Colin Cross23d7aa12015-06-30 16:05:22 -0700547 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800548}
549
Colin Cross7ad621c2015-01-07 16:22:45 -0800550type stringAndScope struct {
551 string
552 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700553}
554
Jamie Gennisd4e10182014-06-12 20:06:50 -0700555// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
556// at rootFile. When it encounters a Blueprints file with a set of subdirs
557// listed it recursively parses any Blueprints files found in those
558// subdirectories.
559//
560// If no errors are encountered while parsing the files, the list of paths on
561// which the future output will depend is returned. This list will include both
562// Blueprints file paths as well as directory paths for cases where wildcard
563// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700564func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
565 errs []error) {
566
Colin Cross7ad621c2015-01-07 16:22:45 -0800567 c.dependenciesReady = false
568
Colin Cross23d7aa12015-06-30 16:05:22 -0700569 moduleCh := make(chan *moduleInfo)
570 errsCh := make(chan []error)
571 doneCh := make(chan struct{})
572 var numErrs uint32
573 var numGoroutines int32
574
575 // handler must be reentrant
576 handler := func(file *parser.File) {
577 if atomic.LoadUint32(&numErrs) > maxErrors {
578 return
579 }
580
581 atomic.AddInt32(&numGoroutines, 1)
582 go func() {
583 for _, def := range file.Defs {
584 var module *moduleInfo
585 var errs []error
586 switch def := def.(type) {
587 case *parser.Module:
588 module, errs = c.processModuleDef(def, file.Name)
589 case *parser.Assignment:
590 // Already handled via Scope object
591 default:
592 panic("unknown definition type")
593 }
594
595 if len(errs) > 0 {
596 atomic.AddUint32(&numErrs, uint32(len(errs)))
597 errsCh <- errs
598 } else if module != nil {
599 moduleCh <- module
600 }
601 }
602 doneCh <- struct{}{}
603 }()
604 }
605
606 atomic.AddInt32(&numGoroutines, 1)
607 go func() {
608 var errs []error
609 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
610 if len(errs) > 0 {
611 errsCh <- errs
612 }
613 doneCh <- struct{}{}
614 }()
615
616loop:
617 for {
618 select {
619 case newErrs := <-errsCh:
620 errs = append(errs, newErrs...)
621 case module := <-moduleCh:
622 newErrs := c.addModule(module)
623 if len(newErrs) > 0 {
624 errs = append(errs, newErrs...)
625 }
626 case <-doneCh:
627 n := atomic.AddInt32(&numGoroutines, -1)
628 if n == 0 {
629 break loop
630 }
631 }
632 }
633
634 return deps, errs
635}
636
637type FileHandler func(*parser.File)
638
639// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
640// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
641// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
642// it must be reentrant.
643//
644// If no errors are encountered while parsing the files, the list of paths on
645// which the future output will depend is returned. This list will include both
646// Blueprints file paths as well as directory paths for cases where wildcard
647// subdirs are found.
648func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
649 errs []error) {
650
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700651 rootDir := filepath.Dir(rootFile)
652
Colin Cross7ad621c2015-01-07 16:22:45 -0800653 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700654
Colin Cross7ad621c2015-01-07 16:22:45 -0800655 // Channels to receive data back from parseBlueprintsFile goroutines
656 blueprintsCh := make(chan stringAndScope)
657 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700658 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800659 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700660
Colin Cross7ad621c2015-01-07 16:22:45 -0800661 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
662 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700663
Colin Cross7ad621c2015-01-07 16:22:45 -0800664 // Number of outstanding goroutines to wait for
665 count := 0
666
667 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
668 count++
669 go func() {
670 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700671 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800672 doneCh <- struct{}{}
673 }()
674 }
675
676 tooManyErrors := false
677
678 startParseBlueprintsFile(rootFile, nil)
679
680loop:
681 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700682 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800683 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700684 }
685
Colin Cross7ad621c2015-01-07 16:22:45 -0800686 select {
687 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700688 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800689 case dep := <-depsCh:
690 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700691 case file := <-fileCh:
692 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800693 case blueprint := <-blueprintsCh:
694 if tooManyErrors {
695 continue
696 }
697 if blueprintsSet[blueprint.string] {
698 continue
699 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700700
Colin Cross7ad621c2015-01-07 16:22:45 -0800701 blueprintsSet[blueprint.string] = true
702 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
703 case <-doneCh:
704 count--
705 if count == 0 {
706 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700707 }
708 }
709 }
710
Colin Cross7ad621c2015-01-07 16:22:45 -0800711 return
712}
713
714// parseBlueprintFile parses a single Blueprints file, returning any errors through
715// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
716// blueprintsCh, and any dependencies on Blueprints files or directories through
717// depsCh.
718func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700719 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800720 depsCh chan<- string) {
721
Colin Cross23d7aa12015-06-30 16:05:22 -0700722 f, err := os.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800723 if err != nil {
724 errsCh <- []error{err}
725 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700726 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700727 defer func() {
728 err = f.Close()
729 if err != nil {
730 errsCh <- []error{err}
731 }
732 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700733
Colin Cross23d7aa12015-06-30 16:05:22 -0700734 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800735 if len(errs) > 0 {
736 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700737 } else {
738 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800739 }
740
Colin Cross1fef5362015-04-20 16:50:54 -0700741 for _, b := range subBlueprints {
742 blueprintsCh <- b
743 }
744
745 for _, d := range deps {
746 depsCh <- d
747 }
Colin Cross1fef5362015-04-20 16:50:54 -0700748}
749
Colin Cross7f507402015-12-16 13:03:41 -0800750func (c *Context) findBuildBlueprints(dir string, build []string,
751 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
752
753 for _, file := range build {
754 globPattern := filepath.Join(dir, file)
755 matches, matchedDirs, err := pathtools.Glob(globPattern)
756 if err != nil {
757 errs = append(errs, &Error{
758 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
759 Pos: buildPos,
760 })
761 continue
762 }
763
764 if len(matches) == 0 {
765 errs = append(errs, &Error{
766 Err: fmt.Errorf("%q: not found", globPattern),
767 Pos: buildPos,
768 })
769 }
770
771 // Depend on all searched directories so we pick up future changes.
772 deps = append(deps, matchedDirs...)
773
774 for _, foundBlueprints := range matches {
775 fileInfo, err := os.Stat(foundBlueprints)
776 if os.IsNotExist(err) {
777 errs = append(errs, &Error{
778 Err: fmt.Errorf("%q not found", foundBlueprints),
779 })
780 continue
781 }
782
783 if fileInfo.IsDir() {
784 errs = append(errs, &Error{
785 Err: fmt.Errorf("%q is a directory", foundBlueprints),
786 })
787 continue
788 }
789
790 blueprints = append(blueprints, foundBlueprints)
791 }
792 }
793
794 return blueprints, deps, errs
795}
796
797func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
798 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800799
800 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700801 globPattern := filepath.Join(dir, subdir)
802 matches, matchedDirs, err := pathtools.Glob(globPattern)
803 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700804 errs = append(errs, &Error{
805 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
806 Pos: subdirsPos,
807 })
808 continue
809 }
810
Colin Cross7f507402015-12-16 13:03:41 -0800811 if len(matches) == 0 && !optional {
Colin Cross1fef5362015-04-20 16:50:54 -0700812 errs = append(errs, &Error{
813 Err: fmt.Errorf("%q: not found", globPattern),
814 Pos: subdirsPos,
815 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700816 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800817
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700818 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700819 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800820
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700821 for _, foundSubdir := range matches {
822 fileInfo, subdirStatErr := os.Stat(foundSubdir)
823 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700824 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700825 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800826 }
827
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700828 // Skip files
829 if !fileInfo.IsDir() {
830 continue
831 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800832
Colin Cross29394222015-04-27 13:18:21 -0700833 var subBlueprints string
834 if subBlueprintsName != "" {
835 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
836 _, err = os.Stat(subBlueprints)
837 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700838
Colin Cross29394222015-04-27 13:18:21 -0700839 if os.IsNotExist(err) || subBlueprints == "" {
840 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
841 _, err = os.Stat(subBlueprints)
842 }
843
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700844 if os.IsNotExist(err) {
845 // There is no Blueprints file in this subdirectory. We
846 // need to add the directory to the list of dependencies
847 // so that if someone adds a Blueprints file in the
848 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700849 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700850 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700851 deps = append(deps, subBlueprints)
852 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800853 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800854 }
855 }
Colin Cross1fef5362015-04-20 16:50:54 -0700856
Colin Cross1fef5362015-04-20 16:50:54 -0700857 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700858}
859
Colin Cross6d8780f2015-07-10 17:51:55 -0700860func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
861 if assignment, local := scope.Get(v); assignment == nil || !local {
862 return nil, scanner.Position{}, nil
863 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700864 switch value := assignment.Value.Eval().(type) {
865 case *parser.List:
866 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700867
Colin Crosse32cc802016-06-07 12:28:16 -0700868 for _, listValue := range value.Values {
869 s, ok := listValue.(*parser.String)
870 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700871 // The parser should not produce this.
872 panic("non-string value found in list")
873 }
874
Colin Crosse32cc802016-06-07 12:28:16 -0700875 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700876 }
877
Colin Cross1fef5362015-04-20 16:50:54 -0700878 return ret, assignment.Pos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700879 case *parser.Bool, *parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700880 return nil, scanner.Position{}, &Error{
881 Err: fmt.Errorf("%q must be a list of strings", v),
882 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700883 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700884 default:
885 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
886 }
887 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700888}
889
Colin Cross29394222015-04-27 13:18:21 -0700890func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700891 if assignment, _ := scope.Get(v); assignment == nil {
892 return "", scanner.Position{}, nil
893 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700894 switch value := assignment.Value.Eval().(type) {
895 case *parser.String:
896 return value.Value, assignment.Pos, nil
897 case *parser.Bool, *parser.List:
Colin Cross29394222015-04-27 13:18:21 -0700898 return "", scanner.Position{}, &Error{
899 Err: fmt.Errorf("%q must be a string", v),
900 Pos: assignment.Pos,
901 }
902 default:
903 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
904 }
905 }
Colin Cross29394222015-04-27 13:18:21 -0700906}
907
Colin Cross910242b2016-04-11 15:41:52 -0700908// Clones a build logic module by calling the factory method for its module type, and then cloning
909// property values. Any values stored in the module object that are not stored in properties
910// structs will be lost.
911func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
912 typeName := origModule.typeName
913 factory, ok := c.moduleFactories[typeName]
914 if !ok {
915 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
916 }
917
918 props := []interface{}{
919 &origModule.properties,
920 }
921 newLogicModule, newProperties := factory()
922
923 newProperties = append(props, newProperties...)
924
925 if len(newProperties) != len(origModule.moduleProperties) {
926 panic("mismatched properties array length in " + origModule.properties.Name)
927 }
928
929 for i := range newProperties {
930 dst := reflect.ValueOf(newProperties[i]).Elem()
931 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
932
933 proptools.CopyProperties(dst, src)
934 }
935
936 return newLogicModule, newProperties
937}
938
Colin Crossf5e34b92015-03-13 16:02:36 -0700939func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
940 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800941
Colin Crossf4d18a62015-03-18 17:43:15 -0700942 if len(variationNames) == 0 {
943 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400944 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700945 }
946
Colin Crossc9028482014-12-18 16:28:54 -0800947 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800948
Colin Cross174ae052015-03-03 17:37:03 -0800949 var errs []error
950
Colin Crossf5e34b92015-03-13 16:02:36 -0700951 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -0800952 var newLogicModule Module
953 var newProperties []interface{}
954
955 if i == 0 {
956 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700957 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
958 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -0700959 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -0800960 } else {
Colin Cross910242b2016-04-11 15:41:52 -0700961 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -0800962 }
963
Colin Crossf5e34b92015-03-13 16:02:36 -0700964 newVariant := origModule.variant.clone()
965 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800966
Colin Crossed342d92015-03-11 00:57:25 -0700967 m := *origModule
968 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -0700969 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -0700970 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700971 newModule.variant = newVariant
972 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700973 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800974
Colin Crosse7daa222015-03-11 14:35:41 -0700975 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700976 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700977 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700978 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700979 }
980
Colin Crossc9028482014-12-18 16:28:54 -0800981 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700982
983 // Insert the new variant into the global module map. If this is the first variant then
984 // it reuses logicModule from the original module, which causes this to replace the
985 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800986 c.moduleInfo[newModule.logicModule] = newModule
987
Colin Crossf5e34b92015-03-13 16:02:36 -0700988 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800989 if len(newErrs) > 0 {
990 errs = append(errs, newErrs...)
991 }
Colin Crossc9028482014-12-18 16:28:54 -0800992 }
993
994 // Mark original variant as invalid. Modules that depend on this module will still
995 // depend on origModule, but we'll fix it when the mutator is called on them.
996 origModule.logicModule = nil
997 origModule.splitModules = newModules
998
Colin Cross174ae052015-03-03 17:37:03 -0800999 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001000}
1001
Colin Crossf5e34b92015-03-13 16:02:36 -07001002func (c *Context) convertDepsToVariation(module *moduleInfo,
1003 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001004
Colin Crossc9028482014-12-18 16:28:54 -08001005 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001006 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001007 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001008 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001009 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001010 newDep = m
1011 break
1012 }
1013 }
1014 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -08001015 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -07001016 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001017 variationName, dep.module.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -07001018 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001019 })
1020 continue
Colin Crossc9028482014-12-18 16:28:54 -08001021 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001022 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001023 }
1024 }
Colin Cross174ae052015-03-03 17:37:03 -08001025
1026 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001027}
1028
Colin Crossf5e34b92015-03-13 16:02:36 -07001029func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001030 names := make([]string, 0, len(variant))
1031 for _, m := range c.variantMutatorNames {
1032 if v, ok := variant[m]; ok {
1033 names = append(names, m+":"+v)
1034 }
1035 }
1036
1037 return strings.Join(names, ", ")
1038}
1039
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001040func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001041 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001042
Colin Crossd1facc12015-01-08 14:56:03 -08001043 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001044 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001045 if !ok {
1046 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001047 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001048 }
1049
Colin Cross7ad621c2015-01-07 16:22:45 -08001050 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001051 &Error{
1052 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -08001053 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001054 },
1055 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001056 }
1057
Colin Crossbbfa51a2014-12-17 16:12:41 -08001058 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001059
1060 module := &moduleInfo{
1061 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -07001062 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -07001063 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001064 }
1065
Jamie Gennis87622922014-09-30 11:38:25 -07001066 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001067 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001068 }
1069 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001070 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001071
Jamie Gennis87622922014-09-30 11:38:25 -07001072 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001073 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001074 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001075 }
1076
Colin Crossed342d92015-03-11 00:57:25 -07001077 module.pos = moduleDef.Type.Pos
1078 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001079 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -07001080 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001081 }
1082
Colin Cross7ad621c2015-01-07 16:22:45 -08001083 return module, nil
1084}
1085
Colin Cross23d7aa12015-06-30 16:05:22 -07001086func (c *Context) addModule(module *moduleInfo) []error {
1087 name := module.properties.Name
1088 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001089
Colin Cross23d7aa12015-06-30 16:05:22 -07001090 if group, present := c.moduleGroups[name]; present {
1091 return []error{
1092 &Error{
1093 Err: fmt.Errorf("module %q already defined", name),
1094 Pos: module.pos,
1095 },
1096 &Error{
1097 Err: fmt.Errorf("<-- previous definition here"),
1098 Pos: group.modules[0].pos,
1099 },
Colin Crossed342d92015-03-11 00:57:25 -07001100 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001101 } else {
1102 ninjaName := toNinjaName(module.properties.Name)
1103
1104 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1105 // already exists
1106 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1107 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1108 }
1109
1110 group := &moduleGroup{
1111 name: module.properties.Name,
1112 ninjaName: ninjaName,
1113 modules: []*moduleInfo{module},
1114 }
1115 module.group = group
1116 c.moduleGroups[name] = group
1117 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001118 }
1119
Colin Cross23d7aa12015-06-30 16:05:22 -07001120 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001121}
1122
Jamie Gennisd4e10182014-06-12 20:06:50 -07001123// ResolveDependencies checks that the dependencies specified by all of the
1124// modules defined in the parsed Blueprints files are valid. This means that
1125// the modules depended upon are defined and that no circular dependencies
1126// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001127func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross763b6f12015-10-29 15:32:56 -07001128 errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001129 if len(errs) > 0 {
1130 return errs
1131 }
1132
Colin Cross910242b2016-04-11 15:41:52 -07001133 c.cloneModules()
1134
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001135 c.dependenciesReady = true
1136 return nil
1137}
1138
Colin Cross763b6f12015-10-29 15:32:56 -07001139// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001140// DynamicDependerModule interface then this set consists of the union of those
1141// module names listed in its "deps" property, those returned by its
1142// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001143// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001144// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001145func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001146 ctx.AddDependency(ctx.Module(), nil, ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001147
Colin Cross763b6f12015-10-29 15:32:56 -07001148 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001149 func() {
1150 defer func() {
1151 if r := recover(); r != nil {
1152 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1153 }
1154 }()
1155 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001156
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001157 if ctx.Failed() {
1158 return
1159 }
Colin Cross763b6f12015-10-29 15:32:56 -07001160
Colin Cross2c1f3d12016-04-11 15:47:28 -07001161 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001162 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001163 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001164}
1165
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001166// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1167// and returns the matching module, or nil if one is not found.
1168func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1169 if len(group.modules) == 1 {
1170 return group.modules[0]
1171 } else {
1172 for _, m := range group.modules {
1173 if m.variant.equal(module.dependencyVariant) {
1174 return m
1175 }
1176 }
1177 }
1178
1179 return nil
1180}
1181
Colin Cross2c1f3d12016-04-11 15:47:28 -07001182func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001183 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001184 return []error{&Error{
1185 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001186 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001187 }}
1188 }
1189
Colin Cross2c1f3d12016-04-11 15:47:28 -07001190 depGroup, ok := c.moduleGroups[depName]
Colin Crossc9028482014-12-18 16:28:54 -08001191 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001192 if c.allowMissingDependencies {
1193 module.missingDeps = append(module.missingDeps, depName)
1194 return nil
1195 }
Colin Crossc9028482014-12-18 16:28:54 -08001196 return []error{&Error{
1197 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001198 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001199 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001200 }}
1201 }
1202
Colin Cross2c1f3d12016-04-11 15:47:28 -07001203 if m := c.findMatchingVariant(module, depGroup); m != nil {
1204 for _, dep := range module.directDeps {
1205 if m == dep.module {
1206 // TODO(ccross): what if adding a dependency with a different tag?
1207 return nil
1208 }
Colin Cross65569e42015-03-10 20:08:19 -07001209 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001210 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001211 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001212 }
Colin Crossc9028482014-12-18 16:28:54 -08001213
Colin Cross65569e42015-03-10 20:08:19 -07001214 return []error{&Error{
1215 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001216 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001217 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001218 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001219 }}
1220}
1221
Colin Cross8d8a7af2015-11-03 16:41:29 -08001222func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001223 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001224 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001225 Err: fmt.Errorf("%q depends on itself", destName),
1226 Pos: module.pos,
1227 }}
1228 }
1229
1230 destInfo, ok := c.moduleGroups[destName]
1231 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001232 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001233 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1234 module.properties.Name, destName),
1235 Pos: module.pos,
1236 }}
1237 }
1238
1239 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001240 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001241 }
1242
Colin Cross8d8a7af2015-11-03 16:41:29 -08001243 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001244 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1245 destName, module.properties.Name,
1246 c.prettyPrintVariant(module.dependencyVariant)),
1247 Pos: module.pos,
1248 }}
1249}
1250
Colin Crossf5e34b92015-03-13 16:02:36 -07001251func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001252 tag DependencyTag, depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001253
Colin Cross2c1f3d12016-04-11 15:47:28 -07001254 depGroup, ok := c.moduleGroups[depName]
Colin Cross65569e42015-03-10 20:08:19 -07001255 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001256 if c.allowMissingDependencies {
1257 module.missingDeps = append(module.missingDeps, depName)
1258 return nil
1259 }
Colin Cross65569e42015-03-10 20:08:19 -07001260 return []error{&Error{
1261 Err: fmt.Errorf("%q depends on undefined module %q",
1262 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001263 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001264 }}
1265 }
1266
1267 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1268 // compare the strings because the result won't be in mutator registration order.
1269 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001270 var newVariant variationMap
1271 if !far {
1272 newVariant = module.dependencyVariant.clone()
1273 } else {
1274 newVariant = make(variationMap)
1275 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001276 for _, v := range variations {
1277 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001278 }
1279
Colin Cross2c1f3d12016-04-11 15:47:28 -07001280 for _, m := range depGroup.modules {
Colin Cross89486232015-05-08 11:14:54 -07001281 var found bool
1282 if far {
1283 found = m.variant.subset(newVariant)
1284 } else {
1285 found = m.variant.equal(newVariant)
1286 }
1287 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001288 if module == m {
1289 return []error{&Error{
1290 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001291 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001292 }}
1293 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001294 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001295 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001296 // run GenerateBuildActions in order for the variants of a module
Colin Cross2c1f3d12016-04-11 15:47:28 -07001297 if depGroup == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross65569e42015-03-10 20:08:19 -07001298 return []error{&Error{
1299 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001300 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001301 }}
1302 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001303 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001304 return nil
1305 }
1306 }
1307
1308 return []error{&Error{
1309 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001310 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001311 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001312 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001313 }}
Colin Crossc9028482014-12-18 16:28:54 -08001314}
1315
Colin Crossf1875462016-04-11 17:33:13 -07001316func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1317 from, to Module) {
1318
1319 var fromInfo, toInfo *moduleInfo
1320 for _, m := range origModule.splitModules {
1321 if m.logicModule == from {
1322 fromInfo = m
1323 }
1324 if m.logicModule == to {
1325 toInfo = m
1326 if fromInfo != nil {
1327 panic(fmt.Errorf("%q depends on later version of itself", origModule.properties.Name))
1328 }
1329 }
1330 }
1331
1332 if fromInfo == nil || toInfo == nil {
1333 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
1334 origModule.properties.Name))
1335 }
1336
1337 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
1338}
1339
Colin Cross7addea32015-03-11 15:43:52 -07001340func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1341 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001342 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001343 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001344
Colin Cross7addea32015-03-11 15:43:52 -07001345 for _, module := range c.modulesSorted {
1346 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001347 }
1348
Colin Cross7addea32015-03-11 15:43:52 -07001349 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001350 count++
1351 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001352 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001353 if ret {
1354 cancel = true
1355 }
Colin Cross7addea32015-03-11 15:43:52 -07001356 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001357 }()
1358 }
1359
Colin Cross7addea32015-03-11 15:43:52 -07001360 for _, module := range c.modulesSorted {
1361 if module.waitingCount == 0 {
1362 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001363 }
1364 }
1365
Colin Cross11e3b0d2015-02-04 10:41:00 -08001366 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001367 select {
Colin Cross7addea32015-03-11 15:43:52 -07001368 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001369 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001370 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001371 parent.waitingCount--
1372 if parent.waitingCount == 0 {
1373 visitOne(parent)
1374 }
Colin Cross691a60d2015-01-07 18:08:56 -08001375 }
1376 }
1377 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001378 }
1379 }
1380}
1381
1382// updateDependencies recursively walks the module dependency graph and updates
1383// additional fields based on the dependencies. It builds a sorted list of modules
1384// such that dependencies of a module always appear first, and populates reverse
1385// dependency links and counts of total dependencies. It also reports errors when
1386// it encounters dependency cycles. This should called after resolveDependencies,
1387// as well as after any mutator pass has called addDependency
1388func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001389 visited := make(map[*moduleInfo]bool) // modules that were already checked
1390 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391
Colin Cross7addea32015-03-11 15:43:52 -07001392 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001393
Colin Cross7addea32015-03-11 15:43:52 -07001394 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001395
Colin Cross7addea32015-03-11 15:43:52 -07001396 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001397 // We are the "start" of the cycle, so we're responsible
1398 // for generating the errors. The cycle list is in
1399 // reverse order because all the 'check' calls append
1400 // their own module to the list.
1401 errs = append(errs, &Error{
1402 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001403 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001404 })
1405
1406 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001407 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001408 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001409 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001410 errs = append(errs, &Error{
1411 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001412 curModule.properties.Name,
1413 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001414 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001415 })
Colin Cross7addea32015-03-11 15:43:52 -07001416 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001417 }
1418 }
1419
Colin Cross7addea32015-03-11 15:43:52 -07001420 check = func(module *moduleInfo) []*moduleInfo {
1421 visited[module] = true
1422 checking[module] = true
1423 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001424
Colin Cross7addea32015-03-11 15:43:52 -07001425 deps := make(map[*moduleInfo]bool)
1426
1427 // Add an implicit dependency ordering on all earlier modules in the same module group
1428 for _, dep := range module.group.modules {
1429 if dep == module {
1430 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001431 }
Colin Cross7addea32015-03-11 15:43:52 -07001432 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001433 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001434
Colin Cross7addea32015-03-11 15:43:52 -07001435 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001436 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001437 }
1438
1439 module.reverseDeps = []*moduleInfo{}
1440 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001441
Colin Crossbbfa51a2014-12-17 16:12:41 -08001442 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001443 if checking[dep] {
1444 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001445 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001446 }
1447
1448 if !visited[dep] {
1449 cycle := check(dep)
1450 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001451 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001452 // We are the "start" of the cycle, so we're responsible
1453 // for generating the errors. The cycle list is in
1454 // reverse order because all the 'check' calls append
1455 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001456 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001457
1458 // We can continue processing this module's children to
1459 // find more cycles. Since all the modules that were
1460 // part of the found cycle were marked as visited we
1461 // won't run into that cycle again.
1462 } else {
1463 // We're not the "start" of the cycle, so we just append
1464 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001465 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001466 }
1467 }
1468 }
Colin Cross691a60d2015-01-07 18:08:56 -08001469
Colin Cross7addea32015-03-11 15:43:52 -07001470 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001471 }
1472
Colin Cross7addea32015-03-11 15:43:52 -07001473 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001474
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001475 return nil
1476 }
1477
Colin Cross7addea32015-03-11 15:43:52 -07001478 for _, module := range c.moduleInfo {
1479 if !visited[module] {
1480 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001481 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001482 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001483 panic("inconceivable!")
1484 }
1485 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001486 }
1487 }
1488 }
1489
Colin Cross7addea32015-03-11 15:43:52 -07001490 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001491
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001492 return
1493}
1494
Jamie Gennisd4e10182014-06-12 20:06:50 -07001495// PrepareBuildActions generates an internal representation of all the build
1496// actions that need to be performed. This process involves invoking the
1497// GenerateBuildActions method on each of the Module objects created during the
1498// parse phase and then on each of the registered Singleton objects.
1499//
1500// If the ResolveDependencies method has not already been called it is called
1501// automatically by this method.
1502//
1503// The config argument is made available to all of the Module and Singleton
1504// objects via the Config method on the ModuleContext and SingletonContext
1505// objects passed to GenerateBuildActions. It is also passed to the functions
1506// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1507// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001508//
1509// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001510// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1511// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1512// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001513func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001514 c.buildActionsReady = false
1515
1516 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001517 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001518 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001519 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001520 }
1521 }
1522
1523 liveGlobals := newLiveTracker(config)
1524
1525 c.initSpecialVariables()
1526
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001527 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001528 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001529 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001530 }
1531
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001532 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
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
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001537 deps = append(depsModules, depsSingletons...)
1538
Colin Crossa2599452015-11-18 16:01:01 -08001539 if c.ninjaBuildDir != nil {
1540 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001541 }
1542
Dan Willemsena481ae22015-12-18 15:18:03 -08001543 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1544
1545 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001546
1547 // This will panic if it finds a problem since it's a programming error.
1548 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1549
1550 c.pkgNames = pkgNames
1551 c.globalVariables = liveGlobals.variables
1552 c.globalPools = liveGlobals.pools
1553 c.globalRules = liveGlobals.rules
1554
1555 c.buildActionsReady = true
1556
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001557 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001558}
1559
Colin Cross65569e42015-03-10 20:08:19 -07001560func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1561 for _, mutator := range c.earlyMutatorInfo {
1562 for _, group := range c.moduleGroups {
1563 newModules := make([]*moduleInfo, 0, len(group.modules))
1564
1565 for _, module := range group.modules {
1566 mctx := &mutatorContext{
1567 baseModuleContext: baseModuleContext{
1568 context: c,
1569 config: config,
1570 module: module,
1571 },
1572 name: mutator.name,
1573 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001574 func() {
1575 defer func() {
1576 if r := recover(); r != nil {
1577 in := fmt.Sprintf("early mutator %q for %s", mutator.name, module)
1578 if err, ok := r.(panicError); ok {
1579 err.addIn(in)
1580 mctx.error(err)
1581 } else {
1582 mctx.error(newPanicErrorf(r, in))
1583 }
1584 }
1585 }()
1586 mutator.mutator(mctx)
1587 }()
Colin Cross65569e42015-03-10 20:08:19 -07001588 if len(mctx.errs) > 0 {
1589 errs = append(errs, mctx.errs...)
1590 return errs
1591 }
1592
1593 if module.splitModules != nil {
1594 newModules = append(newModules, module.splitModules...)
1595 } else {
1596 newModules = append(newModules, module)
1597 }
1598 }
1599
1600 group.modules = newModules
1601 }
1602 }
1603
Colin Cross763b6f12015-10-29 15:32:56 -07001604 errs = c.updateDependencies()
1605 if len(errs) > 0 {
1606 return errs
1607 }
1608
Colin Cross65569e42015-03-10 20:08:19 -07001609 return nil
1610}
1611
Colin Crossc9028482014-12-18 16:28:54 -08001612func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Cross763b6f12015-10-29 15:32:56 -07001613 errs = c.runEarlyMutators(config)
1614 if len(errs) > 0 {
1615 return errs
1616 }
1617
Colin Crossc9028482014-12-18 16:28:54 -08001618 for _, mutator := range c.mutatorInfo {
1619 if mutator.topDownMutator != nil {
1620 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1621 } else if mutator.bottomUpMutator != nil {
1622 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1623 } else {
1624 panic("no mutator set on " + mutator.name)
1625 }
1626 if len(errs) > 0 {
1627 return errs
1628 }
1629 }
1630
1631 return nil
1632}
1633
1634func (c *Context) runTopDownMutator(config interface{},
1635 name string, mutator TopDownMutator) (errs []error) {
1636
Colin Cross7addea32015-03-11 15:43:52 -07001637 for i := 0; i < len(c.modulesSorted); i++ {
1638 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1639 mctx := &mutatorContext{
1640 baseModuleContext: baseModuleContext{
1641 context: c,
1642 config: config,
1643 module: module,
1644 },
1645 name: name,
1646 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001647 func() {
1648 defer func() {
1649 if r := recover(); r != nil {
1650 in := fmt.Sprintf("top down mutator %q for %s", name, module)
1651 if err, ok := r.(panicError); ok {
1652 err.addIn(in)
1653 mctx.error(err)
1654 } else {
1655 mctx.error(newPanicErrorf(r, in))
1656 }
1657 }
1658 }()
1659 mutator(mctx)
1660 }()
Colin Crossc9028482014-12-18 16:28:54 -08001661
Colin Cross7addea32015-03-11 15:43:52 -07001662 if len(mctx.errs) > 0 {
1663 errs = append(errs, mctx.errs...)
1664 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001665 }
1666 }
1667
1668 return errs
1669}
1670
1671func (c *Context) runBottomUpMutator(config interface{},
1672 name string, mutator BottomUpMutator) (errs []error) {
1673
Colin Cross2c1f3d12016-04-11 15:47:28 -07001674 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross8d8a7af2015-11-03 16:41:29 -08001675
Colin Cross7addea32015-03-11 15:43:52 -07001676 for _, module := range c.modulesSorted {
1677 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001678
Jamie Gennisc7988252015-04-14 23:28:10 -04001679 if module.splitModules != nil {
1680 panic("split module found in sorted module list")
1681 }
1682
Colin Cross7addea32015-03-11 15:43:52 -07001683 mctx := &mutatorContext{
1684 baseModuleContext: baseModuleContext{
1685 context: c,
1686 config: config,
1687 module: module,
1688 },
Colin Cross8d8a7af2015-11-03 16:41:29 -08001689 name: name,
1690 reverseDeps: reverseDeps,
Colin Cross7addea32015-03-11 15:43:52 -07001691 }
Colin Crossc9028482014-12-18 16:28:54 -08001692
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001693 func() {
1694 defer func() {
1695 if r := recover(); r != nil {
1696 in := fmt.Sprintf("bottom up mutator %q for %s", name, module)
1697 if err, ok := r.(panicError); ok {
1698 err.addIn(in)
1699 mctx.error(err)
1700 } else {
1701 mctx.error(newPanicErrorf(r, in))
1702 }
1703 }
1704 }()
1705 mutator(mctx)
1706 }()
Colin Cross7addea32015-03-11 15:43:52 -07001707 if len(mctx.errs) > 0 {
1708 errs = append(errs, mctx.errs...)
1709 return errs
1710 }
Colin Crossc9028482014-12-18 16:28:54 -08001711
Colin Cross7addea32015-03-11 15:43:52 -07001712 // Fix up any remaining dependencies on modules that were split into variants
1713 // by replacing them with the first variant
1714 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001715 if dep.module.logicModule == nil {
1716 module.directDeps[i].module = dep.module.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001717 }
1718 }
1719
Colin Cross7addea32015-03-11 15:43:52 -07001720 if module.splitModules != nil {
1721 newModules = append(newModules, module.splitModules...)
1722 } else {
1723 newModules = append(newModules, module)
1724 }
1725
1726 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001727 }
1728
Colin Cross8d8a7af2015-11-03 16:41:29 -08001729 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001730 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001731 module.directDeps = append(module.directDeps, deps...)
1732 }
1733
Jamie Gennisc7988252015-04-14 23:28:10 -04001734 errs = c.updateDependencies()
1735 if len(errs) > 0 {
1736 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001737 }
1738
1739 return errs
1740}
1741
Colin Cross910242b2016-04-11 15:41:52 -07001742// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1743// a mutator sets a non-property member variable on a module, which works until a later mutator
1744// creates variants of that module.
1745func (c *Context) cloneModules() {
1746 for _, m := range c.modulesSorted {
1747 origLogicModule := m.logicModule
1748 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1749 delete(c.moduleInfo, origLogicModule)
1750 c.moduleInfo[m.logicModule] = m
1751 }
1752}
1753
Colin Cross7addea32015-03-11 15:43:52 -07001754func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1755 newModules []*moduleInfo) []*moduleInfo {
1756 for i, m := range modules {
1757 if m == origModule {
1758 return spliceModulesAtIndex(modules, i, newModules)
1759 }
1760 }
1761
1762 panic("failed to find original module to splice")
1763}
1764
1765func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1766 spliceSize := len(newModules)
1767 newLen := len(modules) + spliceSize - 1
1768 var dest []*moduleInfo
1769 if cap(modules) >= len(modules)-1+len(newModules) {
1770 // We can fit the splice in the existing capacity, do everything in place
1771 dest = modules[:newLen]
1772 } else {
1773 dest = make([]*moduleInfo, newLen)
1774 copy(dest, modules[:i])
1775 }
1776
1777 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001778 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001779
1780 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001781 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001782
Colin Cross72bd1932015-03-16 00:13:59 -07001783 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001784}
1785
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001786func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001787 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001788 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001789 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001790 c.requiredNinjaMicro = 0
1791}
1792
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001793func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001794 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001795
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001796 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001797 var errs []error
1798
Colin Cross691a60d2015-01-07 18:08:56 -08001799 cancelCh := make(chan struct{})
1800 errsCh := make(chan []error)
1801 depsCh := make(chan []string)
1802
1803 go func() {
1804 for {
1805 select {
1806 case <-cancelCh:
1807 close(cancelCh)
1808 return
1809 case newErrs := <-errsCh:
1810 errs = append(errs, newErrs...)
1811 case newDeps := <-depsCh:
1812 deps = append(deps, newDeps...)
1813
1814 }
1815 }
1816 }()
1817
Colin Cross7addea32015-03-11 15:43:52 -07001818 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1819 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1820 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1821 // just set it to nil.
1822 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1823 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001824
Colin Cross7addea32015-03-11 15:43:52 -07001825 mctx := &moduleContext{
1826 baseModuleContext: baseModuleContext{
1827 context: c,
1828 config: config,
1829 module: module,
1830 },
Colin Cross036a1df2015-12-17 15:49:30 -08001831 scope: scope,
1832 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001833 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001834
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001835 func() {
1836 defer func() {
1837 if r := recover(); r != nil {
1838 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1839 if err, ok := r.(panicError); ok {
1840 err.addIn(in)
1841 mctx.error(err)
1842 } else {
1843 mctx.error(newPanicErrorf(r, in))
1844 }
1845 }
1846 }()
1847 mctx.module.logicModule.GenerateBuildActions(mctx)
1848 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001849
Colin Cross7addea32015-03-11 15:43:52 -07001850 if len(mctx.errs) > 0 {
1851 errsCh <- mctx.errs
1852 return true
1853 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001854
Colin Cross036a1df2015-12-17 15:49:30 -08001855 if module.missingDeps != nil && !mctx.handledMissingDeps {
1856 var errs []error
1857 for _, depName := range module.missingDeps {
1858 errs = append(errs, &Error{
1859 Err: fmt.Errorf("%q depends on undefined module %q",
1860 module.properties.Name, depName),
1861 Pos: module.pos,
1862 })
1863 }
1864 errsCh <- errs
1865 return true
1866 }
1867
Colin Cross7addea32015-03-11 15:43:52 -07001868 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001869
Colin Crossab6d7902015-03-11 16:17:52 -07001870 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001871 &mctx.actionDefs, liveGlobals)
1872 if len(newErrs) > 0 {
1873 errsCh <- newErrs
1874 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001875 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001876 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001877 })
1878
1879 cancelCh <- struct{}{}
1880 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001881
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001882 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001883}
1884
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001885func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001886 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001887
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001888 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001889 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001890
Yuchen Wub9103ef2015-08-25 17:58:17 -07001891 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001892 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1893 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1894 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001895 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001896
1897 sctx := &singletonContext{
1898 context: c,
1899 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001900 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08001901 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001902 }
1903
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001904 func() {
1905 defer func() {
1906 if r := recover(); r != nil {
1907 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
1908 if err, ok := r.(panicError); ok {
1909 err.addIn(in)
1910 sctx.error(err)
1911 } else {
1912 sctx.error(newPanicErrorf(r, in))
1913 }
1914 }
1915 }()
1916 info.singleton.GenerateBuildActions(sctx)
1917 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001918
1919 if len(sctx.errs) > 0 {
1920 errs = append(errs, sctx.errs...)
1921 if len(errs) > maxErrors {
1922 break
1923 }
1924 continue
1925 }
1926
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001927 deps = append(deps, sctx.ninjaFileDeps...)
1928
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001929 newErrs := c.processLocalBuildActions(&info.actionDefs,
1930 &sctx.actionDefs, liveGlobals)
1931 errs = append(errs, newErrs...)
1932 if len(errs) > maxErrors {
1933 break
1934 }
1935 }
1936
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001937 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001938}
1939
1940func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1941 liveGlobals *liveTracker) []error {
1942
1943 var errs []error
1944
1945 // First we go through and add everything referenced by the module's
1946 // buildDefs to the live globals set. This will end up adding the live
1947 // locals to the set as well, but we'll take them out after.
1948 for _, def := range in.buildDefs {
1949 err := liveGlobals.AddBuildDefDeps(def)
1950 if err != nil {
1951 errs = append(errs, err)
1952 }
1953 }
1954
1955 if len(errs) > 0 {
1956 return errs
1957 }
1958
Colin Crossc9028482014-12-18 16:28:54 -08001959 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001960
1961 // We use the now-incorrect set of live "globals" to determine which local
1962 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001963 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001964 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001965 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001966 if isLive {
1967 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001968 }
1969 }
1970
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001971 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001972 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001973 if isLive {
1974 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001975 }
1976 }
1977
1978 return nil
1979}
1980
Yuchen Wu222e2452015-10-06 14:03:27 -07001981func (c *Context) walkDeps(topModule *moduleInfo,
1982 visit func(Module, Module) bool) {
1983
1984 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001985 var visiting *moduleInfo
1986
1987 defer func() {
1988 if r := recover(); r != nil {
1989 panic(newPanicErrorf(r, "WalkDeps(%s, %s) for dependency %s",
1990 topModule, funcName(visit), visiting))
1991 }
1992 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07001993
1994 var walk func(module *moduleInfo)
1995 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001996 for _, dep := range module.directDeps {
1997 if !visited[dep.module] {
1998 visited[dep.module] = true
1999 visiting = dep.module
2000 if visit(dep.module.logicModule, module.logicModule) {
2001 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002002 }
2003 }
2004 }
2005 }
2006
2007 walk(topModule)
2008}
2009
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002010type innerPanicError error
2011
Colin Crossbbfa51a2014-12-17 16:12:41 -08002012func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
2013 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002014 var visiting *moduleInfo
2015
2016 defer func() {
2017 if r := recover(); r != nil {
2018 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2019 topModule, funcName(visit), visiting))
2020 }
2021 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002022
Colin Crossbbfa51a2014-12-17 16:12:41 -08002023 var walk func(module *moduleInfo)
2024 walk = func(module *moduleInfo) {
2025 visited[module] = true
Colin Cross2c1f3d12016-04-11 15:47:28 -07002026 for _, dep := range module.directDeps {
2027 if !visited[dep.module] {
2028 walk(dep.module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002029 }
2030 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002031
Colin Crossbbfa51a2014-12-17 16:12:41 -08002032 if module != topModule {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002033 visiting = module
Colin Crossbbfa51a2014-12-17 16:12:41 -08002034 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002035 }
2036 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002037
2038 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002039}
2040
Colin Crossbbfa51a2014-12-17 16:12:41 -08002041func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002042 visit func(Module)) {
2043
Colin Crossbbfa51a2014-12-17 16:12:41 -08002044 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002045 var visiting *moduleInfo
2046
2047 defer func() {
2048 if r := recover(); r != nil {
2049 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2050 topModule, funcName(pred), funcName(visit), visiting))
2051 }
2052 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002053
Colin Crossbbfa51a2014-12-17 16:12:41 -08002054 var walk func(module *moduleInfo)
2055 walk = func(module *moduleInfo) {
2056 visited[module] = true
Colin Cross2c1f3d12016-04-11 15:47:28 -07002057 for _, dep := range module.directDeps {
2058 if !visited[dep.module] {
2059 walk(dep.module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002060 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08002061 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002062
2063 if module != topModule {
2064 if pred(module.logicModule) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002065 visiting = module
Colin Crossbbfa51a2014-12-17 16:12:41 -08002066 visit(module.logicModule)
2067 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002068 }
2069 }
2070
Colin Crossbbfa51a2014-12-17 16:12:41 -08002071 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002072}
2073
Jamie Gennisc15544d2014-09-24 20:26:52 -07002074func (c *Context) sortedModuleNames() []string {
2075 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002076 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
2077 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002078 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2079 moduleName)
2080 }
2081 sort.Strings(c.cachedSortedModuleNames)
2082 }
2083
2084 return c.cachedSortedModuleNames
2085}
2086
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002087func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002088 var module *moduleInfo
2089
2090 defer func() {
2091 if r := recover(); r != nil {
2092 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2093 funcName(visit), module))
2094 }
2095 }()
2096
Jamie Gennisc15544d2014-09-24 20:26:52 -07002097 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002098 group := c.moduleGroups[moduleName]
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002099 for _, module = range group.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002100 visit(module.logicModule)
2101 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002102 }
2103}
2104
2105func (c *Context) visitAllModulesIf(pred func(Module) bool,
2106 visit func(Module)) {
2107
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002108 var module *moduleInfo
2109
2110 defer func() {
2111 if r := recover(); r != nil {
2112 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2113 funcName(pred), funcName(visit), module))
2114 }
2115 }()
2116
Jamie Gennisc15544d2014-09-24 20:26:52 -07002117 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002118 group := c.moduleGroups[moduleName]
2119 for _, module := range group.modules {
2120 if pred(module.logicModule) {
2121 visit(module.logicModule)
2122 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002123 }
2124 }
2125}
2126
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002127func (c *Context) visitAllModuleVariants(module *moduleInfo,
2128 visit func(Module)) {
2129
2130 var variant *moduleInfo
2131
2132 defer func() {
2133 if r := recover(); r != nil {
2134 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2135 module, funcName(visit), variant))
2136 }
2137 }()
2138
2139 for _, variant = range module.group.modules {
2140 visit(variant.logicModule)
2141 }
2142}
2143
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002144func (c *Context) requireNinjaVersion(major, minor, micro int) {
2145 if major != 1 {
2146 panic("ninja version with major version != 1 not supported")
2147 }
2148 if c.requiredNinjaMinor < minor {
2149 c.requiredNinjaMinor = minor
2150 c.requiredNinjaMicro = micro
2151 }
2152 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2153 c.requiredNinjaMicro = micro
2154 }
2155}
2156
Colin Crossa2599452015-11-18 16:01:01 -08002157func (c *Context) setNinjaBuildDir(value *ninjaString) {
2158 if c.ninjaBuildDir == nil {
2159 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002160 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002161}
2162
2163func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002164 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002165
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002166 pkgs := make(map[string]*packageContext)
2167 pkgNames := make(map[*packageContext]string)
2168 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002169
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002170 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002171 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002172 // This is a built-in rule and has no package.
2173 return
2174 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002175 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002176 // We've already processed this package.
2177 return
2178 }
2179
Jamie Gennis2fb20952014-10-03 02:49:58 -07002180 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002181 if present {
2182 // Short name collision. Both this package and the one that's
2183 // already there need to use their full names. We leave the short
2184 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002185 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002186 longPkgNames[otherPkg] = true
2187 } else {
2188 // No collision so far. Tentatively set the package's name to be
2189 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002190 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002191 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002192 }
2193 }
2194
2195 // We try to give all packages their short name, but when we get collisions
2196 // we need to use the full unique package name.
2197 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002198 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002199 }
2200 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002201 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002202 }
2203 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002204 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002205 }
2206
2207 // Add the packages that had collisions using their full unique names. This
2208 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002209 for pctx := range longPkgNames {
2210 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002211 }
2212
Dan Willemsena481ae22015-12-18 15:18:03 -08002213 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2214 deps := []string{}
2215 for _, pkg := range pkgs {
2216 deps = append(deps, pkg.ninjaFileDeps...)
2217 }
2218
2219 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002220}
2221
2222func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002223 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002224
2225 visited := make(map[Variable]bool) // variables that were already checked
2226 checking := make(map[Variable]bool) // variables actively being checked
2227
2228 var check func(v Variable) []Variable
2229
2230 check = func(v Variable) []Variable {
2231 visited[v] = true
2232 checking[v] = true
2233 defer delete(checking, v)
2234
2235 value := variables[v]
2236 for _, dep := range value.variables {
2237 if checking[dep] {
2238 // This is a cycle.
2239 return []Variable{dep, v}
2240 }
2241
2242 if !visited[dep] {
2243 cycle := check(dep)
2244 if cycle != nil {
2245 if cycle[0] == v {
2246 // We are the "start" of the cycle, so we're responsible
2247 // for generating the errors. The cycle list is in
2248 // reverse order because all the 'check' calls append
2249 // their own module to the list.
2250 msgs := []string{"detected variable reference cycle:"}
2251
2252 // Iterate backwards through the cycle list.
2253 curName := v.fullName(pkgNames)
2254 curValue := value.Value(pkgNames)
2255 for i := len(cycle) - 1; i >= 0; i-- {
2256 next := cycle[i]
2257 nextName := next.fullName(pkgNames)
2258 nextValue := variables[next].Value(pkgNames)
2259
2260 msgs = append(msgs, fmt.Sprintf(
2261 " %q depends on %q", curName, nextName))
2262 msgs = append(msgs, fmt.Sprintf(
2263 " [%s = %s]", curName, curValue))
2264
2265 curName = nextName
2266 curValue = nextValue
2267 }
2268
2269 // Variable reference cycles are a programming error,
2270 // not the fault of the Blueprint file authors.
2271 panic(strings.Join(msgs, "\n"))
2272 } else {
2273 // We're not the "start" of the cycle, so we just append
2274 // our module to the list and return it.
2275 return append(cycle, v)
2276 }
2277 }
2278 }
2279 }
2280
2281 return nil
2282 }
2283
2284 for v := range variables {
2285 if !visited[v] {
2286 cycle := check(v)
2287 if cycle != nil {
2288 panic("inconceivable!")
2289 }
2290 }
2291 }
2292}
2293
Jamie Gennisaf435562014-10-27 22:34:56 -07002294// AllTargets returns a map all the build target names to the rule used to build
2295// them. This is the same information that is output by running 'ninja -t
2296// targets all'. If this is called before PrepareBuildActions successfully
2297// completes then ErrbuildActionsNotReady is returned.
2298func (c *Context) AllTargets() (map[string]string, error) {
2299 if !c.buildActionsReady {
2300 return nil, ErrBuildActionsNotReady
2301 }
2302
2303 targets := map[string]string{}
2304
2305 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002306 for _, module := range c.moduleInfo {
2307 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002308 ruleName := buildDef.Rule.fullName(c.pkgNames)
2309 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002310 outputValue, err := output.Eval(c.globalVariables)
2311 if err != nil {
2312 return nil, err
2313 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002314 targets[outputValue] = ruleName
2315 }
2316 }
2317 }
2318
2319 // Collect all the singleton build targets.
2320 for _, info := range c.singletonInfo {
2321 for _, buildDef := range info.actionDefs.buildDefs {
2322 ruleName := buildDef.Rule.fullName(c.pkgNames)
2323 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002324 outputValue, err := output.Eval(c.globalVariables)
2325 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002326 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002327 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002328 targets[outputValue] = ruleName
2329 }
2330 }
2331 }
2332
2333 return targets, nil
2334}
2335
Colin Crossa2599452015-11-18 16:01:01 -08002336func (c *Context) NinjaBuildDir() (string, error) {
2337 if c.ninjaBuildDir != nil {
2338 return c.ninjaBuildDir.Eval(c.globalVariables)
2339 } else {
2340 return "", nil
2341 }
2342}
2343
Colin Cross4572edd2015-05-13 14:36:24 -07002344// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2345// property structs returned by the factory for that module type.
2346func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2347 ret := make(map[string][]interface{})
2348 for moduleType, factory := range c.moduleFactories {
2349 _, ret[moduleType] = factory()
2350 }
2351
2352 return ret
2353}
2354
2355func (c *Context) ModuleName(logicModule Module) string {
2356 module := c.moduleInfo[logicModule]
2357 return module.properties.Name
2358}
2359
2360func (c *Context) ModuleDir(logicModule Module) string {
2361 module := c.moduleInfo[logicModule]
2362 return filepath.Dir(module.relBlueprintsFile)
2363}
2364
Colin Cross8c602f72015-12-17 18:02:11 -08002365func (c *Context) ModuleSubDir(logicModule Module) string {
2366 module := c.moduleInfo[logicModule]
2367 return module.variantName
2368}
2369
Colin Cross4572edd2015-05-13 14:36:24 -07002370func (c *Context) BlueprintFile(logicModule Module) string {
2371 module := c.moduleInfo[logicModule]
2372 return module.relBlueprintsFile
2373}
2374
2375func (c *Context) ModuleErrorf(logicModule Module, format string,
2376 args ...interface{}) error {
2377
2378 module := c.moduleInfo[logicModule]
2379 return &Error{
2380 Err: fmt.Errorf(format, args...),
2381 Pos: module.pos,
2382 }
2383}
2384
2385func (c *Context) VisitAllModules(visit func(Module)) {
2386 c.visitAllModules(visit)
2387}
2388
2389func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2390 visit func(Module)) {
2391
2392 c.visitAllModulesIf(pred, visit)
2393}
2394
2395func (c *Context) VisitDepsDepthFirst(module Module,
2396 visit func(Module)) {
2397
2398 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2399}
2400
2401func (c *Context) VisitDepsDepthFirstIf(module Module,
2402 pred func(Module) bool, visit func(Module)) {
2403
2404 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2405}
2406
Colin Cross24ad5872015-11-17 16:22:29 -08002407func (c *Context) PrimaryModule(module Module) Module {
2408 return c.moduleInfo[module].group.modules[0].logicModule
2409}
2410
2411func (c *Context) FinalModule(module Module) Module {
2412 modules := c.moduleInfo[module].group.modules
2413 return modules[len(modules)-1].logicModule
2414}
2415
2416func (c *Context) VisitAllModuleVariants(module Module,
2417 visit func(Module)) {
2418
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002419 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002420}
2421
Jamie Gennisd4e10182014-06-12 20:06:50 -07002422// WriteBuildFile writes the Ninja manifeset text for the generated build
2423// actions to w. If this is called before PrepareBuildActions successfully
2424// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002425func (c *Context) WriteBuildFile(w io.Writer) error {
2426 if !c.buildActionsReady {
2427 return ErrBuildActionsNotReady
2428 }
2429
2430 nw := newNinjaWriter(w)
2431
2432 err := c.writeBuildFileHeader(nw)
2433 if err != nil {
2434 return err
2435 }
2436
2437 err = c.writeNinjaRequiredVersion(nw)
2438 if err != nil {
2439 return err
2440 }
2441
2442 // TODO: Group the globals by package.
2443
2444 err = c.writeGlobalVariables(nw)
2445 if err != nil {
2446 return err
2447 }
2448
2449 err = c.writeGlobalPools(nw)
2450 if err != nil {
2451 return err
2452 }
2453
2454 err = c.writeBuildDir(nw)
2455 if err != nil {
2456 return err
2457 }
2458
2459 err = c.writeGlobalRules(nw)
2460 if err != nil {
2461 return err
2462 }
2463
2464 err = c.writeAllModuleActions(nw)
2465 if err != nil {
2466 return err
2467 }
2468
2469 err = c.writeAllSingletonActions(nw)
2470 if err != nil {
2471 return err
2472 }
2473
2474 return nil
2475}
2476
Jamie Gennisc15544d2014-09-24 20:26:52 -07002477type pkgAssociation struct {
2478 PkgName string
2479 PkgPath string
2480}
2481
2482type pkgAssociationSorter struct {
2483 pkgs []pkgAssociation
2484}
2485
2486func (s *pkgAssociationSorter) Len() int {
2487 return len(s.pkgs)
2488}
2489
2490func (s *pkgAssociationSorter) Less(i, j int) bool {
2491 iName := s.pkgs[i].PkgName
2492 jName := s.pkgs[j].PkgName
2493 return iName < jName
2494}
2495
2496func (s *pkgAssociationSorter) Swap(i, j int) {
2497 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2498}
2499
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002500func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2501 headerTemplate := template.New("fileHeader")
2502 _, err := headerTemplate.Parse(fileHeaderTemplate)
2503 if err != nil {
2504 // This is a programming error.
2505 panic(err)
2506 }
2507
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002508 var pkgs []pkgAssociation
2509 maxNameLen := 0
2510 for pkg, name := range c.pkgNames {
2511 pkgs = append(pkgs, pkgAssociation{
2512 PkgName: name,
2513 PkgPath: pkg.pkgPath,
2514 })
2515 if len(name) > maxNameLen {
2516 maxNameLen = len(name)
2517 }
2518 }
2519
2520 for i := range pkgs {
2521 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2522 }
2523
Jamie Gennisc15544d2014-09-24 20:26:52 -07002524 sort.Sort(&pkgAssociationSorter{pkgs})
2525
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002526 params := map[string]interface{}{
2527 "Pkgs": pkgs,
2528 }
2529
2530 buf := bytes.NewBuffer(nil)
2531 err = headerTemplate.Execute(buf, params)
2532 if err != nil {
2533 return err
2534 }
2535
2536 return nw.Comment(buf.String())
2537}
2538
2539func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2540 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2541 c.requiredNinjaMicro)
2542
2543 err := nw.Assign("ninja_required_version", value)
2544 if err != nil {
2545 return err
2546 }
2547
2548 return nw.BlankLine()
2549}
2550
2551func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002552 if c.ninjaBuildDir != nil {
2553 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002554 if err != nil {
2555 return err
2556 }
2557
2558 err = nw.BlankLine()
2559 if err != nil {
2560 return err
2561 }
2562 }
2563 return nil
2564}
2565
Jamie Gennisc15544d2014-09-24 20:26:52 -07002566type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002567 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002568}
2569
Jamie Gennisc15544d2014-09-24 20:26:52 -07002570type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002571 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002572 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002573}
2574
Jamie Gennisc15544d2014-09-24 20:26:52 -07002575func (s *globalEntitySorter) Len() int {
2576 return len(s.entities)
2577}
2578
2579func (s *globalEntitySorter) Less(i, j int) bool {
2580 iName := s.entities[i].fullName(s.pkgNames)
2581 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002582 return iName < jName
2583}
2584
Jamie Gennisc15544d2014-09-24 20:26:52 -07002585func (s *globalEntitySorter) Swap(i, j int) {
2586 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002587}
2588
2589func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2590 visited := make(map[Variable]bool)
2591
2592 var walk func(v Variable) error
2593 walk = func(v Variable) error {
2594 visited[v] = true
2595
2596 // First visit variables on which this variable depends.
2597 value := c.globalVariables[v]
2598 for _, dep := range value.variables {
2599 if !visited[dep] {
2600 err := walk(dep)
2601 if err != nil {
2602 return err
2603 }
2604 }
2605 }
2606
2607 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2608 if err != nil {
2609 return err
2610 }
2611
2612 err = nw.BlankLine()
2613 if err != nil {
2614 return err
2615 }
2616
2617 return nil
2618 }
2619
Jamie Gennisc15544d2014-09-24 20:26:52 -07002620 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2621 for variable := range c.globalVariables {
2622 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002623 }
2624
Jamie Gennisc15544d2014-09-24 20:26:52 -07002625 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002626
Jamie Gennisc15544d2014-09-24 20:26:52 -07002627 for _, entity := range globalVariables {
2628 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002629 if !visited[v] {
2630 err := walk(v)
2631 if err != nil {
2632 return nil
2633 }
2634 }
2635 }
2636
2637 return nil
2638}
2639
2640func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002641 globalPools := make([]globalEntity, 0, len(c.globalPools))
2642 for pool := range c.globalPools {
2643 globalPools = append(globalPools, pool)
2644 }
2645
2646 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2647
2648 for _, entity := range globalPools {
2649 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002650 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002651 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002652 err := def.WriteTo(nw, name)
2653 if err != nil {
2654 return err
2655 }
2656
2657 err = nw.BlankLine()
2658 if err != nil {
2659 return err
2660 }
2661 }
2662
2663 return nil
2664}
2665
2666func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002667 globalRules := make([]globalEntity, 0, len(c.globalRules))
2668 for rule := range c.globalRules {
2669 globalRules = append(globalRules, rule)
2670 }
2671
2672 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2673
2674 for _, entity := range globalRules {
2675 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002676 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002677 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002678 err := def.WriteTo(nw, name, c.pkgNames)
2679 if err != nil {
2680 return err
2681 }
2682
2683 err = nw.BlankLine()
2684 if err != nil {
2685 return err
2686 }
2687 }
2688
2689 return nil
2690}
2691
Colin Cross2c1f3d12016-04-11 15:47:28 -07002692type depSorter []depInfo
2693
2694func (s depSorter) Len() int {
2695 return len(s)
2696}
2697
2698func (s depSorter) Less(i, j int) bool {
2699 iName := s[i].module.properties.Name
2700 jName := s[j].module.properties.Name
2701 if iName == jName {
2702 iName = s[i].module.variantName
2703 jName = s[j].module.variantName
2704 }
2705 return iName < jName
2706}
2707
2708func (s depSorter) Swap(i, j int) {
2709 s[i], s[j] = s[j], s[i]
2710}
2711
Colin Crossab6d7902015-03-11 16:17:52 -07002712type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002713
Colin Crossab6d7902015-03-11 16:17:52 -07002714func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002715 return len(s)
2716}
2717
Colin Crossab6d7902015-03-11 16:17:52 -07002718func (s moduleSorter) Less(i, j int) bool {
2719 iName := s[i].properties.Name
2720 jName := s[j].properties.Name
2721 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002722 iName = s[i].variantName
2723 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002724 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002725 return iName < jName
2726}
2727
Colin Crossab6d7902015-03-11 16:17:52 -07002728func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002729 s[i], s[j] = s[j], s[i]
2730}
2731
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002732func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2733 headerTemplate := template.New("moduleHeader")
2734 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2735 if err != nil {
2736 // This is a programming error.
2737 panic(err)
2738 }
2739
Colin Crossab6d7902015-03-11 16:17:52 -07002740 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2741 for _, module := range c.moduleInfo {
2742 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002743 }
Colin Crossab6d7902015-03-11 16:17:52 -07002744 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002745
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002746 buf := bytes.NewBuffer(nil)
2747
Colin Crossab6d7902015-03-11 16:17:52 -07002748 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002749 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2750 continue
2751 }
2752
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002753 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002754
2755 // In order to make the bootstrap build manifest independent of the
2756 // build dir we need to output the Blueprints file locations in the
2757 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002758 relPos := module.pos
2759 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002760
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002761 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002762 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002763 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2764 factoryName := factoryFunc.Name()
2765
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002766 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002767 "properties": module.properties,
2768 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002769 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002770 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002771 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002772 }
2773 err = headerTemplate.Execute(buf, infoMap)
2774 if err != nil {
2775 return err
2776 }
2777
2778 err = nw.Comment(buf.String())
2779 if err != nil {
2780 return err
2781 }
2782
2783 err = nw.BlankLine()
2784 if err != nil {
2785 return err
2786 }
2787
Colin Crossab6d7902015-03-11 16:17:52 -07002788 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002789 if err != nil {
2790 return err
2791 }
2792
2793 err = nw.BlankLine()
2794 if err != nil {
2795 return err
2796 }
2797 }
2798
2799 return nil
2800}
2801
2802func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2803 headerTemplate := template.New("singletonHeader")
2804 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2805 if err != nil {
2806 // This is a programming error.
2807 panic(err)
2808 }
2809
2810 buf := bytes.NewBuffer(nil)
2811
Yuchen Wub9103ef2015-08-25 17:58:17 -07002812 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002813 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2814 continue
2815 }
2816
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002817 // Get the name of the factory function for the module.
2818 factory := info.factory
2819 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2820 factoryName := factoryFunc.Name()
2821
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002822 buf.Reset()
2823 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002824 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002825 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002826 }
2827 err = headerTemplate.Execute(buf, infoMap)
2828 if err != nil {
2829 return err
2830 }
2831
2832 err = nw.Comment(buf.String())
2833 if err != nil {
2834 return err
2835 }
2836
2837 err = nw.BlankLine()
2838 if err != nil {
2839 return err
2840 }
2841
2842 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2843 if err != nil {
2844 return err
2845 }
2846
2847 err = nw.BlankLine()
2848 if err != nil {
2849 return err
2850 }
2851 }
2852
2853 return nil
2854}
2855
2856func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2857 defs *localBuildActions) error {
2858
2859 // Write the local variable assignments.
2860 for _, v := range defs.variables {
2861 // A localVariable doesn't need the package names or config to
2862 // determine its name or value.
2863 name := v.fullName(nil)
2864 value, err := v.value(nil)
2865 if err != nil {
2866 panic(err)
2867 }
2868 err = nw.Assign(name, value.Value(c.pkgNames))
2869 if err != nil {
2870 return err
2871 }
2872 }
2873
2874 if len(defs.variables) > 0 {
2875 err := nw.BlankLine()
2876 if err != nil {
2877 return err
2878 }
2879 }
2880
2881 // Write the local rules.
2882 for _, r := range defs.rules {
2883 // A localRule doesn't need the package names or config to determine
2884 // its name or definition.
2885 name := r.fullName(nil)
2886 def, err := r.def(nil)
2887 if err != nil {
2888 panic(err)
2889 }
2890
2891 err = def.WriteTo(nw, name, c.pkgNames)
2892 if err != nil {
2893 return err
2894 }
2895
2896 err = nw.BlankLine()
2897 if err != nil {
2898 return err
2899 }
2900 }
2901
2902 // Write the build definitions.
2903 for _, buildDef := range defs.buildDefs {
2904 err := buildDef.WriteTo(nw, c.pkgNames)
2905 if err != nil {
2906 return err
2907 }
2908
2909 if len(buildDef.Args) > 0 {
2910 err = nw.BlankLine()
2911 if err != nil {
2912 return err
2913 }
2914 }
2915 }
2916
2917 return nil
2918}
2919
Colin Cross65569e42015-03-10 20:08:19 -07002920func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2921 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002922 if a == b {
2923 return false
2924 }
Colin Cross65569e42015-03-10 20:08:19 -07002925 for _, l := range list {
2926 if l == a {
2927 found = true
2928 } else if l == b {
2929 return found
2930 }
2931 }
2932
2933 missing := a
2934 if found {
2935 missing = b
2936 }
2937 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2938}
2939
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002940type panicError struct {
2941 panic interface{}
2942 stack []byte
2943 in string
2944}
2945
2946func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
2947 buf := make([]byte, 4096)
2948 count := runtime.Stack(buf, false)
2949 return panicError{
2950 panic: panic,
2951 in: fmt.Sprintf(in, a...),
2952 stack: buf[:count],
2953 }
2954}
2955
2956func (p panicError) Error() string {
2957 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
2958}
2959
2960func (p *panicError) addIn(in string) {
2961 p.in += " in " + in
2962}
2963
2964func funcName(f interface{}) string {
2965 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
2966}
2967
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002968var fileHeaderTemplate = `******************************************************************************
2969*** This file is generated and should not be edited ***
2970******************************************************************************
2971{{if .Pkgs}}
2972This file contains variables, rules, and pools with name prefixes indicating
2973they were generated by the following Go packages:
2974{{range .Pkgs}}
2975 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2976
2977`
2978
2979var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2980Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002981Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002982Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002983Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002984Defined: {{.pos}}
2985`
2986
2987var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2988Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002989Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002990`