blob: 31541da08daf64a3d034cf41c7154f3a87852320 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "errors"
20 "fmt"
21 "io"
22 "os"
23 "path/filepath"
24 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070025 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070026 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080027 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "strings"
Colin Cross23d7aa12015-06-30 16:05:22 -070029 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "text/scanner"
31 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070032
33 "github.com/google/blueprint/parser"
34 "github.com/google/blueprint/pathtools"
35 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070036)
37
38var ErrBuildActionsNotReady = errors.New("build actions are not ready")
39
40const maxErrors = 10
41
Jamie Gennisd4e10182014-06-12 20:06:50 -070042// A Context contains all the state needed to parse a set of Blueprints files
43// and generate a Ninja file. The process of generating a Ninja file proceeds
44// through a series of four phases. Each phase corresponds with a some methods
45// on the Context object
46//
47// Phase Methods
48// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070049// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070050//
51// 2. Parse ParseBlueprintsFiles, Parse
52//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 4. Write WriteBuildFile
56//
57// The registration phase prepares the context to process Blueprints files
58// containing various types of modules. The parse phase reads in one or more
59// Blueprints files and validates their contents against the module types that
60// have been registered. The generate phase then analyzes the parsed Blueprints
61// contents to create an internal representation for the build actions that must
62// be performed. This phase also performs validation of the module dependencies
63// and property values defined in the parsed Blueprints files. Finally, the
64// write phase generates the Ninja manifest text based on the generated build
65// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066type Context struct {
67 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070068 moduleFactories map[string]ModuleFactory
69 moduleGroups map[string]*moduleGroup
70 moduleInfo map[Module]*moduleInfo
71 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070072 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070073 mutatorInfo []*mutatorInfo
74 earlyMutatorInfo []*earlyMutatorInfo
75 variantMutatorNames []string
76 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070077
78 dependenciesReady bool // set to true on a successful ResolveDependencies
79 buildActionsReady bool // set to true on a successful PrepareBuildActions
80
81 // set by SetIgnoreUnknownModuleTypes
82 ignoreUnknownModuleTypes bool
83
Colin Cross036a1df2015-12-17 15:49:30 -080084 // set by SetAllowMissingDependencies
85 allowMissingDependencies bool
86
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080088 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070089 globalVariables map[Variable]*ninjaString
90 globalPools map[Pool]*poolDef
91 globalRules map[Rule]*ruleDef
92
93 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080094 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095 requiredNinjaMajor int // For the ninja_required_version variable
96 requiredNinjaMinor int // For the ninja_required_version variable
97 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070098
99 // set lazily by sortedModuleNames
100 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101}
102
Jamie Gennisd4e10182014-06-12 20:06:50 -0700103// An Error describes a problem that was encountered that is related to a
104// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700106 Err error // the error that occurred
107 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700108}
109
110type localBuildActions struct {
111 variables []*localVariable
112 rules []*localRule
113 buildDefs []*buildDef
114}
115
Colin Crossbbfa51a2014-12-17 16:12:41 -0800116type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700117 name string
118 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119
Colin Crossbbfa51a2014-12-17 16:12:41 -0800120 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700121}
122
Colin Crossbbfa51a2014-12-17 16:12:41 -0800123type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700124 // set during Parse
125 typeName string
126 relBlueprintsFile string
127 pos scanner.Position
128 propertyPos map[string]scanner.Position
129 properties struct {
130 Name string
131 Deps []string
132 }
133
Colin Crossf5e34b92015-03-13 16:02:36 -0700134 variantName string
135 variant variationMap
136 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700137
Colin Crossc9028482014-12-18 16:28:54 -0800138 logicModule Module
139 group *moduleGroup
140 moduleProperties []interface{}
141
142 // set during ResolveDependencies
Colin Cross036a1df2015-12-17 15:49:30 -0800143 directDeps []*moduleInfo
144 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800145
Colin Cross7addea32015-03-11 15:43:52 -0700146 // set during updateDependencies
147 reverseDeps []*moduleInfo
148 depsCount int
149
150 // used by parallelVisitAllBottomUp
151 waitingCount int
152
Colin Crossc9028482014-12-18 16:28:54 -0800153 // set during each runMutator
154 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700155
156 // set during PrepareBuildActions
157 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800158}
159
Colin Crossf5e34b92015-03-13 16:02:36 -0700160// A Variation is a way that a variant of a module differs from other variants of the same module.
161// For example, two variants of the same module might have Variation{"arch","arm"} and
162// Variation{"arch","arm64"}
163type Variation struct {
164 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700165 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700166 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
167 // "shared" or "static" for link.
168 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700169}
170
Colin Crossf5e34b92015-03-13 16:02:36 -0700171// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
172type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700173
Colin Crossf5e34b92015-03-13 16:02:36 -0700174func (vm variationMap) clone() variationMap {
175 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700176 for k, v := range vm {
177 newVm[k] = v
178 }
179
180 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800181}
182
Colin Cross89486232015-05-08 11:14:54 -0700183// Compare this variationMap to another one. Returns true if the every entry in this map
184// is either the same in the other map or doesn't exist in the other map.
185func (vm variationMap) subset(other variationMap) bool {
186 for k, v1 := range vm {
187 if v2, ok := other[k]; ok && v1 != v2 {
188 return false
189 }
190 }
191 return true
192}
193
Colin Crossf5e34b92015-03-13 16:02:36 -0700194func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700195 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800196}
197
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700198type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700199 // set during RegisterSingletonType
200 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700201 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700202 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700203
204 // set during PrepareBuildActions
205 actionDefs localBuildActions
206}
207
Colin Crossc9028482014-12-18 16:28:54 -0800208type mutatorInfo struct {
209 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800210 topDownMutator TopDownMutator
211 bottomUpMutator BottomUpMutator
212 name string
Colin Crossc9028482014-12-18 16:28:54 -0800213}
214
Colin Cross65569e42015-03-10 20:08:19 -0700215type earlyMutatorInfo struct {
216 // set during RegisterEarlyMutator
217 mutator EarlyMutator
218 name string
219}
220
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700221func (e *Error) Error() string {
222
223 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
224}
225
Jamie Gennisd4e10182014-06-12 20:06:50 -0700226// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700227// no module or singleton factories registered, so the RegisterModuleFactory and
228// RegisterSingletonFactory methods must be called before it can do anything
229// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700230func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700231 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800232 moduleFactories: make(map[string]ModuleFactory),
233 moduleGroups: make(map[string]*moduleGroup),
234 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800235 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700236 }
Colin Cross763b6f12015-10-29 15:32:56 -0700237
238 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
239
240 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700241}
242
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700243// A ModuleFactory function creates a new Module object. See the
244// Context.RegisterModuleType method for details about how a registered
245// ModuleFactory is used by a Context.
246type ModuleFactory func() (m Module, propertyStructs []interface{})
247
Jamie Gennisd4e10182014-06-12 20:06:50 -0700248// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700249// Blueprints file) with a Module factory function. When the given module type
250// name is encountered in a Blueprints file during parsing, the Module factory
251// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800252// generation for the module. If a Mutator splits a module into multiple variants,
253// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700254//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700255// The module type names given here must be unique for the context. The factory
256// function should be a named function so that its package and name can be
257// included in the generated Ninja file for debugging purposes.
258//
259// The factory function returns two values. The first is the newly created
260// Module object. The second is a slice of pointers to that Module object's
261// properties structs. Each properties struct is examined when parsing a module
262// definition of this type in a Blueprints file. Exported fields of the
263// properties structs are automatically set to the property values specified in
264// the Blueprints file. The properties struct field names determine the name of
265// the Blueprints file properties that are used - the Blueprints property name
266// matches that of the properties struct field name with the first letter
267// converted to lower-case.
268//
269// The fields of the properties struct must be either []string, a string, or
270// bool. The Context will panic if a Module gets instantiated with a properties
271// struct containing a field that is not one these supported types.
272//
273// Any properties that appear in the Blueprints files that are not built-in
274// module properties (such as "name" and "deps") and do not have a corresponding
275// field in the returned module properties struct result in an error during the
276// Context's parse phase.
277//
278// As an example, the follow code:
279//
280// type myModule struct {
281// properties struct {
282// Foo string
283// Bar []string
284// }
285// }
286//
287// func NewMyModule() (blueprint.Module, []interface{}) {
288// module := new(myModule)
289// properties := &module.properties
290// return module, []interface{}{properties}
291// }
292//
293// func main() {
294// ctx := blueprint.NewContext()
295// ctx.RegisterModuleType("my_module", NewMyModule)
296// // ...
297// }
298//
299// would support parsing a module defined in a Blueprints file as follows:
300//
301// my_module {
302// name: "myName",
303// foo: "my foo string",
304// bar: ["my", "bar", "strings"],
305// }
306//
Colin Cross7ad621c2015-01-07 16:22:45 -0800307// The factory function may be called from multiple goroutines. Any accesses
308// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700309func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
310 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700311 panic(errors.New("module type name is already registered"))
312 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700313 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700314}
315
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700316// A SingletonFactory function creates a new Singleton object. See the
317// Context.RegisterSingletonType method for details about how a registered
318// SingletonFactory is used by a Context.
319type SingletonFactory func() Singleton
320
321// RegisterSingletonType registers a singleton type that will be invoked to
322// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700323// and invoked exactly once as part of the generate phase. Each registered
324// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700325//
326// The singleton type names given here must be unique for the context. The
327// factory function should be a named function so that its package and name can
328// be included in the generated Ninja file for debugging purposes.
329func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700330 for _, s := range c.singletonInfo {
331 if s.name == name {
332 panic(errors.New("singleton name is already registered"))
333 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700334 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700335
Yuchen Wub9103ef2015-08-25 17:58:17 -0700336 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700337 factory: factory,
338 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700339 name: name,
340 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700341}
342
343func singletonPkgPath(singleton Singleton) string {
344 typ := reflect.TypeOf(singleton)
345 for typ.Kind() == reflect.Ptr {
346 typ = typ.Elem()
347 }
348 return typ.PkgPath()
349}
350
351func singletonTypeName(singleton Singleton) string {
352 typ := reflect.TypeOf(singleton)
353 for typ.Kind() == reflect.Ptr {
354 typ = typ.Elem()
355 }
356 return typ.PkgPath() + "." + typ.Name()
357}
358
Colin Crossc9028482014-12-18 16:28:54 -0800359// RegisterTopDownMutator registers a mutator that will be invoked to propagate
360// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700361// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
362// once per Module, and is invoked on a module before being invoked on any of its
363// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800364//
Colin Cross65569e42015-03-10 20:08:19 -0700365// The mutator type names given here must be unique to all top down mutators in
366// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800367func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
368 for _, m := range c.mutatorInfo {
369 if m.name == name && m.topDownMutator != nil {
370 panic(fmt.Errorf("mutator name %s is already registered", name))
371 }
372 }
373
374 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
375 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800376 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800377 })
378}
379
380// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700381// Modules into variants. Each registered mutator is invoked in registration
382// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
383// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800384//
Colin Cross65569e42015-03-10 20:08:19 -0700385// The mutator type names given here must be unique to all bottom up or early
386// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800387func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700388 for _, m := range c.variantMutatorNames {
389 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800390 panic(fmt.Errorf("mutator name %s is already registered", name))
391 }
392 }
393
394 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
395 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800396 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800397 })
Colin Cross65569e42015-03-10 20:08:19 -0700398
399 c.variantMutatorNames = append(c.variantMutatorNames, name)
400}
401
402// RegisterEarlyMutator registers a mutator that will be invoked to split
403// Modules into multiple variant Modules before any dependencies have been
404// created. Each registered mutator is invoked in registration order once
405// per Module (including each variant from previous early mutators). Module
406// order is unpredictable.
407//
408// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700409// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700410//
411// The mutator type names given here must be unique to all bottom up or early
412// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700413//
414// Deprecated, use a BottomUpMutator instead. The only difference between
415// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
416// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700417func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
418 for _, m := range c.variantMutatorNames {
419 if m == name {
420 panic(fmt.Errorf("mutator name %s is already registered", name))
421 }
422 }
423
424 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
425 mutator: mutator,
426 name: name,
427 })
428
429 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800430}
431
Jamie Gennisd4e10182014-06-12 20:06:50 -0700432// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
433// where it encounters an unknown module type while parsing Blueprints files. By
434// default, the context will report unknown module types as an error. If this
435// method is called with ignoreUnknownModuleTypes set to true then the context
436// will silently ignore unknown module types.
437//
438// This method should generally not be used. It exists to facilitate the
439// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700440func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
441 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
442}
443
Colin Cross036a1df2015-12-17 15:49:30 -0800444// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
445// unresolved dependencies. If the module's GenerateBuildActions calls
446// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
447// for missing dependencies.
448func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
449 c.allowMissingDependencies = allowMissingDependencies
450}
451
Jamie Gennisd4e10182014-06-12 20:06:50 -0700452// Parse parses a single Blueprints file from r, creating Module objects for
453// each of the module definitions encountered. If the Blueprints file contains
454// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700455// searched for Blueprints files returned in the subBlueprints return value.
456// If the Blueprints file contains an assignment to the "build" variable, then
457// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700458//
459// rootDir specifies the path to the root directory of the source tree, while
460// filename specifies the path to the Blueprints file. These paths are used for
461// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800462func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700463 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700464 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700465
Jamie Gennisec701282014-06-12 20:06:31 -0700466 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700467 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700468 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700469 }
470
Colin Crossc0dbc552015-01-02 15:19:28 -0800471 scope = parser.NewScope(scope)
472 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800473 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700474 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700475 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700476 if len(errs) > 0 {
477 for i, err := range errs {
478 if parseErr, ok := err.(*parser.ParseError); ok {
479 err = &Error{
480 Err: parseErr.Err,
481 Pos: parseErr.Pos,
482 }
483 errs[i] = err
484 }
485 }
486
487 // If there were any parse errors don't bother trying to interpret the
488 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700489 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700490 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700491 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700492
Colin Cross6d8780f2015-07-10 17:51:55 -0700493 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700494 if err != nil {
495 errs = append(errs, err)
496 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700497
Colin Cross7f507402015-12-16 13:03:41 -0800498 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
499 if err != nil {
500 errs = append(errs, err)
501 }
502
Colin Cross6d8780f2015-07-10 17:51:55 -0700503 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700504 if err != nil {
505 errs = append(errs, err)
506 }
507
Colin Cross29394222015-04-27 13:18:21 -0700508 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
509
Colin Cross7f507402015-12-16 13:03:41 -0800510 var blueprints []string
511
512 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
513 blueprints = append(blueprints, newBlueprints...)
514 deps = append(deps, newDeps...)
515 errs = append(errs, newErrs...)
516
517 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
518 subBlueprintsName, false)
519 blueprints = append(blueprints, newBlueprints...)
520 deps = append(deps, newDeps...)
521 errs = append(errs, newErrs...)
522
523 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
524 optionalSubdirsPos, subBlueprintsName, true)
525 blueprints = append(blueprints, newBlueprints...)
526 deps = append(deps, newDeps...)
527 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800528
Colin Cross1fef5362015-04-20 16:50:54 -0700529 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
530 for i, b := range blueprints {
531 subBlueprintsAndScope[i] = stringAndScope{b, scope}
532 }
533
Colin Cross23d7aa12015-06-30 16:05:22 -0700534 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800535}
536
Colin Cross7ad621c2015-01-07 16:22:45 -0800537type stringAndScope struct {
538 string
539 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700540}
541
Jamie Gennisd4e10182014-06-12 20:06:50 -0700542// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
543// at rootFile. When it encounters a Blueprints file with a set of subdirs
544// listed it recursively parses any Blueprints files found in those
545// subdirectories.
546//
547// If no errors are encountered while parsing the files, the list of paths on
548// which the future output will depend is returned. This list will include both
549// Blueprints file paths as well as directory paths for cases where wildcard
550// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700551func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
552 errs []error) {
553
Colin Cross7ad621c2015-01-07 16:22:45 -0800554 c.dependenciesReady = false
555
Colin Cross23d7aa12015-06-30 16:05:22 -0700556 moduleCh := make(chan *moduleInfo)
557 errsCh := make(chan []error)
558 doneCh := make(chan struct{})
559 var numErrs uint32
560 var numGoroutines int32
561
562 // handler must be reentrant
563 handler := func(file *parser.File) {
564 if atomic.LoadUint32(&numErrs) > maxErrors {
565 return
566 }
567
568 atomic.AddInt32(&numGoroutines, 1)
569 go func() {
570 for _, def := range file.Defs {
571 var module *moduleInfo
572 var errs []error
573 switch def := def.(type) {
574 case *parser.Module:
575 module, errs = c.processModuleDef(def, file.Name)
576 case *parser.Assignment:
577 // Already handled via Scope object
578 default:
579 panic("unknown definition type")
580 }
581
582 if len(errs) > 0 {
583 atomic.AddUint32(&numErrs, uint32(len(errs)))
584 errsCh <- errs
585 } else if module != nil {
586 moduleCh <- module
587 }
588 }
589 doneCh <- struct{}{}
590 }()
591 }
592
593 atomic.AddInt32(&numGoroutines, 1)
594 go func() {
595 var errs []error
596 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
597 if len(errs) > 0 {
598 errsCh <- errs
599 }
600 doneCh <- struct{}{}
601 }()
602
603loop:
604 for {
605 select {
606 case newErrs := <-errsCh:
607 errs = append(errs, newErrs...)
608 case module := <-moduleCh:
609 newErrs := c.addModule(module)
610 if len(newErrs) > 0 {
611 errs = append(errs, newErrs...)
612 }
613 case <-doneCh:
614 n := atomic.AddInt32(&numGoroutines, -1)
615 if n == 0 {
616 break loop
617 }
618 }
619 }
620
621 return deps, errs
622}
623
624type FileHandler func(*parser.File)
625
626// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
627// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
628// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
629// it must be reentrant.
630//
631// If no errors are encountered while parsing the files, the list of paths on
632// which the future output will depend is returned. This list will include both
633// Blueprints file paths as well as directory paths for cases where wildcard
634// subdirs are found.
635func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
636 errs []error) {
637
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700638 rootDir := filepath.Dir(rootFile)
639
Colin Cross7ad621c2015-01-07 16:22:45 -0800640 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700641
Colin Cross7ad621c2015-01-07 16:22:45 -0800642 // Channels to receive data back from parseBlueprintsFile goroutines
643 blueprintsCh := make(chan stringAndScope)
644 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700645 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800646 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700647
Colin Cross7ad621c2015-01-07 16:22:45 -0800648 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
649 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700650
Colin Cross7ad621c2015-01-07 16:22:45 -0800651 // Number of outstanding goroutines to wait for
652 count := 0
653
654 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
655 count++
656 go func() {
657 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700658 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800659 doneCh <- struct{}{}
660 }()
661 }
662
663 tooManyErrors := false
664
665 startParseBlueprintsFile(rootFile, nil)
666
667loop:
668 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700669 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800670 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700671 }
672
Colin Cross7ad621c2015-01-07 16:22:45 -0800673 select {
674 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700675 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800676 case dep := <-depsCh:
677 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700678 case file := <-fileCh:
679 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800680 case blueprint := <-blueprintsCh:
681 if tooManyErrors {
682 continue
683 }
684 if blueprintsSet[blueprint.string] {
685 continue
686 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700687
Colin Cross7ad621c2015-01-07 16:22:45 -0800688 blueprintsSet[blueprint.string] = true
689 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
690 case <-doneCh:
691 count--
692 if count == 0 {
693 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700694 }
695 }
696 }
697
Colin Cross7ad621c2015-01-07 16:22:45 -0800698 return
699}
700
701// parseBlueprintFile parses a single Blueprints file, returning any errors through
702// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
703// blueprintsCh, and any dependencies on Blueprints files or directories through
704// depsCh.
705func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700706 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800707 depsCh chan<- string) {
708
Colin Cross23d7aa12015-06-30 16:05:22 -0700709 f, err := os.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 if err != nil {
711 errsCh <- []error{err}
712 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700713 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700714 defer func() {
715 err = f.Close()
716 if err != nil {
717 errsCh <- []error{err}
718 }
719 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700720
Colin Cross23d7aa12015-06-30 16:05:22 -0700721 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800722 if len(errs) > 0 {
723 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700724 } else {
725 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800726 }
727
Colin Cross1fef5362015-04-20 16:50:54 -0700728 for _, b := range subBlueprints {
729 blueprintsCh <- b
730 }
731
732 for _, d := range deps {
733 depsCh <- d
734 }
Colin Cross1fef5362015-04-20 16:50:54 -0700735}
736
Colin Cross7f507402015-12-16 13:03:41 -0800737func (c *Context) findBuildBlueprints(dir string, build []string,
738 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
739
740 for _, file := range build {
741 globPattern := filepath.Join(dir, file)
742 matches, matchedDirs, err := pathtools.Glob(globPattern)
743 if err != nil {
744 errs = append(errs, &Error{
745 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
746 Pos: buildPos,
747 })
748 continue
749 }
750
751 if len(matches) == 0 {
752 errs = append(errs, &Error{
753 Err: fmt.Errorf("%q: not found", globPattern),
754 Pos: buildPos,
755 })
756 }
757
758 // Depend on all searched directories so we pick up future changes.
759 deps = append(deps, matchedDirs...)
760
761 for _, foundBlueprints := range matches {
762 fileInfo, err := os.Stat(foundBlueprints)
763 if os.IsNotExist(err) {
764 errs = append(errs, &Error{
765 Err: fmt.Errorf("%q not found", foundBlueprints),
766 })
767 continue
768 }
769
770 if fileInfo.IsDir() {
771 errs = append(errs, &Error{
772 Err: fmt.Errorf("%q is a directory", foundBlueprints),
773 })
774 continue
775 }
776
777 blueprints = append(blueprints, foundBlueprints)
778 }
779 }
780
781 return blueprints, deps, errs
782}
783
784func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
785 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800786
787 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700788 globPattern := filepath.Join(dir, subdir)
789 matches, matchedDirs, err := pathtools.Glob(globPattern)
790 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700791 errs = append(errs, &Error{
792 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
793 Pos: subdirsPos,
794 })
795 continue
796 }
797
Colin Cross7f507402015-12-16 13:03:41 -0800798 if len(matches) == 0 && !optional {
Colin Cross1fef5362015-04-20 16:50:54 -0700799 errs = append(errs, &Error{
800 Err: fmt.Errorf("%q: not found", globPattern),
801 Pos: subdirsPos,
802 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700803 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800804
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700805 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700806 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800807
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700808 for _, foundSubdir := range matches {
809 fileInfo, subdirStatErr := os.Stat(foundSubdir)
810 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700811 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700812 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800813 }
814
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700815 // Skip files
816 if !fileInfo.IsDir() {
817 continue
818 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800819
Colin Cross29394222015-04-27 13:18:21 -0700820 var subBlueprints string
821 if subBlueprintsName != "" {
822 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
823 _, err = os.Stat(subBlueprints)
824 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700825
Colin Cross29394222015-04-27 13:18:21 -0700826 if os.IsNotExist(err) || subBlueprints == "" {
827 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
828 _, err = os.Stat(subBlueprints)
829 }
830
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700831 if os.IsNotExist(err) {
832 // There is no Blueprints file in this subdirectory. We
833 // need to add the directory to the list of dependencies
834 // so that if someone adds a Blueprints file in the
835 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700836 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700837 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700838 deps = append(deps, subBlueprints)
839 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800840 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800841 }
842 }
Colin Cross1fef5362015-04-20 16:50:54 -0700843
Colin Cross1fef5362015-04-20 16:50:54 -0700844 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700845}
846
Colin Cross6d8780f2015-07-10 17:51:55 -0700847func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
848 if assignment, local := scope.Get(v); assignment == nil || !local {
849 return nil, scanner.Position{}, nil
850 } else {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700851 switch assignment.Value.Type {
852 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700853 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700854
855 for _, value := range assignment.Value.ListValue {
856 if value.Type != parser.String {
857 // The parser should not produce this.
858 panic("non-string value found in list")
859 }
860
Colin Cross1fef5362015-04-20 16:50:54 -0700861 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700862 }
863
Colin Cross1fef5362015-04-20 16:50:54 -0700864 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700865 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700866 return nil, scanner.Position{}, &Error{
867 Err: fmt.Errorf("%q must be a list of strings", v),
868 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700869 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700870 default:
871 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
872 }
873 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700874}
875
Colin Cross29394222015-04-27 13:18:21 -0700876func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700877 if assignment, _ := scope.Get(v); assignment == nil {
878 return "", scanner.Position{}, nil
879 } else {
Colin Cross29394222015-04-27 13:18:21 -0700880 switch assignment.Value.Type {
881 case parser.String:
882 return assignment.Value.StringValue, assignment.Pos, nil
883 case parser.Bool, parser.List:
884 return "", scanner.Position{}, &Error{
885 Err: fmt.Errorf("%q must be a string", v),
886 Pos: assignment.Pos,
887 }
888 default:
889 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
890 }
891 }
Colin Cross29394222015-04-27 13:18:21 -0700892}
893
Colin Crossf5e34b92015-03-13 16:02:36 -0700894func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
895 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800896
Colin Crossf4d18a62015-03-18 17:43:15 -0700897 if len(variationNames) == 0 {
898 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400899 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700900 }
901
Colin Crossc9028482014-12-18 16:28:54 -0800902 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800903
Colin Cross174ae052015-03-03 17:37:03 -0800904 var errs []error
905
Colin Crossf5e34b92015-03-13 16:02:36 -0700906 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700907 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800908 factory, ok := c.moduleFactories[typeName]
909 if !ok {
910 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
911 }
912
913 var newLogicModule Module
914 var newProperties []interface{}
915
916 if i == 0 {
917 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700918 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
919 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800920 newLogicModule = origModule.logicModule
921 newProperties = origModule.moduleProperties
922 } else {
923 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700924 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800925 }
926 newLogicModule, newProperties = factory()
927
928 newProperties = append(props, newProperties...)
929
930 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700931 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800932 }
933
934 for i := range newProperties {
935 dst := reflect.ValueOf(newProperties[i]).Elem()
936 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
937
938 proptools.CopyProperties(dst, src)
939 }
940 }
941
Colin Crossf5e34b92015-03-13 16:02:36 -0700942 newVariant := origModule.variant.clone()
943 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800944
Colin Crossed342d92015-03-11 00:57:25 -0700945 m := *origModule
946 newModule := &m
947 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
948 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700949 newModule.variant = newVariant
950 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700951 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800952
Colin Crosse7daa222015-03-11 14:35:41 -0700953 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700954 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700955 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700956 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700957 }
958
Colin Crossc9028482014-12-18 16:28:54 -0800959 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700960
961 // Insert the new variant into the global module map. If this is the first variant then
962 // it reuses logicModule from the original module, which causes this to replace the
963 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800964 c.moduleInfo[newModule.logicModule] = newModule
965
Colin Crossf5e34b92015-03-13 16:02:36 -0700966 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800967 if len(newErrs) > 0 {
968 errs = append(errs, newErrs...)
969 }
Colin Crossc9028482014-12-18 16:28:54 -0800970 }
971
972 // Mark original variant as invalid. Modules that depend on this module will still
973 // depend on origModule, but we'll fix it when the mutator is called on them.
974 origModule.logicModule = nil
975 origModule.splitModules = newModules
976
Colin Cross174ae052015-03-03 17:37:03 -0800977 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800978}
979
Colin Crossf5e34b92015-03-13 16:02:36 -0700980func (c *Context) convertDepsToVariation(module *moduleInfo,
981 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800982
Colin Crossc9028482014-12-18 16:28:54 -0800983 for i, dep := range module.directDeps {
984 if dep.logicModule == nil {
985 var newDep *moduleInfo
986 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700987 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800988 newDep = m
989 break
990 }
991 }
992 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800993 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700994 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
995 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700996 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800997 })
998 continue
Colin Crossc9028482014-12-18 16:28:54 -0800999 }
1000 module.directDeps[i] = newDep
1001 }
1002 }
Colin Cross174ae052015-03-03 17:37:03 -08001003
1004 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001005}
1006
Colin Crossf5e34b92015-03-13 16:02:36 -07001007func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001008 names := make([]string, 0, len(variant))
1009 for _, m := range c.variantMutatorNames {
1010 if v, ok := variant[m]; ok {
1011 names = append(names, m+":"+v)
1012 }
1013 }
1014
1015 return strings.Join(names, ", ")
1016}
1017
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001018func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001019 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001020
Colin Crossd1facc12015-01-08 14:56:03 -08001021 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001022 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001023 if !ok {
1024 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001025 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001026 }
1027
Colin Cross7ad621c2015-01-07 16:22:45 -08001028 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001029 &Error{
1030 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -08001031 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001032 },
1033 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001034 }
1035
Colin Crossbbfa51a2014-12-17 16:12:41 -08001036 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001037
1038 module := &moduleInfo{
1039 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -07001040 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -07001041 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001042 }
1043
Jamie Gennis87622922014-09-30 11:38:25 -07001044 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001045 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001046 }
1047 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001048 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001049
Jamie Gennis87622922014-09-30 11:38:25 -07001050 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001051 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001052 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001053 }
1054
Colin Crossed342d92015-03-11 00:57:25 -07001055 module.pos = moduleDef.Type.Pos
1056 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001057 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -07001058 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001059 }
1060
Colin Cross7ad621c2015-01-07 16:22:45 -08001061 return module, nil
1062}
1063
Colin Cross23d7aa12015-06-30 16:05:22 -07001064func (c *Context) addModule(module *moduleInfo) []error {
1065 name := module.properties.Name
1066 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001067
Colin Cross23d7aa12015-06-30 16:05:22 -07001068 if group, present := c.moduleGroups[name]; present {
1069 return []error{
1070 &Error{
1071 Err: fmt.Errorf("module %q already defined", name),
1072 Pos: module.pos,
1073 },
1074 &Error{
1075 Err: fmt.Errorf("<-- previous definition here"),
1076 Pos: group.modules[0].pos,
1077 },
Colin Crossed342d92015-03-11 00:57:25 -07001078 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001079 } else {
1080 ninjaName := toNinjaName(module.properties.Name)
1081
1082 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1083 // already exists
1084 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1085 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1086 }
1087
1088 group := &moduleGroup{
1089 name: module.properties.Name,
1090 ninjaName: ninjaName,
1091 modules: []*moduleInfo{module},
1092 }
1093 module.group = group
1094 c.moduleGroups[name] = group
1095 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001096 }
1097
Colin Cross23d7aa12015-06-30 16:05:22 -07001098 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001099}
1100
Jamie Gennisd4e10182014-06-12 20:06:50 -07001101// ResolveDependencies checks that the dependencies specified by all of the
1102// modules defined in the parsed Blueprints files are valid. This means that
1103// the modules depended upon are defined and that no circular dependencies
1104// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001105func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Cross763b6f12015-10-29 15:32:56 -07001106 errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001107 if len(errs) > 0 {
1108 return errs
1109 }
1110
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001111 c.dependenciesReady = true
1112 return nil
1113}
1114
Colin Cross763b6f12015-10-29 15:32:56 -07001115// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001116// DynamicDependerModule interface then this set consists of the union of those
1117// module names listed in its "deps" property, those returned by its
1118// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001119// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001120// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001121func blueprintDepsMutator(ctx BottomUpMutatorContext) {
1122 ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001123
Colin Cross763b6f12015-10-29 15:32:56 -07001124 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
1125 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001126
Colin Cross763b6f12015-10-29 15:32:56 -07001127 if ctx.Failed() {
1128 return
Colin Crossa434b3f2015-01-13 10:59:52 -08001129 }
Colin Cross763b6f12015-10-29 15:32:56 -07001130
1131 ctx.AddDependency(ctx.Module(), dynamicDeps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001132 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001133}
1134
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001135// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1136// and returns the matching module, or nil if one is not found.
1137func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1138 if len(group.modules) == 1 {
1139 return group.modules[0]
1140 } else {
1141 for _, m := range group.modules {
1142 if m.variant.equal(module.dependencyVariant) {
1143 return m
1144 }
1145 }
1146 }
1147
1148 return nil
1149}
1150
Colin Crossc9028482014-12-18 16:28:54 -08001151func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001152 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001153 return []error{&Error{
1154 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001155 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001156 }}
1157 }
1158
1159 depInfo, ok := c.moduleGroups[depName]
1160 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001161 if c.allowMissingDependencies {
1162 module.missingDeps = append(module.missingDeps, depName)
1163 return nil
1164 }
Colin Crossc9028482014-12-18 16:28:54 -08001165 return []error{&Error{
1166 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001167 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001168 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001169 }}
1170 }
1171
Colin Cross65569e42015-03-10 20:08:19 -07001172 for _, m := range module.directDeps {
1173 if m.group == depInfo {
1174 return nil
1175 }
Colin Crossc9028482014-12-18 16:28:54 -08001176 }
1177
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001178 if m := c.findMatchingVariant(module, depInfo); m != nil {
1179 module.directDeps = append(module.directDeps, m)
Colin Cross65569e42015-03-10 20:08:19 -07001180 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001181 }
Colin Crossc9028482014-12-18 16:28:54 -08001182
Colin Cross65569e42015-03-10 20:08:19 -07001183 return []error{&Error{
1184 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1185 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001186 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001187 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001188 }}
1189}
1190
Colin Cross8d8a7af2015-11-03 16:41:29 -08001191func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001192 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001193 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001194 Err: fmt.Errorf("%q depends on itself", destName),
1195 Pos: module.pos,
1196 }}
1197 }
1198
1199 destInfo, ok := c.moduleGroups[destName]
1200 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001201 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001202 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1203 module.properties.Name, destName),
1204 Pos: module.pos,
1205 }}
1206 }
1207
1208 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001209 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001210 }
1211
Colin Cross8d8a7af2015-11-03 16:41:29 -08001212 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001213 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1214 destName, module.properties.Name,
1215 c.prettyPrintVariant(module.dependencyVariant)),
1216 Pos: module.pos,
1217 }}
1218}
1219
Colin Crossf5e34b92015-03-13 16:02:36 -07001220func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross89486232015-05-08 11:14:54 -07001221 depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001222
Colin Cross65569e42015-03-10 20:08:19 -07001223 depInfo, ok := c.moduleGroups[depName]
1224 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001225 if c.allowMissingDependencies {
1226 module.missingDeps = append(module.missingDeps, depName)
1227 return nil
1228 }
Colin Cross65569e42015-03-10 20:08:19 -07001229 return []error{&Error{
1230 Err: fmt.Errorf("%q depends on undefined module %q",
1231 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001232 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001233 }}
1234 }
1235
1236 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1237 // compare the strings because the result won't be in mutator registration order.
1238 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001239 var newVariant variationMap
1240 if !far {
1241 newVariant = module.dependencyVariant.clone()
1242 } else {
1243 newVariant = make(variationMap)
1244 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001245 for _, v := range variations {
1246 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001247 }
1248
1249 for _, m := range depInfo.modules {
Colin Cross89486232015-05-08 11:14:54 -07001250 var found bool
1251 if far {
1252 found = m.variant.subset(newVariant)
1253 } else {
1254 found = m.variant.equal(newVariant)
1255 }
1256 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001257 if module == m {
1258 return []error{&Error{
1259 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001260 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001261 }}
1262 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001263 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001264 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001265 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001266 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1267 return []error{&Error{
1268 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001269 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001270 }}
1271 }
1272 module.directDeps = append(module.directDeps, m)
1273 return nil
1274 }
1275 }
1276
1277 return []error{&Error{
1278 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1279 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001280 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001281 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001282 }}
Colin Crossc9028482014-12-18 16:28:54 -08001283}
1284
Colin Cross7addea32015-03-11 15:43:52 -07001285func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1286 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001287 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001288 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001289
Colin Cross7addea32015-03-11 15:43:52 -07001290 for _, module := range c.modulesSorted {
1291 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001292 }
1293
Colin Cross7addea32015-03-11 15:43:52 -07001294 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001295 count++
1296 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001297 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001298 if ret {
1299 cancel = true
1300 }
Colin Cross7addea32015-03-11 15:43:52 -07001301 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001302 }()
1303 }
1304
Colin Cross7addea32015-03-11 15:43:52 -07001305 for _, module := range c.modulesSorted {
1306 if module.waitingCount == 0 {
1307 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001308 }
1309 }
1310
Colin Cross11e3b0d2015-02-04 10:41:00 -08001311 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001312 select {
Colin Cross7addea32015-03-11 15:43:52 -07001313 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001314 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001315 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001316 parent.waitingCount--
1317 if parent.waitingCount == 0 {
1318 visitOne(parent)
1319 }
Colin Cross691a60d2015-01-07 18:08:56 -08001320 }
1321 }
1322 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001323 }
1324 }
1325}
1326
1327// updateDependencies recursively walks the module dependency graph and updates
1328// additional fields based on the dependencies. It builds a sorted list of modules
1329// such that dependencies of a module always appear first, and populates reverse
1330// dependency links and counts of total dependencies. It also reports errors when
1331// it encounters dependency cycles. This should called after resolveDependencies,
1332// as well as after any mutator pass has called addDependency
1333func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001334 visited := make(map[*moduleInfo]bool) // modules that were already checked
1335 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001336
Colin Cross7addea32015-03-11 15:43:52 -07001337 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001338
Colin Cross7addea32015-03-11 15:43:52 -07001339 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001340
Colin Cross7addea32015-03-11 15:43:52 -07001341 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001342 // We are the "start" of the cycle, so we're responsible
1343 // for generating the errors. The cycle list is in
1344 // reverse order because all the 'check' calls append
1345 // their own module to the list.
1346 errs = append(errs, &Error{
1347 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001348 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001349 })
1350
1351 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001352 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001353 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001354 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001355 errs = append(errs, &Error{
1356 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001357 curModule.properties.Name,
1358 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001359 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001360 })
Colin Cross7addea32015-03-11 15:43:52 -07001361 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001362 }
1363 }
1364
Colin Cross7addea32015-03-11 15:43:52 -07001365 check = func(module *moduleInfo) []*moduleInfo {
1366 visited[module] = true
1367 checking[module] = true
1368 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001369
Colin Cross7addea32015-03-11 15:43:52 -07001370 deps := make(map[*moduleInfo]bool)
1371
1372 // Add an implicit dependency ordering on all earlier modules in the same module group
1373 for _, dep := range module.group.modules {
1374 if dep == module {
1375 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001376 }
Colin Cross7addea32015-03-11 15:43:52 -07001377 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001378 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001379
Colin Cross7addea32015-03-11 15:43:52 -07001380 for _, dep := range module.directDeps {
1381 deps[dep] = true
1382 }
1383
1384 module.reverseDeps = []*moduleInfo{}
1385 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001386
Colin Crossbbfa51a2014-12-17 16:12:41 -08001387 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001388 if checking[dep] {
1389 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001390 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391 }
1392
1393 if !visited[dep] {
1394 cycle := check(dep)
1395 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001396 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001397 // We are the "start" of the cycle, so we're responsible
1398 // for generating the errors. The cycle list is in
1399 // reverse order because all the 'check' calls append
1400 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001401 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001402
1403 // We can continue processing this module's children to
1404 // find more cycles. Since all the modules that were
1405 // part of the found cycle were marked as visited we
1406 // won't run into that cycle again.
1407 } else {
1408 // We're not the "start" of the cycle, so we just append
1409 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001410 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001411 }
1412 }
1413 }
Colin Cross691a60d2015-01-07 18:08:56 -08001414
Colin Cross7addea32015-03-11 15:43:52 -07001415 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001416 }
1417
Colin Cross7addea32015-03-11 15:43:52 -07001418 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001419
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001420 return nil
1421 }
1422
Colin Cross7addea32015-03-11 15:43:52 -07001423 for _, module := range c.moduleInfo {
1424 if !visited[module] {
1425 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001426 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001427 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001428 panic("inconceivable!")
1429 }
1430 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001431 }
1432 }
1433 }
1434
Colin Cross7addea32015-03-11 15:43:52 -07001435 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001436
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001437 return
1438}
1439
Jamie Gennisd4e10182014-06-12 20:06:50 -07001440// PrepareBuildActions generates an internal representation of all the build
1441// actions that need to be performed. This process involves invoking the
1442// GenerateBuildActions method on each of the Module objects created during the
1443// parse phase and then on each of the registered Singleton objects.
1444//
1445// If the ResolveDependencies method has not already been called it is called
1446// automatically by this method.
1447//
1448// The config argument is made available to all of the Module and Singleton
1449// objects via the Config method on the ModuleContext and SingletonContext
1450// objects passed to GenerateBuildActions. It is also passed to the functions
1451// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1452// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001453//
1454// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001455// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1456// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1457// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001458func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459 c.buildActionsReady = false
1460
1461 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001462 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001463 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001464 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001465 }
1466 }
1467
1468 liveGlobals := newLiveTracker(config)
1469
1470 c.initSpecialVariables()
1471
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001472 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001473 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001474 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001475 }
1476
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001477 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001478 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001479 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001480 }
1481
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001482 deps = append(depsModules, depsSingletons...)
1483
Colin Crossa2599452015-11-18 16:01:01 -08001484 if c.ninjaBuildDir != nil {
1485 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001486 }
1487
Dan Willemsena481ae22015-12-18 15:18:03 -08001488 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1489
1490 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001491
1492 // This will panic if it finds a problem since it's a programming error.
1493 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1494
1495 c.pkgNames = pkgNames
1496 c.globalVariables = liveGlobals.variables
1497 c.globalPools = liveGlobals.pools
1498 c.globalRules = liveGlobals.rules
1499
1500 c.buildActionsReady = true
1501
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001502 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001503}
1504
Colin Cross65569e42015-03-10 20:08:19 -07001505func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1506 for _, mutator := range c.earlyMutatorInfo {
1507 for _, group := range c.moduleGroups {
1508 newModules := make([]*moduleInfo, 0, len(group.modules))
1509
1510 for _, module := range group.modules {
1511 mctx := &mutatorContext{
1512 baseModuleContext: baseModuleContext{
1513 context: c,
1514 config: config,
1515 module: module,
1516 },
1517 name: mutator.name,
1518 }
1519 mutator.mutator(mctx)
1520 if len(mctx.errs) > 0 {
1521 errs = append(errs, mctx.errs...)
1522 return errs
1523 }
1524
1525 if module.splitModules != nil {
1526 newModules = append(newModules, module.splitModules...)
1527 } else {
1528 newModules = append(newModules, module)
1529 }
1530 }
1531
1532 group.modules = newModules
1533 }
1534 }
1535
Colin Cross763b6f12015-10-29 15:32:56 -07001536 errs = c.updateDependencies()
1537 if len(errs) > 0 {
1538 return errs
1539 }
1540
Colin Cross65569e42015-03-10 20:08:19 -07001541 return nil
1542}
1543
Colin Crossc9028482014-12-18 16:28:54 -08001544func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Cross763b6f12015-10-29 15:32:56 -07001545 errs = c.runEarlyMutators(config)
1546 if len(errs) > 0 {
1547 return errs
1548 }
1549
Colin Crossc9028482014-12-18 16:28:54 -08001550 for _, mutator := range c.mutatorInfo {
1551 if mutator.topDownMutator != nil {
1552 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1553 } else if mutator.bottomUpMutator != nil {
1554 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1555 } else {
1556 panic("no mutator set on " + mutator.name)
1557 }
1558 if len(errs) > 0 {
1559 return errs
1560 }
1561 }
1562
1563 return nil
1564}
1565
1566func (c *Context) runTopDownMutator(config interface{},
1567 name string, mutator TopDownMutator) (errs []error) {
1568
Colin Cross7addea32015-03-11 15:43:52 -07001569 for i := 0; i < len(c.modulesSorted); i++ {
1570 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1571 mctx := &mutatorContext{
1572 baseModuleContext: baseModuleContext{
1573 context: c,
1574 config: config,
1575 module: module,
1576 },
1577 name: name,
1578 }
Colin Crossc9028482014-12-18 16:28:54 -08001579
Colin Cross7addea32015-03-11 15:43:52 -07001580 mutator(mctx)
1581 if len(mctx.errs) > 0 {
1582 errs = append(errs, mctx.errs...)
1583 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001584 }
1585 }
1586
1587 return errs
1588}
1589
1590func (c *Context) runBottomUpMutator(config interface{},
1591 name string, mutator BottomUpMutator) (errs []error) {
1592
Colin Cross8d8a7af2015-11-03 16:41:29 -08001593 reverseDeps := make(map[*moduleInfo][]*moduleInfo)
1594
Colin Cross7addea32015-03-11 15:43:52 -07001595 for _, module := range c.modulesSorted {
1596 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001597
Jamie Gennisc7988252015-04-14 23:28:10 -04001598 if module.splitModules != nil {
1599 panic("split module found in sorted module list")
1600 }
1601
Colin Cross7addea32015-03-11 15:43:52 -07001602 mctx := &mutatorContext{
1603 baseModuleContext: baseModuleContext{
1604 context: c,
1605 config: config,
1606 module: module,
1607 },
Colin Cross8d8a7af2015-11-03 16:41:29 -08001608 name: name,
1609 reverseDeps: reverseDeps,
Colin Cross7addea32015-03-11 15:43:52 -07001610 }
Colin Crossc9028482014-12-18 16:28:54 -08001611
Colin Cross7addea32015-03-11 15:43:52 -07001612 mutator(mctx)
1613 if len(mctx.errs) > 0 {
1614 errs = append(errs, mctx.errs...)
1615 return errs
1616 }
Colin Crossc9028482014-12-18 16:28:54 -08001617
Colin Cross7addea32015-03-11 15:43:52 -07001618 // Fix up any remaining dependencies on modules that were split into variants
1619 // by replacing them with the first variant
1620 for i, dep := range module.directDeps {
1621 if dep.logicModule == nil {
1622 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001623 }
1624 }
1625
Colin Cross7addea32015-03-11 15:43:52 -07001626 if module.splitModules != nil {
1627 newModules = append(newModules, module.splitModules...)
1628 } else {
1629 newModules = append(newModules, module)
1630 }
1631
1632 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001633 }
1634
Colin Cross8d8a7af2015-11-03 16:41:29 -08001635 for module, deps := range reverseDeps {
1636 sort.Sort(moduleSorter(deps))
1637 module.directDeps = append(module.directDeps, deps...)
1638 }
1639
Jamie Gennisc7988252015-04-14 23:28:10 -04001640 errs = c.updateDependencies()
1641 if len(errs) > 0 {
1642 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001643 }
1644
1645 return errs
1646}
1647
Colin Cross7addea32015-03-11 15:43:52 -07001648func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1649 newModules []*moduleInfo) []*moduleInfo {
1650 for i, m := range modules {
1651 if m == origModule {
1652 return spliceModulesAtIndex(modules, i, newModules)
1653 }
1654 }
1655
1656 panic("failed to find original module to splice")
1657}
1658
1659func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1660 spliceSize := len(newModules)
1661 newLen := len(modules) + spliceSize - 1
1662 var dest []*moduleInfo
1663 if cap(modules) >= len(modules)-1+len(newModules) {
1664 // We can fit the splice in the existing capacity, do everything in place
1665 dest = modules[:newLen]
1666 } else {
1667 dest = make([]*moduleInfo, newLen)
1668 copy(dest, modules[:i])
1669 }
1670
1671 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001672 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001673
1674 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001675 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001676
Colin Cross72bd1932015-03-16 00:13:59 -07001677 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001678}
1679
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001680func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001681 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001682 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001683 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001684 c.requiredNinjaMicro = 0
1685}
1686
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001687func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001688 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001689
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001690 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001691 var errs []error
1692
Colin Cross691a60d2015-01-07 18:08:56 -08001693 cancelCh := make(chan struct{})
1694 errsCh := make(chan []error)
1695 depsCh := make(chan []string)
1696
1697 go func() {
1698 for {
1699 select {
1700 case <-cancelCh:
1701 close(cancelCh)
1702 return
1703 case newErrs := <-errsCh:
1704 errs = append(errs, newErrs...)
1705 case newDeps := <-depsCh:
1706 deps = append(deps, newDeps...)
1707
1708 }
1709 }
1710 }()
1711
Colin Cross7addea32015-03-11 15:43:52 -07001712 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1713 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1714 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1715 // just set it to nil.
1716 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1717 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001718
Colin Cross7addea32015-03-11 15:43:52 -07001719 mctx := &moduleContext{
1720 baseModuleContext: baseModuleContext{
1721 context: c,
1722 config: config,
1723 module: module,
1724 },
Colin Cross036a1df2015-12-17 15:49:30 -08001725 scope: scope,
1726 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001727 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001728
Colin Cross7addea32015-03-11 15:43:52 -07001729 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001730
Colin Cross7addea32015-03-11 15:43:52 -07001731 if len(mctx.errs) > 0 {
1732 errsCh <- mctx.errs
1733 return true
1734 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001735
Colin Cross036a1df2015-12-17 15:49:30 -08001736 if module.missingDeps != nil && !mctx.handledMissingDeps {
1737 var errs []error
1738 for _, depName := range module.missingDeps {
1739 errs = append(errs, &Error{
1740 Err: fmt.Errorf("%q depends on undefined module %q",
1741 module.properties.Name, depName),
1742 Pos: module.pos,
1743 })
1744 }
1745 errsCh <- errs
1746 return true
1747 }
1748
Colin Cross7addea32015-03-11 15:43:52 -07001749 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001750
Colin Crossab6d7902015-03-11 16:17:52 -07001751 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001752 &mctx.actionDefs, liveGlobals)
1753 if len(newErrs) > 0 {
1754 errsCh <- newErrs
1755 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001756 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001757 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001758 })
1759
1760 cancelCh <- struct{}{}
1761 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001762
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001763 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001764}
1765
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001766func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001767 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001768
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001769 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001770 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001771
Yuchen Wub9103ef2015-08-25 17:58:17 -07001772 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001773 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1774 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1775 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001776 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001777
1778 sctx := &singletonContext{
1779 context: c,
1780 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001781 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001782 }
1783
1784 info.singleton.GenerateBuildActions(sctx)
1785
1786 if len(sctx.errs) > 0 {
1787 errs = append(errs, sctx.errs...)
1788 if len(errs) > maxErrors {
1789 break
1790 }
1791 continue
1792 }
1793
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001794 deps = append(deps, sctx.ninjaFileDeps...)
1795
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001796 newErrs := c.processLocalBuildActions(&info.actionDefs,
1797 &sctx.actionDefs, liveGlobals)
1798 errs = append(errs, newErrs...)
1799 if len(errs) > maxErrors {
1800 break
1801 }
1802 }
1803
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001804 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001805}
1806
1807func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1808 liveGlobals *liveTracker) []error {
1809
1810 var errs []error
1811
1812 // First we go through and add everything referenced by the module's
1813 // buildDefs to the live globals set. This will end up adding the live
1814 // locals to the set as well, but we'll take them out after.
1815 for _, def := range in.buildDefs {
1816 err := liveGlobals.AddBuildDefDeps(def)
1817 if err != nil {
1818 errs = append(errs, err)
1819 }
1820 }
1821
1822 if len(errs) > 0 {
1823 return errs
1824 }
1825
Colin Crossc9028482014-12-18 16:28:54 -08001826 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001827
1828 // We use the now-incorrect set of live "globals" to determine which local
1829 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001830 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001831 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001832 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001833 if isLive {
1834 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001835 }
1836 }
1837
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001838 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001839 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001840 if isLive {
1841 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001842 }
1843 }
1844
1845 return nil
1846}
1847
Yuchen Wu222e2452015-10-06 14:03:27 -07001848func (c *Context) walkDeps(topModule *moduleInfo,
1849 visit func(Module, Module) bool) {
1850
1851 visited := make(map[*moduleInfo]bool)
1852
1853 var walk func(module *moduleInfo)
1854 walk = func(module *moduleInfo) {
1855 visited[module] = true
1856
1857 for _, moduleDep := range module.directDeps {
1858 if !visited[moduleDep] {
1859 if visit(moduleDep.logicModule, module.logicModule) {
1860 walk(moduleDep)
1861 }
1862 }
1863 }
1864 }
1865
1866 walk(topModule)
1867}
1868
Colin Crossbbfa51a2014-12-17 16:12:41 -08001869func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1870 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001871
Colin Crossbbfa51a2014-12-17 16:12:41 -08001872 var walk func(module *moduleInfo)
1873 walk = func(module *moduleInfo) {
1874 visited[module] = true
1875 for _, moduleDep := range module.directDeps {
1876 if !visited[moduleDep] {
1877 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001878 }
1879 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001880
Colin Crossbbfa51a2014-12-17 16:12:41 -08001881 if module != topModule {
1882 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001883 }
1884 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001885
1886 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001887}
1888
Colin Crossbbfa51a2014-12-17 16:12:41 -08001889func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001890 visit func(Module)) {
1891
Colin Crossbbfa51a2014-12-17 16:12:41 -08001892 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001893
Colin Crossbbfa51a2014-12-17 16:12:41 -08001894 var walk func(module *moduleInfo)
1895 walk = func(module *moduleInfo) {
1896 visited[module] = true
1897 for _, moduleDep := range module.directDeps {
1898 if !visited[moduleDep] {
1899 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001900 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001901 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001902
1903 if module != topModule {
1904 if pred(module.logicModule) {
1905 visit(module.logicModule)
1906 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001907 }
1908 }
1909
Colin Crossbbfa51a2014-12-17 16:12:41 -08001910 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001911}
1912
Colin Crossc9028482014-12-18 16:28:54 -08001913func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1914 for _, dep := range module.directDeps {
1915 visit(dep.logicModule)
1916 }
1917}
1918
1919func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1920 visit func(Module)) {
1921
1922 for _, dep := range module.directDeps {
1923 if pred(dep.logicModule) {
1924 visit(dep.logicModule)
1925 }
1926 }
1927}
1928
Jamie Gennisc15544d2014-09-24 20:26:52 -07001929func (c *Context) sortedModuleNames() []string {
1930 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001931 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1932 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001933 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1934 moduleName)
1935 }
1936 sort.Strings(c.cachedSortedModuleNames)
1937 }
1938
1939 return c.cachedSortedModuleNames
1940}
1941
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001942func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001943 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001944 group := c.moduleGroups[moduleName]
1945 for _, module := range group.modules {
1946 visit(module.logicModule)
1947 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001948 }
1949}
1950
1951func (c *Context) visitAllModulesIf(pred func(Module) bool,
1952 visit func(Module)) {
1953
Jamie Gennisc15544d2014-09-24 20:26:52 -07001954 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001955 group := c.moduleGroups[moduleName]
1956 for _, module := range group.modules {
1957 if pred(module.logicModule) {
1958 visit(module.logicModule)
1959 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001960 }
1961 }
1962}
1963
1964func (c *Context) requireNinjaVersion(major, minor, micro int) {
1965 if major != 1 {
1966 panic("ninja version with major version != 1 not supported")
1967 }
1968 if c.requiredNinjaMinor < minor {
1969 c.requiredNinjaMinor = minor
1970 c.requiredNinjaMicro = micro
1971 }
1972 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1973 c.requiredNinjaMicro = micro
1974 }
1975}
1976
Colin Crossa2599452015-11-18 16:01:01 -08001977func (c *Context) setNinjaBuildDir(value *ninjaString) {
1978 if c.ninjaBuildDir == nil {
1979 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001980 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001981}
1982
1983func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08001984 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001985
Dan Willemsenaeffbf72015-11-25 15:29:32 -08001986 pkgs := make(map[string]*packageContext)
1987 pkgNames := make(map[*packageContext]string)
1988 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001989
Dan Willemsenaeffbf72015-11-25 15:29:32 -08001990 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001991 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001992 // This is a built-in rule and has no package.
1993 return
1994 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001995 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001996 // We've already processed this package.
1997 return
1998 }
1999
Jamie Gennis2fb20952014-10-03 02:49:58 -07002000 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002001 if present {
2002 // Short name collision. Both this package and the one that's
2003 // already there need to use their full names. We leave the short
2004 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002005 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002006 longPkgNames[otherPkg] = true
2007 } else {
2008 // No collision so far. Tentatively set the package's name to be
2009 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002010 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002011 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002012 }
2013 }
2014
2015 // We try to give all packages their short name, but when we get collisions
2016 // we need to use the full unique package name.
2017 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002018 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002019 }
2020 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002021 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002022 }
2023 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002024 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002025 }
2026
2027 // Add the packages that had collisions using their full unique names. This
2028 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002029 for pctx := range longPkgNames {
2030 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002031 }
2032
Dan Willemsena481ae22015-12-18 15:18:03 -08002033 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2034 deps := []string{}
2035 for _, pkg := range pkgs {
2036 deps = append(deps, pkg.ninjaFileDeps...)
2037 }
2038
2039 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002040}
2041
2042func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002043 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002044
2045 visited := make(map[Variable]bool) // variables that were already checked
2046 checking := make(map[Variable]bool) // variables actively being checked
2047
2048 var check func(v Variable) []Variable
2049
2050 check = func(v Variable) []Variable {
2051 visited[v] = true
2052 checking[v] = true
2053 defer delete(checking, v)
2054
2055 value := variables[v]
2056 for _, dep := range value.variables {
2057 if checking[dep] {
2058 // This is a cycle.
2059 return []Variable{dep, v}
2060 }
2061
2062 if !visited[dep] {
2063 cycle := check(dep)
2064 if cycle != nil {
2065 if cycle[0] == v {
2066 // We are the "start" of the cycle, so we're responsible
2067 // for generating the errors. The cycle list is in
2068 // reverse order because all the 'check' calls append
2069 // their own module to the list.
2070 msgs := []string{"detected variable reference cycle:"}
2071
2072 // Iterate backwards through the cycle list.
2073 curName := v.fullName(pkgNames)
2074 curValue := value.Value(pkgNames)
2075 for i := len(cycle) - 1; i >= 0; i-- {
2076 next := cycle[i]
2077 nextName := next.fullName(pkgNames)
2078 nextValue := variables[next].Value(pkgNames)
2079
2080 msgs = append(msgs, fmt.Sprintf(
2081 " %q depends on %q", curName, nextName))
2082 msgs = append(msgs, fmt.Sprintf(
2083 " [%s = %s]", curName, curValue))
2084
2085 curName = nextName
2086 curValue = nextValue
2087 }
2088
2089 // Variable reference cycles are a programming error,
2090 // not the fault of the Blueprint file authors.
2091 panic(strings.Join(msgs, "\n"))
2092 } else {
2093 // We're not the "start" of the cycle, so we just append
2094 // our module to the list and return it.
2095 return append(cycle, v)
2096 }
2097 }
2098 }
2099 }
2100
2101 return nil
2102 }
2103
2104 for v := range variables {
2105 if !visited[v] {
2106 cycle := check(v)
2107 if cycle != nil {
2108 panic("inconceivable!")
2109 }
2110 }
2111 }
2112}
2113
Jamie Gennisaf435562014-10-27 22:34:56 -07002114// AllTargets returns a map all the build target names to the rule used to build
2115// them. This is the same information that is output by running 'ninja -t
2116// targets all'. If this is called before PrepareBuildActions successfully
2117// completes then ErrbuildActionsNotReady is returned.
2118func (c *Context) AllTargets() (map[string]string, error) {
2119 if !c.buildActionsReady {
2120 return nil, ErrBuildActionsNotReady
2121 }
2122
2123 targets := map[string]string{}
2124
2125 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002126 for _, module := range c.moduleInfo {
2127 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002128 ruleName := buildDef.Rule.fullName(c.pkgNames)
2129 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002130 outputValue, err := output.Eval(c.globalVariables)
2131 if err != nil {
2132 return nil, err
2133 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002134 targets[outputValue] = ruleName
2135 }
2136 }
2137 }
2138
2139 // Collect all the singleton build targets.
2140 for _, info := range c.singletonInfo {
2141 for _, buildDef := range info.actionDefs.buildDefs {
2142 ruleName := buildDef.Rule.fullName(c.pkgNames)
2143 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002144 outputValue, err := output.Eval(c.globalVariables)
2145 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002146 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002147 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002148 targets[outputValue] = ruleName
2149 }
2150 }
2151 }
2152
2153 return targets, nil
2154}
2155
Colin Crossa2599452015-11-18 16:01:01 -08002156func (c *Context) NinjaBuildDir() (string, error) {
2157 if c.ninjaBuildDir != nil {
2158 return c.ninjaBuildDir.Eval(c.globalVariables)
2159 } else {
2160 return "", nil
2161 }
2162}
2163
Colin Cross4572edd2015-05-13 14:36:24 -07002164// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2165// property structs returned by the factory for that module type.
2166func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2167 ret := make(map[string][]interface{})
2168 for moduleType, factory := range c.moduleFactories {
2169 _, ret[moduleType] = factory()
2170 }
2171
2172 return ret
2173}
2174
2175func (c *Context) ModuleName(logicModule Module) string {
2176 module := c.moduleInfo[logicModule]
2177 return module.properties.Name
2178}
2179
2180func (c *Context) ModuleDir(logicModule Module) string {
2181 module := c.moduleInfo[logicModule]
2182 return filepath.Dir(module.relBlueprintsFile)
2183}
2184
Colin Cross8c602f72015-12-17 18:02:11 -08002185func (c *Context) ModuleSubDir(logicModule Module) string {
2186 module := c.moduleInfo[logicModule]
2187 return module.variantName
2188}
2189
Colin Cross4572edd2015-05-13 14:36:24 -07002190func (c *Context) BlueprintFile(logicModule Module) string {
2191 module := c.moduleInfo[logicModule]
2192 return module.relBlueprintsFile
2193}
2194
2195func (c *Context) ModuleErrorf(logicModule Module, format string,
2196 args ...interface{}) error {
2197
2198 module := c.moduleInfo[logicModule]
2199 return &Error{
2200 Err: fmt.Errorf(format, args...),
2201 Pos: module.pos,
2202 }
2203}
2204
2205func (c *Context) VisitAllModules(visit func(Module)) {
2206 c.visitAllModules(visit)
2207}
2208
2209func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2210 visit func(Module)) {
2211
2212 c.visitAllModulesIf(pred, visit)
2213}
2214
2215func (c *Context) VisitDepsDepthFirst(module Module,
2216 visit func(Module)) {
2217
2218 c.visitDepsDepthFirst(c.moduleInfo[module], visit)
2219}
2220
2221func (c *Context) VisitDepsDepthFirstIf(module Module,
2222 pred func(Module) bool, visit func(Module)) {
2223
2224 c.visitDepsDepthFirstIf(c.moduleInfo[module], pred, visit)
2225}
2226
Colin Cross24ad5872015-11-17 16:22:29 -08002227func (c *Context) PrimaryModule(module Module) Module {
2228 return c.moduleInfo[module].group.modules[0].logicModule
2229}
2230
2231func (c *Context) FinalModule(module Module) Module {
2232 modules := c.moduleInfo[module].group.modules
2233 return modules[len(modules)-1].logicModule
2234}
2235
2236func (c *Context) VisitAllModuleVariants(module Module,
2237 visit func(Module)) {
2238
2239 for _, module := range c.moduleInfo[module].group.modules {
2240 visit(module.logicModule)
2241 }
2242}
2243
Jamie Gennisd4e10182014-06-12 20:06:50 -07002244// WriteBuildFile writes the Ninja manifeset text for the generated build
2245// actions to w. If this is called before PrepareBuildActions successfully
2246// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002247func (c *Context) WriteBuildFile(w io.Writer) error {
2248 if !c.buildActionsReady {
2249 return ErrBuildActionsNotReady
2250 }
2251
2252 nw := newNinjaWriter(w)
2253
2254 err := c.writeBuildFileHeader(nw)
2255 if err != nil {
2256 return err
2257 }
2258
2259 err = c.writeNinjaRequiredVersion(nw)
2260 if err != nil {
2261 return err
2262 }
2263
2264 // TODO: Group the globals by package.
2265
2266 err = c.writeGlobalVariables(nw)
2267 if err != nil {
2268 return err
2269 }
2270
2271 err = c.writeGlobalPools(nw)
2272 if err != nil {
2273 return err
2274 }
2275
2276 err = c.writeBuildDir(nw)
2277 if err != nil {
2278 return err
2279 }
2280
2281 err = c.writeGlobalRules(nw)
2282 if err != nil {
2283 return err
2284 }
2285
2286 err = c.writeAllModuleActions(nw)
2287 if err != nil {
2288 return err
2289 }
2290
2291 err = c.writeAllSingletonActions(nw)
2292 if err != nil {
2293 return err
2294 }
2295
2296 return nil
2297}
2298
Jamie Gennisc15544d2014-09-24 20:26:52 -07002299type pkgAssociation struct {
2300 PkgName string
2301 PkgPath string
2302}
2303
2304type pkgAssociationSorter struct {
2305 pkgs []pkgAssociation
2306}
2307
2308func (s *pkgAssociationSorter) Len() int {
2309 return len(s.pkgs)
2310}
2311
2312func (s *pkgAssociationSorter) Less(i, j int) bool {
2313 iName := s.pkgs[i].PkgName
2314 jName := s.pkgs[j].PkgName
2315 return iName < jName
2316}
2317
2318func (s *pkgAssociationSorter) Swap(i, j int) {
2319 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2320}
2321
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002322func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2323 headerTemplate := template.New("fileHeader")
2324 _, err := headerTemplate.Parse(fileHeaderTemplate)
2325 if err != nil {
2326 // This is a programming error.
2327 panic(err)
2328 }
2329
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002330 var pkgs []pkgAssociation
2331 maxNameLen := 0
2332 for pkg, name := range c.pkgNames {
2333 pkgs = append(pkgs, pkgAssociation{
2334 PkgName: name,
2335 PkgPath: pkg.pkgPath,
2336 })
2337 if len(name) > maxNameLen {
2338 maxNameLen = len(name)
2339 }
2340 }
2341
2342 for i := range pkgs {
2343 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2344 }
2345
Jamie Gennisc15544d2014-09-24 20:26:52 -07002346 sort.Sort(&pkgAssociationSorter{pkgs})
2347
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002348 params := map[string]interface{}{
2349 "Pkgs": pkgs,
2350 }
2351
2352 buf := bytes.NewBuffer(nil)
2353 err = headerTemplate.Execute(buf, params)
2354 if err != nil {
2355 return err
2356 }
2357
2358 return nw.Comment(buf.String())
2359}
2360
2361func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2362 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2363 c.requiredNinjaMicro)
2364
2365 err := nw.Assign("ninja_required_version", value)
2366 if err != nil {
2367 return err
2368 }
2369
2370 return nw.BlankLine()
2371}
2372
2373func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002374 if c.ninjaBuildDir != nil {
2375 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002376 if err != nil {
2377 return err
2378 }
2379
2380 err = nw.BlankLine()
2381 if err != nil {
2382 return err
2383 }
2384 }
2385 return nil
2386}
2387
Jamie Gennisc15544d2014-09-24 20:26:52 -07002388type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002389 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002390}
2391
Jamie Gennisc15544d2014-09-24 20:26:52 -07002392type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002393 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002394 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002395}
2396
Jamie Gennisc15544d2014-09-24 20:26:52 -07002397func (s *globalEntitySorter) Len() int {
2398 return len(s.entities)
2399}
2400
2401func (s *globalEntitySorter) Less(i, j int) bool {
2402 iName := s.entities[i].fullName(s.pkgNames)
2403 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002404 return iName < jName
2405}
2406
Jamie Gennisc15544d2014-09-24 20:26:52 -07002407func (s *globalEntitySorter) Swap(i, j int) {
2408 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002409}
2410
2411func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2412 visited := make(map[Variable]bool)
2413
2414 var walk func(v Variable) error
2415 walk = func(v Variable) error {
2416 visited[v] = true
2417
2418 // First visit variables on which this variable depends.
2419 value := c.globalVariables[v]
2420 for _, dep := range value.variables {
2421 if !visited[dep] {
2422 err := walk(dep)
2423 if err != nil {
2424 return err
2425 }
2426 }
2427 }
2428
2429 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2430 if err != nil {
2431 return err
2432 }
2433
2434 err = nw.BlankLine()
2435 if err != nil {
2436 return err
2437 }
2438
2439 return nil
2440 }
2441
Jamie Gennisc15544d2014-09-24 20:26:52 -07002442 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2443 for variable := range c.globalVariables {
2444 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002445 }
2446
Jamie Gennisc15544d2014-09-24 20:26:52 -07002447 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002448
Jamie Gennisc15544d2014-09-24 20:26:52 -07002449 for _, entity := range globalVariables {
2450 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002451 if !visited[v] {
2452 err := walk(v)
2453 if err != nil {
2454 return nil
2455 }
2456 }
2457 }
2458
2459 return nil
2460}
2461
2462func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002463 globalPools := make([]globalEntity, 0, len(c.globalPools))
2464 for pool := range c.globalPools {
2465 globalPools = append(globalPools, pool)
2466 }
2467
2468 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2469
2470 for _, entity := range globalPools {
2471 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002472 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002473 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002474 err := def.WriteTo(nw, name)
2475 if err != nil {
2476 return err
2477 }
2478
2479 err = nw.BlankLine()
2480 if err != nil {
2481 return err
2482 }
2483 }
2484
2485 return nil
2486}
2487
2488func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002489 globalRules := make([]globalEntity, 0, len(c.globalRules))
2490 for rule := range c.globalRules {
2491 globalRules = append(globalRules, rule)
2492 }
2493
2494 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2495
2496 for _, entity := range globalRules {
2497 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002498 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002499 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002500 err := def.WriteTo(nw, name, c.pkgNames)
2501 if err != nil {
2502 return err
2503 }
2504
2505 err = nw.BlankLine()
2506 if err != nil {
2507 return err
2508 }
2509 }
2510
2511 return nil
2512}
2513
Colin Crossab6d7902015-03-11 16:17:52 -07002514type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002515
Colin Crossab6d7902015-03-11 16:17:52 -07002516func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002517 return len(s)
2518}
2519
Colin Crossab6d7902015-03-11 16:17:52 -07002520func (s moduleSorter) Less(i, j int) bool {
2521 iName := s[i].properties.Name
2522 jName := s[j].properties.Name
2523 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002524 iName = s[i].variantName
2525 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002526 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002527 return iName < jName
2528}
2529
Colin Crossab6d7902015-03-11 16:17:52 -07002530func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002531 s[i], s[j] = s[j], s[i]
2532}
2533
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002534func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2535 headerTemplate := template.New("moduleHeader")
2536 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2537 if err != nil {
2538 // This is a programming error.
2539 panic(err)
2540 }
2541
Colin Crossab6d7902015-03-11 16:17:52 -07002542 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2543 for _, module := range c.moduleInfo {
2544 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002545 }
Colin Crossab6d7902015-03-11 16:17:52 -07002546 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002547
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002548 buf := bytes.NewBuffer(nil)
2549
Colin Crossab6d7902015-03-11 16:17:52 -07002550 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002551 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2552 continue
2553 }
2554
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002555 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002556
2557 // In order to make the bootstrap build manifest independent of the
2558 // build dir we need to output the Blueprints file locations in the
2559 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002560 relPos := module.pos
2561 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002562
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002563 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002564 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002565 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2566 factoryName := factoryFunc.Name()
2567
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002568 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002569 "properties": module.properties,
2570 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002571 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002572 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002573 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002574 }
2575 err = headerTemplate.Execute(buf, infoMap)
2576 if err != nil {
2577 return err
2578 }
2579
2580 err = nw.Comment(buf.String())
2581 if err != nil {
2582 return err
2583 }
2584
2585 err = nw.BlankLine()
2586 if err != nil {
2587 return err
2588 }
2589
Colin Crossab6d7902015-03-11 16:17:52 -07002590 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002591 if err != nil {
2592 return err
2593 }
2594
2595 err = nw.BlankLine()
2596 if err != nil {
2597 return err
2598 }
2599 }
2600
2601 return nil
2602}
2603
2604func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2605 headerTemplate := template.New("singletonHeader")
2606 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2607 if err != nil {
2608 // This is a programming error.
2609 panic(err)
2610 }
2611
2612 buf := bytes.NewBuffer(nil)
2613
Yuchen Wub9103ef2015-08-25 17:58:17 -07002614 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002615 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2616 continue
2617 }
2618
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002619 // Get the name of the factory function for the module.
2620 factory := info.factory
2621 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2622 factoryName := factoryFunc.Name()
2623
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002624 buf.Reset()
2625 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002626 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002627 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002628 }
2629 err = headerTemplate.Execute(buf, infoMap)
2630 if err != nil {
2631 return err
2632 }
2633
2634 err = nw.Comment(buf.String())
2635 if err != nil {
2636 return err
2637 }
2638
2639 err = nw.BlankLine()
2640 if err != nil {
2641 return err
2642 }
2643
2644 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2645 if err != nil {
2646 return err
2647 }
2648
2649 err = nw.BlankLine()
2650 if err != nil {
2651 return err
2652 }
2653 }
2654
2655 return nil
2656}
2657
2658func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2659 defs *localBuildActions) error {
2660
2661 // Write the local variable assignments.
2662 for _, v := range defs.variables {
2663 // A localVariable doesn't need the package names or config to
2664 // determine its name or value.
2665 name := v.fullName(nil)
2666 value, err := v.value(nil)
2667 if err != nil {
2668 panic(err)
2669 }
2670 err = nw.Assign(name, value.Value(c.pkgNames))
2671 if err != nil {
2672 return err
2673 }
2674 }
2675
2676 if len(defs.variables) > 0 {
2677 err := nw.BlankLine()
2678 if err != nil {
2679 return err
2680 }
2681 }
2682
2683 // Write the local rules.
2684 for _, r := range defs.rules {
2685 // A localRule doesn't need the package names or config to determine
2686 // its name or definition.
2687 name := r.fullName(nil)
2688 def, err := r.def(nil)
2689 if err != nil {
2690 panic(err)
2691 }
2692
2693 err = def.WriteTo(nw, name, c.pkgNames)
2694 if err != nil {
2695 return err
2696 }
2697
2698 err = nw.BlankLine()
2699 if err != nil {
2700 return err
2701 }
2702 }
2703
2704 // Write the build definitions.
2705 for _, buildDef := range defs.buildDefs {
2706 err := buildDef.WriteTo(nw, c.pkgNames)
2707 if err != nil {
2708 return err
2709 }
2710
2711 if len(buildDef.Args) > 0 {
2712 err = nw.BlankLine()
2713 if err != nil {
2714 return err
2715 }
2716 }
2717 }
2718
2719 return nil
2720}
2721
Colin Cross65569e42015-03-10 20:08:19 -07002722func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2723 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002724 if a == b {
2725 return false
2726 }
Colin Cross65569e42015-03-10 20:08:19 -07002727 for _, l := range list {
2728 if l == a {
2729 found = true
2730 } else if l == b {
2731 return found
2732 }
2733 }
2734
2735 missing := a
2736 if found {
2737 missing = b
2738 }
2739 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2740}
2741
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002742var fileHeaderTemplate = `******************************************************************************
2743*** This file is generated and should not be edited ***
2744******************************************************************************
2745{{if .Pkgs}}
2746This file contains variables, rules, and pools with name prefixes indicating
2747they were generated by the following Go packages:
2748{{range .Pkgs}}
2749 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2750
2751`
2752
2753var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2754Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002755Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002756Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002757Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002758Defined: {{.pos}}
2759`
2760
2761var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2762Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002763Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002764`