blob: 83ff6ae0e72e7c5d47c8ce20d856ac94c80b7757 [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
84 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080085 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070086 globalVariables map[Variable]*ninjaString
87 globalPools map[Pool]*poolDef
88 globalRules map[Rule]*ruleDef
89
90 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080091 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070092 requiredNinjaMajor int // For the ninja_required_version variable
93 requiredNinjaMinor int // For the ninja_required_version variable
94 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070095
96 // set lazily by sortedModuleNames
97 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070098}
99
Jamie Gennisd4e10182014-06-12 20:06:50 -0700100// An Error describes a problem that was encountered that is related to a
101// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700103 Err error // the error that occurred
104 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105}
106
107type localBuildActions struct {
108 variables []*localVariable
109 rules []*localRule
110 buildDefs []*buildDef
111}
112
Colin Crossbbfa51a2014-12-17 16:12:41 -0800113type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700114 name string
115 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118}
119
Colin Crossbbfa51a2014-12-17 16:12:41 -0800120type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700121 // set during Parse
122 typeName string
123 relBlueprintsFile string
124 pos scanner.Position
125 propertyPos map[string]scanner.Position
126 properties struct {
127 Name string
128 Deps []string
129 }
130
Colin Crossf5e34b92015-03-13 16:02:36 -0700131 variantName string
132 variant variationMap
133 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700134
Colin Crossc9028482014-12-18 16:28:54 -0800135 logicModule Module
136 group *moduleGroup
137 moduleProperties []interface{}
138
139 // set during ResolveDependencies
140 directDeps []*moduleInfo
141
Colin Cross7addea32015-03-11 15:43:52 -0700142 // set during updateDependencies
143 reverseDeps []*moduleInfo
144 depsCount int
145
146 // used by parallelVisitAllBottomUp
147 waitingCount int
148
Colin Crossc9028482014-12-18 16:28:54 -0800149 // set during each runMutator
150 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700151
152 // set during PrepareBuildActions
153 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800154}
155
Colin Crossf5e34b92015-03-13 16:02:36 -0700156// A Variation is a way that a variant of a module differs from other variants of the same module.
157// For example, two variants of the same module might have Variation{"arch","arm"} and
158// Variation{"arch","arm64"}
159type Variation struct {
160 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700161 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700162 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
163 // "shared" or "static" for link.
164 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700165}
166
Colin Crossf5e34b92015-03-13 16:02:36 -0700167// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
168type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700169
Colin Crossf5e34b92015-03-13 16:02:36 -0700170func (vm variationMap) clone() variationMap {
171 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700172 for k, v := range vm {
173 newVm[k] = v
174 }
175
176 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800177}
178
Colin Cross89486232015-05-08 11:14:54 -0700179// Compare this variationMap to another one. Returns true if the every entry in this map
180// is either the same in the other map or doesn't exist in the other map.
181func (vm variationMap) subset(other variationMap) bool {
182 for k, v1 := range vm {
183 if v2, ok := other[k]; ok && v1 != v2 {
184 return false
185 }
186 }
187 return true
188}
189
Colin Crossf5e34b92015-03-13 16:02:36 -0700190func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700191 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800192}
193
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700194type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700195 // set during RegisterSingletonType
196 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700197 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700198 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700199
200 // set during PrepareBuildActions
201 actionDefs localBuildActions
202}
203
Colin Crossc9028482014-12-18 16:28:54 -0800204type mutatorInfo struct {
205 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800206 topDownMutator TopDownMutator
207 bottomUpMutator BottomUpMutator
208 name string
Colin Crossc9028482014-12-18 16:28:54 -0800209}
210
Colin Cross65569e42015-03-10 20:08:19 -0700211type earlyMutatorInfo struct {
212 // set during RegisterEarlyMutator
213 mutator EarlyMutator
214 name string
215}
216
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700217func (e *Error) Error() string {
218
219 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
220}
221
Jamie Gennisd4e10182014-06-12 20:06:50 -0700222// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700223// no module or singleton factories registered, so the RegisterModuleFactory and
224// RegisterSingletonFactory methods must be called before it can do anything
225// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700227 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800228 moduleFactories: make(map[string]ModuleFactory),
229 moduleGroups: make(map[string]*moduleGroup),
230 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800231 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700232 }
Colin Cross763b6f12015-10-29 15:32:56 -0700233
234 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
235
236 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700237}
238
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700239// A ModuleFactory function creates a new Module object. See the
240// Context.RegisterModuleType method for details about how a registered
241// ModuleFactory is used by a Context.
242type ModuleFactory func() (m Module, propertyStructs []interface{})
243
Jamie Gennisd4e10182014-06-12 20:06:50 -0700244// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700245// Blueprints file) with a Module factory function. When the given module type
246// name is encountered in a Blueprints file during parsing, the Module factory
247// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800248// generation for the module. If a Mutator splits a module into multiple variants,
249// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700250//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700251// The module type names given here must be unique for the context. The factory
252// function should be a named function so that its package and name can be
253// included in the generated Ninja file for debugging purposes.
254//
255// The factory function returns two values. The first is the newly created
256// Module object. The second is a slice of pointers to that Module object's
257// properties structs. Each properties struct is examined when parsing a module
258// definition of this type in a Blueprints file. Exported fields of the
259// properties structs are automatically set to the property values specified in
260// the Blueprints file. The properties struct field names determine the name of
261// the Blueprints file properties that are used - the Blueprints property name
262// matches that of the properties struct field name with the first letter
263// converted to lower-case.
264//
265// The fields of the properties struct must be either []string, a string, or
266// bool. The Context will panic if a Module gets instantiated with a properties
267// struct containing a field that is not one these supported types.
268//
269// Any properties that appear in the Blueprints files that are not built-in
270// module properties (such as "name" and "deps") and do not have a corresponding
271// field in the returned module properties struct result in an error during the
272// Context's parse phase.
273//
274// As an example, the follow code:
275//
276// type myModule struct {
277// properties struct {
278// Foo string
279// Bar []string
280// }
281// }
282//
283// func NewMyModule() (blueprint.Module, []interface{}) {
284// module := new(myModule)
285// properties := &module.properties
286// return module, []interface{}{properties}
287// }
288//
289// func main() {
290// ctx := blueprint.NewContext()
291// ctx.RegisterModuleType("my_module", NewMyModule)
292// // ...
293// }
294//
295// would support parsing a module defined in a Blueprints file as follows:
296//
297// my_module {
298// name: "myName",
299// foo: "my foo string",
300// bar: ["my", "bar", "strings"],
301// }
302//
Colin Cross7ad621c2015-01-07 16:22:45 -0800303// The factory function may be called from multiple goroutines. Any accesses
304// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700305func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
306 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700307 panic(errors.New("module type name is already registered"))
308 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700309 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700310}
311
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312// A SingletonFactory function creates a new Singleton object. See the
313// Context.RegisterSingletonType method for details about how a registered
314// SingletonFactory is used by a Context.
315type SingletonFactory func() Singleton
316
317// RegisterSingletonType registers a singleton type that will be invoked to
318// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700319// and invoked exactly once as part of the generate phase. Each registered
320// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700321//
322// The singleton type names given here must be unique for the context. The
323// factory function should be a named function so that its package and name can
324// be included in the generated Ninja file for debugging purposes.
325func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700326 for _, s := range c.singletonInfo {
327 if s.name == name {
328 panic(errors.New("singleton name is already registered"))
329 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700330 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700331
Yuchen Wub9103ef2015-08-25 17:58:17 -0700332 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700333 factory: factory,
334 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700335 name: name,
336 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700337}
338
339func singletonPkgPath(singleton Singleton) string {
340 typ := reflect.TypeOf(singleton)
341 for typ.Kind() == reflect.Ptr {
342 typ = typ.Elem()
343 }
344 return typ.PkgPath()
345}
346
347func singletonTypeName(singleton Singleton) string {
348 typ := reflect.TypeOf(singleton)
349 for typ.Kind() == reflect.Ptr {
350 typ = typ.Elem()
351 }
352 return typ.PkgPath() + "." + typ.Name()
353}
354
Colin Crossc9028482014-12-18 16:28:54 -0800355// RegisterTopDownMutator registers a mutator that will be invoked to propagate
356// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700357// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
358// once per Module, and is invoked on a module before being invoked on any of its
359// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800360//
Colin Cross65569e42015-03-10 20:08:19 -0700361// The mutator type names given here must be unique to all top down mutators in
362// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800363func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
364 for _, m := range c.mutatorInfo {
365 if m.name == name && m.topDownMutator != nil {
366 panic(fmt.Errorf("mutator name %s is already registered", name))
367 }
368 }
369
370 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
371 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800372 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800373 })
374}
375
376// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700377// Modules into variants. Each registered mutator is invoked in registration
378// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
379// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800380//
Colin Cross65569e42015-03-10 20:08:19 -0700381// The mutator type names given here must be unique to all bottom up or early
382// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800383func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700384 for _, m := range c.variantMutatorNames {
385 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800386 panic(fmt.Errorf("mutator name %s is already registered", name))
387 }
388 }
389
390 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
391 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800392 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800393 })
Colin Cross65569e42015-03-10 20:08:19 -0700394
395 c.variantMutatorNames = append(c.variantMutatorNames, name)
396}
397
398// RegisterEarlyMutator registers a mutator that will be invoked to split
399// Modules into multiple variant Modules before any dependencies have been
400// created. Each registered mutator is invoked in registration order once
401// per Module (including each variant from previous early mutators). Module
402// order is unpredictable.
403//
404// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700405// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700406//
407// The mutator type names given here must be unique to all bottom up or early
408// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700409//
410// Deprecated, use a BottomUpMutator instead. The only difference between
411// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
412// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700413func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
414 for _, m := range c.variantMutatorNames {
415 if m == name {
416 panic(fmt.Errorf("mutator name %s is already registered", name))
417 }
418 }
419
420 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
421 mutator: mutator,
422 name: name,
423 })
424
425 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800426}
427
Jamie Gennisd4e10182014-06-12 20:06:50 -0700428// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
429// where it encounters an unknown module type while parsing Blueprints files. By
430// default, the context will report unknown module types as an error. If this
431// method is called with ignoreUnknownModuleTypes set to true then the context
432// will silently ignore unknown module types.
433//
434// This method should generally not be used. It exists to facilitate the
435// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700436func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
437 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
438}
439
Jamie Gennisd4e10182014-06-12 20:06:50 -0700440// Parse parses a single Blueprints file from r, creating Module objects for
441// each of the module definitions encountered. If the Blueprints file contains
442// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700443// searched for Blueprints files returned in the subBlueprints return value.
444// If the Blueprints file contains an assignment to the "build" variable, then
445// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700446//
447// rootDir specifies the path to the root directory of the source tree, while
448// filename specifies the path to the Blueprints file. These paths are used for
449// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800450func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700451 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700452 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700453
Jamie Gennisec701282014-06-12 20:06:31 -0700454 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700455 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700456 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700457 }
458
Colin Crossc0dbc552015-01-02 15:19:28 -0800459 scope = parser.NewScope(scope)
460 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800461 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700462 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700463 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700464 if len(errs) > 0 {
465 for i, err := range errs {
466 if parseErr, ok := err.(*parser.ParseError); ok {
467 err = &Error{
468 Err: parseErr.Err,
469 Pos: parseErr.Pos,
470 }
471 errs[i] = err
472 }
473 }
474
475 // If there were any parse errors don't bother trying to interpret the
476 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700477 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700479 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700480
Colin Cross6d8780f2015-07-10 17:51:55 -0700481 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700482 if err != nil {
483 errs = append(errs, err)
484 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700485
Colin Cross7f507402015-12-16 13:03:41 -0800486 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
487 if err != nil {
488 errs = append(errs, err)
489 }
490
Colin Cross6d8780f2015-07-10 17:51:55 -0700491 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700492 if err != nil {
493 errs = append(errs, err)
494 }
495
Colin Cross29394222015-04-27 13:18:21 -0700496 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
497
Colin Cross7f507402015-12-16 13:03:41 -0800498 var blueprints []string
499
500 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
501 blueprints = append(blueprints, newBlueprints...)
502 deps = append(deps, newDeps...)
503 errs = append(errs, newErrs...)
504
505 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
506 subBlueprintsName, false)
507 blueprints = append(blueprints, newBlueprints...)
508 deps = append(deps, newDeps...)
509 errs = append(errs, newErrs...)
510
511 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
512 optionalSubdirsPos, subBlueprintsName, true)
513 blueprints = append(blueprints, newBlueprints...)
514 deps = append(deps, newDeps...)
515 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800516
Colin Cross1fef5362015-04-20 16:50:54 -0700517 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
518 for i, b := range blueprints {
519 subBlueprintsAndScope[i] = stringAndScope{b, scope}
520 }
521
Colin Cross23d7aa12015-06-30 16:05:22 -0700522 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800523}
524
Colin Cross7ad621c2015-01-07 16:22:45 -0800525type stringAndScope struct {
526 string
527 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700528}
529
Jamie Gennisd4e10182014-06-12 20:06:50 -0700530// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
531// at rootFile. When it encounters a Blueprints file with a set of subdirs
532// listed it recursively parses any Blueprints files found in those
533// subdirectories.
534//
535// If no errors are encountered while parsing the files, the list of paths on
536// which the future output will depend is returned. This list will include both
537// Blueprints file paths as well as directory paths for cases where wildcard
538// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700539func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
540 errs []error) {
541
Colin Cross7ad621c2015-01-07 16:22:45 -0800542 c.dependenciesReady = false
543
Colin Cross23d7aa12015-06-30 16:05:22 -0700544 moduleCh := make(chan *moduleInfo)
545 errsCh := make(chan []error)
546 doneCh := make(chan struct{})
547 var numErrs uint32
548 var numGoroutines int32
549
550 // handler must be reentrant
551 handler := func(file *parser.File) {
552 if atomic.LoadUint32(&numErrs) > maxErrors {
553 return
554 }
555
556 atomic.AddInt32(&numGoroutines, 1)
557 go func() {
558 for _, def := range file.Defs {
559 var module *moduleInfo
560 var errs []error
561 switch def := def.(type) {
562 case *parser.Module:
563 module, errs = c.processModuleDef(def, file.Name)
564 case *parser.Assignment:
565 // Already handled via Scope object
566 default:
567 panic("unknown definition type")
568 }
569
570 if len(errs) > 0 {
571 atomic.AddUint32(&numErrs, uint32(len(errs)))
572 errsCh <- errs
573 } else if module != nil {
574 moduleCh <- module
575 }
576 }
577 doneCh <- struct{}{}
578 }()
579 }
580
581 atomic.AddInt32(&numGoroutines, 1)
582 go func() {
583 var errs []error
584 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
585 if len(errs) > 0 {
586 errsCh <- errs
587 }
588 doneCh <- struct{}{}
589 }()
590
591loop:
592 for {
593 select {
594 case newErrs := <-errsCh:
595 errs = append(errs, newErrs...)
596 case module := <-moduleCh:
597 newErrs := c.addModule(module)
598 if len(newErrs) > 0 {
599 errs = append(errs, newErrs...)
600 }
601 case <-doneCh:
602 n := atomic.AddInt32(&numGoroutines, -1)
603 if n == 0 {
604 break loop
605 }
606 }
607 }
608
609 return deps, errs
610}
611
612type FileHandler func(*parser.File)
613
614// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
615// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
616// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
617// it must be reentrant.
618//
619// If no errors are encountered while parsing the files, the list of paths on
620// which the future output will depend is returned. This list will include both
621// Blueprints file paths as well as directory paths for cases where wildcard
622// subdirs are found.
623func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
624 errs []error) {
625
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700626 rootDir := filepath.Dir(rootFile)
627
Colin Cross7ad621c2015-01-07 16:22:45 -0800628 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700629
Colin Cross7ad621c2015-01-07 16:22:45 -0800630 // Channels to receive data back from parseBlueprintsFile goroutines
631 blueprintsCh := make(chan stringAndScope)
632 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700633 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800634 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700635
Colin Cross7ad621c2015-01-07 16:22:45 -0800636 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
637 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700638
Colin Cross7ad621c2015-01-07 16:22:45 -0800639 // Number of outstanding goroutines to wait for
640 count := 0
641
642 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
643 count++
644 go func() {
645 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700646 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800647 doneCh <- struct{}{}
648 }()
649 }
650
651 tooManyErrors := false
652
653 startParseBlueprintsFile(rootFile, nil)
654
655loop:
656 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700657 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800658 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700659 }
660
Colin Cross7ad621c2015-01-07 16:22:45 -0800661 select {
662 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700663 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800664 case dep := <-depsCh:
665 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700666 case file := <-fileCh:
667 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800668 case blueprint := <-blueprintsCh:
669 if tooManyErrors {
670 continue
671 }
672 if blueprintsSet[blueprint.string] {
673 continue
674 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700675
Colin Cross7ad621c2015-01-07 16:22:45 -0800676 blueprintsSet[blueprint.string] = true
677 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
678 case <-doneCh:
679 count--
680 if count == 0 {
681 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700682 }
683 }
684 }
685
Colin Cross7ad621c2015-01-07 16:22:45 -0800686 return
687}
688
689// parseBlueprintFile parses a single Blueprints file, returning any errors through
690// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
691// blueprintsCh, and any dependencies on Blueprints files or directories through
692// depsCh.
693func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700694 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800695 depsCh chan<- string) {
696
Colin Cross23d7aa12015-06-30 16:05:22 -0700697 f, err := os.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800698 if err != nil {
699 errsCh <- []error{err}
700 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700701 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700702 defer func() {
703 err = f.Close()
704 if err != nil {
705 errsCh <- []error{err}
706 }
707 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700708
Colin Cross23d7aa12015-06-30 16:05:22 -0700709 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 if len(errs) > 0 {
711 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700712 } else {
713 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800714 }
715
Colin Cross1fef5362015-04-20 16:50:54 -0700716 for _, b := range subBlueprints {
717 blueprintsCh <- b
718 }
719
720 for _, d := range deps {
721 depsCh <- d
722 }
Colin Cross1fef5362015-04-20 16:50:54 -0700723}
724
Colin Cross7f507402015-12-16 13:03:41 -0800725func (c *Context) findBuildBlueprints(dir string, build []string,
726 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
727
728 for _, file := range build {
729 globPattern := filepath.Join(dir, file)
730 matches, matchedDirs, err := pathtools.Glob(globPattern)
731 if err != nil {
732 errs = append(errs, &Error{
733 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
734 Pos: buildPos,
735 })
736 continue
737 }
738
739 if len(matches) == 0 {
740 errs = append(errs, &Error{
741 Err: fmt.Errorf("%q: not found", globPattern),
742 Pos: buildPos,
743 })
744 }
745
746 // Depend on all searched directories so we pick up future changes.
747 deps = append(deps, matchedDirs...)
748
749 for _, foundBlueprints := range matches {
750 fileInfo, err := os.Stat(foundBlueprints)
751 if os.IsNotExist(err) {
752 errs = append(errs, &Error{
753 Err: fmt.Errorf("%q not found", foundBlueprints),
754 })
755 continue
756 }
757
758 if fileInfo.IsDir() {
759 errs = append(errs, &Error{
760 Err: fmt.Errorf("%q is a directory", foundBlueprints),
761 })
762 continue
763 }
764
765 blueprints = append(blueprints, foundBlueprints)
766 }
767 }
768
769 return blueprints, deps, errs
770}
771
772func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
773 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800774
775 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700776 globPattern := filepath.Join(dir, subdir)
777 matches, matchedDirs, err := pathtools.Glob(globPattern)
778 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700779 errs = append(errs, &Error{
780 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
781 Pos: subdirsPos,
782 })
783 continue
784 }
785
Colin Cross7f507402015-12-16 13:03:41 -0800786 if len(matches) == 0 && !optional {
Colin Cross1fef5362015-04-20 16:50:54 -0700787 errs = append(errs, &Error{
788 Err: fmt.Errorf("%q: not found", globPattern),
789 Pos: subdirsPos,
790 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700791 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800792
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700793 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700794 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800795
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700796 for _, foundSubdir := range matches {
797 fileInfo, subdirStatErr := os.Stat(foundSubdir)
798 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700799 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700800 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800801 }
802
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700803 // Skip files
804 if !fileInfo.IsDir() {
805 continue
806 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800807
Colin Cross29394222015-04-27 13:18:21 -0700808 var subBlueprints string
809 if subBlueprintsName != "" {
810 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
811 _, err = os.Stat(subBlueprints)
812 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700813
Colin Cross29394222015-04-27 13:18:21 -0700814 if os.IsNotExist(err) || subBlueprints == "" {
815 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
816 _, err = os.Stat(subBlueprints)
817 }
818
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700819 if os.IsNotExist(err) {
820 // There is no Blueprints file in this subdirectory. We
821 // need to add the directory to the list of dependencies
822 // so that if someone adds a Blueprints file in the
823 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700824 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700825 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700826 deps = append(deps, subBlueprints)
827 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800828 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800829 }
830 }
Colin Cross1fef5362015-04-20 16:50:54 -0700831
Colin Cross1fef5362015-04-20 16:50:54 -0700832 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700833}
834
Colin Cross6d8780f2015-07-10 17:51:55 -0700835func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
836 if assignment, local := scope.Get(v); assignment == nil || !local {
837 return nil, scanner.Position{}, nil
838 } else {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700839 switch assignment.Value.Type {
840 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700841 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700842
843 for _, value := range assignment.Value.ListValue {
844 if value.Type != parser.String {
845 // The parser should not produce this.
846 panic("non-string value found in list")
847 }
848
Colin Cross1fef5362015-04-20 16:50:54 -0700849 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700850 }
851
Colin Cross1fef5362015-04-20 16:50:54 -0700852 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700853 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700854 return nil, scanner.Position{}, &Error{
855 Err: fmt.Errorf("%q must be a list of strings", v),
856 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700857 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700858 default:
859 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
860 }
861 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700862}
863
Colin Cross29394222015-04-27 13:18:21 -0700864func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700865 if assignment, _ := scope.Get(v); assignment == nil {
866 return "", scanner.Position{}, nil
867 } else {
Colin Cross29394222015-04-27 13:18:21 -0700868 switch assignment.Value.Type {
869 case parser.String:
870 return assignment.Value.StringValue, assignment.Pos, nil
871 case parser.Bool, parser.List:
872 return "", scanner.Position{}, &Error{
873 Err: fmt.Errorf("%q must be a string", v),
874 Pos: assignment.Pos,
875 }
876 default:
877 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
878 }
879 }
Colin Cross29394222015-04-27 13:18:21 -0700880}
881
Colin Crossf5e34b92015-03-13 16:02:36 -0700882func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
883 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800884
Colin Crossf4d18a62015-03-18 17:43:15 -0700885 if len(variationNames) == 0 {
886 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400887 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700888 }
889
Colin Crossc9028482014-12-18 16:28:54 -0800890 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800891
Colin Cross174ae052015-03-03 17:37:03 -0800892 var errs []error
893
Colin Crossf5e34b92015-03-13 16:02:36 -0700894 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700895 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800896 factory, ok := c.moduleFactories[typeName]
897 if !ok {
898 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
899 }
900
901 var newLogicModule Module
902 var newProperties []interface{}
903
904 if i == 0 {
905 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700906 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
907 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800908 newLogicModule = origModule.logicModule
909 newProperties = origModule.moduleProperties
910 } else {
911 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700912 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800913 }
914 newLogicModule, newProperties = factory()
915
916 newProperties = append(props, newProperties...)
917
918 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700919 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800920 }
921
922 for i := range newProperties {
923 dst := reflect.ValueOf(newProperties[i]).Elem()
924 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
925
926 proptools.CopyProperties(dst, src)
927 }
928 }
929
Colin Crossf5e34b92015-03-13 16:02:36 -0700930 newVariant := origModule.variant.clone()
931 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800932
Colin Crossed342d92015-03-11 00:57:25 -0700933 m := *origModule
934 newModule := &m
935 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
936 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700937 newModule.variant = newVariant
938 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700939 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800940
Colin Crosse7daa222015-03-11 14:35:41 -0700941 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700942 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700943 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700944 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700945 }
946
Colin Crossc9028482014-12-18 16:28:54 -0800947 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700948
949 // Insert the new variant into the global module map. If this is the first variant then
950 // it reuses logicModule from the original module, which causes this to replace the
951 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800952 c.moduleInfo[newModule.logicModule] = newModule
953
Colin Crossf5e34b92015-03-13 16:02:36 -0700954 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800955 if len(newErrs) > 0 {
956 errs = append(errs, newErrs...)
957 }
Colin Crossc9028482014-12-18 16:28:54 -0800958 }
959
960 // Mark original variant as invalid. Modules that depend on this module will still
961 // depend on origModule, but we'll fix it when the mutator is called on them.
962 origModule.logicModule = nil
963 origModule.splitModules = newModules
964
Colin Cross174ae052015-03-03 17:37:03 -0800965 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800966}
967
Colin Crossf5e34b92015-03-13 16:02:36 -0700968func (c *Context) convertDepsToVariation(module *moduleInfo,
969 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800970
Colin Crossc9028482014-12-18 16:28:54 -0800971 for i, dep := range module.directDeps {
972 if dep.logicModule == nil {
973 var newDep *moduleInfo
974 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700975 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800976 newDep = m
977 break
978 }
979 }
980 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800981 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700982 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
983 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700984 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800985 })
986 continue
Colin Crossc9028482014-12-18 16:28:54 -0800987 }
988 module.directDeps[i] = newDep
989 }
990 }
Colin Cross174ae052015-03-03 17:37:03 -0800991
992 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800993}
994
Colin Crossf5e34b92015-03-13 16:02:36 -0700995func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700996 names := make([]string, 0, len(variant))
997 for _, m := range c.variantMutatorNames {
998 if v, ok := variant[m]; ok {
999 names = append(names, m+":"+v)
1000 }
1001 }
1002
1003 return strings.Join(names, ", ")
1004}
1005
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001006func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001007 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001008
Colin Crossd1facc12015-01-08 14:56:03 -08001009 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001010 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001011 if !ok {
1012 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001013 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001014 }
1015
Colin Cross7ad621c2015-01-07 16:22:45 -08001016 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001017 &Error{
1018 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -08001019 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001020 },
1021 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001022 }
1023
Colin Crossbbfa51a2014-12-17 16:12:41 -08001024 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001025
1026 module := &moduleInfo{
1027 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -07001028 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -07001029 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001030 }
1031
Jamie Gennis87622922014-09-30 11:38:25 -07001032 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001033 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001034 }
1035 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001036 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001037
Jamie Gennis87622922014-09-30 11:38:25 -07001038 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001039 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001040 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001041 }
1042
Colin Crossed342d92015-03-11 00:57:25 -07001043 module.pos = moduleDef.Type.Pos
1044 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001045 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -07001046 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001047 }
1048
Colin Cross7ad621c2015-01-07 16:22:45 -08001049 return module, nil
1050}
1051
Colin Cross23d7aa12015-06-30 16:05:22 -07001052func (c *Context) addModule(module *moduleInfo) []error {
1053 name := module.properties.Name
1054 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001055
Colin Cross23d7aa12015-06-30 16:05:22 -07001056 if group, present := c.moduleGroups[name]; present {
1057 return []error{
1058 &Error{
1059 Err: fmt.Errorf("module %q already defined", name),
1060 Pos: module.pos,
1061 },
1062 &Error{
1063 Err: fmt.Errorf("<-- previous definition here"),
1064 Pos: group.modules[0].pos,
1065 },
Colin Crossed342d92015-03-11 00:57:25 -07001066 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001067 } else {
1068 ninjaName := toNinjaName(module.properties.Name)
1069
1070 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1071 // already exists
1072 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1073 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1074 }
1075
1076 group := &moduleGroup{
1077 name: module.properties.Name,
1078 ninjaName: ninjaName,
1079 modules: []*moduleInfo{module},
1080 }
1081 module.group = group
1082 c.moduleGroups[name] = group
1083 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001084 }
1085
Colin Cross23d7aa12015-06-30 16:05:22 -07001086 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001087}
1088
Jamie Gennisd4e10182014-06-12 20:06:50 -07001089// ResolveDependencies checks that the dependencies specified by all of the
1090// modules defined in the parsed Blueprints files are valid. This means that
1091// the modules depended upon are defined and that no circular dependencies
1092// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001093func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross763b6f12015-10-29 15:32:56 -07001094 errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001095 if len(errs) > 0 {
1096 return errs
1097 }
1098
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001099 c.dependenciesReady = true
1100 return nil
1101}
1102
Colin Cross763b6f12015-10-29 15:32:56 -07001103// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001104// DynamicDependerModule interface then this set consists of the union of those
1105// module names listed in its "deps" property, those returned by its
1106// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001107// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001108// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001109func blueprintDepsMutator(ctx BottomUpMutatorContext) {
1110 ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001111
Colin Cross763b6f12015-10-29 15:32:56 -07001112 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
1113 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001114
Colin Cross763b6f12015-10-29 15:32:56 -07001115 if ctx.Failed() {
1116 return
Colin Crossa434b3f2015-01-13 10:59:52 -08001117 }
Colin Cross763b6f12015-10-29 15:32:56 -07001118
1119 ctx.AddDependency(ctx.Module(), dynamicDeps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001120 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001121}
1122
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001123// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1124// and returns the matching module, or nil if one is not found.
1125func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1126 if len(group.modules) == 1 {
1127 return group.modules[0]
1128 } else {
1129 for _, m := range group.modules {
1130 if m.variant.equal(module.dependencyVariant) {
1131 return m
1132 }
1133 }
1134 }
1135
1136 return nil
1137}
1138
Colin Crossc9028482014-12-18 16:28:54 -08001139func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001140 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001141 return []error{&Error{
1142 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001143 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001144 }}
1145 }
1146
1147 depInfo, ok := c.moduleGroups[depName]
1148 if !ok {
1149 return []error{&Error{
1150 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001151 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001152 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001153 }}
1154 }
1155
Colin Cross65569e42015-03-10 20:08:19 -07001156 for _, m := range module.directDeps {
1157 if m.group == depInfo {
1158 return nil
1159 }
Colin Crossc9028482014-12-18 16:28:54 -08001160 }
1161
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001162 if m := c.findMatchingVariant(module, depInfo); m != nil {
1163 module.directDeps = append(module.directDeps, m)
Colin Cross65569e42015-03-10 20:08:19 -07001164 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001165 }
Colin Crossc9028482014-12-18 16:28:54 -08001166
Colin Cross65569e42015-03-10 20:08:19 -07001167 return []error{&Error{
1168 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1169 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001170 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001171 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001172 }}
1173}
1174
Colin Cross8d8a7af2015-11-03 16:41:29 -08001175func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001176 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001177 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001178 Err: fmt.Errorf("%q depends on itself", destName),
1179 Pos: module.pos,
1180 }}
1181 }
1182
1183 destInfo, ok := c.moduleGroups[destName]
1184 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001185 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001186 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1187 module.properties.Name, destName),
1188 Pos: module.pos,
1189 }}
1190 }
1191
1192 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001193 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001194 }
1195
Colin Cross8d8a7af2015-11-03 16:41:29 -08001196 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001197 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1198 destName, module.properties.Name,
1199 c.prettyPrintVariant(module.dependencyVariant)),
1200 Pos: module.pos,
1201 }}
1202}
1203
Colin Crossf5e34b92015-03-13 16:02:36 -07001204func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross89486232015-05-08 11:14:54 -07001205 depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001206
Colin Cross65569e42015-03-10 20:08:19 -07001207 depInfo, ok := c.moduleGroups[depName]
1208 if !ok {
1209 return []error{&Error{
1210 Err: fmt.Errorf("%q depends on undefined module %q",
1211 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001212 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001213 }}
1214 }
1215
1216 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1217 // compare the strings because the result won't be in mutator registration order.
1218 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001219 var newVariant variationMap
1220 if !far {
1221 newVariant = module.dependencyVariant.clone()
1222 } else {
1223 newVariant = make(variationMap)
1224 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001225 for _, v := range variations {
1226 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001227 }
1228
1229 for _, m := range depInfo.modules {
Colin Cross89486232015-05-08 11:14:54 -07001230 var found bool
1231 if far {
1232 found = m.variant.subset(newVariant)
1233 } else {
1234 found = m.variant.equal(newVariant)
1235 }
1236 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001237 if module == m {
1238 return []error{&Error{
1239 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001240 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001241 }}
1242 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001243 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001244 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001245 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001246 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1247 return []error{&Error{
1248 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001249 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001250 }}
1251 }
1252 module.directDeps = append(module.directDeps, m)
1253 return nil
1254 }
1255 }
1256
1257 return []error{&Error{
1258 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1259 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001260 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001261 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001262 }}
Colin Crossc9028482014-12-18 16:28:54 -08001263}
1264
Colin Cross7addea32015-03-11 15:43:52 -07001265func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1266 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001267 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001268 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001269
Colin Cross7addea32015-03-11 15:43:52 -07001270 for _, module := range c.modulesSorted {
1271 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001272 }
1273
Colin Cross7addea32015-03-11 15:43:52 -07001274 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001275 count++
1276 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001277 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001278 if ret {
1279 cancel = true
1280 }
Colin Cross7addea32015-03-11 15:43:52 -07001281 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001282 }()
1283 }
1284
Colin Cross7addea32015-03-11 15:43:52 -07001285 for _, module := range c.modulesSorted {
1286 if module.waitingCount == 0 {
1287 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001288 }
1289 }
1290
Colin Cross11e3b0d2015-02-04 10:41:00 -08001291 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001292 select {
Colin Cross7addea32015-03-11 15:43:52 -07001293 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001294 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001295 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001296 parent.waitingCount--
1297 if parent.waitingCount == 0 {
1298 visitOne(parent)
1299 }
Colin Cross691a60d2015-01-07 18:08:56 -08001300 }
1301 }
1302 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001303 }
1304 }
1305}
1306
1307// updateDependencies recursively walks the module dependency graph and updates
1308// additional fields based on the dependencies. It builds a sorted list of modules
1309// such that dependencies of a module always appear first, and populates reverse
1310// dependency links and counts of total dependencies. It also reports errors when
1311// it encounters dependency cycles. This should called after resolveDependencies,
1312// as well as after any mutator pass has called addDependency
1313func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001314 visited := make(map[*moduleInfo]bool) // modules that were already checked
1315 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001316
Colin Cross7addea32015-03-11 15:43:52 -07001317 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001318
Colin Cross7addea32015-03-11 15:43:52 -07001319 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001320
Colin Cross7addea32015-03-11 15:43:52 -07001321 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001322 // We are the "start" of the cycle, so we're responsible
1323 // for generating the errors. The cycle list is in
1324 // reverse order because all the 'check' calls append
1325 // their own module to the list.
1326 errs = append(errs, &Error{
1327 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001328 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001329 })
1330
1331 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001332 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001333 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001334 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001335 errs = append(errs, &Error{
1336 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001337 curModule.properties.Name,
1338 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001339 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001340 })
Colin Cross7addea32015-03-11 15:43:52 -07001341 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001342 }
1343 }
1344
Colin Cross7addea32015-03-11 15:43:52 -07001345 check = func(module *moduleInfo) []*moduleInfo {
1346 visited[module] = true
1347 checking[module] = true
1348 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001349
Colin Cross7addea32015-03-11 15:43:52 -07001350 deps := make(map[*moduleInfo]bool)
1351
1352 // Add an implicit dependency ordering on all earlier modules in the same module group
1353 for _, dep := range module.group.modules {
1354 if dep == module {
1355 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001356 }
Colin Cross7addea32015-03-11 15:43:52 -07001357 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001358 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001359
Colin Cross7addea32015-03-11 15:43:52 -07001360 for _, dep := range module.directDeps {
1361 deps[dep] = true
1362 }
1363
1364 module.reverseDeps = []*moduleInfo{}
1365 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001366
Colin Crossbbfa51a2014-12-17 16:12:41 -08001367 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001368 if checking[dep] {
1369 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001370 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001371 }
1372
1373 if !visited[dep] {
1374 cycle := check(dep)
1375 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001376 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001377 // We are the "start" of the cycle, so we're responsible
1378 // for generating the errors. The cycle list is in
1379 // reverse order because all the 'check' calls append
1380 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001381 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001382
1383 // We can continue processing this module's children to
1384 // find more cycles. Since all the modules that were
1385 // part of the found cycle were marked as visited we
1386 // won't run into that cycle again.
1387 } else {
1388 // We're not the "start" of the cycle, so we just append
1389 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001390 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391 }
1392 }
1393 }
Colin Cross691a60d2015-01-07 18:08:56 -08001394
Colin Cross7addea32015-03-11 15:43:52 -07001395 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001396 }
1397
Colin Cross7addea32015-03-11 15:43:52 -07001398 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001399
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001400 return nil
1401 }
1402
Colin Cross7addea32015-03-11 15:43:52 -07001403 for _, module := range c.moduleInfo {
1404 if !visited[module] {
1405 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001406 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001407 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001408 panic("inconceivable!")
1409 }
1410 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001411 }
1412 }
1413 }
1414
Colin Cross7addea32015-03-11 15:43:52 -07001415 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001416
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001417 return
1418}
1419
Jamie Gennisd4e10182014-06-12 20:06:50 -07001420// PrepareBuildActions generates an internal representation of all the build
1421// actions that need to be performed. This process involves invoking the
1422// GenerateBuildActions method on each of the Module objects created during the
1423// parse phase and then on each of the registered Singleton objects.
1424//
1425// If the ResolveDependencies method has not already been called it is called
1426// automatically by this method.
1427//
1428// The config argument is made available to all of the Module and Singleton
1429// objects via the Config method on the ModuleContext and SingletonContext
1430// objects passed to GenerateBuildActions. It is also passed to the functions
1431// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1432// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001433//
1434// The returned deps is a list of the ninja files dependencies that were added
1435// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1436// SingletonContext.AddNinjaFileDeps() methods.
1437func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001438 c.buildActionsReady = false
1439
1440 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001441 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001442 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001443 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001444 }
1445 }
1446
1447 liveGlobals := newLiveTracker(config)
1448
1449 c.initSpecialVariables()
1450
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001451 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001452 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001453 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001454 }
1455
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001456 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001457 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001458 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459 }
1460
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001461 deps = append(depsModules, depsSingletons...)
1462
Colin Crossa2599452015-11-18 16:01:01 -08001463 if c.ninjaBuildDir != nil {
1464 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001465 }
1466
1467 pkgNames := c.makeUniquePackageNames(liveGlobals)
1468
1469 // This will panic if it finds a problem since it's a programming error.
1470 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1471
1472 c.pkgNames = pkgNames
1473 c.globalVariables = liveGlobals.variables
1474 c.globalPools = liveGlobals.pools
1475 c.globalRules = liveGlobals.rules
1476
1477 c.buildActionsReady = true
1478
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001479 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001480}
1481
Colin Cross65569e42015-03-10 20:08:19 -07001482func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1483 for _, mutator := range c.earlyMutatorInfo {
1484 for _, group := range c.moduleGroups {
1485 newModules := make([]*moduleInfo, 0, len(group.modules))
1486
1487 for _, module := range group.modules {
1488 mctx := &mutatorContext{
1489 baseModuleContext: baseModuleContext{
1490 context: c,
1491 config: config,
1492 module: module,
1493 },
1494 name: mutator.name,
1495 }
1496 mutator.mutator(mctx)
1497 if len(mctx.errs) > 0 {
1498 errs = append(errs, mctx.errs...)
1499 return errs
1500 }
1501
1502 if module.splitModules != nil {
1503 newModules = append(newModules, module.splitModules...)
1504 } else {
1505 newModules = append(newModules, module)
1506 }
1507 }
1508
1509 group.modules = newModules
1510 }
1511 }
1512
Colin Cross763b6f12015-10-29 15:32:56 -07001513 errs = c.updateDependencies()
1514 if len(errs) > 0 {
1515 return errs
1516 }
1517
Colin Cross65569e42015-03-10 20:08:19 -07001518 return nil
1519}
1520
Colin Crossc9028482014-12-18 16:28:54 -08001521func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Cross763b6f12015-10-29 15:32:56 -07001522 errs = c.runEarlyMutators(config)
1523 if len(errs) > 0 {
1524 return errs
1525 }
1526
Colin Crossc9028482014-12-18 16:28:54 -08001527 for _, mutator := range c.mutatorInfo {
1528 if mutator.topDownMutator != nil {
1529 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1530 } else if mutator.bottomUpMutator != nil {
1531 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1532 } else {
1533 panic("no mutator set on " + mutator.name)
1534 }
1535 if len(errs) > 0 {
1536 return errs
1537 }
1538 }
1539
1540 return nil
1541}
1542
1543func (c *Context) runTopDownMutator(config interface{},
1544 name string, mutator TopDownMutator) (errs []error) {
1545
Colin Cross7addea32015-03-11 15:43:52 -07001546 for i := 0; i < len(c.modulesSorted); i++ {
1547 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1548 mctx := &mutatorContext{
1549 baseModuleContext: baseModuleContext{
1550 context: c,
1551 config: config,
1552 module: module,
1553 },
1554 name: name,
1555 }
Colin Crossc9028482014-12-18 16:28:54 -08001556
Colin Cross7addea32015-03-11 15:43:52 -07001557 mutator(mctx)
1558 if len(mctx.errs) > 0 {
1559 errs = append(errs, mctx.errs...)
1560 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001561 }
1562 }
1563
1564 return errs
1565}
1566
1567func (c *Context) runBottomUpMutator(config interface{},
1568 name string, mutator BottomUpMutator) (errs []error) {
1569
Colin Cross8d8a7af2015-11-03 16:41:29 -08001570 reverseDeps := make(map[*moduleInfo][]*moduleInfo)
1571
Colin Cross7addea32015-03-11 15:43:52 -07001572 for _, module := range c.modulesSorted {
1573 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001574
Jamie Gennisc7988252015-04-14 23:28:10 -04001575 if module.splitModules != nil {
1576 panic("split module found in sorted module list")
1577 }
1578
Colin Cross7addea32015-03-11 15:43:52 -07001579 mctx := &mutatorContext{
1580 baseModuleContext: baseModuleContext{
1581 context: c,
1582 config: config,
1583 module: module,
1584 },
Colin Cross8d8a7af2015-11-03 16:41:29 -08001585 name: name,
1586 reverseDeps: reverseDeps,
Colin Cross7addea32015-03-11 15:43:52 -07001587 }
Colin Crossc9028482014-12-18 16:28:54 -08001588
Colin Cross7addea32015-03-11 15:43:52 -07001589 mutator(mctx)
1590 if len(mctx.errs) > 0 {
1591 errs = append(errs, mctx.errs...)
1592 return errs
1593 }
Colin Crossc9028482014-12-18 16:28:54 -08001594
Colin Cross7addea32015-03-11 15:43:52 -07001595 // Fix up any remaining dependencies on modules that were split into variants
1596 // by replacing them with the first variant
1597 for i, dep := range module.directDeps {
1598 if dep.logicModule == nil {
1599 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001600 }
1601 }
1602
Colin Cross7addea32015-03-11 15:43:52 -07001603 if module.splitModules != nil {
1604 newModules = append(newModules, module.splitModules...)
1605 } else {
1606 newModules = append(newModules, module)
1607 }
1608
1609 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001610 }
1611
Colin Cross8d8a7af2015-11-03 16:41:29 -08001612 for module, deps := range reverseDeps {
1613 sort.Sort(moduleSorter(deps))
1614 module.directDeps = append(module.directDeps, deps...)
1615 }
1616
Jamie Gennisc7988252015-04-14 23:28:10 -04001617 errs = c.updateDependencies()
1618 if len(errs) > 0 {
1619 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001620 }
1621
1622 return errs
1623}
1624
Colin Cross7addea32015-03-11 15:43:52 -07001625func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1626 newModules []*moduleInfo) []*moduleInfo {
1627 for i, m := range modules {
1628 if m == origModule {
1629 return spliceModulesAtIndex(modules, i, newModules)
1630 }
1631 }
1632
1633 panic("failed to find original module to splice")
1634}
1635
1636func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1637 spliceSize := len(newModules)
1638 newLen := len(modules) + spliceSize - 1
1639 var dest []*moduleInfo
1640 if cap(modules) >= len(modules)-1+len(newModules) {
1641 // We can fit the splice in the existing capacity, do everything in place
1642 dest = modules[:newLen]
1643 } else {
1644 dest = make([]*moduleInfo, newLen)
1645 copy(dest, modules[:i])
1646 }
1647
1648 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001649 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001650
1651 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001652 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001653
Colin Cross72bd1932015-03-16 00:13:59 -07001654 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001655}
1656
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001657func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001658 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001659 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001660 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001661 c.requiredNinjaMicro = 0
1662}
1663
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001664func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001665 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001666
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001667 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001668 var errs []error
1669
Colin Cross691a60d2015-01-07 18:08:56 -08001670 cancelCh := make(chan struct{})
1671 errsCh := make(chan []error)
1672 depsCh := make(chan []string)
1673
1674 go func() {
1675 for {
1676 select {
1677 case <-cancelCh:
1678 close(cancelCh)
1679 return
1680 case newErrs := <-errsCh:
1681 errs = append(errs, newErrs...)
1682 case newDeps := <-depsCh:
1683 deps = append(deps, newDeps...)
1684
1685 }
1686 }
1687 }()
1688
Colin Cross7addea32015-03-11 15:43:52 -07001689 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1690 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1691 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1692 // just set it to nil.
1693 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1694 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001695
Colin Cross7addea32015-03-11 15:43:52 -07001696 mctx := &moduleContext{
1697 baseModuleContext: baseModuleContext{
1698 context: c,
1699 config: config,
1700 module: module,
1701 },
1702 scope: scope,
1703 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001704
Colin Cross7addea32015-03-11 15:43:52 -07001705 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001706
Colin Cross7addea32015-03-11 15:43:52 -07001707 if len(mctx.errs) > 0 {
1708 errsCh <- mctx.errs
1709 return true
1710 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001711
Colin Cross7addea32015-03-11 15:43:52 -07001712 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001713
Colin Crossab6d7902015-03-11 16:17:52 -07001714 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001715 &mctx.actionDefs, liveGlobals)
1716 if len(newErrs) > 0 {
1717 errsCh <- newErrs
1718 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001719 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001720 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001721 })
1722
1723 cancelCh <- struct{}{}
1724 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001725
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001726 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001727}
1728
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001729func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001730 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001731
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001732 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001733 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001734
Yuchen Wub9103ef2015-08-25 17:58:17 -07001735 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001736 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1737 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1738 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001739 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001740
1741 sctx := &singletonContext{
1742 context: c,
1743 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001744 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001745 }
1746
1747 info.singleton.GenerateBuildActions(sctx)
1748
1749 if len(sctx.errs) > 0 {
1750 errs = append(errs, sctx.errs...)
1751 if len(errs) > maxErrors {
1752 break
1753 }
1754 continue
1755 }
1756
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001757 deps = append(deps, sctx.ninjaFileDeps...)
1758
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001759 newErrs := c.processLocalBuildActions(&info.actionDefs,
1760 &sctx.actionDefs, liveGlobals)
1761 errs = append(errs, newErrs...)
1762 if len(errs) > maxErrors {
1763 break
1764 }
1765 }
1766
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001767 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001768}
1769
1770func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1771 liveGlobals *liveTracker) []error {
1772
1773 var errs []error
1774
1775 // First we go through and add everything referenced by the module's
1776 // buildDefs to the live globals set. This will end up adding the live
1777 // locals to the set as well, but we'll take them out after.
1778 for _, def := range in.buildDefs {
1779 err := liveGlobals.AddBuildDefDeps(def)
1780 if err != nil {
1781 errs = append(errs, err)
1782 }
1783 }
1784
1785 if len(errs) > 0 {
1786 return errs
1787 }
1788
Colin Crossc9028482014-12-18 16:28:54 -08001789 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001790
1791 // We use the now-incorrect set of live "globals" to determine which local
1792 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001793 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001794 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001795 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001796 if isLive {
1797 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 }
1799 }
1800
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001801 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001802 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001803 if isLive {
1804 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001805 }
1806 }
1807
1808 return nil
1809}
1810
Yuchen Wu222e2452015-10-06 14:03:27 -07001811func (c *Context) walkDeps(topModule *moduleInfo,
1812 visit func(Module, Module) bool) {
1813
1814 visited := make(map[*moduleInfo]bool)
1815
1816 var walk func(module *moduleInfo)
1817 walk = func(module *moduleInfo) {
1818 visited[module] = true
1819
1820 for _, moduleDep := range module.directDeps {
1821 if !visited[moduleDep] {
1822 if visit(moduleDep.logicModule, module.logicModule) {
1823 walk(moduleDep)
1824 }
1825 }
1826 }
1827 }
1828
1829 walk(topModule)
1830}
1831
Colin Crossbbfa51a2014-12-17 16:12:41 -08001832func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1833 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001834
Colin Crossbbfa51a2014-12-17 16:12:41 -08001835 var walk func(module *moduleInfo)
1836 walk = func(module *moduleInfo) {
1837 visited[module] = true
1838 for _, moduleDep := range module.directDeps {
1839 if !visited[moduleDep] {
1840 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001841 }
1842 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001843
Colin Crossbbfa51a2014-12-17 16:12:41 -08001844 if module != topModule {
1845 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001846 }
1847 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001848
1849 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001850}
1851
Colin Crossbbfa51a2014-12-17 16:12:41 -08001852func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001853 visit func(Module)) {
1854
Colin Crossbbfa51a2014-12-17 16:12:41 -08001855 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001856
Colin Crossbbfa51a2014-12-17 16:12:41 -08001857 var walk func(module *moduleInfo)
1858 walk = func(module *moduleInfo) {
1859 visited[module] = true
1860 for _, moduleDep := range module.directDeps {
1861 if !visited[moduleDep] {
1862 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001863 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001864 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001865
1866 if module != topModule {
1867 if pred(module.logicModule) {
1868 visit(module.logicModule)
1869 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001870 }
1871 }
1872
Colin Crossbbfa51a2014-12-17 16:12:41 -08001873 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001874}
1875
Colin Crossc9028482014-12-18 16:28:54 -08001876func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1877 for _, dep := range module.directDeps {
1878 visit(dep.logicModule)
1879 }
1880}
1881
1882func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1883 visit func(Module)) {
1884
1885 for _, dep := range module.directDeps {
1886 if pred(dep.logicModule) {
1887 visit(dep.logicModule)
1888 }
1889 }
1890}
1891
Jamie Gennisc15544d2014-09-24 20:26:52 -07001892func (c *Context) sortedModuleNames() []string {
1893 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001894 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1895 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001896 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1897 moduleName)
1898 }
1899 sort.Strings(c.cachedSortedModuleNames)
1900 }
1901
1902 return c.cachedSortedModuleNames
1903}
1904
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001905func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001906 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001907 group := c.moduleGroups[moduleName]
1908 for _, module := range group.modules {
1909 visit(module.logicModule)
1910 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001911 }
1912}
1913
1914func (c *Context) visitAllModulesIf(pred func(Module) bool,
1915 visit func(Module)) {
1916
Jamie Gennisc15544d2014-09-24 20:26:52 -07001917 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001918 group := c.moduleGroups[moduleName]
1919 for _, module := range group.modules {
1920 if pred(module.logicModule) {
1921 visit(module.logicModule)
1922 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001923 }
1924 }
1925}
1926
1927func (c *Context) requireNinjaVersion(major, minor, micro int) {
1928 if major != 1 {
1929 panic("ninja version with major version != 1 not supported")
1930 }
1931 if c.requiredNinjaMinor < minor {
1932 c.requiredNinjaMinor = minor
1933 c.requiredNinjaMicro = micro
1934 }
1935 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1936 c.requiredNinjaMicro = micro
1937 }
1938}
1939
Colin Crossa2599452015-11-18 16:01:01 -08001940func (c *Context) setNinjaBuildDir(value *ninjaString) {
1941 if c.ninjaBuildDir == nil {
1942 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001943 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001944}
1945
1946func (c *Context) makeUniquePackageNames(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08001947 liveGlobals *liveTracker) map[*packageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001948
Dan Willemsenaeffbf72015-11-25 15:29:32 -08001949 pkgs := make(map[string]*packageContext)
1950 pkgNames := make(map[*packageContext]string)
1951 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001952
Dan Willemsenaeffbf72015-11-25 15:29:32 -08001953 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001954 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001955 // This is a built-in rule and has no package.
1956 return
1957 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001958 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001959 // We've already processed this package.
1960 return
1961 }
1962
Jamie Gennis2fb20952014-10-03 02:49:58 -07001963 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001964 if present {
1965 // Short name collision. Both this package and the one that's
1966 // already there need to use their full names. We leave the short
1967 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001968 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001969 longPkgNames[otherPkg] = true
1970 } else {
1971 // No collision so far. Tentatively set the package's name to be
1972 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001973 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07001974 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001975 }
1976 }
1977
1978 // We try to give all packages their short name, but when we get collisions
1979 // we need to use the full unique package name.
1980 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001981 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001982 }
1983 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001984 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001985 }
1986 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001987 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001988 }
1989
1990 // Add the packages that had collisions using their full unique names. This
1991 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001992 for pctx := range longPkgNames {
1993 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001994 }
1995
1996 return pkgNames
1997}
1998
1999func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002000 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002001
2002 visited := make(map[Variable]bool) // variables that were already checked
2003 checking := make(map[Variable]bool) // variables actively being checked
2004
2005 var check func(v Variable) []Variable
2006
2007 check = func(v Variable) []Variable {
2008 visited[v] = true
2009 checking[v] = true
2010 defer delete(checking, v)
2011
2012 value := variables[v]
2013 for _, dep := range value.variables {
2014 if checking[dep] {
2015 // This is a cycle.
2016 return []Variable{dep, v}
2017 }
2018
2019 if !visited[dep] {
2020 cycle := check(dep)
2021 if cycle != nil {
2022 if cycle[0] == v {
2023 // We are the "start" of the cycle, so we're responsible
2024 // for generating the errors. The cycle list is in
2025 // reverse order because all the 'check' calls append
2026 // their own module to the list.
2027 msgs := []string{"detected variable reference cycle:"}
2028
2029 // Iterate backwards through the cycle list.
2030 curName := v.fullName(pkgNames)
2031 curValue := value.Value(pkgNames)
2032 for i := len(cycle) - 1; i >= 0; i-- {
2033 next := cycle[i]
2034 nextName := next.fullName(pkgNames)
2035 nextValue := variables[next].Value(pkgNames)
2036
2037 msgs = append(msgs, fmt.Sprintf(
2038 " %q depends on %q", curName, nextName))
2039 msgs = append(msgs, fmt.Sprintf(
2040 " [%s = %s]", curName, curValue))
2041
2042 curName = nextName
2043 curValue = nextValue
2044 }
2045
2046 // Variable reference cycles are a programming error,
2047 // not the fault of the Blueprint file authors.
2048 panic(strings.Join(msgs, "\n"))
2049 } else {
2050 // We're not the "start" of the cycle, so we just append
2051 // our module to the list and return it.
2052 return append(cycle, v)
2053 }
2054 }
2055 }
2056 }
2057
2058 return nil
2059 }
2060
2061 for v := range variables {
2062 if !visited[v] {
2063 cycle := check(v)
2064 if cycle != nil {
2065 panic("inconceivable!")
2066 }
2067 }
2068 }
2069}
2070
Jamie Gennisaf435562014-10-27 22:34:56 -07002071// AllTargets returns a map all the build target names to the rule used to build
2072// them. This is the same information that is output by running 'ninja -t
2073// targets all'. If this is called before PrepareBuildActions successfully
2074// completes then ErrbuildActionsNotReady is returned.
2075func (c *Context) AllTargets() (map[string]string, error) {
2076 if !c.buildActionsReady {
2077 return nil, ErrBuildActionsNotReady
2078 }
2079
2080 targets := map[string]string{}
2081
2082 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002083 for _, module := range c.moduleInfo {
2084 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002085 ruleName := buildDef.Rule.fullName(c.pkgNames)
2086 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002087 outputValue, err := output.Eval(c.globalVariables)
2088 if err != nil {
2089 return nil, err
2090 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002091 targets[outputValue] = ruleName
2092 }
2093 }
2094 }
2095
2096 // Collect all the singleton build targets.
2097 for _, info := range c.singletonInfo {
2098 for _, buildDef := range info.actionDefs.buildDefs {
2099 ruleName := buildDef.Rule.fullName(c.pkgNames)
2100 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002101 outputValue, err := output.Eval(c.globalVariables)
2102 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002103 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002104 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002105 targets[outputValue] = ruleName
2106 }
2107 }
2108 }
2109
2110 return targets, nil
2111}
2112
Colin Crossa2599452015-11-18 16:01:01 -08002113func (c *Context) NinjaBuildDir() (string, error) {
2114 if c.ninjaBuildDir != nil {
2115 return c.ninjaBuildDir.Eval(c.globalVariables)
2116 } else {
2117 return "", nil
2118 }
2119}
2120
Colin Cross4572edd2015-05-13 14:36:24 -07002121// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2122// property structs returned by the factory for that module type.
2123func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2124 ret := make(map[string][]interface{})
2125 for moduleType, factory := range c.moduleFactories {
2126 _, ret[moduleType] = factory()
2127 }
2128
2129 return ret
2130}
2131
2132func (c *Context) ModuleName(logicModule Module) string {
2133 module := c.moduleInfo[logicModule]
2134 return module.properties.Name
2135}
2136
2137func (c *Context) ModuleDir(logicModule Module) string {
2138 module := c.moduleInfo[logicModule]
2139 return filepath.Dir(module.relBlueprintsFile)
2140}
2141
2142func (c *Context) BlueprintFile(logicModule Module) string {
2143 module := c.moduleInfo[logicModule]
2144 return module.relBlueprintsFile
2145}
2146
2147func (c *Context) ModuleErrorf(logicModule Module, format string,
2148 args ...interface{}) error {
2149
2150 module := c.moduleInfo[logicModule]
2151 return &Error{
2152 Err: fmt.Errorf(format, args...),
2153 Pos: module.pos,
2154 }
2155}
2156
2157func (c *Context) VisitAllModules(visit func(Module)) {
2158 c.visitAllModules(visit)
2159}
2160
2161func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2162 visit func(Module)) {
2163
2164 c.visitAllModulesIf(pred, visit)
2165}
2166
2167func (c *Context) VisitDepsDepthFirst(module Module,
2168 visit func(Module)) {
2169
2170 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2171}
2172
2173func (c *Context) VisitDepsDepthFirstIf(module Module,
2174 pred func(Module) bool, visit func(Module)) {
2175
2176 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2177}
2178
Colin Cross24ad5872015-11-17 16:22:29 -08002179func (c *Context) PrimaryModule(module Module) Module {
2180 return c.moduleInfo[module].group.modules[0].logicModule
2181}
2182
2183func (c *Context) FinalModule(module Module) Module {
2184 modules := c.moduleInfo[module].group.modules
2185 return modules[len(modules)-1].logicModule
2186}
2187
2188func (c *Context) VisitAllModuleVariants(module Module,
2189 visit func(Module)) {
2190
2191 for _, module := range c.moduleInfo[module].group.modules {
2192 visit(module.logicModule)
2193 }
2194}
2195
Jamie Gennisd4e10182014-06-12 20:06:50 -07002196// WriteBuildFile writes the Ninja manifeset text for the generated build
2197// actions to w. If this is called before PrepareBuildActions successfully
2198// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002199func (c *Context) WriteBuildFile(w io.Writer) error {
2200 if !c.buildActionsReady {
2201 return ErrBuildActionsNotReady
2202 }
2203
2204 nw := newNinjaWriter(w)
2205
2206 err := c.writeBuildFileHeader(nw)
2207 if err != nil {
2208 return err
2209 }
2210
2211 err = c.writeNinjaRequiredVersion(nw)
2212 if err != nil {
2213 return err
2214 }
2215
2216 // TODO: Group the globals by package.
2217
2218 err = c.writeGlobalVariables(nw)
2219 if err != nil {
2220 return err
2221 }
2222
2223 err = c.writeGlobalPools(nw)
2224 if err != nil {
2225 return err
2226 }
2227
2228 err = c.writeBuildDir(nw)
2229 if err != nil {
2230 return err
2231 }
2232
2233 err = c.writeGlobalRules(nw)
2234 if err != nil {
2235 return err
2236 }
2237
2238 err = c.writeAllModuleActions(nw)
2239 if err != nil {
2240 return err
2241 }
2242
2243 err = c.writeAllSingletonActions(nw)
2244 if err != nil {
2245 return err
2246 }
2247
2248 return nil
2249}
2250
Jamie Gennisc15544d2014-09-24 20:26:52 -07002251type pkgAssociation struct {
2252 PkgName string
2253 PkgPath string
2254}
2255
2256type pkgAssociationSorter struct {
2257 pkgs []pkgAssociation
2258}
2259
2260func (s *pkgAssociationSorter) Len() int {
2261 return len(s.pkgs)
2262}
2263
2264func (s *pkgAssociationSorter) Less(i, j int) bool {
2265 iName := s.pkgs[i].PkgName
2266 jName := s.pkgs[j].PkgName
2267 return iName < jName
2268}
2269
2270func (s *pkgAssociationSorter) Swap(i, j int) {
2271 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2272}
2273
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002274func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2275 headerTemplate := template.New("fileHeader")
2276 _, err := headerTemplate.Parse(fileHeaderTemplate)
2277 if err != nil {
2278 // This is a programming error.
2279 panic(err)
2280 }
2281
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002282 var pkgs []pkgAssociation
2283 maxNameLen := 0
2284 for pkg, name := range c.pkgNames {
2285 pkgs = append(pkgs, pkgAssociation{
2286 PkgName: name,
2287 PkgPath: pkg.pkgPath,
2288 })
2289 if len(name) > maxNameLen {
2290 maxNameLen = len(name)
2291 }
2292 }
2293
2294 for i := range pkgs {
2295 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2296 }
2297
Jamie Gennisc15544d2014-09-24 20:26:52 -07002298 sort.Sort(&pkgAssociationSorter{pkgs})
2299
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002300 params := map[string]interface{}{
2301 "Pkgs": pkgs,
2302 }
2303
2304 buf := bytes.NewBuffer(nil)
2305 err = headerTemplate.Execute(buf, params)
2306 if err != nil {
2307 return err
2308 }
2309
2310 return nw.Comment(buf.String())
2311}
2312
2313func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2314 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2315 c.requiredNinjaMicro)
2316
2317 err := nw.Assign("ninja_required_version", value)
2318 if err != nil {
2319 return err
2320 }
2321
2322 return nw.BlankLine()
2323}
2324
2325func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002326 if c.ninjaBuildDir != nil {
2327 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002328 if err != nil {
2329 return err
2330 }
2331
2332 err = nw.BlankLine()
2333 if err != nil {
2334 return err
2335 }
2336 }
2337 return nil
2338}
2339
Jamie Gennisc15544d2014-09-24 20:26:52 -07002340type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002341 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002342}
2343
Jamie Gennisc15544d2014-09-24 20:26:52 -07002344type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002345 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002346 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002347}
2348
Jamie Gennisc15544d2014-09-24 20:26:52 -07002349func (s *globalEntitySorter) Len() int {
2350 return len(s.entities)
2351}
2352
2353func (s *globalEntitySorter) Less(i, j int) bool {
2354 iName := s.entities[i].fullName(s.pkgNames)
2355 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002356 return iName < jName
2357}
2358
Jamie Gennisc15544d2014-09-24 20:26:52 -07002359func (s *globalEntitySorter) Swap(i, j int) {
2360 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002361}
2362
2363func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2364 visited := make(map[Variable]bool)
2365
2366 var walk func(v Variable) error
2367 walk = func(v Variable) error {
2368 visited[v] = true
2369
2370 // First visit variables on which this variable depends.
2371 value := c.globalVariables[v]
2372 for _, dep := range value.variables {
2373 if !visited[dep] {
2374 err := walk(dep)
2375 if err != nil {
2376 return err
2377 }
2378 }
2379 }
2380
2381 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2382 if err != nil {
2383 return err
2384 }
2385
2386 err = nw.BlankLine()
2387 if err != nil {
2388 return err
2389 }
2390
2391 return nil
2392 }
2393
Jamie Gennisc15544d2014-09-24 20:26:52 -07002394 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2395 for variable := range c.globalVariables {
2396 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002397 }
2398
Jamie Gennisc15544d2014-09-24 20:26:52 -07002399 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002400
Jamie Gennisc15544d2014-09-24 20:26:52 -07002401 for _, entity := range globalVariables {
2402 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002403 if !visited[v] {
2404 err := walk(v)
2405 if err != nil {
2406 return nil
2407 }
2408 }
2409 }
2410
2411 return nil
2412}
2413
2414func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002415 globalPools := make([]globalEntity, 0, len(c.globalPools))
2416 for pool := range c.globalPools {
2417 globalPools = append(globalPools, pool)
2418 }
2419
2420 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2421
2422 for _, entity := range globalPools {
2423 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002424 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002425 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002426 err := def.WriteTo(nw, name)
2427 if err != nil {
2428 return err
2429 }
2430
2431 err = nw.BlankLine()
2432 if err != nil {
2433 return err
2434 }
2435 }
2436
2437 return nil
2438}
2439
2440func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002441 globalRules := make([]globalEntity, 0, len(c.globalRules))
2442 for rule := range c.globalRules {
2443 globalRules = append(globalRules, rule)
2444 }
2445
2446 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2447
2448 for _, entity := range globalRules {
2449 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002450 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002451 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002452 err := def.WriteTo(nw, name, c.pkgNames)
2453 if err != nil {
2454 return err
2455 }
2456
2457 err = nw.BlankLine()
2458 if err != nil {
2459 return err
2460 }
2461 }
2462
2463 return nil
2464}
2465
Colin Crossab6d7902015-03-11 16:17:52 -07002466type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002467
Colin Crossab6d7902015-03-11 16:17:52 -07002468func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002469 return len(s)
2470}
2471
Colin Crossab6d7902015-03-11 16:17:52 -07002472func (s moduleSorter) Less(i, j int) bool {
2473 iName := s[i].properties.Name
2474 jName := s[j].properties.Name
2475 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002476 iName = s[i].variantName
2477 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002478 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002479 return iName < jName
2480}
2481
Colin Crossab6d7902015-03-11 16:17:52 -07002482func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002483 s[i], s[j] = s[j], s[i]
2484}
2485
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002486func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2487 headerTemplate := template.New("moduleHeader")
2488 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2489 if err != nil {
2490 // This is a programming error.
2491 panic(err)
2492 }
2493
Colin Crossab6d7902015-03-11 16:17:52 -07002494 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2495 for _, module := range c.moduleInfo {
2496 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002497 }
Colin Crossab6d7902015-03-11 16:17:52 -07002498 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002499
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002500 buf := bytes.NewBuffer(nil)
2501
Colin Crossab6d7902015-03-11 16:17:52 -07002502 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002503 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2504 continue
2505 }
2506
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002507 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002508
2509 // In order to make the bootstrap build manifest independent of the
2510 // build dir we need to output the Blueprints file locations in the
2511 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002512 relPos := module.pos
2513 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002514
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002515 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002516 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002517 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2518 factoryName := factoryFunc.Name()
2519
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002520 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002521 "properties": module.properties,
2522 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002523 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002524 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002525 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002526 }
2527 err = headerTemplate.Execute(buf, infoMap)
2528 if err != nil {
2529 return err
2530 }
2531
2532 err = nw.Comment(buf.String())
2533 if err != nil {
2534 return err
2535 }
2536
2537 err = nw.BlankLine()
2538 if err != nil {
2539 return err
2540 }
2541
Colin Crossab6d7902015-03-11 16:17:52 -07002542 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002543 if err != nil {
2544 return err
2545 }
2546
2547 err = nw.BlankLine()
2548 if err != nil {
2549 return err
2550 }
2551 }
2552
2553 return nil
2554}
2555
2556func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2557 headerTemplate := template.New("singletonHeader")
2558 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2559 if err != nil {
2560 // This is a programming error.
2561 panic(err)
2562 }
2563
2564 buf := bytes.NewBuffer(nil)
2565
Yuchen Wub9103ef2015-08-25 17:58:17 -07002566 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002567 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2568 continue
2569 }
2570
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002571 // Get the name of the factory function for the module.
2572 factory := info.factory
2573 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2574 factoryName := factoryFunc.Name()
2575
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002576 buf.Reset()
2577 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002578 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002579 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002580 }
2581 err = headerTemplate.Execute(buf, infoMap)
2582 if err != nil {
2583 return err
2584 }
2585
2586 err = nw.Comment(buf.String())
2587 if err != nil {
2588 return err
2589 }
2590
2591 err = nw.BlankLine()
2592 if err != nil {
2593 return err
2594 }
2595
2596 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2597 if err != nil {
2598 return err
2599 }
2600
2601 err = nw.BlankLine()
2602 if err != nil {
2603 return err
2604 }
2605 }
2606
2607 return nil
2608}
2609
2610func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2611 defs *localBuildActions) error {
2612
2613 // Write the local variable assignments.
2614 for _, v := range defs.variables {
2615 // A localVariable doesn't need the package names or config to
2616 // determine its name or value.
2617 name := v.fullName(nil)
2618 value, err := v.value(nil)
2619 if err != nil {
2620 panic(err)
2621 }
2622 err = nw.Assign(name, value.Value(c.pkgNames))
2623 if err != nil {
2624 return err
2625 }
2626 }
2627
2628 if len(defs.variables) > 0 {
2629 err := nw.BlankLine()
2630 if err != nil {
2631 return err
2632 }
2633 }
2634
2635 // Write the local rules.
2636 for _, r := range defs.rules {
2637 // A localRule doesn't need the package names or config to determine
2638 // its name or definition.
2639 name := r.fullName(nil)
2640 def, err := r.def(nil)
2641 if err != nil {
2642 panic(err)
2643 }
2644
2645 err = def.WriteTo(nw, name, c.pkgNames)
2646 if err != nil {
2647 return err
2648 }
2649
2650 err = nw.BlankLine()
2651 if err != nil {
2652 return err
2653 }
2654 }
2655
2656 // Write the build definitions.
2657 for _, buildDef := range defs.buildDefs {
2658 err := buildDef.WriteTo(nw, c.pkgNames)
2659 if err != nil {
2660 return err
2661 }
2662
2663 if len(buildDef.Args) > 0 {
2664 err = nw.BlankLine()
2665 if err != nil {
2666 return err
2667 }
2668 }
2669 }
2670
2671 return nil
2672}
2673
Colin Cross65569e42015-03-10 20:08:19 -07002674func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2675 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002676 if a == b {
2677 return false
2678 }
Colin Cross65569e42015-03-10 20:08:19 -07002679 for _, l := range list {
2680 if l == a {
2681 found = true
2682 } else if l == b {
2683 return found
2684 }
2685 }
2686
2687 missing := a
2688 if found {
2689 missing = b
2690 }
2691 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2692}
2693
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002694var fileHeaderTemplate = `******************************************************************************
2695*** This file is generated and should not be edited ***
2696******************************************************************************
2697{{if .Pkgs}}
2698This file contains variables, rules, and pools with name prefixes indicating
2699they were generated by the following Go packages:
2700{{range .Pkgs}}
2701 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2702
2703`
2704
2705var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2706Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002707Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002708Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002709Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002710Defined: {{.pos}}
2711`
2712
2713var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2714Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002715Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002716`