blob: 811df15333130cf1234e461897abdb9fcd276468 [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
Colin Crossa2599452015-11-18 16:01:01 -080091 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070092 requiredNinjaMajor int // For the ninja_required_version variable
93 requiredNinjaMinor int // For the ninja_required_version variable
94 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070095
96 // set lazily by sortedModuleNames
97 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070098}
99
Jamie Gennisd4e10182014-06-12 20:06:50 -0700100// An Error describes a problem that was encountered that is related to a
101// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700103 Err error // the error that occurred
104 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105}
106
107type localBuildActions struct {
108 variables []*localVariable
109 rules []*localRule
110 buildDefs []*buildDef
111}
112
Colin Crossbbfa51a2014-12-17 16:12:41 -0800113type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700114 name string
115 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118}
119
Colin Crossbbfa51a2014-12-17 16:12:41 -0800120type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700121 // set during Parse
122 typeName string
123 relBlueprintsFile string
124 pos scanner.Position
125 propertyPos map[string]scanner.Position
126 properties struct {
127 Name string
128 Deps []string
129 }
130
Colin Crossf5e34b92015-03-13 16:02:36 -0700131 variantName string
132 variant variationMap
133 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700134
Colin Crossc9028482014-12-18 16:28:54 -0800135 logicModule Module
136 group *moduleGroup
137 moduleProperties []interface{}
138
139 // set during ResolveDependencies
140 directDeps []*moduleInfo
141
Colin Cross7addea32015-03-11 15:43:52 -0700142 // set during updateDependencies
143 reverseDeps []*moduleInfo
144 depsCount int
145
146 // used by parallelVisitAllBottomUp
147 waitingCount int
148
Colin Crossc9028482014-12-18 16:28:54 -0800149 // set during each runMutator
150 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700151
152 // set during PrepareBuildActions
153 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800154}
155
Colin Crossf5e34b92015-03-13 16:02:36 -0700156// A Variation is a way that a variant of a module differs from other variants of the same module.
157// For example, two variants of the same module might have Variation{"arch","arm"} and
158// Variation{"arch","arm64"}
159type Variation struct {
160 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700161 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700162 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
163 // "shared" or "static" for link.
164 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700165}
166
Colin Crossf5e34b92015-03-13 16:02:36 -0700167// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
168type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700169
Colin Crossf5e34b92015-03-13 16:02:36 -0700170func (vm variationMap) clone() variationMap {
171 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700172 for k, v := range vm {
173 newVm[k] = v
174 }
175
176 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800177}
178
Colin Cross89486232015-05-08 11:14:54 -0700179// Compare this variationMap to another one. Returns true if the every entry in this map
180// is either the same in the other map or doesn't exist in the other map.
181func (vm variationMap) subset(other variationMap) bool {
182 for k, v1 := range vm {
183 if v2, ok := other[k]; ok && v1 != v2 {
184 return false
185 }
186 }
187 return true
188}
189
Colin Crossf5e34b92015-03-13 16:02:36 -0700190func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700191 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800192}
193
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700194type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700195 // set during RegisterSingletonType
196 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700197 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700198 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700199
200 // set during PrepareBuildActions
201 actionDefs localBuildActions
202}
203
Colin Crossc9028482014-12-18 16:28:54 -0800204type mutatorInfo struct {
205 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800206 topDownMutator TopDownMutator
207 bottomUpMutator BottomUpMutator
208 name string
Colin Crossc9028482014-12-18 16:28:54 -0800209}
210
Colin Cross65569e42015-03-10 20:08:19 -0700211type earlyMutatorInfo struct {
212 // set during RegisterEarlyMutator
213 mutator EarlyMutator
214 name string
215}
216
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700217func (e *Error) Error() string {
218
219 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
220}
221
Jamie Gennisd4e10182014-06-12 20:06:50 -0700222// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700223// no module or singleton factories registered, so the RegisterModuleFactory and
224// RegisterSingletonFactory methods must be called before it can do anything
225// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700227 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800228 moduleFactories: make(map[string]ModuleFactory),
229 moduleGroups: make(map[string]*moduleGroup),
230 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800231 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700232 }
Colin Cross763b6f12015-10-29 15:32:56 -0700233
234 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
235
236 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700237}
238
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700239// A ModuleFactory function creates a new Module object. See the
240// Context.RegisterModuleType method for details about how a registered
241// ModuleFactory is used by a Context.
242type ModuleFactory func() (m Module, propertyStructs []interface{})
243
Jamie Gennisd4e10182014-06-12 20:06:50 -0700244// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700245// Blueprints file) with a Module factory function. When the given module type
246// name is encountered in a Blueprints file during parsing, the Module factory
247// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800248// generation for the module. If a Mutator splits a module into multiple variants,
249// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700250//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700251// The module type names given here must be unique for the context. The factory
252// function should be a named function so that its package and name can be
253// included in the generated Ninja file for debugging purposes.
254//
255// The factory function returns two values. The first is the newly created
256// Module object. The second is a slice of pointers to that Module object's
257// properties structs. Each properties struct is examined when parsing a module
258// definition of this type in a Blueprints file. Exported fields of the
259// properties structs are automatically set to the property values specified in
260// the Blueprints file. The properties struct field names determine the name of
261// the Blueprints file properties that are used - the Blueprints property name
262// matches that of the properties struct field name with the first letter
263// converted to lower-case.
264//
265// The fields of the properties struct must be either []string, a string, or
266// bool. The Context will panic if a Module gets instantiated with a properties
267// struct containing a field that is not one these supported types.
268//
269// Any properties that appear in the Blueprints files that are not built-in
270// module properties (such as "name" and "deps") and do not have a corresponding
271// field in the returned module properties struct result in an error during the
272// Context's parse phase.
273//
274// As an example, the follow code:
275//
276// type myModule struct {
277// properties struct {
278// Foo string
279// Bar []string
280// }
281// }
282//
283// func NewMyModule() (blueprint.Module, []interface{}) {
284// module := new(myModule)
285// properties := &module.properties
286// return module, []interface{}{properties}
287// }
288//
289// func main() {
290// ctx := blueprint.NewContext()
291// ctx.RegisterModuleType("my_module", NewMyModule)
292// // ...
293// }
294//
295// would support parsing a module defined in a Blueprints file as follows:
296//
297// my_module {
298// name: "myName",
299// foo: "my foo string",
300// bar: ["my", "bar", "strings"],
301// }
302//
Colin Cross7ad621c2015-01-07 16:22:45 -0800303// The factory function may be called from multiple goroutines. Any accesses
304// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700305func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
306 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700307 panic(errors.New("module type name is already registered"))
308 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700309 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700310}
311
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312// A SingletonFactory function creates a new Singleton object. See the
313// Context.RegisterSingletonType method for details about how a registered
314// SingletonFactory is used by a Context.
315type SingletonFactory func() Singleton
316
317// RegisterSingletonType registers a singleton type that will be invoked to
318// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700319// and invoked exactly once as part of the generate phase. Each registered
320// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700321//
322// The singleton type names given here must be unique for the context. The
323// factory function should be a named function so that its package and name can
324// be included in the generated Ninja file for debugging purposes.
325func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700326 for _, s := range c.singletonInfo {
327 if s.name == name {
328 panic(errors.New("singleton name is already registered"))
329 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700330 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700331
Yuchen Wub9103ef2015-08-25 17:58:17 -0700332 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700333 factory: factory,
334 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700335 name: name,
336 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700337}
338
339func singletonPkgPath(singleton Singleton) string {
340 typ := reflect.TypeOf(singleton)
341 for typ.Kind() == reflect.Ptr {
342 typ = typ.Elem()
343 }
344 return typ.PkgPath()
345}
346
347func singletonTypeName(singleton Singleton) string {
348 typ := reflect.TypeOf(singleton)
349 for typ.Kind() == reflect.Ptr {
350 typ = typ.Elem()
351 }
352 return typ.PkgPath() + "." + typ.Name()
353}
354
Colin Crossc9028482014-12-18 16:28:54 -0800355// RegisterTopDownMutator registers a mutator that will be invoked to propagate
356// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700357// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
358// once per Module, and is invoked on a module before being invoked on any of its
359// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800360//
Colin Cross65569e42015-03-10 20:08:19 -0700361// The mutator type names given here must be unique to all top down mutators in
362// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800363func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
364 for _, m := range c.mutatorInfo {
365 if m.name == name && m.topDownMutator != nil {
366 panic(fmt.Errorf("mutator name %s is already registered", name))
367 }
368 }
369
370 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
371 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800372 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800373 })
374}
375
376// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700377// Modules into variants. Each registered mutator is invoked in registration
378// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
379// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800380//
Colin Cross65569e42015-03-10 20:08:19 -0700381// The mutator type names given here must be unique to all bottom up or early
382// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800383func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700384 for _, m := range c.variantMutatorNames {
385 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800386 panic(fmt.Errorf("mutator name %s is already registered", name))
387 }
388 }
389
390 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
391 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800392 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800393 })
Colin Cross65569e42015-03-10 20:08:19 -0700394
395 c.variantMutatorNames = append(c.variantMutatorNames, name)
396}
397
398// RegisterEarlyMutator registers a mutator that will be invoked to split
399// Modules into multiple variant Modules before any dependencies have been
400// created. Each registered mutator is invoked in registration order once
401// per Module (including each variant from previous early mutators). Module
402// order is unpredictable.
403//
404// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700405// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700406//
407// The mutator type names given here must be unique to all bottom up or early
408// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700409//
410// Deprecated, use a BottomUpMutator instead. The only difference between
411// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
412// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700413func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
414 for _, m := range c.variantMutatorNames {
415 if m == name {
416 panic(fmt.Errorf("mutator name %s is already registered", name))
417 }
418 }
419
420 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
421 mutator: mutator,
422 name: name,
423 })
424
425 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800426}
427
Jamie Gennisd4e10182014-06-12 20:06:50 -0700428// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
429// where it encounters an unknown module type while parsing Blueprints files. By
430// default, the context will report unknown module types as an error. If this
431// method is called with ignoreUnknownModuleTypes set to true then the context
432// will silently ignore unknown module types.
433//
434// This method should generally not be used. It exists to facilitate the
435// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700436func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
437 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
438}
439
Jamie Gennisd4e10182014-06-12 20:06:50 -0700440// Parse parses a single Blueprints file from r, creating Module objects for
441// each of the module definitions encountered. If the Blueprints file contains
442// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700443// searched for Blueprints files returned in the subBlueprints return value.
444// If the Blueprints file contains an assignment to the "build" variable, then
445// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700446//
447// rootDir specifies the path to the root directory of the source tree, while
448// filename specifies the path to the Blueprints file. These paths are used for
449// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800450func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700451 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700452 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700453
Jamie Gennisec701282014-06-12 20:06:31 -0700454 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700455 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700456 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700457 }
458
Colin Crossc0dbc552015-01-02 15:19:28 -0800459 scope = parser.NewScope(scope)
460 scope.Remove("subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700461 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700462 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700463 if len(errs) > 0 {
464 for i, err := range errs {
465 if parseErr, ok := err.(*parser.ParseError); ok {
466 err = &Error{
467 Err: parseErr.Err,
468 Pos: parseErr.Pos,
469 }
470 errs[i] = err
471 }
472 }
473
474 // If there were any parse errors don't bother trying to interpret the
475 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700476 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700477 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700478 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700479
Colin Cross6d8780f2015-07-10 17:51:55 -0700480 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700481 if err != nil {
482 errs = append(errs, err)
483 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700484
Colin Cross6d8780f2015-07-10 17:51:55 -0700485 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700486 if err != nil {
487 errs = append(errs, err)
488 }
489
Colin Cross29394222015-04-27 13:18:21 -0700490 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
491
Colin Cross1fef5362015-04-20 16:50:54 -0700492 blueprints, deps, newErrs := c.findSubdirBlueprints(filepath.Dir(filename), subdirs, build,
Colin Cross29394222015-04-27 13:18:21 -0700493 subBlueprintsName, subdirsPos, buildPos)
Colin Crossc0dbc552015-01-02 15:19:28 -0800494 if len(newErrs) > 0 {
495 errs = append(errs, newErrs...)
496 }
497
Colin Cross1fef5362015-04-20 16:50:54 -0700498 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
499 for i, b := range blueprints {
500 subBlueprintsAndScope[i] = stringAndScope{b, scope}
501 }
502
Colin Cross23d7aa12015-06-30 16:05:22 -0700503 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800504}
505
Colin Cross7ad621c2015-01-07 16:22:45 -0800506type stringAndScope struct {
507 string
508 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700509}
510
Jamie Gennisd4e10182014-06-12 20:06:50 -0700511// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
512// at rootFile. When it encounters a Blueprints file with a set of subdirs
513// listed it recursively parses any Blueprints files found in those
514// subdirectories.
515//
516// If no errors are encountered while parsing the files, the list of paths on
517// which the future output will depend is returned. This list will include both
518// Blueprints file paths as well as directory paths for cases where wildcard
519// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700520func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
521 errs []error) {
522
Colin Cross7ad621c2015-01-07 16:22:45 -0800523 c.dependenciesReady = false
524
Colin Cross23d7aa12015-06-30 16:05:22 -0700525 moduleCh := make(chan *moduleInfo)
526 errsCh := make(chan []error)
527 doneCh := make(chan struct{})
528 var numErrs uint32
529 var numGoroutines int32
530
531 // handler must be reentrant
532 handler := func(file *parser.File) {
533 if atomic.LoadUint32(&numErrs) > maxErrors {
534 return
535 }
536
537 atomic.AddInt32(&numGoroutines, 1)
538 go func() {
539 for _, def := range file.Defs {
540 var module *moduleInfo
541 var errs []error
542 switch def := def.(type) {
543 case *parser.Module:
544 module, errs = c.processModuleDef(def, file.Name)
545 case *parser.Assignment:
546 // Already handled via Scope object
547 default:
548 panic("unknown definition type")
549 }
550
551 if len(errs) > 0 {
552 atomic.AddUint32(&numErrs, uint32(len(errs)))
553 errsCh <- errs
554 } else if module != nil {
555 moduleCh <- module
556 }
557 }
558 doneCh <- struct{}{}
559 }()
560 }
561
562 atomic.AddInt32(&numGoroutines, 1)
563 go func() {
564 var errs []error
565 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
566 if len(errs) > 0 {
567 errsCh <- errs
568 }
569 doneCh <- struct{}{}
570 }()
571
572loop:
573 for {
574 select {
575 case newErrs := <-errsCh:
576 errs = append(errs, newErrs...)
577 case module := <-moduleCh:
578 newErrs := c.addModule(module)
579 if len(newErrs) > 0 {
580 errs = append(errs, newErrs...)
581 }
582 case <-doneCh:
583 n := atomic.AddInt32(&numGoroutines, -1)
584 if n == 0 {
585 break loop
586 }
587 }
588 }
589
590 return deps, errs
591}
592
593type FileHandler func(*parser.File)
594
595// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
596// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
597// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
598// it must be reentrant.
599//
600// If no errors are encountered while parsing the files, the list of paths on
601// which the future output will depend is returned. This list will include both
602// Blueprints file paths as well as directory paths for cases where wildcard
603// subdirs are found.
604func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
605 errs []error) {
606
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700607 rootDir := filepath.Dir(rootFile)
608
Colin Cross7ad621c2015-01-07 16:22:45 -0800609 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700610
Colin Cross7ad621c2015-01-07 16:22:45 -0800611 // Channels to receive data back from parseBlueprintsFile goroutines
612 blueprintsCh := make(chan stringAndScope)
613 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700614 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800615 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700616
Colin Cross7ad621c2015-01-07 16:22:45 -0800617 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
618 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700619
Colin Cross7ad621c2015-01-07 16:22:45 -0800620 // Number of outstanding goroutines to wait for
621 count := 0
622
623 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
624 count++
625 go func() {
626 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700627 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800628 doneCh <- struct{}{}
629 }()
630 }
631
632 tooManyErrors := false
633
634 startParseBlueprintsFile(rootFile, nil)
635
636loop:
637 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700638 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800639 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700640 }
641
Colin Cross7ad621c2015-01-07 16:22:45 -0800642 select {
643 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700644 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800645 case dep := <-depsCh:
646 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700647 case file := <-fileCh:
648 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800649 case blueprint := <-blueprintsCh:
650 if tooManyErrors {
651 continue
652 }
653 if blueprintsSet[blueprint.string] {
654 continue
655 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700656
Colin Cross7ad621c2015-01-07 16:22:45 -0800657 blueprintsSet[blueprint.string] = true
658 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
659 case <-doneCh:
660 count--
661 if count == 0 {
662 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700663 }
664 }
665 }
666
Colin Cross7ad621c2015-01-07 16:22:45 -0800667 return
668}
669
670// parseBlueprintFile parses a single Blueprints file, returning any errors through
671// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
672// blueprintsCh, and any dependencies on Blueprints files or directories through
673// depsCh.
674func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700675 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800676 depsCh chan<- string) {
677
Colin Cross23d7aa12015-06-30 16:05:22 -0700678 f, err := os.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800679 if err != nil {
680 errsCh <- []error{err}
681 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700682 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700683 defer func() {
684 err = f.Close()
685 if err != nil {
686 errsCh <- []error{err}
687 }
688 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700689
Colin Cross23d7aa12015-06-30 16:05:22 -0700690 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800691 if len(errs) > 0 {
692 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700693 } else {
694 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800695 }
696
Colin Cross1fef5362015-04-20 16:50:54 -0700697 for _, b := range subBlueprints {
698 blueprintsCh <- b
699 }
700
701 for _, d := range deps {
702 depsCh <- d
703 }
Colin Cross1fef5362015-04-20 16:50:54 -0700704}
705
Colin Cross29394222015-04-27 13:18:21 -0700706func (c *Context) findSubdirBlueprints(dir string, subdirs, build []string, subBlueprintsName string,
Colin Cross1fef5362015-04-20 16:50:54 -0700707 subdirsPos, buildPos scanner.Position) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800708
709 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700710 globPattern := filepath.Join(dir, subdir)
711 matches, matchedDirs, err := pathtools.Glob(globPattern)
712 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700713 errs = append(errs, &Error{
714 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
715 Pos: subdirsPos,
716 })
717 continue
718 }
719
720 if len(matches) == 0 {
721 errs = append(errs, &Error{
722 Err: fmt.Errorf("%q: not found", globPattern),
723 Pos: subdirsPos,
724 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700725 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800726
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700727 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700728 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800729
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700730 for _, foundSubdir := range matches {
731 fileInfo, subdirStatErr := os.Stat(foundSubdir)
732 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700733 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700734 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800735 }
736
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700737 // Skip files
738 if !fileInfo.IsDir() {
739 continue
740 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800741
Colin Cross29394222015-04-27 13:18:21 -0700742 var subBlueprints string
743 if subBlueprintsName != "" {
744 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
745 _, err = os.Stat(subBlueprints)
746 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700747
Colin Cross29394222015-04-27 13:18:21 -0700748 if os.IsNotExist(err) || subBlueprints == "" {
749 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
750 _, err = os.Stat(subBlueprints)
751 }
752
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700753 if os.IsNotExist(err) {
754 // There is no Blueprints file in this subdirectory. We
755 // need to add the directory to the list of dependencies
756 // so that if someone adds a Blueprints file in the
757 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700758 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700759 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700760 deps = append(deps, subBlueprints)
761 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800762 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800763 }
764 }
Colin Cross1fef5362015-04-20 16:50:54 -0700765
766 for _, file := range build {
767 globPattern := filepath.Join(dir, file)
768 matches, matchedDirs, err := pathtools.Glob(globPattern)
769 if err != nil {
770 errs = append(errs, &Error{
771 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
772 Pos: buildPos,
773 })
774 continue
775 }
776
777 if len(matches) == 0 {
778 errs = append(errs, &Error{
779 Err: fmt.Errorf("%q: not found", globPattern),
780 Pos: buildPos,
781 })
782 }
783
784 // Depend on all searched directories so we pick up future changes.
785 deps = append(deps, matchedDirs...)
786
787 for _, foundBlueprints := range matches {
788 fileInfo, err := os.Stat(foundBlueprints)
789 if os.IsNotExist(err) {
790 errs = append(errs, &Error{
791 Err: fmt.Errorf("%q not found", foundBlueprints),
792 })
793 continue
794 }
795
796 if fileInfo.IsDir() {
797 errs = append(errs, &Error{
798 Err: fmt.Errorf("%q is a directory", foundBlueprints),
799 })
800 continue
801 }
802
803 blueprints = append(blueprints, foundBlueprints)
804 }
805 }
806
807 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700808}
809
Colin Cross6d8780f2015-07-10 17:51:55 -0700810func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
811 if assignment, local := scope.Get(v); assignment == nil || !local {
812 return nil, scanner.Position{}, nil
813 } else {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700814 switch assignment.Value.Type {
815 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700816 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700817
818 for _, value := range assignment.Value.ListValue {
819 if value.Type != parser.String {
820 // The parser should not produce this.
821 panic("non-string value found in list")
822 }
823
Colin Cross1fef5362015-04-20 16:50:54 -0700824 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700825 }
826
Colin Cross1fef5362015-04-20 16:50:54 -0700827 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700828 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700829 return nil, scanner.Position{}, &Error{
830 Err: fmt.Errorf("%q must be a list of strings", v),
831 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700832 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700833 default:
834 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
835 }
836 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700837}
838
Colin Cross29394222015-04-27 13:18:21 -0700839func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700840 if assignment, _ := scope.Get(v); assignment == nil {
841 return "", scanner.Position{}, nil
842 } else {
Colin Cross29394222015-04-27 13:18:21 -0700843 switch assignment.Value.Type {
844 case parser.String:
845 return assignment.Value.StringValue, assignment.Pos, nil
846 case parser.Bool, parser.List:
847 return "", scanner.Position{}, &Error{
848 Err: fmt.Errorf("%q must be a string", v),
849 Pos: assignment.Pos,
850 }
851 default:
852 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
853 }
854 }
Colin Cross29394222015-04-27 13:18:21 -0700855}
856
Colin Crossf5e34b92015-03-13 16:02:36 -0700857func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
858 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800859
Colin Crossf4d18a62015-03-18 17:43:15 -0700860 if len(variationNames) == 0 {
861 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400862 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700863 }
864
Colin Crossc9028482014-12-18 16:28:54 -0800865 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800866
Colin Cross174ae052015-03-03 17:37:03 -0800867 var errs []error
868
Colin Crossf5e34b92015-03-13 16:02:36 -0700869 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700870 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800871 factory, ok := c.moduleFactories[typeName]
872 if !ok {
873 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
874 }
875
876 var newLogicModule Module
877 var newProperties []interface{}
878
879 if i == 0 {
880 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700881 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
882 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800883 newLogicModule = origModule.logicModule
884 newProperties = origModule.moduleProperties
885 } else {
886 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700887 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800888 }
889 newLogicModule, newProperties = factory()
890
891 newProperties = append(props, newProperties...)
892
893 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700894 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800895 }
896
897 for i := range newProperties {
898 dst := reflect.ValueOf(newProperties[i]).Elem()
899 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
900
901 proptools.CopyProperties(dst, src)
902 }
903 }
904
Colin Crossf5e34b92015-03-13 16:02:36 -0700905 newVariant := origModule.variant.clone()
906 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800907
Colin Crossed342d92015-03-11 00:57:25 -0700908 m := *origModule
909 newModule := &m
910 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
911 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700912 newModule.variant = newVariant
913 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700914 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800915
Colin Crosse7daa222015-03-11 14:35:41 -0700916 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700917 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700918 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700919 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700920 }
921
Colin Crossc9028482014-12-18 16:28:54 -0800922 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700923
924 // Insert the new variant into the global module map. If this is the first variant then
925 // it reuses logicModule from the original module, which causes this to replace the
926 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800927 c.moduleInfo[newModule.logicModule] = newModule
928
Colin Crossf5e34b92015-03-13 16:02:36 -0700929 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800930 if len(newErrs) > 0 {
931 errs = append(errs, newErrs...)
932 }
Colin Crossc9028482014-12-18 16:28:54 -0800933 }
934
935 // Mark original variant as invalid. Modules that depend on this module will still
936 // depend on origModule, but we'll fix it when the mutator is called on them.
937 origModule.logicModule = nil
938 origModule.splitModules = newModules
939
Colin Cross174ae052015-03-03 17:37:03 -0800940 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800941}
942
Colin Crossf5e34b92015-03-13 16:02:36 -0700943func (c *Context) convertDepsToVariation(module *moduleInfo,
944 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800945
Colin Crossc9028482014-12-18 16:28:54 -0800946 for i, dep := range module.directDeps {
947 if dep.logicModule == nil {
948 var newDep *moduleInfo
949 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700950 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800951 newDep = m
952 break
953 }
954 }
955 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800956 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700957 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
958 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700959 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800960 })
961 continue
Colin Crossc9028482014-12-18 16:28:54 -0800962 }
963 module.directDeps[i] = newDep
964 }
965 }
Colin Cross174ae052015-03-03 17:37:03 -0800966
967 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800968}
969
Colin Crossf5e34b92015-03-13 16:02:36 -0700970func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700971 names := make([]string, 0, len(variant))
972 for _, m := range c.variantMutatorNames {
973 if v, ok := variant[m]; ok {
974 names = append(names, m+":"+v)
975 }
976 }
977
978 return strings.Join(names, ", ")
979}
980
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700981func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800982 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700983
Colin Crossd1facc12015-01-08 14:56:03 -0800984 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700985 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700986 if !ok {
987 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800988 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700989 }
990
Colin Cross7ad621c2015-01-07 16:22:45 -0800991 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700992 &Error{
993 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800994 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700995 },
996 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700997 }
998
Colin Crossbbfa51a2014-12-17 16:12:41 -0800999 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001000
1001 module := &moduleInfo{
1002 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -07001003 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -07001004 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001005 }
1006
Jamie Gennis87622922014-09-30 11:38:25 -07001007 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001008 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001009 }
1010 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001011 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001012
Jamie Gennis87622922014-09-30 11:38:25 -07001013 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001014 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001015 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001016 }
1017
Colin Crossed342d92015-03-11 00:57:25 -07001018 module.pos = moduleDef.Type.Pos
1019 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001020 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -07001021 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001022 }
1023
Colin Cross7ad621c2015-01-07 16:22:45 -08001024 return module, nil
1025}
1026
Colin Cross23d7aa12015-06-30 16:05:22 -07001027func (c *Context) addModule(module *moduleInfo) []error {
1028 name := module.properties.Name
1029 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001030
Colin Cross23d7aa12015-06-30 16:05:22 -07001031 if group, present := c.moduleGroups[name]; present {
1032 return []error{
1033 &Error{
1034 Err: fmt.Errorf("module %q already defined", name),
1035 Pos: module.pos,
1036 },
1037 &Error{
1038 Err: fmt.Errorf("<-- previous definition here"),
1039 Pos: group.modules[0].pos,
1040 },
Colin Crossed342d92015-03-11 00:57:25 -07001041 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001042 } else {
1043 ninjaName := toNinjaName(module.properties.Name)
1044
1045 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1046 // already exists
1047 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1048 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1049 }
1050
1051 group := &moduleGroup{
1052 name: module.properties.Name,
1053 ninjaName: ninjaName,
1054 modules: []*moduleInfo{module},
1055 }
1056 module.group = group
1057 c.moduleGroups[name] = group
1058 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001059 }
1060
Colin Cross23d7aa12015-06-30 16:05:22 -07001061 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001062}
1063
Jamie Gennisd4e10182014-06-12 20:06:50 -07001064// ResolveDependencies checks that the dependencies specified by all of the
1065// modules defined in the parsed Blueprints files are valid. This means that
1066// the modules depended upon are defined and that no circular dependencies
1067// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001068func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross763b6f12015-10-29 15:32:56 -07001069 errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001070 if len(errs) > 0 {
1071 return errs
1072 }
1073
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001074 c.dependenciesReady = true
1075 return nil
1076}
1077
Colin Cross763b6f12015-10-29 15:32:56 -07001078// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001079// DynamicDependerModule interface then this set consists of the union of those
1080// module names listed in its "deps" property, those returned by its
1081// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001082// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001083// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001084func blueprintDepsMutator(ctx BottomUpMutatorContext) {
1085 ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001086
Colin Cross763b6f12015-10-29 15:32:56 -07001087 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
1088 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001089
Colin Cross763b6f12015-10-29 15:32:56 -07001090 if ctx.Failed() {
1091 return
Colin Crossa434b3f2015-01-13 10:59:52 -08001092 }
Colin Cross763b6f12015-10-29 15:32:56 -07001093
1094 ctx.AddDependency(ctx.Module(), dynamicDeps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001095 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001096}
1097
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001098// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1099// and returns the matching module, or nil if one is not found.
1100func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1101 if len(group.modules) == 1 {
1102 return group.modules[0]
1103 } else {
1104 for _, m := range group.modules {
1105 if m.variant.equal(module.dependencyVariant) {
1106 return m
1107 }
1108 }
1109 }
1110
1111 return nil
1112}
1113
Colin Crossc9028482014-12-18 16:28:54 -08001114func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001115 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001116 return []error{&Error{
1117 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001118 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001119 }}
1120 }
1121
1122 depInfo, ok := c.moduleGroups[depName]
1123 if !ok {
1124 return []error{&Error{
1125 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001126 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001127 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001128 }}
1129 }
1130
Colin Cross65569e42015-03-10 20:08:19 -07001131 for _, m := range module.directDeps {
1132 if m.group == depInfo {
1133 return nil
1134 }
Colin Crossc9028482014-12-18 16:28:54 -08001135 }
1136
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001137 if m := c.findMatchingVariant(module, depInfo); m != nil {
1138 module.directDeps = append(module.directDeps, m)
Colin Cross65569e42015-03-10 20:08:19 -07001139 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001140 }
Colin Crossc9028482014-12-18 16:28:54 -08001141
Colin Cross65569e42015-03-10 20:08:19 -07001142 return []error{&Error{
1143 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1144 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001145 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001146 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001147 }}
1148}
1149
Colin Cross8d8a7af2015-11-03 16:41:29 -08001150func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001151 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001152 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001153 Err: fmt.Errorf("%q depends on itself", destName),
1154 Pos: module.pos,
1155 }}
1156 }
1157
1158 destInfo, ok := c.moduleGroups[destName]
1159 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001160 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001161 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1162 module.properties.Name, destName),
1163 Pos: module.pos,
1164 }}
1165 }
1166
1167 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001168 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001169 }
1170
Colin Cross8d8a7af2015-11-03 16:41:29 -08001171 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001172 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1173 destName, module.properties.Name,
1174 c.prettyPrintVariant(module.dependencyVariant)),
1175 Pos: module.pos,
1176 }}
1177}
1178
Colin Crossf5e34b92015-03-13 16:02:36 -07001179func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross89486232015-05-08 11:14:54 -07001180 depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001181
Colin Cross65569e42015-03-10 20:08:19 -07001182 depInfo, ok := c.moduleGroups[depName]
1183 if !ok {
1184 return []error{&Error{
1185 Err: fmt.Errorf("%q depends on undefined module %q",
1186 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001187 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001188 }}
1189 }
1190
1191 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1192 // compare the strings because the result won't be in mutator registration order.
1193 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001194 var newVariant variationMap
1195 if !far {
1196 newVariant = module.dependencyVariant.clone()
1197 } else {
1198 newVariant = make(variationMap)
1199 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001200 for _, v := range variations {
1201 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001202 }
1203
1204 for _, m := range depInfo.modules {
Colin Cross89486232015-05-08 11:14:54 -07001205 var found bool
1206 if far {
1207 found = m.variant.subset(newVariant)
1208 } else {
1209 found = m.variant.equal(newVariant)
1210 }
1211 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001212 if module == m {
1213 return []error{&Error{
1214 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001215 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001216 }}
1217 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001218 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001219 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001220 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001221 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1222 return []error{&Error{
1223 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001224 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001225 }}
1226 }
1227 module.directDeps = append(module.directDeps, m)
1228 return nil
1229 }
1230 }
1231
1232 return []error{&Error{
1233 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1234 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001235 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001236 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001237 }}
Colin Crossc9028482014-12-18 16:28:54 -08001238}
1239
Colin Cross7addea32015-03-11 15:43:52 -07001240func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1241 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001242 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001243 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001244
Colin Cross7addea32015-03-11 15:43:52 -07001245 for _, module := range c.modulesSorted {
1246 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001247 }
1248
Colin Cross7addea32015-03-11 15:43:52 -07001249 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001250 count++
1251 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001252 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001253 if ret {
1254 cancel = true
1255 }
Colin Cross7addea32015-03-11 15:43:52 -07001256 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001257 }()
1258 }
1259
Colin Cross7addea32015-03-11 15:43:52 -07001260 for _, module := range c.modulesSorted {
1261 if module.waitingCount == 0 {
1262 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001263 }
1264 }
1265
Colin Cross11e3b0d2015-02-04 10:41:00 -08001266 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001267 select {
Colin Cross7addea32015-03-11 15:43:52 -07001268 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001269 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001270 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001271 parent.waitingCount--
1272 if parent.waitingCount == 0 {
1273 visitOne(parent)
1274 }
Colin Cross691a60d2015-01-07 18:08:56 -08001275 }
1276 }
1277 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001278 }
1279 }
1280}
1281
1282// updateDependencies recursively walks the module dependency graph and updates
1283// additional fields based on the dependencies. It builds a sorted list of modules
1284// such that dependencies of a module always appear first, and populates reverse
1285// dependency links and counts of total dependencies. It also reports errors when
1286// it encounters dependency cycles. This should called after resolveDependencies,
1287// as well as after any mutator pass has called addDependency
1288func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001289 visited := make(map[*moduleInfo]bool) // modules that were already checked
1290 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001291
Colin Cross7addea32015-03-11 15:43:52 -07001292 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001293
Colin Cross7addea32015-03-11 15:43:52 -07001294 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001295
Colin Cross7addea32015-03-11 15:43:52 -07001296 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001297 // We are the "start" of the cycle, so we're responsible
1298 // for generating the errors. The cycle list is in
1299 // reverse order because all the 'check' calls append
1300 // their own module to the list.
1301 errs = append(errs, &Error{
1302 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001303 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001304 })
1305
1306 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001307 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001308 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001309 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001310 errs = append(errs, &Error{
1311 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001312 curModule.properties.Name,
1313 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001314 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001315 })
Colin Cross7addea32015-03-11 15:43:52 -07001316 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001317 }
1318 }
1319
Colin Cross7addea32015-03-11 15:43:52 -07001320 check = func(module *moduleInfo) []*moduleInfo {
1321 visited[module] = true
1322 checking[module] = true
1323 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001324
Colin Cross7addea32015-03-11 15:43:52 -07001325 deps := make(map[*moduleInfo]bool)
1326
1327 // Add an implicit dependency ordering on all earlier modules in the same module group
1328 for _, dep := range module.group.modules {
1329 if dep == module {
1330 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001331 }
Colin Cross7addea32015-03-11 15:43:52 -07001332 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001333 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001334
Colin Cross7addea32015-03-11 15:43:52 -07001335 for _, dep := range module.directDeps {
1336 deps[dep] = true
1337 }
1338
1339 module.reverseDeps = []*moduleInfo{}
1340 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001341
Colin Crossbbfa51a2014-12-17 16:12:41 -08001342 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001343 if checking[dep] {
1344 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001345 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001346 }
1347
1348 if !visited[dep] {
1349 cycle := check(dep)
1350 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001351 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001352 // We are the "start" of the cycle, so we're responsible
1353 // for generating the errors. The cycle list is in
1354 // reverse order because all the 'check' calls append
1355 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001356 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001357
1358 // We can continue processing this module's children to
1359 // find more cycles. Since all the modules that were
1360 // part of the found cycle were marked as visited we
1361 // won't run into that cycle again.
1362 } else {
1363 // We're not the "start" of the cycle, so we just append
1364 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001365 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001366 }
1367 }
1368 }
Colin Cross691a60d2015-01-07 18:08:56 -08001369
Colin Cross7addea32015-03-11 15:43:52 -07001370 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001371 }
1372
Colin Cross7addea32015-03-11 15:43:52 -07001373 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001374
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001375 return nil
1376 }
1377
Colin Cross7addea32015-03-11 15:43:52 -07001378 for _, module := range c.moduleInfo {
1379 if !visited[module] {
1380 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001381 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001382 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001383 panic("inconceivable!")
1384 }
1385 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001386 }
1387 }
1388 }
1389
Colin Cross7addea32015-03-11 15:43:52 -07001390 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001391
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001392 return
1393}
1394
Jamie Gennisd4e10182014-06-12 20:06:50 -07001395// PrepareBuildActions generates an internal representation of all the build
1396// actions that need to be performed. This process involves invoking the
1397// GenerateBuildActions method on each of the Module objects created during the
1398// parse phase and then on each of the registered Singleton objects.
1399//
1400// If the ResolveDependencies method has not already been called it is called
1401// automatically by this method.
1402//
1403// The config argument is made available to all of the Module and Singleton
1404// objects via the Config method on the ModuleContext and SingletonContext
1405// objects passed to GenerateBuildActions. It is also passed to the functions
1406// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1407// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001408//
1409// The returned deps is a list of the ninja files dependencies that were added
1410// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1411// SingletonContext.AddNinjaFileDeps() methods.
1412func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001413 c.buildActionsReady = false
1414
1415 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001416 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001417 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001418 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001419 }
1420 }
1421
1422 liveGlobals := newLiveTracker(config)
1423
1424 c.initSpecialVariables()
1425
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001426 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001427 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001428 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001429 }
1430
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001431 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001432 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001433 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001434 }
1435
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001436 deps = append(depsModules, depsSingletons...)
1437
Colin Crossa2599452015-11-18 16:01:01 -08001438 if c.ninjaBuildDir != nil {
1439 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001440 }
1441
1442 pkgNames := c.makeUniquePackageNames(liveGlobals)
1443
1444 // This will panic if it finds a problem since it's a programming error.
1445 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1446
1447 c.pkgNames = pkgNames
1448 c.globalVariables = liveGlobals.variables
1449 c.globalPools = liveGlobals.pools
1450 c.globalRules = liveGlobals.rules
1451
1452 c.buildActionsReady = true
1453
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001454 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001455}
1456
Colin Cross65569e42015-03-10 20:08:19 -07001457func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1458 for _, mutator := range c.earlyMutatorInfo {
1459 for _, group := range c.moduleGroups {
1460 newModules := make([]*moduleInfo, 0, len(group.modules))
1461
1462 for _, module := range group.modules {
1463 mctx := &mutatorContext{
1464 baseModuleContext: baseModuleContext{
1465 context: c,
1466 config: config,
1467 module: module,
1468 },
1469 name: mutator.name,
1470 }
1471 mutator.mutator(mctx)
1472 if len(mctx.errs) > 0 {
1473 errs = append(errs, mctx.errs...)
1474 return errs
1475 }
1476
1477 if module.splitModules != nil {
1478 newModules = append(newModules, module.splitModules...)
1479 } else {
1480 newModules = append(newModules, module)
1481 }
1482 }
1483
1484 group.modules = newModules
1485 }
1486 }
1487
Colin Cross763b6f12015-10-29 15:32:56 -07001488 errs = c.updateDependencies()
1489 if len(errs) > 0 {
1490 return errs
1491 }
1492
Colin Cross65569e42015-03-10 20:08:19 -07001493 return nil
1494}
1495
Colin Crossc9028482014-12-18 16:28:54 -08001496func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Cross763b6f12015-10-29 15:32:56 -07001497 errs = c.runEarlyMutators(config)
1498 if len(errs) > 0 {
1499 return errs
1500 }
1501
Colin Crossc9028482014-12-18 16:28:54 -08001502 for _, mutator := range c.mutatorInfo {
1503 if mutator.topDownMutator != nil {
1504 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1505 } else if mutator.bottomUpMutator != nil {
1506 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1507 } else {
1508 panic("no mutator set on " + mutator.name)
1509 }
1510 if len(errs) > 0 {
1511 return errs
1512 }
1513 }
1514
1515 return nil
1516}
1517
1518func (c *Context) runTopDownMutator(config interface{},
1519 name string, mutator TopDownMutator) (errs []error) {
1520
Colin Cross7addea32015-03-11 15:43:52 -07001521 for i := 0; i < len(c.modulesSorted); i++ {
1522 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1523 mctx := &mutatorContext{
1524 baseModuleContext: baseModuleContext{
1525 context: c,
1526 config: config,
1527 module: module,
1528 },
1529 name: name,
1530 }
Colin Crossc9028482014-12-18 16:28:54 -08001531
Colin Cross7addea32015-03-11 15:43:52 -07001532 mutator(mctx)
1533 if len(mctx.errs) > 0 {
1534 errs = append(errs, mctx.errs...)
1535 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001536 }
1537 }
1538
1539 return errs
1540}
1541
1542func (c *Context) runBottomUpMutator(config interface{},
1543 name string, mutator BottomUpMutator) (errs []error) {
1544
Colin Cross8d8a7af2015-11-03 16:41:29 -08001545 reverseDeps := make(map[*moduleInfo][]*moduleInfo)
1546
Colin Cross7addea32015-03-11 15:43:52 -07001547 for _, module := range c.modulesSorted {
1548 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001549
Jamie Gennisc7988252015-04-14 23:28:10 -04001550 if module.splitModules != nil {
1551 panic("split module found in sorted module list")
1552 }
1553
Colin Cross7addea32015-03-11 15:43:52 -07001554 mctx := &mutatorContext{
1555 baseModuleContext: baseModuleContext{
1556 context: c,
1557 config: config,
1558 module: module,
1559 },
Colin Cross8d8a7af2015-11-03 16:41:29 -08001560 name: name,
1561 reverseDeps: reverseDeps,
Colin Cross7addea32015-03-11 15:43:52 -07001562 }
Colin Crossc9028482014-12-18 16:28:54 -08001563
Colin Cross7addea32015-03-11 15:43:52 -07001564 mutator(mctx)
1565 if len(mctx.errs) > 0 {
1566 errs = append(errs, mctx.errs...)
1567 return errs
1568 }
Colin Crossc9028482014-12-18 16:28:54 -08001569
Colin Cross7addea32015-03-11 15:43:52 -07001570 // Fix up any remaining dependencies on modules that were split into variants
1571 // by replacing them with the first variant
1572 for i, dep := range module.directDeps {
1573 if dep.logicModule == nil {
1574 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001575 }
1576 }
1577
Colin Cross7addea32015-03-11 15:43:52 -07001578 if module.splitModules != nil {
1579 newModules = append(newModules, module.splitModules...)
1580 } else {
1581 newModules = append(newModules, module)
1582 }
1583
1584 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001585 }
1586
Colin Cross8d8a7af2015-11-03 16:41:29 -08001587 for module, deps := range reverseDeps {
1588 sort.Sort(moduleSorter(deps))
1589 module.directDeps = append(module.directDeps, deps...)
1590 }
1591
Jamie Gennisc7988252015-04-14 23:28:10 -04001592 errs = c.updateDependencies()
1593 if len(errs) > 0 {
1594 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001595 }
1596
1597 return errs
1598}
1599
Colin Cross7addea32015-03-11 15:43:52 -07001600func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1601 newModules []*moduleInfo) []*moduleInfo {
1602 for i, m := range modules {
1603 if m == origModule {
1604 return spliceModulesAtIndex(modules, i, newModules)
1605 }
1606 }
1607
1608 panic("failed to find original module to splice")
1609}
1610
1611func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1612 spliceSize := len(newModules)
1613 newLen := len(modules) + spliceSize - 1
1614 var dest []*moduleInfo
1615 if cap(modules) >= len(modules)-1+len(newModules) {
1616 // We can fit the splice in the existing capacity, do everything in place
1617 dest = modules[:newLen]
1618 } else {
1619 dest = make([]*moduleInfo, newLen)
1620 copy(dest, modules[:i])
1621 }
1622
1623 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001624 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001625
1626 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001627 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001628
Colin Cross72bd1932015-03-16 00:13:59 -07001629 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001630}
1631
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001632func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001633 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001634 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001635 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001636 c.requiredNinjaMicro = 0
1637}
1638
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001639func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001640 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001641
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001642 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001643 var errs []error
1644
Colin Cross691a60d2015-01-07 18:08:56 -08001645 cancelCh := make(chan struct{})
1646 errsCh := make(chan []error)
1647 depsCh := make(chan []string)
1648
1649 go func() {
1650 for {
1651 select {
1652 case <-cancelCh:
1653 close(cancelCh)
1654 return
1655 case newErrs := <-errsCh:
1656 errs = append(errs, newErrs...)
1657 case newDeps := <-depsCh:
1658 deps = append(deps, newDeps...)
1659
1660 }
1661 }
1662 }()
1663
Colin Cross7addea32015-03-11 15:43:52 -07001664 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1665 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1666 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1667 // just set it to nil.
1668 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1669 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001670
Colin Cross7addea32015-03-11 15:43:52 -07001671 mctx := &moduleContext{
1672 baseModuleContext: baseModuleContext{
1673 context: c,
1674 config: config,
1675 module: module,
1676 },
1677 scope: scope,
1678 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001679
Colin Cross7addea32015-03-11 15:43:52 -07001680 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001681
Colin Cross7addea32015-03-11 15:43:52 -07001682 if len(mctx.errs) > 0 {
1683 errsCh <- mctx.errs
1684 return true
1685 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001686
Colin Cross7addea32015-03-11 15:43:52 -07001687 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001688
Colin Crossab6d7902015-03-11 16:17:52 -07001689 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001690 &mctx.actionDefs, liveGlobals)
1691 if len(newErrs) > 0 {
1692 errsCh <- newErrs
1693 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001694 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001695 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001696 })
1697
1698 cancelCh <- struct{}{}
1699 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001700
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001701 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001702}
1703
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001704func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001705 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001706
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001707 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001708 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001709
Yuchen Wub9103ef2015-08-25 17:58:17 -07001710 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001711 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1712 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1713 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001714 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001715
1716 sctx := &singletonContext{
1717 context: c,
1718 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001719 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001720 }
1721
1722 info.singleton.GenerateBuildActions(sctx)
1723
1724 if len(sctx.errs) > 0 {
1725 errs = append(errs, sctx.errs...)
1726 if len(errs) > maxErrors {
1727 break
1728 }
1729 continue
1730 }
1731
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001732 deps = append(deps, sctx.ninjaFileDeps...)
1733
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001734 newErrs := c.processLocalBuildActions(&info.actionDefs,
1735 &sctx.actionDefs, liveGlobals)
1736 errs = append(errs, newErrs...)
1737 if len(errs) > maxErrors {
1738 break
1739 }
1740 }
1741
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001742 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001743}
1744
1745func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1746 liveGlobals *liveTracker) []error {
1747
1748 var errs []error
1749
1750 // First we go through and add everything referenced by the module's
1751 // buildDefs to the live globals set. This will end up adding the live
1752 // locals to the set as well, but we'll take them out after.
1753 for _, def := range in.buildDefs {
1754 err := liveGlobals.AddBuildDefDeps(def)
1755 if err != nil {
1756 errs = append(errs, err)
1757 }
1758 }
1759
1760 if len(errs) > 0 {
1761 return errs
1762 }
1763
Colin Crossc9028482014-12-18 16:28:54 -08001764 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001765
1766 // We use the now-incorrect set of live "globals" to determine which local
1767 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001768 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001769 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001770 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001771 if isLive {
1772 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001773 }
1774 }
1775
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001776 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001777 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001778 if isLive {
1779 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001780 }
1781 }
1782
1783 return nil
1784}
1785
Yuchen Wu222e2452015-10-06 14:03:27 -07001786func (c *Context) walkDeps(topModule *moduleInfo,
1787 visit func(Module, Module) bool) {
1788
1789 visited := make(map[*moduleInfo]bool)
1790
1791 var walk func(module *moduleInfo)
1792 walk = func(module *moduleInfo) {
1793 visited[module] = true
1794
1795 for _, moduleDep := range module.directDeps {
1796 if !visited[moduleDep] {
1797 if visit(moduleDep.logicModule, module.logicModule) {
1798 walk(moduleDep)
1799 }
1800 }
1801 }
1802 }
1803
1804 walk(topModule)
1805}
1806
Colin Crossbbfa51a2014-12-17 16:12:41 -08001807func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1808 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001809
Colin Crossbbfa51a2014-12-17 16:12:41 -08001810 var walk func(module *moduleInfo)
1811 walk = func(module *moduleInfo) {
1812 visited[module] = true
1813 for _, moduleDep := range module.directDeps {
1814 if !visited[moduleDep] {
1815 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001816 }
1817 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001818
Colin Crossbbfa51a2014-12-17 16:12:41 -08001819 if module != topModule {
1820 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001821 }
1822 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001823
1824 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001825}
1826
Colin Crossbbfa51a2014-12-17 16:12:41 -08001827func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001828 visit func(Module)) {
1829
Colin Crossbbfa51a2014-12-17 16:12:41 -08001830 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001831
Colin Crossbbfa51a2014-12-17 16:12:41 -08001832 var walk func(module *moduleInfo)
1833 walk = func(module *moduleInfo) {
1834 visited[module] = true
1835 for _, moduleDep := range module.directDeps {
1836 if !visited[moduleDep] {
1837 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001838 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001839 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001840
1841 if module != topModule {
1842 if pred(module.logicModule) {
1843 visit(module.logicModule)
1844 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001845 }
1846 }
1847
Colin Crossbbfa51a2014-12-17 16:12:41 -08001848 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001849}
1850
Colin Crossc9028482014-12-18 16:28:54 -08001851func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1852 for _, dep := range module.directDeps {
1853 visit(dep.logicModule)
1854 }
1855}
1856
1857func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1858 visit func(Module)) {
1859
1860 for _, dep := range module.directDeps {
1861 if pred(dep.logicModule) {
1862 visit(dep.logicModule)
1863 }
1864 }
1865}
1866
Jamie Gennisc15544d2014-09-24 20:26:52 -07001867func (c *Context) sortedModuleNames() []string {
1868 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001869 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1870 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001871 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1872 moduleName)
1873 }
1874 sort.Strings(c.cachedSortedModuleNames)
1875 }
1876
1877 return c.cachedSortedModuleNames
1878}
1879
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001880func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001881 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001882 group := c.moduleGroups[moduleName]
1883 for _, module := range group.modules {
1884 visit(module.logicModule)
1885 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001886 }
1887}
1888
1889func (c *Context) visitAllModulesIf(pred func(Module) bool,
1890 visit func(Module)) {
1891
Jamie Gennisc15544d2014-09-24 20:26:52 -07001892 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001893 group := c.moduleGroups[moduleName]
1894 for _, module := range group.modules {
1895 if pred(module.logicModule) {
1896 visit(module.logicModule)
1897 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001898 }
1899 }
1900}
1901
1902func (c *Context) requireNinjaVersion(major, minor, micro int) {
1903 if major != 1 {
1904 panic("ninja version with major version != 1 not supported")
1905 }
1906 if c.requiredNinjaMinor < minor {
1907 c.requiredNinjaMinor = minor
1908 c.requiredNinjaMicro = micro
1909 }
1910 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1911 c.requiredNinjaMicro = micro
1912 }
1913}
1914
Colin Crossa2599452015-11-18 16:01:01 -08001915func (c *Context) setNinjaBuildDir(value *ninjaString) {
1916 if c.ninjaBuildDir == nil {
1917 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001918 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001919}
1920
1921func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001922 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001923
Jamie Gennis2fb20952014-10-03 02:49:58 -07001924 pkgs := make(map[string]*PackageContext)
1925 pkgNames := make(map[*PackageContext]string)
1926 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927
Jamie Gennis2fb20952014-10-03 02:49:58 -07001928 processPackage := func(pctx *PackageContext) {
1929 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930 // This is a built-in rule and has no package.
1931 return
1932 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001933 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001934 // We've already processed this package.
1935 return
1936 }
1937
Jamie Gennis2fb20952014-10-03 02:49:58 -07001938 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001939 if present {
1940 // Short name collision. Both this package and the one that's
1941 // already there need to use their full names. We leave the short
1942 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001943 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001944 longPkgNames[otherPkg] = true
1945 } else {
1946 // No collision so far. Tentatively set the package's name to be
1947 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001948 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07001949 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001950 }
1951 }
1952
1953 // We try to give all packages their short name, but when we get collisions
1954 // we need to use the full unique package name.
1955 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001956 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001957 }
1958 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001959 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001960 }
1961 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001962 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001963 }
1964
1965 // Add the packages that had collisions using their full unique names. This
1966 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001967 for pctx := range longPkgNames {
1968 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001969 }
1970
1971 return pkgNames
1972}
1973
1974func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001975 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001976
1977 visited := make(map[Variable]bool) // variables that were already checked
1978 checking := make(map[Variable]bool) // variables actively being checked
1979
1980 var check func(v Variable) []Variable
1981
1982 check = func(v Variable) []Variable {
1983 visited[v] = true
1984 checking[v] = true
1985 defer delete(checking, v)
1986
1987 value := variables[v]
1988 for _, dep := range value.variables {
1989 if checking[dep] {
1990 // This is a cycle.
1991 return []Variable{dep, v}
1992 }
1993
1994 if !visited[dep] {
1995 cycle := check(dep)
1996 if cycle != nil {
1997 if cycle[0] == v {
1998 // We are the "start" of the cycle, so we're responsible
1999 // for generating the errors. The cycle list is in
2000 // reverse order because all the 'check' calls append
2001 // their own module to the list.
2002 msgs := []string{"detected variable reference cycle:"}
2003
2004 // Iterate backwards through the cycle list.
2005 curName := v.fullName(pkgNames)
2006 curValue := value.Value(pkgNames)
2007 for i := len(cycle) - 1; i >= 0; i-- {
2008 next := cycle[i]
2009 nextName := next.fullName(pkgNames)
2010 nextValue := variables[next].Value(pkgNames)
2011
2012 msgs = append(msgs, fmt.Sprintf(
2013 " %q depends on %q", curName, nextName))
2014 msgs = append(msgs, fmt.Sprintf(
2015 " [%s = %s]", curName, curValue))
2016
2017 curName = nextName
2018 curValue = nextValue
2019 }
2020
2021 // Variable reference cycles are a programming error,
2022 // not the fault of the Blueprint file authors.
2023 panic(strings.Join(msgs, "\n"))
2024 } else {
2025 // We're not the "start" of the cycle, so we just append
2026 // our module to the list and return it.
2027 return append(cycle, v)
2028 }
2029 }
2030 }
2031 }
2032
2033 return nil
2034 }
2035
2036 for v := range variables {
2037 if !visited[v] {
2038 cycle := check(v)
2039 if cycle != nil {
2040 panic("inconceivable!")
2041 }
2042 }
2043 }
2044}
2045
Jamie Gennisaf435562014-10-27 22:34:56 -07002046// AllTargets returns a map all the build target names to the rule used to build
2047// them. This is the same information that is output by running 'ninja -t
2048// targets all'. If this is called before PrepareBuildActions successfully
2049// completes then ErrbuildActionsNotReady is returned.
2050func (c *Context) AllTargets() (map[string]string, error) {
2051 if !c.buildActionsReady {
2052 return nil, ErrBuildActionsNotReady
2053 }
2054
2055 targets := map[string]string{}
2056
2057 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002058 for _, module := range c.moduleInfo {
2059 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002060 ruleName := buildDef.Rule.fullName(c.pkgNames)
2061 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002062 outputValue, err := output.Eval(c.globalVariables)
2063 if err != nil {
2064 return nil, err
2065 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002066 targets[outputValue] = ruleName
2067 }
2068 }
2069 }
2070
2071 // Collect all the singleton build targets.
2072 for _, info := range c.singletonInfo {
2073 for _, buildDef := range info.actionDefs.buildDefs {
2074 ruleName := buildDef.Rule.fullName(c.pkgNames)
2075 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002076 outputValue, err := output.Eval(c.globalVariables)
2077 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002078 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002079 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002080 targets[outputValue] = ruleName
2081 }
2082 }
2083 }
2084
2085 return targets, nil
2086}
2087
Colin Crossa2599452015-11-18 16:01:01 -08002088func (c *Context) NinjaBuildDir() (string, error) {
2089 if c.ninjaBuildDir != nil {
2090 return c.ninjaBuildDir.Eval(c.globalVariables)
2091 } else {
2092 return "", nil
2093 }
2094}
2095
Colin Cross4572edd2015-05-13 14:36:24 -07002096// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2097// property structs returned by the factory for that module type.
2098func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2099 ret := make(map[string][]interface{})
2100 for moduleType, factory := range c.moduleFactories {
2101 _, ret[moduleType] = factory()
2102 }
2103
2104 return ret
2105}
2106
2107func (c *Context) ModuleName(logicModule Module) string {
2108 module := c.moduleInfo[logicModule]
2109 return module.properties.Name
2110}
2111
2112func (c *Context) ModuleDir(logicModule Module) string {
2113 module := c.moduleInfo[logicModule]
2114 return filepath.Dir(module.relBlueprintsFile)
2115}
2116
2117func (c *Context) BlueprintFile(logicModule Module) string {
2118 module := c.moduleInfo[logicModule]
2119 return module.relBlueprintsFile
2120}
2121
2122func (c *Context) ModuleErrorf(logicModule Module, format string,
2123 args ...interface{}) error {
2124
2125 module := c.moduleInfo[logicModule]
2126 return &Error{
2127 Err: fmt.Errorf(format, args...),
2128 Pos: module.pos,
2129 }
2130}
2131
2132func (c *Context) VisitAllModules(visit func(Module)) {
2133 c.visitAllModules(visit)
2134}
2135
2136func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2137 visit func(Module)) {
2138
2139 c.visitAllModulesIf(pred, visit)
2140}
2141
2142func (c *Context) VisitDepsDepthFirst(module Module,
2143 visit func(Module)) {
2144
2145 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2146}
2147
2148func (c *Context) VisitDepsDepthFirstIf(module Module,
2149 pred func(Module) bool, visit func(Module)) {
2150
2151 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2152}
2153
Colin Cross24ad5872015-11-17 16:22:29 -08002154func (c *Context) PrimaryModule(module Module) Module {
2155 return c.moduleInfo[module].group.modules[0].logicModule
2156}
2157
2158func (c *Context) FinalModule(module Module) Module {
2159 modules := c.moduleInfo[module].group.modules
2160 return modules[len(modules)-1].logicModule
2161}
2162
2163func (c *Context) VisitAllModuleVariants(module Module,
2164 visit func(Module)) {
2165
2166 for _, module := range c.moduleInfo[module].group.modules {
2167 visit(module.logicModule)
2168 }
2169}
2170
Jamie Gennisd4e10182014-06-12 20:06:50 -07002171// WriteBuildFile writes the Ninja manifeset text for the generated build
2172// actions to w. If this is called before PrepareBuildActions successfully
2173// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002174func (c *Context) WriteBuildFile(w io.Writer) error {
2175 if !c.buildActionsReady {
2176 return ErrBuildActionsNotReady
2177 }
2178
2179 nw := newNinjaWriter(w)
2180
2181 err := c.writeBuildFileHeader(nw)
2182 if err != nil {
2183 return err
2184 }
2185
2186 err = c.writeNinjaRequiredVersion(nw)
2187 if err != nil {
2188 return err
2189 }
2190
2191 // TODO: Group the globals by package.
2192
2193 err = c.writeGlobalVariables(nw)
2194 if err != nil {
2195 return err
2196 }
2197
2198 err = c.writeGlobalPools(nw)
2199 if err != nil {
2200 return err
2201 }
2202
2203 err = c.writeBuildDir(nw)
2204 if err != nil {
2205 return err
2206 }
2207
2208 err = c.writeGlobalRules(nw)
2209 if err != nil {
2210 return err
2211 }
2212
2213 err = c.writeAllModuleActions(nw)
2214 if err != nil {
2215 return err
2216 }
2217
2218 err = c.writeAllSingletonActions(nw)
2219 if err != nil {
2220 return err
2221 }
2222
2223 return nil
2224}
2225
Jamie Gennisc15544d2014-09-24 20:26:52 -07002226type pkgAssociation struct {
2227 PkgName string
2228 PkgPath string
2229}
2230
2231type pkgAssociationSorter struct {
2232 pkgs []pkgAssociation
2233}
2234
2235func (s *pkgAssociationSorter) Len() int {
2236 return len(s.pkgs)
2237}
2238
2239func (s *pkgAssociationSorter) Less(i, j int) bool {
2240 iName := s.pkgs[i].PkgName
2241 jName := s.pkgs[j].PkgName
2242 return iName < jName
2243}
2244
2245func (s *pkgAssociationSorter) Swap(i, j int) {
2246 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2247}
2248
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002249func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2250 headerTemplate := template.New("fileHeader")
2251 _, err := headerTemplate.Parse(fileHeaderTemplate)
2252 if err != nil {
2253 // This is a programming error.
2254 panic(err)
2255 }
2256
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002257 var pkgs []pkgAssociation
2258 maxNameLen := 0
2259 for pkg, name := range c.pkgNames {
2260 pkgs = append(pkgs, pkgAssociation{
2261 PkgName: name,
2262 PkgPath: pkg.pkgPath,
2263 })
2264 if len(name) > maxNameLen {
2265 maxNameLen = len(name)
2266 }
2267 }
2268
2269 for i := range pkgs {
2270 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2271 }
2272
Jamie Gennisc15544d2014-09-24 20:26:52 -07002273 sort.Sort(&pkgAssociationSorter{pkgs})
2274
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002275 params := map[string]interface{}{
2276 "Pkgs": pkgs,
2277 }
2278
2279 buf := bytes.NewBuffer(nil)
2280 err = headerTemplate.Execute(buf, params)
2281 if err != nil {
2282 return err
2283 }
2284
2285 return nw.Comment(buf.String())
2286}
2287
2288func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2289 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2290 c.requiredNinjaMicro)
2291
2292 err := nw.Assign("ninja_required_version", value)
2293 if err != nil {
2294 return err
2295 }
2296
2297 return nw.BlankLine()
2298}
2299
2300func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002301 if c.ninjaBuildDir != nil {
2302 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002303 if err != nil {
2304 return err
2305 }
2306
2307 err = nw.BlankLine()
2308 if err != nil {
2309 return err
2310 }
2311 }
2312 return nil
2313}
2314
Jamie Gennisc15544d2014-09-24 20:26:52 -07002315type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002316 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002317}
2318
Jamie Gennisc15544d2014-09-24 20:26:52 -07002319type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002320 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002321 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002322}
2323
Jamie Gennisc15544d2014-09-24 20:26:52 -07002324func (s *globalEntitySorter) Len() int {
2325 return len(s.entities)
2326}
2327
2328func (s *globalEntitySorter) Less(i, j int) bool {
2329 iName := s.entities[i].fullName(s.pkgNames)
2330 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002331 return iName < jName
2332}
2333
Jamie Gennisc15544d2014-09-24 20:26:52 -07002334func (s *globalEntitySorter) Swap(i, j int) {
2335 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002336}
2337
2338func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2339 visited := make(map[Variable]bool)
2340
2341 var walk func(v Variable) error
2342 walk = func(v Variable) error {
2343 visited[v] = true
2344
2345 // First visit variables on which this variable depends.
2346 value := c.globalVariables[v]
2347 for _, dep := range value.variables {
2348 if !visited[dep] {
2349 err := walk(dep)
2350 if err != nil {
2351 return err
2352 }
2353 }
2354 }
2355
2356 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2357 if err != nil {
2358 return err
2359 }
2360
2361 err = nw.BlankLine()
2362 if err != nil {
2363 return err
2364 }
2365
2366 return nil
2367 }
2368
Jamie Gennisc15544d2014-09-24 20:26:52 -07002369 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2370 for variable := range c.globalVariables {
2371 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002372 }
2373
Jamie Gennisc15544d2014-09-24 20:26:52 -07002374 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002375
Jamie Gennisc15544d2014-09-24 20:26:52 -07002376 for _, entity := range globalVariables {
2377 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002378 if !visited[v] {
2379 err := walk(v)
2380 if err != nil {
2381 return nil
2382 }
2383 }
2384 }
2385
2386 return nil
2387}
2388
2389func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002390 globalPools := make([]globalEntity, 0, len(c.globalPools))
2391 for pool := range c.globalPools {
2392 globalPools = append(globalPools, pool)
2393 }
2394
2395 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2396
2397 for _, entity := range globalPools {
2398 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002399 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002400 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002401 err := def.WriteTo(nw, name)
2402 if err != nil {
2403 return err
2404 }
2405
2406 err = nw.BlankLine()
2407 if err != nil {
2408 return err
2409 }
2410 }
2411
2412 return nil
2413}
2414
2415func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002416 globalRules := make([]globalEntity, 0, len(c.globalRules))
2417 for rule := range c.globalRules {
2418 globalRules = append(globalRules, rule)
2419 }
2420
2421 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2422
2423 for _, entity := range globalRules {
2424 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002425 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002426 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002427 err := def.WriteTo(nw, name, c.pkgNames)
2428 if err != nil {
2429 return err
2430 }
2431
2432 err = nw.BlankLine()
2433 if err != nil {
2434 return err
2435 }
2436 }
2437
2438 return nil
2439}
2440
Colin Crossab6d7902015-03-11 16:17:52 -07002441type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002442
Colin Crossab6d7902015-03-11 16:17:52 -07002443func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002444 return len(s)
2445}
2446
Colin Crossab6d7902015-03-11 16:17:52 -07002447func (s moduleSorter) Less(i, j int) bool {
2448 iName := s[i].properties.Name
2449 jName := s[j].properties.Name
2450 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002451 iName = s[i].variantName
2452 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002453 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002454 return iName < jName
2455}
2456
Colin Crossab6d7902015-03-11 16:17:52 -07002457func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002458 s[i], s[j] = s[j], s[i]
2459}
2460
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002461func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2462 headerTemplate := template.New("moduleHeader")
2463 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2464 if err != nil {
2465 // This is a programming error.
2466 panic(err)
2467 }
2468
Colin Crossab6d7902015-03-11 16:17:52 -07002469 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2470 for _, module := range c.moduleInfo {
2471 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002472 }
Colin Crossab6d7902015-03-11 16:17:52 -07002473 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002474
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002475 buf := bytes.NewBuffer(nil)
2476
Colin Crossab6d7902015-03-11 16:17:52 -07002477 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002478 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2479 continue
2480 }
2481
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002482 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002483
2484 // In order to make the bootstrap build manifest independent of the
2485 // build dir we need to output the Blueprints file locations in the
2486 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002487 relPos := module.pos
2488 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002489
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002490 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002491 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002492 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2493 factoryName := factoryFunc.Name()
2494
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002495 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002496 "properties": module.properties,
2497 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002498 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002499 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002500 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002501 }
2502 err = headerTemplate.Execute(buf, infoMap)
2503 if err != nil {
2504 return err
2505 }
2506
2507 err = nw.Comment(buf.String())
2508 if err != nil {
2509 return err
2510 }
2511
2512 err = nw.BlankLine()
2513 if err != nil {
2514 return err
2515 }
2516
Colin Crossab6d7902015-03-11 16:17:52 -07002517 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002518 if err != nil {
2519 return err
2520 }
2521
2522 err = nw.BlankLine()
2523 if err != nil {
2524 return err
2525 }
2526 }
2527
2528 return nil
2529}
2530
2531func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2532 headerTemplate := template.New("singletonHeader")
2533 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2534 if err != nil {
2535 // This is a programming error.
2536 panic(err)
2537 }
2538
2539 buf := bytes.NewBuffer(nil)
2540
Yuchen Wub9103ef2015-08-25 17:58:17 -07002541 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002542 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2543 continue
2544 }
2545
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002546 // Get the name of the factory function for the module.
2547 factory := info.factory
2548 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2549 factoryName := factoryFunc.Name()
2550
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002551 buf.Reset()
2552 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002553 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002554 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002555 }
2556 err = headerTemplate.Execute(buf, infoMap)
2557 if err != nil {
2558 return err
2559 }
2560
2561 err = nw.Comment(buf.String())
2562 if err != nil {
2563 return err
2564 }
2565
2566 err = nw.BlankLine()
2567 if err != nil {
2568 return err
2569 }
2570
2571 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2572 if err != nil {
2573 return err
2574 }
2575
2576 err = nw.BlankLine()
2577 if err != nil {
2578 return err
2579 }
2580 }
2581
2582 return nil
2583}
2584
2585func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2586 defs *localBuildActions) error {
2587
2588 // Write the local variable assignments.
2589 for _, v := range defs.variables {
2590 // A localVariable doesn't need the package names or config to
2591 // determine its name or value.
2592 name := v.fullName(nil)
2593 value, err := v.value(nil)
2594 if err != nil {
2595 panic(err)
2596 }
2597 err = nw.Assign(name, value.Value(c.pkgNames))
2598 if err != nil {
2599 return err
2600 }
2601 }
2602
2603 if len(defs.variables) > 0 {
2604 err := nw.BlankLine()
2605 if err != nil {
2606 return err
2607 }
2608 }
2609
2610 // Write the local rules.
2611 for _, r := range defs.rules {
2612 // A localRule doesn't need the package names or config to determine
2613 // its name or definition.
2614 name := r.fullName(nil)
2615 def, err := r.def(nil)
2616 if err != nil {
2617 panic(err)
2618 }
2619
2620 err = def.WriteTo(nw, name, c.pkgNames)
2621 if err != nil {
2622 return err
2623 }
2624
2625 err = nw.BlankLine()
2626 if err != nil {
2627 return err
2628 }
2629 }
2630
2631 // Write the build definitions.
2632 for _, buildDef := range defs.buildDefs {
2633 err := buildDef.WriteTo(nw, c.pkgNames)
2634 if err != nil {
2635 return err
2636 }
2637
2638 if len(buildDef.Args) > 0 {
2639 err = nw.BlankLine()
2640 if err != nil {
2641 return err
2642 }
2643 }
2644 }
2645
2646 return nil
2647}
2648
Colin Cross65569e42015-03-10 20:08:19 -07002649func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2650 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002651 if a == b {
2652 return false
2653 }
Colin Cross65569e42015-03-10 20:08:19 -07002654 for _, l := range list {
2655 if l == a {
2656 found = true
2657 } else if l == b {
2658 return found
2659 }
2660 }
2661
2662 missing := a
2663 if found {
2664 missing = b
2665 }
2666 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2667}
2668
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002669var fileHeaderTemplate = `******************************************************************************
2670*** This file is generated and should not be edited ***
2671******************************************************************************
2672{{if .Pkgs}}
2673This file contains variables, rules, and pools with name prefixes indicating
2674they were generated by the following Go packages:
2675{{range .Pkgs}}
2676 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2677
2678`
2679
2680var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2681Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002682Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002683Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002684Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002685Defined: {{.pos}}
2686`
2687
2688var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2689Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002690Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002691`