blob: c5e8b15a6ed5c457c6f5fbe5068e596e70630609 [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
Jamie Gennis2fb20952014-10-03 02:49:58 -070085 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
91 buildDir *ninjaString // The builddir special Ninja variable
92 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 {
227 return &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 }
233}
234
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700235// A ModuleFactory function creates a new Module object. See the
236// Context.RegisterModuleType method for details about how a registered
237// ModuleFactory is used by a Context.
238type ModuleFactory func() (m Module, propertyStructs []interface{})
239
Jamie Gennisd4e10182014-06-12 20:06:50 -0700240// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700241// Blueprints file) with a Module factory function. When the given module type
242// name is encountered in a Blueprints file during parsing, the Module factory
243// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800244// generation for the module. If a Mutator splits a module into multiple variants,
245// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700246//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700247// The module type names given here must be unique for the context. The factory
248// function should be a named function so that its package and name can be
249// included in the generated Ninja file for debugging purposes.
250//
251// The factory function returns two values. The first is the newly created
252// Module object. The second is a slice of pointers to that Module object's
253// properties structs. Each properties struct is examined when parsing a module
254// definition of this type in a Blueprints file. Exported fields of the
255// properties structs are automatically set to the property values specified in
256// the Blueprints file. The properties struct field names determine the name of
257// the Blueprints file properties that are used - the Blueprints property name
258// matches that of the properties struct field name with the first letter
259// converted to lower-case.
260//
261// The fields of the properties struct must be either []string, a string, or
262// bool. The Context will panic if a Module gets instantiated with a properties
263// struct containing a field that is not one these supported types.
264//
265// Any properties that appear in the Blueprints files that are not built-in
266// module properties (such as "name" and "deps") and do not have a corresponding
267// field in the returned module properties struct result in an error during the
268// Context's parse phase.
269//
270// As an example, the follow code:
271//
272// type myModule struct {
273// properties struct {
274// Foo string
275// Bar []string
276// }
277// }
278//
279// func NewMyModule() (blueprint.Module, []interface{}) {
280// module := new(myModule)
281// properties := &module.properties
282// return module, []interface{}{properties}
283// }
284//
285// func main() {
286// ctx := blueprint.NewContext()
287// ctx.RegisterModuleType("my_module", NewMyModule)
288// // ...
289// }
290//
291// would support parsing a module defined in a Blueprints file as follows:
292//
293// my_module {
294// name: "myName",
295// foo: "my foo string",
296// bar: ["my", "bar", "strings"],
297// }
298//
Colin Cross7ad621c2015-01-07 16:22:45 -0800299// The factory function may be called from multiple goroutines. Any accesses
300// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700301func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
302 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700303 panic(errors.New("module type name is already registered"))
304 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700305 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700306}
307
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700308// A SingletonFactory function creates a new Singleton object. See the
309// Context.RegisterSingletonType method for details about how a registered
310// SingletonFactory is used by a Context.
311type SingletonFactory func() Singleton
312
313// RegisterSingletonType registers a singleton type that will be invoked to
314// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700315// and invoked exactly once as part of the generate phase. Each registered
316// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700317//
318// The singleton type names given here must be unique for the context. The
319// factory function should be a named function so that its package and name can
320// be included in the generated Ninja file for debugging purposes.
321func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700322 for _, s := range c.singletonInfo {
323 if s.name == name {
324 panic(errors.New("singleton name is already registered"))
325 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700326 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700327
Yuchen Wub9103ef2015-08-25 17:58:17 -0700328 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700329 factory: factory,
330 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700331 name: name,
332 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700333}
334
335func singletonPkgPath(singleton Singleton) string {
336 typ := reflect.TypeOf(singleton)
337 for typ.Kind() == reflect.Ptr {
338 typ = typ.Elem()
339 }
340 return typ.PkgPath()
341}
342
343func singletonTypeName(singleton Singleton) string {
344 typ := reflect.TypeOf(singleton)
345 for typ.Kind() == reflect.Ptr {
346 typ = typ.Elem()
347 }
348 return typ.PkgPath() + "." + typ.Name()
349}
350
Colin Crossc9028482014-12-18 16:28:54 -0800351// RegisterTopDownMutator registers a mutator that will be invoked to propagate
352// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700353// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
354// once per Module, and is invoked on a module before being invoked on any of its
355// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800356//
Colin Cross65569e42015-03-10 20:08:19 -0700357// The mutator type names given here must be unique to all top down mutators in
358// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800359func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
360 for _, m := range c.mutatorInfo {
361 if m.name == name && m.topDownMutator != nil {
362 panic(fmt.Errorf("mutator name %s is already registered", name))
363 }
364 }
365
366 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
367 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800368 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800369 })
370}
371
372// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700373// Modules into variants. Each registered mutator is invoked in registration
374// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
375// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800376//
Colin Cross65569e42015-03-10 20:08:19 -0700377// The mutator type names given here must be unique to all bottom up or early
378// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800379func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700380 for _, m := range c.variantMutatorNames {
381 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800382 panic(fmt.Errorf("mutator name %s is already registered", name))
383 }
384 }
385
386 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
387 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800388 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800389 })
Colin Cross65569e42015-03-10 20:08:19 -0700390
391 c.variantMutatorNames = append(c.variantMutatorNames, name)
392}
393
394// RegisterEarlyMutator registers a mutator that will be invoked to split
395// Modules into multiple variant Modules before any dependencies have been
396// created. Each registered mutator is invoked in registration order once
397// per Module (including each variant from previous early mutators). Module
398// order is unpredictable.
399//
400// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700401// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700402//
403// The mutator type names given here must be unique to all bottom up or early
404// mutators in the Context.
405func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
406 for _, m := range c.variantMutatorNames {
407 if m == name {
408 panic(fmt.Errorf("mutator name %s is already registered", name))
409 }
410 }
411
412 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
413 mutator: mutator,
414 name: name,
415 })
416
417 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800418}
419
Jamie Gennisd4e10182014-06-12 20:06:50 -0700420// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
421// where it encounters an unknown module type while parsing Blueprints files. By
422// default, the context will report unknown module types as an error. If this
423// method is called with ignoreUnknownModuleTypes set to true then the context
424// will silently ignore unknown module types.
425//
426// This method should generally not be used. It exists to facilitate the
427// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700428func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
429 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
430}
431
Jamie Gennisd4e10182014-06-12 20:06:50 -0700432// Parse parses a single Blueprints file from r, creating Module objects for
433// each of the module definitions encountered. If the Blueprints file contains
434// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700435// searched for Blueprints files returned in the subBlueprints return value.
436// If the Blueprints file contains an assignment to the "build" variable, then
437// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700438//
439// rootDir specifies the path to the root directory of the source tree, while
440// filename specifies the path to the Blueprints file. These paths are used for
441// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800442func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700443 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700444 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700445
Jamie Gennisec701282014-06-12 20:06:31 -0700446 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700447 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700448 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700449 }
450
Colin Crossc0dbc552015-01-02 15:19:28 -0800451 scope = parser.NewScope(scope)
452 scope.Remove("subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700453 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700454 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700455 if len(errs) > 0 {
456 for i, err := range errs {
457 if parseErr, ok := err.(*parser.ParseError); ok {
458 err = &Error{
459 Err: parseErr.Err,
460 Pos: parseErr.Pos,
461 }
462 errs[i] = err
463 }
464 }
465
466 // If there were any parse errors don't bother trying to interpret the
467 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700468 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700469 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700470 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700471
Colin Cross1fef5362015-04-20 16:50:54 -0700472 subdirs, subdirsPos, err := getStringListFromScope(scope, "subdirs")
473 if err != nil {
474 errs = append(errs, err)
475 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700476
Colin Cross1fef5362015-04-20 16:50:54 -0700477 build, buildPos, err := getStringListFromScope(scope, "build")
478 if err != nil {
479 errs = append(errs, err)
480 }
481
Colin Cross29394222015-04-27 13:18:21 -0700482 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
483
Colin Cross1fef5362015-04-20 16:50:54 -0700484 blueprints, deps, newErrs := c.findSubdirBlueprints(filepath.Dir(filename), subdirs, build,
Colin Cross29394222015-04-27 13:18:21 -0700485 subBlueprintsName, subdirsPos, buildPos)
Colin Crossc0dbc552015-01-02 15:19:28 -0800486 if len(newErrs) > 0 {
487 errs = append(errs, newErrs...)
488 }
489
Colin Cross1fef5362015-04-20 16:50:54 -0700490 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
491 for i, b := range blueprints {
492 subBlueprintsAndScope[i] = stringAndScope{b, scope}
493 }
494
Colin Cross23d7aa12015-06-30 16:05:22 -0700495 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800496}
497
Colin Cross7ad621c2015-01-07 16:22:45 -0800498type stringAndScope struct {
499 string
500 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700501}
502
Jamie Gennisd4e10182014-06-12 20:06:50 -0700503// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
504// at rootFile. When it encounters a Blueprints file with a set of subdirs
505// listed it recursively parses any Blueprints files found in those
506// subdirectories.
507//
508// If no errors are encountered while parsing the files, the list of paths on
509// which the future output will depend is returned. This list will include both
510// Blueprints file paths as well as directory paths for cases where wildcard
511// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700512func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
513 errs []error) {
514
Colin Cross7ad621c2015-01-07 16:22:45 -0800515 c.dependenciesReady = false
516
Colin Cross23d7aa12015-06-30 16:05:22 -0700517 moduleCh := make(chan *moduleInfo)
518 errsCh := make(chan []error)
519 doneCh := make(chan struct{})
520 var numErrs uint32
521 var numGoroutines int32
522
523 // handler must be reentrant
524 handler := func(file *parser.File) {
525 if atomic.LoadUint32(&numErrs) > maxErrors {
526 return
527 }
528
529 atomic.AddInt32(&numGoroutines, 1)
530 go func() {
531 for _, def := range file.Defs {
532 var module *moduleInfo
533 var errs []error
534 switch def := def.(type) {
535 case *parser.Module:
536 module, errs = c.processModuleDef(def, file.Name)
537 case *parser.Assignment:
538 // Already handled via Scope object
539 default:
540 panic("unknown definition type")
541 }
542
543 if len(errs) > 0 {
544 atomic.AddUint32(&numErrs, uint32(len(errs)))
545 errsCh <- errs
546 } else if module != nil {
547 moduleCh <- module
548 }
549 }
550 doneCh <- struct{}{}
551 }()
552 }
553
554 atomic.AddInt32(&numGoroutines, 1)
555 go func() {
556 var errs []error
557 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
558 if len(errs) > 0 {
559 errsCh <- errs
560 }
561 doneCh <- struct{}{}
562 }()
563
564loop:
565 for {
566 select {
567 case newErrs := <-errsCh:
568 errs = append(errs, newErrs...)
569 case module := <-moduleCh:
570 newErrs := c.addModule(module)
571 if len(newErrs) > 0 {
572 errs = append(errs, newErrs...)
573 }
574 case <-doneCh:
575 n := atomic.AddInt32(&numGoroutines, -1)
576 if n == 0 {
577 break loop
578 }
579 }
580 }
581
582 return deps, errs
583}
584
585type FileHandler func(*parser.File)
586
587// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
588// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
589// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
590// it must be reentrant.
591//
592// If no errors are encountered while parsing the files, the list of paths on
593// which the future output will depend is returned. This list will include both
594// Blueprints file paths as well as directory paths for cases where wildcard
595// subdirs are found.
596func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
597 errs []error) {
598
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700599 rootDir := filepath.Dir(rootFile)
600
Colin Cross7ad621c2015-01-07 16:22:45 -0800601 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700602
Colin Cross7ad621c2015-01-07 16:22:45 -0800603 // Channels to receive data back from parseBlueprintsFile goroutines
604 blueprintsCh := make(chan stringAndScope)
605 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700606 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800607 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700608
Colin Cross7ad621c2015-01-07 16:22:45 -0800609 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
610 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700611
Colin Cross7ad621c2015-01-07 16:22:45 -0800612 // Number of outstanding goroutines to wait for
613 count := 0
614
615 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
616 count++
617 go func() {
618 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700619 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800620 doneCh <- struct{}{}
621 }()
622 }
623
624 tooManyErrors := false
625
626 startParseBlueprintsFile(rootFile, nil)
627
628loop:
629 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700630 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800631 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700632 }
633
Colin Cross7ad621c2015-01-07 16:22:45 -0800634 select {
635 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700636 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800637 case dep := <-depsCh:
638 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700639 case file := <-fileCh:
640 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800641 case blueprint := <-blueprintsCh:
642 if tooManyErrors {
643 continue
644 }
645 if blueprintsSet[blueprint.string] {
646 continue
647 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700648
Colin Cross7ad621c2015-01-07 16:22:45 -0800649 blueprintsSet[blueprint.string] = true
650 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
651 case <-doneCh:
652 count--
653 if count == 0 {
654 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700655 }
656 }
657 }
658
Colin Cross7ad621c2015-01-07 16:22:45 -0800659 return
660}
661
662// parseBlueprintFile parses a single Blueprints file, returning any errors through
663// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
664// blueprintsCh, and any dependencies on Blueprints files or directories through
665// depsCh.
666func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700667 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800668 depsCh chan<- string) {
669
Colin Cross23d7aa12015-06-30 16:05:22 -0700670 f, err := os.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800671 if err != nil {
672 errsCh <- []error{err}
673 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700674 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700675 defer func() {
676 err = f.Close()
677 if err != nil {
678 errsCh <- []error{err}
679 }
680 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700681
Colin Cross23d7aa12015-06-30 16:05:22 -0700682 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800683 if len(errs) > 0 {
684 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700685 } else {
686 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800687 }
688
Colin Cross1fef5362015-04-20 16:50:54 -0700689 for _, b := range subBlueprints {
690 blueprintsCh <- b
691 }
692
693 for _, d := range deps {
694 depsCh <- d
695 }
Colin Cross1fef5362015-04-20 16:50:54 -0700696}
697
Colin Cross29394222015-04-27 13:18:21 -0700698func (c *Context) findSubdirBlueprints(dir string, subdirs, build []string, subBlueprintsName string,
Colin Cross1fef5362015-04-20 16:50:54 -0700699 subdirsPos, buildPos scanner.Position) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800700
701 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700702 globPattern := filepath.Join(dir, subdir)
703 matches, matchedDirs, err := pathtools.Glob(globPattern)
704 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700705 errs = append(errs, &Error{
706 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
707 Pos: subdirsPos,
708 })
709 continue
710 }
711
712 if len(matches) == 0 {
713 errs = append(errs, &Error{
714 Err: fmt.Errorf("%q: not found", globPattern),
715 Pos: subdirsPos,
716 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700717 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800718
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700719 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700720 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800721
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700722 for _, foundSubdir := range matches {
723 fileInfo, subdirStatErr := os.Stat(foundSubdir)
724 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700725 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700726 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800727 }
728
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700729 // Skip files
730 if !fileInfo.IsDir() {
731 continue
732 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800733
Colin Cross29394222015-04-27 13:18:21 -0700734 var subBlueprints string
735 if subBlueprintsName != "" {
736 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
737 _, err = os.Stat(subBlueprints)
738 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700739
Colin Cross29394222015-04-27 13:18:21 -0700740 if os.IsNotExist(err) || subBlueprints == "" {
741 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
742 _, err = os.Stat(subBlueprints)
743 }
744
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700745 if os.IsNotExist(err) {
746 // There is no Blueprints file in this subdirectory. We
747 // need to add the directory to the list of dependencies
748 // so that if someone adds a Blueprints file in the
749 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700750 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700751 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700752 deps = append(deps, subBlueprints)
753 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800754 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800755 }
756 }
Colin Cross1fef5362015-04-20 16:50:54 -0700757
758 for _, file := range build {
759 globPattern := filepath.Join(dir, file)
760 matches, matchedDirs, err := pathtools.Glob(globPattern)
761 if err != nil {
762 errs = append(errs, &Error{
763 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
764 Pos: buildPos,
765 })
766 continue
767 }
768
769 if len(matches) == 0 {
770 errs = append(errs, &Error{
771 Err: fmt.Errorf("%q: not found", globPattern),
772 Pos: buildPos,
773 })
774 }
775
776 // Depend on all searched directories so we pick up future changes.
777 deps = append(deps, matchedDirs...)
778
779 for _, foundBlueprints := range matches {
780 fileInfo, err := os.Stat(foundBlueprints)
781 if os.IsNotExist(err) {
782 errs = append(errs, &Error{
783 Err: fmt.Errorf("%q not found", foundBlueprints),
784 })
785 continue
786 }
787
788 if fileInfo.IsDir() {
789 errs = append(errs, &Error{
790 Err: fmt.Errorf("%q is a directory", foundBlueprints),
791 })
792 continue
793 }
794
795 blueprints = append(blueprints, foundBlueprints)
796 }
797 }
798
799 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700800}
801
Colin Cross1fef5362015-04-20 16:50:54 -0700802func getStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
803 if assignment, err := scope.Get(v); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700804 switch assignment.Value.Type {
805 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700806 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700807
808 for _, value := range assignment.Value.ListValue {
809 if value.Type != parser.String {
810 // The parser should not produce this.
811 panic("non-string value found in list")
812 }
813
Colin Cross1fef5362015-04-20 16:50:54 -0700814 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700815 }
816
Colin Cross1fef5362015-04-20 16:50:54 -0700817 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700818 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700819 return nil, scanner.Position{}, &Error{
820 Err: fmt.Errorf("%q must be a list of strings", v),
821 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700822 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700823 default:
824 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
825 }
826 }
827
Colin Cross1fef5362015-04-20 16:50:54 -0700828 return nil, scanner.Position{}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700829}
830
Colin Cross29394222015-04-27 13:18:21 -0700831func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
832 if assignment, err := scope.Get(v); err == nil {
833 switch assignment.Value.Type {
834 case parser.String:
835 return assignment.Value.StringValue, assignment.Pos, nil
836 case parser.Bool, parser.List:
837 return "", scanner.Position{}, &Error{
838 Err: fmt.Errorf("%q must be a string", v),
839 Pos: assignment.Pos,
840 }
841 default:
842 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
843 }
844 }
845
846 return "", scanner.Position{}, nil
847}
848
Colin Crossf5e34b92015-03-13 16:02:36 -0700849func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
850 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800851
Colin Crossf4d18a62015-03-18 17:43:15 -0700852 if len(variationNames) == 0 {
853 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400854 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700855 }
856
Colin Crossc9028482014-12-18 16:28:54 -0800857 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800858
Colin Cross174ae052015-03-03 17:37:03 -0800859 var errs []error
860
Colin Crossf5e34b92015-03-13 16:02:36 -0700861 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700862 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800863 factory, ok := c.moduleFactories[typeName]
864 if !ok {
865 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
866 }
867
868 var newLogicModule Module
869 var newProperties []interface{}
870
871 if i == 0 {
872 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700873 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
874 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800875 newLogicModule = origModule.logicModule
876 newProperties = origModule.moduleProperties
877 } else {
878 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700879 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800880 }
881 newLogicModule, newProperties = factory()
882
883 newProperties = append(props, newProperties...)
884
885 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700886 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800887 }
888
889 for i := range newProperties {
890 dst := reflect.ValueOf(newProperties[i]).Elem()
891 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
892
893 proptools.CopyProperties(dst, src)
894 }
895 }
896
Colin Crossf5e34b92015-03-13 16:02:36 -0700897 newVariant := origModule.variant.clone()
898 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800899
Colin Crossed342d92015-03-11 00:57:25 -0700900 m := *origModule
901 newModule := &m
902 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
903 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700904 newModule.variant = newVariant
905 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700906 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800907
Colin Crosse7daa222015-03-11 14:35:41 -0700908 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700909 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700910 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700911 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700912 }
913
Colin Crossc9028482014-12-18 16:28:54 -0800914 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700915
916 // Insert the new variant into the global module map. If this is the first variant then
917 // it reuses logicModule from the original module, which causes this to replace the
918 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800919 c.moduleInfo[newModule.logicModule] = newModule
920
Colin Crossf5e34b92015-03-13 16:02:36 -0700921 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800922 if len(newErrs) > 0 {
923 errs = append(errs, newErrs...)
924 }
Colin Crossc9028482014-12-18 16:28:54 -0800925 }
926
927 // Mark original variant as invalid. Modules that depend on this module will still
928 // depend on origModule, but we'll fix it when the mutator is called on them.
929 origModule.logicModule = nil
930 origModule.splitModules = newModules
931
Colin Cross174ae052015-03-03 17:37:03 -0800932 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800933}
934
Colin Crossf5e34b92015-03-13 16:02:36 -0700935func (c *Context) convertDepsToVariation(module *moduleInfo,
936 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800937
Colin Crossc9028482014-12-18 16:28:54 -0800938 for i, dep := range module.directDeps {
939 if dep.logicModule == nil {
940 var newDep *moduleInfo
941 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700942 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800943 newDep = m
944 break
945 }
946 }
947 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800948 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700949 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
950 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700951 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800952 })
953 continue
Colin Crossc9028482014-12-18 16:28:54 -0800954 }
955 module.directDeps[i] = newDep
956 }
957 }
Colin Cross174ae052015-03-03 17:37:03 -0800958
959 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800960}
961
Colin Crossf5e34b92015-03-13 16:02:36 -0700962func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700963 names := make([]string, 0, len(variant))
964 for _, m := range c.variantMutatorNames {
965 if v, ok := variant[m]; ok {
966 names = append(names, m+":"+v)
967 }
968 }
969
970 return strings.Join(names, ", ")
971}
972
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700973func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800974 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700975
Colin Crossd1facc12015-01-08 14:56:03 -0800976 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700977 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700978 if !ok {
979 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800980 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700981 }
982
Colin Cross7ad621c2015-01-07 16:22:45 -0800983 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700984 &Error{
985 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800986 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700987 },
988 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700989 }
990
Colin Crossbbfa51a2014-12-17 16:12:41 -0800991 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700992
993 module := &moduleInfo{
994 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700995 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700996 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700997 }
998
Jamie Gennis87622922014-09-30 11:38:25 -0700999 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001000 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001001 }
1002 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001003 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001004
Jamie Gennis87622922014-09-30 11:38:25 -07001005 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001006 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001007 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001008 }
1009
Colin Crossed342d92015-03-11 00:57:25 -07001010 module.pos = moduleDef.Type.Pos
1011 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001012 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -07001013 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001014 }
1015
Colin Cross7ad621c2015-01-07 16:22:45 -08001016 return module, nil
1017}
1018
Colin Cross23d7aa12015-06-30 16:05:22 -07001019func (c *Context) addModule(module *moduleInfo) []error {
1020 name := module.properties.Name
1021 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001022
Colin Cross23d7aa12015-06-30 16:05:22 -07001023 if group, present := c.moduleGroups[name]; present {
1024 return []error{
1025 &Error{
1026 Err: fmt.Errorf("module %q already defined", name),
1027 Pos: module.pos,
1028 },
1029 &Error{
1030 Err: fmt.Errorf("<-- previous definition here"),
1031 Pos: group.modules[0].pos,
1032 },
Colin Crossed342d92015-03-11 00:57:25 -07001033 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001034 } else {
1035 ninjaName := toNinjaName(module.properties.Name)
1036
1037 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1038 // already exists
1039 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1040 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1041 }
1042
1043 group := &moduleGroup{
1044 name: module.properties.Name,
1045 ninjaName: ninjaName,
1046 modules: []*moduleInfo{module},
1047 }
1048 module.group = group
1049 c.moduleGroups[name] = group
1050 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001051 }
1052
Colin Cross23d7aa12015-06-30 16:05:22 -07001053 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001054}
1055
Jamie Gennisd4e10182014-06-12 20:06:50 -07001056// ResolveDependencies checks that the dependencies specified by all of the
1057// modules defined in the parsed Blueprints files are valid. This means that
1058// the modules depended upon are defined and that no circular dependencies
1059// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001060//
1061// The config argument is made available to all of the DynamicDependerModule
1062// objects via the Config method on the DynamicDependerModuleContext objects
1063// passed to their DynamicDependencies method.
1064func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross4572edd2015-05-13 14:36:24 -07001065 errs := c.runEarlyMutators(config)
1066 if len(errs) > 0 {
1067 return errs
1068 }
1069
1070 errs = c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001071 if len(errs) > 0 {
1072 return errs
1073 }
1074
Colin Cross691a60d2015-01-07 18:08:56 -08001075 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001076 if len(errs) > 0 {
1077 return errs
1078 }
1079
1080 c.dependenciesReady = true
1081 return nil
1082}
1083
Colin Cross65569e42015-03-10 20:08:19 -07001084// moduleDeps adds dependencies to a module. If the module implements the
1085// DynamicDependerModule interface then this set consists of the union of those
1086// module names listed in its "deps" property, those returned by its
1087// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001088// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001089// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -07001090func (c *Context) moduleDeps(module *moduleInfo,
1091 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001092
1093 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -08001094 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001095
Colin Crossed342d92015-03-11 00:57:25 -07001096 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001097 if !depNamesSet[depName] {
1098 depNamesSet[depName] = true
1099 depNames = append(depNames, depName)
1100 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001101 }
1102
Colin Cross65569e42015-03-10 20:08:19 -07001103 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001104 if ok {
Colin Cross65569e42015-03-10 20:08:19 -07001105 ddmctx := &dynamicDependerModuleContext{
1106 baseModuleContext: baseModuleContext{
1107 context: c,
1108 config: config,
1109 module: module,
1110 },
1111 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001112 }
1113
1114 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
1115
1116 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -07001117 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001118 }
1119
1120 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001121 if !depNamesSet[depName] {
1122 depNamesSet[depName] = true
1123 depNames = append(depNames, depName)
1124 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001125 }
1126 }
1127
Colin Cross65569e42015-03-10 20:08:19 -07001128 for _, depName := range depNames {
1129 newErrs := c.addDependency(module, depName)
1130 if len(newErrs) > 0 {
1131 errs = append(errs, newErrs...)
1132 }
1133 }
1134 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001135}
1136
Colin Cross65569e42015-03-10 20:08:19 -07001137// resolveDependencies populates the directDeps list for every module. In doing so it checks for
1138// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001139func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001140 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -07001141 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -07001142 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1143
1144 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001145 if len(newErrs) > 0 {
1146 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001147 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001148 }
1149 }
1150
1151 return
1152}
1153
Colin Crossc9028482014-12-18 16:28:54 -08001154func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001155 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001156
Colin Crossed342d92015-03-11 00:57:25 -07001157 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001158 return []error{&Error{
1159 Err: fmt.Errorf("%q depends on itself", depName),
1160 Pos: depsPos,
1161 }}
1162 }
1163
1164 depInfo, ok := c.moduleGroups[depName]
1165 if !ok {
1166 return []error{&Error{
1167 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001168 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001169 Pos: depsPos,
1170 }}
1171 }
1172
Colin Cross65569e42015-03-10 20:08:19 -07001173 for _, m := range module.directDeps {
1174 if m.group == depInfo {
1175 return nil
1176 }
Colin Crossc9028482014-12-18 16:28:54 -08001177 }
1178
Colin Cross65569e42015-03-10 20:08:19 -07001179 if len(depInfo.modules) == 1 {
1180 module.directDeps = append(module.directDeps, depInfo.modules[0])
1181 return nil
1182 } else {
1183 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001184 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001185 module.directDeps = append(module.directDeps, m)
1186 return nil
1187 }
1188 }
1189 }
Colin Crossc9028482014-12-18 16:28:54 -08001190
Colin Cross65569e42015-03-10 20:08:19 -07001191 return []error{&Error{
1192 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1193 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001194 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001195 Pos: depsPos,
1196 }}
1197}
1198
Colin Crossf5e34b92015-03-13 16:02:36 -07001199func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross89486232015-05-08 11:14:54 -07001200 depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001201
1202 depsPos := module.propertyPos["deps"]
1203
1204 depInfo, ok := c.moduleGroups[depName]
1205 if !ok {
1206 return []error{&Error{
1207 Err: fmt.Errorf("%q depends on undefined module %q",
1208 module.properties.Name, depName),
1209 Pos: depsPos,
1210 }}
1211 }
1212
1213 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1214 // compare the strings because the result won't be in mutator registration order.
1215 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001216 var newVariant variationMap
1217 if !far {
1218 newVariant = module.dependencyVariant.clone()
1219 } else {
1220 newVariant = make(variationMap)
1221 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001222 for _, v := range variations {
1223 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001224 }
1225
1226 for _, m := range depInfo.modules {
Colin Cross89486232015-05-08 11:14:54 -07001227 var found bool
1228 if far {
1229 found = m.variant.subset(newVariant)
1230 } else {
1231 found = m.variant.equal(newVariant)
1232 }
1233 if found {
Colin Crossf5e34b92015-03-13 16:02:36 -07001234 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001235 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001236 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001237 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1238 return []error{&Error{
1239 Err: fmt.Errorf("%q depends on later version of itself", depName),
1240 Pos: depsPos,
1241 }}
1242 }
1243 module.directDeps = append(module.directDeps, m)
1244 return nil
1245 }
1246 }
1247
1248 return []error{&Error{
1249 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1250 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001251 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001252 Pos: depsPos,
1253 }}
Colin Crossc9028482014-12-18 16:28:54 -08001254}
1255
Colin Cross7addea32015-03-11 15:43:52 -07001256func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1257 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001258 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001259 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001260
Colin Cross7addea32015-03-11 15:43:52 -07001261 for _, module := range c.modulesSorted {
1262 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001263 }
1264
Colin Cross7addea32015-03-11 15:43:52 -07001265 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001266 count++
1267 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001268 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001269 if ret {
1270 cancel = true
1271 }
Colin Cross7addea32015-03-11 15:43:52 -07001272 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001273 }()
1274 }
1275
Colin Cross7addea32015-03-11 15:43:52 -07001276 for _, module := range c.modulesSorted {
1277 if module.waitingCount == 0 {
1278 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001279 }
1280 }
1281
Colin Cross11e3b0d2015-02-04 10:41:00 -08001282 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001283 select {
Colin Cross7addea32015-03-11 15:43:52 -07001284 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001285 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001286 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001287 parent.waitingCount--
1288 if parent.waitingCount == 0 {
1289 visitOne(parent)
1290 }
Colin Cross691a60d2015-01-07 18:08:56 -08001291 }
1292 }
1293 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001294 }
1295 }
1296}
1297
1298// updateDependencies recursively walks the module dependency graph and updates
1299// additional fields based on the dependencies. It builds a sorted list of modules
1300// such that dependencies of a module always appear first, and populates reverse
1301// dependency links and counts of total dependencies. It also reports errors when
1302// it encounters dependency cycles. This should called after resolveDependencies,
1303// as well as after any mutator pass has called addDependency
1304func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001305 visited := make(map[*moduleInfo]bool) // modules that were already checked
1306 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001307
Colin Cross7addea32015-03-11 15:43:52 -07001308 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001309
Colin Cross7addea32015-03-11 15:43:52 -07001310 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001311
Colin Cross7addea32015-03-11 15:43:52 -07001312 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001313 // We are the "start" of the cycle, so we're responsible
1314 // for generating the errors. The cycle list is in
1315 // reverse order because all the 'check' calls append
1316 // their own module to the list.
1317 errs = append(errs, &Error{
1318 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001319 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001320 })
1321
1322 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001323 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001324 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001325 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001326 errs = append(errs, &Error{
1327 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001328 curModule.properties.Name,
1329 nextModule.properties.Name),
1330 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001331 })
Colin Cross7addea32015-03-11 15:43:52 -07001332 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001333 }
1334 }
1335
Colin Cross7addea32015-03-11 15:43:52 -07001336 check = func(module *moduleInfo) []*moduleInfo {
1337 visited[module] = true
1338 checking[module] = true
1339 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001340
Colin Cross7addea32015-03-11 15:43:52 -07001341 deps := make(map[*moduleInfo]bool)
1342
1343 // Add an implicit dependency ordering on all earlier modules in the same module group
1344 for _, dep := range module.group.modules {
1345 if dep == module {
1346 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001347 }
Colin Cross7addea32015-03-11 15:43:52 -07001348 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001349 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001350
Colin Cross7addea32015-03-11 15:43:52 -07001351 for _, dep := range module.directDeps {
1352 deps[dep] = true
1353 }
1354
1355 module.reverseDeps = []*moduleInfo{}
1356 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001357
Colin Crossbbfa51a2014-12-17 16:12:41 -08001358 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001359 if checking[dep] {
1360 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001361 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001362 }
1363
1364 if !visited[dep] {
1365 cycle := check(dep)
1366 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001367 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001368 // We are the "start" of the cycle, so we're responsible
1369 // for generating the errors. The cycle list is in
1370 // reverse order because all the 'check' calls append
1371 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001372 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001373
1374 // We can continue processing this module's children to
1375 // find more cycles. Since all the modules that were
1376 // part of the found cycle were marked as visited we
1377 // won't run into that cycle again.
1378 } else {
1379 // We're not the "start" of the cycle, so we just append
1380 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001381 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001382 }
1383 }
1384 }
Colin Cross691a60d2015-01-07 18:08:56 -08001385
Colin Cross7addea32015-03-11 15:43:52 -07001386 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001387 }
1388
Colin Cross7addea32015-03-11 15:43:52 -07001389 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001390
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391 return nil
1392 }
1393
Colin Cross7addea32015-03-11 15:43:52 -07001394 for _, module := range c.moduleInfo {
1395 if !visited[module] {
1396 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001397 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001398 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001399 panic("inconceivable!")
1400 }
1401 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001402 }
1403 }
1404 }
1405
Colin Cross7addea32015-03-11 15:43:52 -07001406 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001407
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001408 return
1409}
1410
Jamie Gennisd4e10182014-06-12 20:06:50 -07001411// PrepareBuildActions generates an internal representation of all the build
1412// actions that need to be performed. This process involves invoking the
1413// GenerateBuildActions method on each of the Module objects created during the
1414// parse phase and then on each of the registered Singleton objects.
1415//
1416// If the ResolveDependencies method has not already been called it is called
1417// automatically by this method.
1418//
1419// The config argument is made available to all of the Module and Singleton
1420// objects via the Config method on the ModuleContext and SingletonContext
1421// objects passed to GenerateBuildActions. It is also passed to the functions
1422// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1423// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001424//
1425// The returned deps is a list of the ninja files dependencies that were added
1426// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1427// SingletonContext.AddNinjaFileDeps() methods.
1428func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001429 c.buildActionsReady = false
1430
1431 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001432 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001433 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001434 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001435 }
1436 }
1437
Colin Crossc9028482014-12-18 16:28:54 -08001438 errs = c.runMutators(config)
1439 if len(errs) > 0 {
1440 return nil, errs
1441 }
1442
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001443 liveGlobals := newLiveTracker(config)
1444
1445 c.initSpecialVariables()
1446
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001447 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001448 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001449 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001450 }
1451
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001452 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001453 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001454 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001455 }
1456
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001457 deps = append(depsModules, depsSingletons...)
1458
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459 if c.buildDir != nil {
1460 liveGlobals.addNinjaStringDeps(c.buildDir)
1461 }
1462
1463 pkgNames := c.makeUniquePackageNames(liveGlobals)
1464
1465 // This will panic if it finds a problem since it's a programming error.
1466 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1467
1468 c.pkgNames = pkgNames
1469 c.globalVariables = liveGlobals.variables
1470 c.globalPools = liveGlobals.pools
1471 c.globalRules = liveGlobals.rules
1472
1473 c.buildActionsReady = true
1474
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001475 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001476}
1477
Colin Cross65569e42015-03-10 20:08:19 -07001478func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1479 for _, mutator := range c.earlyMutatorInfo {
1480 for _, group := range c.moduleGroups {
1481 newModules := make([]*moduleInfo, 0, len(group.modules))
1482
1483 for _, module := range group.modules {
1484 mctx := &mutatorContext{
1485 baseModuleContext: baseModuleContext{
1486 context: c,
1487 config: config,
1488 module: module,
1489 },
1490 name: mutator.name,
1491 }
1492 mutator.mutator(mctx)
1493 if len(mctx.errs) > 0 {
1494 errs = append(errs, mctx.errs...)
1495 return errs
1496 }
1497
1498 if module.splitModules != nil {
1499 newModules = append(newModules, module.splitModules...)
1500 } else {
1501 newModules = append(newModules, module)
1502 }
1503 }
1504
1505 group.modules = newModules
1506 }
1507 }
1508
1509 return nil
1510}
1511
Colin Crossc9028482014-12-18 16:28:54 -08001512func (c *Context) runMutators(config interface{}) (errs []error) {
1513 for _, mutator := range c.mutatorInfo {
1514 if mutator.topDownMutator != nil {
1515 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1516 } else if mutator.bottomUpMutator != nil {
1517 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1518 } else {
1519 panic("no mutator set on " + mutator.name)
1520 }
1521 if len(errs) > 0 {
1522 return errs
1523 }
1524 }
1525
1526 return nil
1527}
1528
1529func (c *Context) runTopDownMutator(config interface{},
1530 name string, mutator TopDownMutator) (errs []error) {
1531
Colin Cross7addea32015-03-11 15:43:52 -07001532 for i := 0; i < len(c.modulesSorted); i++ {
1533 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1534 mctx := &mutatorContext{
1535 baseModuleContext: baseModuleContext{
1536 context: c,
1537 config: config,
1538 module: module,
1539 },
1540 name: name,
1541 }
Colin Crossc9028482014-12-18 16:28:54 -08001542
Colin Cross7addea32015-03-11 15:43:52 -07001543 mutator(mctx)
1544 if len(mctx.errs) > 0 {
1545 errs = append(errs, mctx.errs...)
1546 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001547 }
1548 }
1549
1550 return errs
1551}
1552
1553func (c *Context) runBottomUpMutator(config interface{},
1554 name string, mutator BottomUpMutator) (errs []error) {
1555
Colin Cross7addea32015-03-11 15:43:52 -07001556 for _, module := range c.modulesSorted {
1557 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001558
Jamie Gennisc7988252015-04-14 23:28:10 -04001559 if module.splitModules != nil {
1560 panic("split module found in sorted module list")
1561 }
1562
Colin Cross7addea32015-03-11 15:43:52 -07001563 mctx := &mutatorContext{
1564 baseModuleContext: baseModuleContext{
1565 context: c,
1566 config: config,
1567 module: module,
1568 },
1569 name: name,
1570 }
Colin Crossc9028482014-12-18 16:28:54 -08001571
Colin Cross7addea32015-03-11 15:43:52 -07001572 mutator(mctx)
1573 if len(mctx.errs) > 0 {
1574 errs = append(errs, mctx.errs...)
1575 return errs
1576 }
Colin Crossc9028482014-12-18 16:28:54 -08001577
Colin Cross7addea32015-03-11 15:43:52 -07001578 // Fix up any remaining dependencies on modules that were split into variants
1579 // by replacing them with the first variant
1580 for i, dep := range module.directDeps {
1581 if dep.logicModule == nil {
1582 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001583 }
1584 }
1585
Colin Cross7addea32015-03-11 15:43:52 -07001586 if module.splitModules != nil {
1587 newModules = append(newModules, module.splitModules...)
1588 } else {
1589 newModules = append(newModules, module)
1590 }
1591
1592 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001593 }
1594
Jamie Gennisc7988252015-04-14 23:28:10 -04001595 errs = c.updateDependencies()
1596 if len(errs) > 0 {
1597 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001598 }
1599
1600 return errs
1601}
1602
Colin Cross7addea32015-03-11 15:43:52 -07001603func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1604 newModules []*moduleInfo) []*moduleInfo {
1605 for i, m := range modules {
1606 if m == origModule {
1607 return spliceModulesAtIndex(modules, i, newModules)
1608 }
1609 }
1610
1611 panic("failed to find original module to splice")
1612}
1613
1614func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1615 spliceSize := len(newModules)
1616 newLen := len(modules) + spliceSize - 1
1617 var dest []*moduleInfo
1618 if cap(modules) >= len(modules)-1+len(newModules) {
1619 // We can fit the splice in the existing capacity, do everything in place
1620 dest = modules[:newLen]
1621 } else {
1622 dest = make([]*moduleInfo, newLen)
1623 copy(dest, modules[:i])
1624 }
1625
1626 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001627 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001628
1629 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001630 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001631
Colin Cross72bd1932015-03-16 00:13:59 -07001632 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001633}
1634
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635func (c *Context) initSpecialVariables() {
1636 c.buildDir = nil
1637 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001638 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001639 c.requiredNinjaMicro = 0
1640}
1641
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001642func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001643 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001644
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001645 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001646 var errs []error
1647
Colin Cross691a60d2015-01-07 18:08:56 -08001648 cancelCh := make(chan struct{})
1649 errsCh := make(chan []error)
1650 depsCh := make(chan []string)
1651
1652 go func() {
1653 for {
1654 select {
1655 case <-cancelCh:
1656 close(cancelCh)
1657 return
1658 case newErrs := <-errsCh:
1659 errs = append(errs, newErrs...)
1660 case newDeps := <-depsCh:
1661 deps = append(deps, newDeps...)
1662
1663 }
1664 }
1665 }()
1666
Colin Cross7addea32015-03-11 15:43:52 -07001667 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1668 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1669 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1670 // just set it to nil.
1671 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1672 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001673
Colin Cross7addea32015-03-11 15:43:52 -07001674 mctx := &moduleContext{
1675 baseModuleContext: baseModuleContext{
1676 context: c,
1677 config: config,
1678 module: module,
1679 },
1680 scope: scope,
1681 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001682
Colin Cross7addea32015-03-11 15:43:52 -07001683 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001684
Colin Cross7addea32015-03-11 15:43:52 -07001685 if len(mctx.errs) > 0 {
1686 errsCh <- mctx.errs
1687 return true
1688 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001689
Colin Cross7addea32015-03-11 15:43:52 -07001690 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001691
Colin Crossab6d7902015-03-11 16:17:52 -07001692 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001693 &mctx.actionDefs, liveGlobals)
1694 if len(newErrs) > 0 {
1695 errsCh <- newErrs
1696 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001697 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001698 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001699 })
1700
1701 cancelCh <- struct{}{}
1702 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001703
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001704 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001705}
1706
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001707func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001708 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001709
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001710 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001711 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001712
Yuchen Wub9103ef2015-08-25 17:58:17 -07001713 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001714 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1715 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1716 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001717 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001718
1719 sctx := &singletonContext{
1720 context: c,
1721 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001722 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001723 }
1724
1725 info.singleton.GenerateBuildActions(sctx)
1726
1727 if len(sctx.errs) > 0 {
1728 errs = append(errs, sctx.errs...)
1729 if len(errs) > maxErrors {
1730 break
1731 }
1732 continue
1733 }
1734
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001735 deps = append(deps, sctx.ninjaFileDeps...)
1736
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001737 newErrs := c.processLocalBuildActions(&info.actionDefs,
1738 &sctx.actionDefs, liveGlobals)
1739 errs = append(errs, newErrs...)
1740 if len(errs) > maxErrors {
1741 break
1742 }
1743 }
1744
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001745 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001746}
1747
1748func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1749 liveGlobals *liveTracker) []error {
1750
1751 var errs []error
1752
1753 // First we go through and add everything referenced by the module's
1754 // buildDefs to the live globals set. This will end up adding the live
1755 // locals to the set as well, but we'll take them out after.
1756 for _, def := range in.buildDefs {
1757 err := liveGlobals.AddBuildDefDeps(def)
1758 if err != nil {
1759 errs = append(errs, err)
1760 }
1761 }
1762
1763 if len(errs) > 0 {
1764 return errs
1765 }
1766
Colin Crossc9028482014-12-18 16:28:54 -08001767 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001768
1769 // We use the now-incorrect set of live "globals" to determine which local
1770 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001771 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001772 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001773 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001774 if isLive {
1775 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001776 }
1777 }
1778
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001779 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001780 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001781 if isLive {
1782 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001783 }
1784 }
1785
1786 return nil
1787}
1788
Colin Crossbbfa51a2014-12-17 16:12:41 -08001789func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1790 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001791
Colin Crossbbfa51a2014-12-17 16:12:41 -08001792 var walk func(module *moduleInfo)
1793 walk = func(module *moduleInfo) {
1794 visited[module] = true
1795 for _, moduleDep := range module.directDeps {
1796 if !visited[moduleDep] {
1797 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 }
1799 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001800
Colin Crossbbfa51a2014-12-17 16:12:41 -08001801 if module != topModule {
1802 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001803 }
1804 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001805
1806 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001807}
1808
Colin Crossbbfa51a2014-12-17 16:12:41 -08001809func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001810 visit func(Module)) {
1811
Colin Crossbbfa51a2014-12-17 16:12:41 -08001812 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001813
Colin Crossbbfa51a2014-12-17 16:12:41 -08001814 var walk func(module *moduleInfo)
1815 walk = func(module *moduleInfo) {
1816 visited[module] = true
1817 for _, moduleDep := range module.directDeps {
1818 if !visited[moduleDep] {
1819 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001820 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001821 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001822
1823 if module != topModule {
1824 if pred(module.logicModule) {
1825 visit(module.logicModule)
1826 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001827 }
1828 }
1829
Colin Crossbbfa51a2014-12-17 16:12:41 -08001830 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001831}
1832
Colin Crossc9028482014-12-18 16:28:54 -08001833func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1834 for _, dep := range module.directDeps {
1835 visit(dep.logicModule)
1836 }
1837}
1838
1839func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1840 visit func(Module)) {
1841
1842 for _, dep := range module.directDeps {
1843 if pred(dep.logicModule) {
1844 visit(dep.logicModule)
1845 }
1846 }
1847}
1848
Jamie Gennisc15544d2014-09-24 20:26:52 -07001849func (c *Context) sortedModuleNames() []string {
1850 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001851 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1852 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001853 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1854 moduleName)
1855 }
1856 sort.Strings(c.cachedSortedModuleNames)
1857 }
1858
1859 return c.cachedSortedModuleNames
1860}
1861
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001862func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001863 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001864 group := c.moduleGroups[moduleName]
1865 for _, module := range group.modules {
1866 visit(module.logicModule)
1867 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001868 }
1869}
1870
1871func (c *Context) visitAllModulesIf(pred func(Module) bool,
1872 visit func(Module)) {
1873
Jamie Gennisc15544d2014-09-24 20:26:52 -07001874 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001875 group := c.moduleGroups[moduleName]
1876 for _, module := range group.modules {
1877 if pred(module.logicModule) {
1878 visit(module.logicModule)
1879 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001880 }
1881 }
1882}
1883
1884func (c *Context) requireNinjaVersion(major, minor, micro int) {
1885 if major != 1 {
1886 panic("ninja version with major version != 1 not supported")
1887 }
1888 if c.requiredNinjaMinor < minor {
1889 c.requiredNinjaMinor = minor
1890 c.requiredNinjaMicro = micro
1891 }
1892 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1893 c.requiredNinjaMicro = micro
1894 }
1895}
1896
1897func (c *Context) setBuildDir(value *ninjaString) {
1898 if c.buildDir != nil {
1899 panic("buildDir set multiple times")
1900 }
1901 c.buildDir = value
1902}
1903
1904func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001905 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001906
Jamie Gennis2fb20952014-10-03 02:49:58 -07001907 pkgs := make(map[string]*PackageContext)
1908 pkgNames := make(map[*PackageContext]string)
1909 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001910
Jamie Gennis2fb20952014-10-03 02:49:58 -07001911 processPackage := func(pctx *PackageContext) {
1912 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001913 // This is a built-in rule and has no package.
1914 return
1915 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001916 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001917 // We've already processed this package.
1918 return
1919 }
1920
Jamie Gennis2fb20952014-10-03 02:49:58 -07001921 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001922 if present {
1923 // Short name collision. Both this package and the one that's
1924 // already there need to use their full names. We leave the short
1925 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001926 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927 longPkgNames[otherPkg] = true
1928 } else {
1929 // No collision so far. Tentatively set the package's name to be
1930 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001931 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07001932 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001933 }
1934 }
1935
1936 // We try to give all packages their short name, but when we get collisions
1937 // we need to use the full unique package name.
1938 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001939 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001940 }
1941 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001942 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001943 }
1944 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001945 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001946 }
1947
1948 // Add the packages that had collisions using their full unique names. This
1949 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001950 for pctx := range longPkgNames {
1951 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001952 }
1953
1954 return pkgNames
1955}
1956
1957func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001958 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001959
1960 visited := make(map[Variable]bool) // variables that were already checked
1961 checking := make(map[Variable]bool) // variables actively being checked
1962
1963 var check func(v Variable) []Variable
1964
1965 check = func(v Variable) []Variable {
1966 visited[v] = true
1967 checking[v] = true
1968 defer delete(checking, v)
1969
1970 value := variables[v]
1971 for _, dep := range value.variables {
1972 if checking[dep] {
1973 // This is a cycle.
1974 return []Variable{dep, v}
1975 }
1976
1977 if !visited[dep] {
1978 cycle := check(dep)
1979 if cycle != nil {
1980 if cycle[0] == v {
1981 // We are the "start" of the cycle, so we're responsible
1982 // for generating the errors. The cycle list is in
1983 // reverse order because all the 'check' calls append
1984 // their own module to the list.
1985 msgs := []string{"detected variable reference cycle:"}
1986
1987 // Iterate backwards through the cycle list.
1988 curName := v.fullName(pkgNames)
1989 curValue := value.Value(pkgNames)
1990 for i := len(cycle) - 1; i >= 0; i-- {
1991 next := cycle[i]
1992 nextName := next.fullName(pkgNames)
1993 nextValue := variables[next].Value(pkgNames)
1994
1995 msgs = append(msgs, fmt.Sprintf(
1996 " %q depends on %q", curName, nextName))
1997 msgs = append(msgs, fmt.Sprintf(
1998 " [%s = %s]", curName, curValue))
1999
2000 curName = nextName
2001 curValue = nextValue
2002 }
2003
2004 // Variable reference cycles are a programming error,
2005 // not the fault of the Blueprint file authors.
2006 panic(strings.Join(msgs, "\n"))
2007 } else {
2008 // We're not the "start" of the cycle, so we just append
2009 // our module to the list and return it.
2010 return append(cycle, v)
2011 }
2012 }
2013 }
2014 }
2015
2016 return nil
2017 }
2018
2019 for v := range variables {
2020 if !visited[v] {
2021 cycle := check(v)
2022 if cycle != nil {
2023 panic("inconceivable!")
2024 }
2025 }
2026 }
2027}
2028
Jamie Gennisaf435562014-10-27 22:34:56 -07002029// AllTargets returns a map all the build target names to the rule used to build
2030// them. This is the same information that is output by running 'ninja -t
2031// targets all'. If this is called before PrepareBuildActions successfully
2032// completes then ErrbuildActionsNotReady is returned.
2033func (c *Context) AllTargets() (map[string]string, error) {
2034 if !c.buildActionsReady {
2035 return nil, ErrBuildActionsNotReady
2036 }
2037
2038 targets := map[string]string{}
2039
2040 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002041 for _, module := range c.moduleInfo {
2042 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002043 ruleName := buildDef.Rule.fullName(c.pkgNames)
2044 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002045 outputValue, err := output.Eval(c.globalVariables)
2046 if err != nil {
2047 return nil, err
2048 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002049 targets[outputValue] = ruleName
2050 }
2051 }
2052 }
2053
2054 // Collect all the singleton build targets.
2055 for _, info := range c.singletonInfo {
2056 for _, buildDef := range info.actionDefs.buildDefs {
2057 ruleName := buildDef.Rule.fullName(c.pkgNames)
2058 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002059 outputValue, err := output.Eval(c.globalVariables)
2060 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002061 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002062 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002063 targets[outputValue] = ruleName
2064 }
2065 }
2066 }
2067
2068 return targets, nil
2069}
2070
Colin Cross4572edd2015-05-13 14:36:24 -07002071// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2072// property structs returned by the factory for that module type.
2073func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2074 ret := make(map[string][]interface{})
2075 for moduleType, factory := range c.moduleFactories {
2076 _, ret[moduleType] = factory()
2077 }
2078
2079 return ret
2080}
2081
2082func (c *Context) ModuleName(logicModule Module) string {
2083 module := c.moduleInfo[logicModule]
2084 return module.properties.Name
2085}
2086
2087func (c *Context) ModuleDir(logicModule Module) string {
2088 module := c.moduleInfo[logicModule]
2089 return filepath.Dir(module.relBlueprintsFile)
2090}
2091
2092func (c *Context) BlueprintFile(logicModule Module) string {
2093 module := c.moduleInfo[logicModule]
2094 return module.relBlueprintsFile
2095}
2096
2097func (c *Context) ModuleErrorf(logicModule Module, format string,
2098 args ...interface{}) error {
2099
2100 module := c.moduleInfo[logicModule]
2101 return &Error{
2102 Err: fmt.Errorf(format, args...),
2103 Pos: module.pos,
2104 }
2105}
2106
2107func (c *Context) VisitAllModules(visit func(Module)) {
2108 c.visitAllModules(visit)
2109}
2110
2111func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2112 visit func(Module)) {
2113
2114 c.visitAllModulesIf(pred, visit)
2115}
2116
2117func (c *Context) VisitDepsDepthFirst(module Module,
2118 visit func(Module)) {
2119
2120 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2121}
2122
2123func (c *Context) VisitDepsDepthFirstIf(module Module,
2124 pred func(Module) bool, visit func(Module)) {
2125
2126 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2127}
2128
Jamie Gennisd4e10182014-06-12 20:06:50 -07002129// WriteBuildFile writes the Ninja manifeset text for the generated build
2130// actions to w. If this is called before PrepareBuildActions successfully
2131// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002132func (c *Context) WriteBuildFile(w io.Writer) error {
2133 if !c.buildActionsReady {
2134 return ErrBuildActionsNotReady
2135 }
2136
2137 nw := newNinjaWriter(w)
2138
2139 err := c.writeBuildFileHeader(nw)
2140 if err != nil {
2141 return err
2142 }
2143
2144 err = c.writeNinjaRequiredVersion(nw)
2145 if err != nil {
2146 return err
2147 }
2148
2149 // TODO: Group the globals by package.
2150
2151 err = c.writeGlobalVariables(nw)
2152 if err != nil {
2153 return err
2154 }
2155
2156 err = c.writeGlobalPools(nw)
2157 if err != nil {
2158 return err
2159 }
2160
2161 err = c.writeBuildDir(nw)
2162 if err != nil {
2163 return err
2164 }
2165
2166 err = c.writeGlobalRules(nw)
2167 if err != nil {
2168 return err
2169 }
2170
2171 err = c.writeAllModuleActions(nw)
2172 if err != nil {
2173 return err
2174 }
2175
2176 err = c.writeAllSingletonActions(nw)
2177 if err != nil {
2178 return err
2179 }
2180
2181 return nil
2182}
2183
Jamie Gennisc15544d2014-09-24 20:26:52 -07002184type pkgAssociation struct {
2185 PkgName string
2186 PkgPath string
2187}
2188
2189type pkgAssociationSorter struct {
2190 pkgs []pkgAssociation
2191}
2192
2193func (s *pkgAssociationSorter) Len() int {
2194 return len(s.pkgs)
2195}
2196
2197func (s *pkgAssociationSorter) Less(i, j int) bool {
2198 iName := s.pkgs[i].PkgName
2199 jName := s.pkgs[j].PkgName
2200 return iName < jName
2201}
2202
2203func (s *pkgAssociationSorter) Swap(i, j int) {
2204 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2205}
2206
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002207func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2208 headerTemplate := template.New("fileHeader")
2209 _, err := headerTemplate.Parse(fileHeaderTemplate)
2210 if err != nil {
2211 // This is a programming error.
2212 panic(err)
2213 }
2214
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002215 var pkgs []pkgAssociation
2216 maxNameLen := 0
2217 for pkg, name := range c.pkgNames {
2218 pkgs = append(pkgs, pkgAssociation{
2219 PkgName: name,
2220 PkgPath: pkg.pkgPath,
2221 })
2222 if len(name) > maxNameLen {
2223 maxNameLen = len(name)
2224 }
2225 }
2226
2227 for i := range pkgs {
2228 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2229 }
2230
Jamie Gennisc15544d2014-09-24 20:26:52 -07002231 sort.Sort(&pkgAssociationSorter{pkgs})
2232
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002233 params := map[string]interface{}{
2234 "Pkgs": pkgs,
2235 }
2236
2237 buf := bytes.NewBuffer(nil)
2238 err = headerTemplate.Execute(buf, params)
2239 if err != nil {
2240 return err
2241 }
2242
2243 return nw.Comment(buf.String())
2244}
2245
2246func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2247 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2248 c.requiredNinjaMicro)
2249
2250 err := nw.Assign("ninja_required_version", value)
2251 if err != nil {
2252 return err
2253 }
2254
2255 return nw.BlankLine()
2256}
2257
2258func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2259 if c.buildDir != nil {
2260 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2261 if err != nil {
2262 return err
2263 }
2264
2265 err = nw.BlankLine()
2266 if err != nil {
2267 return err
2268 }
2269 }
2270 return nil
2271}
2272
Jamie Gennisc15544d2014-09-24 20:26:52 -07002273type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002274 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002275}
2276
Jamie Gennisc15544d2014-09-24 20:26:52 -07002277type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002278 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002279 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002280}
2281
Jamie Gennisc15544d2014-09-24 20:26:52 -07002282func (s *globalEntitySorter) Len() int {
2283 return len(s.entities)
2284}
2285
2286func (s *globalEntitySorter) Less(i, j int) bool {
2287 iName := s.entities[i].fullName(s.pkgNames)
2288 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002289 return iName < jName
2290}
2291
Jamie Gennisc15544d2014-09-24 20:26:52 -07002292func (s *globalEntitySorter) Swap(i, j int) {
2293 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002294}
2295
2296func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2297 visited := make(map[Variable]bool)
2298
2299 var walk func(v Variable) error
2300 walk = func(v Variable) error {
2301 visited[v] = true
2302
2303 // First visit variables on which this variable depends.
2304 value := c.globalVariables[v]
2305 for _, dep := range value.variables {
2306 if !visited[dep] {
2307 err := walk(dep)
2308 if err != nil {
2309 return err
2310 }
2311 }
2312 }
2313
2314 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2315 if err != nil {
2316 return err
2317 }
2318
2319 err = nw.BlankLine()
2320 if err != nil {
2321 return err
2322 }
2323
2324 return nil
2325 }
2326
Jamie Gennisc15544d2014-09-24 20:26:52 -07002327 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2328 for variable := range c.globalVariables {
2329 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002330 }
2331
Jamie Gennisc15544d2014-09-24 20:26:52 -07002332 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002333
Jamie Gennisc15544d2014-09-24 20:26:52 -07002334 for _, entity := range globalVariables {
2335 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002336 if !visited[v] {
2337 err := walk(v)
2338 if err != nil {
2339 return nil
2340 }
2341 }
2342 }
2343
2344 return nil
2345}
2346
2347func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002348 globalPools := make([]globalEntity, 0, len(c.globalPools))
2349 for pool := range c.globalPools {
2350 globalPools = append(globalPools, pool)
2351 }
2352
2353 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2354
2355 for _, entity := range globalPools {
2356 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002357 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002358 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002359 err := def.WriteTo(nw, name)
2360 if err != nil {
2361 return err
2362 }
2363
2364 err = nw.BlankLine()
2365 if err != nil {
2366 return err
2367 }
2368 }
2369
2370 return nil
2371}
2372
2373func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002374 globalRules := make([]globalEntity, 0, len(c.globalRules))
2375 for rule := range c.globalRules {
2376 globalRules = append(globalRules, rule)
2377 }
2378
2379 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2380
2381 for _, entity := range globalRules {
2382 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002383 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002384 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002385 err := def.WriteTo(nw, name, c.pkgNames)
2386 if err != nil {
2387 return err
2388 }
2389
2390 err = nw.BlankLine()
2391 if err != nil {
2392 return err
2393 }
2394 }
2395
2396 return nil
2397}
2398
Colin Crossab6d7902015-03-11 16:17:52 -07002399type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002400
Colin Crossab6d7902015-03-11 16:17:52 -07002401func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002402 return len(s)
2403}
2404
Colin Crossab6d7902015-03-11 16:17:52 -07002405func (s moduleSorter) Less(i, j int) bool {
2406 iName := s[i].properties.Name
2407 jName := s[j].properties.Name
2408 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002409 iName = s[i].variantName
2410 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002411 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002412 return iName < jName
2413}
2414
Colin Crossab6d7902015-03-11 16:17:52 -07002415func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002416 s[i], s[j] = s[j], s[i]
2417}
2418
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002419func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2420 headerTemplate := template.New("moduleHeader")
2421 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2422 if err != nil {
2423 // This is a programming error.
2424 panic(err)
2425 }
2426
Colin Crossab6d7902015-03-11 16:17:52 -07002427 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2428 for _, module := range c.moduleInfo {
2429 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002430 }
Colin Crossab6d7902015-03-11 16:17:52 -07002431 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002432
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002433 buf := bytes.NewBuffer(nil)
2434
Colin Crossab6d7902015-03-11 16:17:52 -07002435 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002436 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2437 continue
2438 }
2439
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002440 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002441
2442 // In order to make the bootstrap build manifest independent of the
2443 // build dir we need to output the Blueprints file locations in the
2444 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002445 relPos := module.pos
2446 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002447
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002448 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002449 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002450 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2451 factoryName := factoryFunc.Name()
2452
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002453 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002454 "properties": module.properties,
2455 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002456 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002457 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002458 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002459 }
2460 err = headerTemplate.Execute(buf, infoMap)
2461 if err != nil {
2462 return err
2463 }
2464
2465 err = nw.Comment(buf.String())
2466 if err != nil {
2467 return err
2468 }
2469
2470 err = nw.BlankLine()
2471 if err != nil {
2472 return err
2473 }
2474
Colin Crossab6d7902015-03-11 16:17:52 -07002475 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002476 if err != nil {
2477 return err
2478 }
2479
2480 err = nw.BlankLine()
2481 if err != nil {
2482 return err
2483 }
2484 }
2485
2486 return nil
2487}
2488
2489func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2490 headerTemplate := template.New("singletonHeader")
2491 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2492 if err != nil {
2493 // This is a programming error.
2494 panic(err)
2495 }
2496
2497 buf := bytes.NewBuffer(nil)
2498
Yuchen Wub9103ef2015-08-25 17:58:17 -07002499 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002500 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2501 continue
2502 }
2503
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002504 // Get the name of the factory function for the module.
2505 factory := info.factory
2506 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2507 factoryName := factoryFunc.Name()
2508
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002509 buf.Reset()
2510 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002511 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002512 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002513 }
2514 err = headerTemplate.Execute(buf, infoMap)
2515 if err != nil {
2516 return err
2517 }
2518
2519 err = nw.Comment(buf.String())
2520 if err != nil {
2521 return err
2522 }
2523
2524 err = nw.BlankLine()
2525 if err != nil {
2526 return err
2527 }
2528
2529 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2530 if err != nil {
2531 return err
2532 }
2533
2534 err = nw.BlankLine()
2535 if err != nil {
2536 return err
2537 }
2538 }
2539
2540 return nil
2541}
2542
2543func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2544 defs *localBuildActions) error {
2545
2546 // Write the local variable assignments.
2547 for _, v := range defs.variables {
2548 // A localVariable doesn't need the package names or config to
2549 // determine its name or value.
2550 name := v.fullName(nil)
2551 value, err := v.value(nil)
2552 if err != nil {
2553 panic(err)
2554 }
2555 err = nw.Assign(name, value.Value(c.pkgNames))
2556 if err != nil {
2557 return err
2558 }
2559 }
2560
2561 if len(defs.variables) > 0 {
2562 err := nw.BlankLine()
2563 if err != nil {
2564 return err
2565 }
2566 }
2567
2568 // Write the local rules.
2569 for _, r := range defs.rules {
2570 // A localRule doesn't need the package names or config to determine
2571 // its name or definition.
2572 name := r.fullName(nil)
2573 def, err := r.def(nil)
2574 if err != nil {
2575 panic(err)
2576 }
2577
2578 err = def.WriteTo(nw, name, c.pkgNames)
2579 if err != nil {
2580 return err
2581 }
2582
2583 err = nw.BlankLine()
2584 if err != nil {
2585 return err
2586 }
2587 }
2588
2589 // Write the build definitions.
2590 for _, buildDef := range defs.buildDefs {
2591 err := buildDef.WriteTo(nw, c.pkgNames)
2592 if err != nil {
2593 return err
2594 }
2595
2596 if len(buildDef.Args) > 0 {
2597 err = nw.BlankLine()
2598 if err != nil {
2599 return err
2600 }
2601 }
2602 }
2603
2604 return nil
2605}
2606
Colin Cross65569e42015-03-10 20:08:19 -07002607func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2608 found := false
2609 for _, l := range list {
2610 if l == a {
2611 found = true
2612 } else if l == b {
2613 return found
2614 }
2615 }
2616
2617 missing := a
2618 if found {
2619 missing = b
2620 }
2621 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2622}
2623
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002624var fileHeaderTemplate = `******************************************************************************
2625*** This file is generated and should not be edited ***
2626******************************************************************************
2627{{if .Pkgs}}
2628This file contains variables, rules, and pools with name prefixes indicating
2629they were generated by the following Go packages:
2630{{range .Pkgs}}
2631 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2632
2633`
2634
2635var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2636Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002637Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002638Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002639Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002640Defined: {{.pos}}
2641`
2642
2643var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2644Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002645Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002646`