blob: e2bfc58db250dc6e8140e2e95939d8c803dc386e [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"
29 "text/scanner"
30 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070031
32 "github.com/google/blueprint/parser"
33 "github.com/google/blueprint/pathtools"
34 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070035)
36
37var ErrBuildActionsNotReady = errors.New("build actions are not ready")
38
39const maxErrors = 10
40
Jamie Gennisd4e10182014-06-12 20:06:50 -070041// A Context contains all the state needed to parse a set of Blueprints files
42// and generate a Ninja file. The process of generating a Ninja file proceeds
43// through a series of four phases. Each phase corresponds with a some methods
44// on the Context object
45//
46// Phase Methods
47// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070048// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070049//
50// 2. Parse ParseBlueprintsFiles, Parse
51//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070052// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070053//
54// 4. Write WriteBuildFile
55//
56// The registration phase prepares the context to process Blueprints files
57// containing various types of modules. The parse phase reads in one or more
58// Blueprints files and validates their contents against the module types that
59// have been registered. The generate phase then analyzes the parsed Blueprints
60// contents to create an internal representation for the build actions that must
61// be performed. This phase also performs validation of the module dependencies
62// and property values defined in the parsed Blueprints files. Finally, the
63// write phase generates the Ninja manifest text based on the generated build
64// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070065type Context struct {
66 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070067 moduleFactories map[string]ModuleFactory
68 moduleGroups map[string]*moduleGroup
69 moduleInfo map[Module]*moduleInfo
70 modulesSorted []*moduleInfo
71 singletonInfo map[string]*singletonInfo
72 mutatorInfo []*mutatorInfo
73 earlyMutatorInfo []*earlyMutatorInfo
74 variantMutatorNames []string
75 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070076
77 dependenciesReady bool // set to true on a successful ResolveDependencies
78 buildActionsReady bool // set to true on a successful PrepareBuildActions
79
80 // set by SetIgnoreUnknownModuleTypes
81 ignoreUnknownModuleTypes bool
82
83 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070084 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085 globalVariables map[Variable]*ninjaString
86 globalPools map[Pool]*poolDef
87 globalRules map[Rule]*ruleDef
88
89 // set during PrepareBuildActions
90 buildDir *ninjaString // The builddir special Ninja variable
91 requiredNinjaMajor int // For the ninja_required_version variable
92 requiredNinjaMinor int // For the ninja_required_version variable
93 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070094
95 // set lazily by sortedModuleNames
96 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097}
98
Jamie Gennisd4e10182014-06-12 20:06:50 -070099// An Error describes a problem that was encountered that is related to a
100// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700102 Err error // the error that occurred
103 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700104}
105
106type localBuildActions struct {
107 variables []*localVariable
108 rules []*localRule
109 buildDefs []*buildDef
110}
111
Colin Crossbbfa51a2014-12-17 16:12:41 -0800112type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700113 name string
114 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115
Colin Crossbbfa51a2014-12-17 16:12:41 -0800116 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700117}
118
Colin Crossbbfa51a2014-12-17 16:12:41 -0800119type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700120 // set during Parse
121 typeName string
122 relBlueprintsFile string
123 pos scanner.Position
124 propertyPos map[string]scanner.Position
125 properties struct {
126 Name string
127 Deps []string
128 }
129
Colin Crossf5e34b92015-03-13 16:02:36 -0700130 variantName string
131 variant variationMap
132 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700133
Colin Crossc9028482014-12-18 16:28:54 -0800134 logicModule Module
135 group *moduleGroup
136 moduleProperties []interface{}
137
138 // set during ResolveDependencies
139 directDeps []*moduleInfo
140
Colin Cross7addea32015-03-11 15:43:52 -0700141 // set during updateDependencies
142 reverseDeps []*moduleInfo
143 depsCount int
144
145 // used by parallelVisitAllBottomUp
146 waitingCount int
147
Colin Crossc9028482014-12-18 16:28:54 -0800148 // set during each runMutator
149 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700150
151 // set during PrepareBuildActions
152 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800153}
154
Colin Crossf5e34b92015-03-13 16:02:36 -0700155// A Variation is a way that a variant of a module differs from other variants of the same module.
156// For example, two variants of the same module might have Variation{"arch","arm"} and
157// Variation{"arch","arm64"}
158type Variation struct {
159 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700160 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700161 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
162 // "shared" or "static" for link.
163 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700164}
165
Colin Crossf5e34b92015-03-13 16:02:36 -0700166// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
167type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700168
Colin Crossf5e34b92015-03-13 16:02:36 -0700169func (vm variationMap) clone() variationMap {
170 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700171 for k, v := range vm {
172 newVm[k] = v
173 }
174
175 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800176}
177
Colin Crossf5e34b92015-03-13 16:02:36 -0700178func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700179 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800180}
181
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700182type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700183 // set during RegisterSingletonType
184 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700185 singleton Singleton
186
187 // set during PrepareBuildActions
188 actionDefs localBuildActions
189}
190
Colin Crossc9028482014-12-18 16:28:54 -0800191type mutatorInfo struct {
192 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800193 topDownMutator TopDownMutator
194 bottomUpMutator BottomUpMutator
195 name string
Colin Crossc9028482014-12-18 16:28:54 -0800196}
197
Colin Cross65569e42015-03-10 20:08:19 -0700198type earlyMutatorInfo struct {
199 // set during RegisterEarlyMutator
200 mutator EarlyMutator
201 name string
202}
203
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700204func (e *Error) Error() string {
205
206 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
207}
208
Jamie Gennisd4e10182014-06-12 20:06:50 -0700209// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700210// no module or singleton factories registered, so the RegisterModuleFactory and
211// RegisterSingletonFactory methods must be called before it can do anything
212// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700213func NewContext() *Context {
214 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800215 moduleFactories: make(map[string]ModuleFactory),
216 moduleGroups: make(map[string]*moduleGroup),
217 moduleInfo: make(map[Module]*moduleInfo),
218 singletonInfo: make(map[string]*singletonInfo),
219 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700220 }
221}
222
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700223// A ModuleFactory function creates a new Module object. See the
224// Context.RegisterModuleType method for details about how a registered
225// ModuleFactory is used by a Context.
226type ModuleFactory func() (m Module, propertyStructs []interface{})
227
Jamie Gennisd4e10182014-06-12 20:06:50 -0700228// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700229// Blueprints file) with a Module factory function. When the given module type
230// name is encountered in a Blueprints file during parsing, the Module factory
231// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800232// generation for the module. If a Mutator splits a module into multiple variants,
233// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700234//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700235// The module type names given here must be unique for the context. The factory
236// function should be a named function so that its package and name can be
237// included in the generated Ninja file for debugging purposes.
238//
239// The factory function returns two values. The first is the newly created
240// Module object. The second is a slice of pointers to that Module object's
241// properties structs. Each properties struct is examined when parsing a module
242// definition of this type in a Blueprints file. Exported fields of the
243// properties structs are automatically set to the property values specified in
244// the Blueprints file. The properties struct field names determine the name of
245// the Blueprints file properties that are used - the Blueprints property name
246// matches that of the properties struct field name with the first letter
247// converted to lower-case.
248//
249// The fields of the properties struct must be either []string, a string, or
250// bool. The Context will panic if a Module gets instantiated with a properties
251// struct containing a field that is not one these supported types.
252//
253// Any properties that appear in the Blueprints files that are not built-in
254// module properties (such as "name" and "deps") and do not have a corresponding
255// field in the returned module properties struct result in an error during the
256// Context's parse phase.
257//
258// As an example, the follow code:
259//
260// type myModule struct {
261// properties struct {
262// Foo string
263// Bar []string
264// }
265// }
266//
267// func NewMyModule() (blueprint.Module, []interface{}) {
268// module := new(myModule)
269// properties := &module.properties
270// return module, []interface{}{properties}
271// }
272//
273// func main() {
274// ctx := blueprint.NewContext()
275// ctx.RegisterModuleType("my_module", NewMyModule)
276// // ...
277// }
278//
279// would support parsing a module defined in a Blueprints file as follows:
280//
281// my_module {
282// name: "myName",
283// foo: "my foo string",
284// bar: ["my", "bar", "strings"],
285// }
286//
Colin Cross7ad621c2015-01-07 16:22:45 -0800287// The factory function may be called from multiple goroutines. Any accesses
288// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700289func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
290 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700291 panic(errors.New("module type name is already registered"))
292 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700293 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700294}
295
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700296// A SingletonFactory function creates a new Singleton object. See the
297// Context.RegisterSingletonType method for details about how a registered
298// SingletonFactory is used by a Context.
299type SingletonFactory func() Singleton
300
301// RegisterSingletonType registers a singleton type that will be invoked to
302// generate build actions. Each registered singleton type is instantiated and
303// and invoked exactly once as part of the generate phase.
304//
305// The singleton type names given here must be unique for the context. The
306// factory function should be a named function so that its package and name can
307// be included in the generated Ninja file for debugging purposes.
308func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700309 if _, present := c.singletonInfo[name]; present {
310 panic(errors.New("singleton name is already registered"))
311 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700313 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700314 factory: factory,
315 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700316 }
317}
318
319func singletonPkgPath(singleton Singleton) string {
320 typ := reflect.TypeOf(singleton)
321 for typ.Kind() == reflect.Ptr {
322 typ = typ.Elem()
323 }
324 return typ.PkgPath()
325}
326
327func singletonTypeName(singleton Singleton) string {
328 typ := reflect.TypeOf(singleton)
329 for typ.Kind() == reflect.Ptr {
330 typ = typ.Elem()
331 }
332 return typ.PkgPath() + "." + typ.Name()
333}
334
Colin Crossc9028482014-12-18 16:28:54 -0800335// RegisterTopDownMutator registers a mutator that will be invoked to propagate
336// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700337// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
338// once per Module, and is invoked on a module before being invoked on any of its
339// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800340//
Colin Cross65569e42015-03-10 20:08:19 -0700341// The mutator type names given here must be unique to all top down mutators in
342// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800343func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
344 for _, m := range c.mutatorInfo {
345 if m.name == name && m.topDownMutator != nil {
346 panic(fmt.Errorf("mutator name %s is already registered", name))
347 }
348 }
349
350 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
351 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800352 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800353 })
354}
355
356// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700357// Modules into variants. Each registered mutator is invoked in registration
358// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
359// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800360//
Colin Cross65569e42015-03-10 20:08:19 -0700361// The mutator type names given here must be unique to all bottom up or early
362// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800363func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700364 for _, m := range c.variantMutatorNames {
365 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800366 panic(fmt.Errorf("mutator name %s is already registered", name))
367 }
368 }
369
370 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
371 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800372 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800373 })
Colin Cross65569e42015-03-10 20:08:19 -0700374
375 c.variantMutatorNames = append(c.variantMutatorNames, name)
376}
377
378// RegisterEarlyMutator registers a mutator that will be invoked to split
379// Modules into multiple variant Modules before any dependencies have been
380// created. Each registered mutator is invoked in registration order once
381// per Module (including each variant from previous early mutators). Module
382// order is unpredictable.
383//
384// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700385// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700386//
387// The mutator type names given here must be unique to all bottom up or early
388// mutators in the Context.
389func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
390 for _, m := range c.variantMutatorNames {
391 if m == name {
392 panic(fmt.Errorf("mutator name %s is already registered", name))
393 }
394 }
395
396 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
397 mutator: mutator,
398 name: name,
399 })
400
401 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800402}
403
Jamie Gennisd4e10182014-06-12 20:06:50 -0700404// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
405// where it encounters an unknown module type while parsing Blueprints files. By
406// default, the context will report unknown module types as an error. If this
407// method is called with ignoreUnknownModuleTypes set to true then the context
408// will silently ignore unknown module types.
409//
410// This method should generally not be used. It exists to facilitate the
411// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700412func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
413 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
414}
415
Jamie Gennisd4e10182014-06-12 20:06:50 -0700416// Parse parses a single Blueprints file from r, creating Module objects for
417// each of the module definitions encountered. If the Blueprints file contains
418// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700419// searched for Blueprints files returned in the subBlueprints return value.
420// If the Blueprints file contains an assignment to the "build" variable, then
421// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700422//
423// rootDir specifies the path to the root directory of the source tree, while
424// filename specifies the path to the Blueprints file. These paths are used for
425// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800426func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross1fef5362015-04-20 16:50:54 -0700427 scope *parser.Scope) (modules []*moduleInfo, subBlueprints []stringAndScope, deps []string,
428 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700429
Jamie Gennisec701282014-06-12 20:06:31 -0700430 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700431 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700432 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700433 }
434
Colin Crossc0dbc552015-01-02 15:19:28 -0800435 scope = parser.NewScope(scope)
436 scope.Remove("subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700437 scope.Remove("build")
Colin Cross96e56702015-03-19 17:28:06 -0700438 file, errs := parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700439 if len(errs) > 0 {
440 for i, err := range errs {
441 if parseErr, ok := err.(*parser.ParseError); ok {
442 err = &Error{
443 Err: parseErr.Err,
444 Pos: parseErr.Pos,
445 }
446 errs[i] = err
447 }
448 }
449
450 // If there were any parse errors don't bother trying to interpret the
451 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700452 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700453 }
454
Colin Crossd1facc12015-01-08 14:56:03 -0800455 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700456 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800457 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700458 switch def := def.(type) {
459 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800460 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700461
462 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800463 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700464 default:
465 panic("unknown definition type")
466 }
467
468 if len(newErrs) > 0 {
469 errs = append(errs, newErrs...)
470 if len(errs) > maxErrors {
471 break
472 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800473 } else if newModule != nil {
474 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700475 }
476 }
477
Colin Cross1fef5362015-04-20 16:50:54 -0700478 subdirs, subdirsPos, err := getStringListFromScope(scope, "subdirs")
479 if err != nil {
480 errs = append(errs, err)
481 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700482
Colin Cross1fef5362015-04-20 16:50:54 -0700483 build, buildPos, err := getStringListFromScope(scope, "build")
484 if err != nil {
485 errs = append(errs, err)
486 }
487
Colin Cross29394222015-04-27 13:18:21 -0700488 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
489
Colin Cross1fef5362015-04-20 16:50:54 -0700490 blueprints, deps, newErrs := c.findSubdirBlueprints(filepath.Dir(filename), subdirs, build,
Colin Cross29394222015-04-27 13:18:21 -0700491 subBlueprintsName, subdirsPos, buildPos)
Colin Crossc0dbc552015-01-02 15:19:28 -0800492 if len(newErrs) > 0 {
493 errs = append(errs, newErrs...)
494 }
495
Colin Cross1fef5362015-04-20 16:50:54 -0700496 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
497 for i, b := range blueprints {
498 subBlueprintsAndScope[i] = stringAndScope{b, scope}
499 }
500
501 return modules, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800502}
503
Colin Cross7ad621c2015-01-07 16:22:45 -0800504type stringAndScope struct {
505 string
506 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700507}
508
Jamie Gennisd4e10182014-06-12 20:06:50 -0700509// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
510// at rootFile. When it encounters a Blueprints file with a set of subdirs
511// listed it recursively parses any Blueprints files found in those
512// subdirectories.
513//
514// If no errors are encountered while parsing the files, the list of paths on
515// which the future output will depend is returned. This list will include both
516// Blueprints file paths as well as directory paths for cases where wildcard
517// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700518func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
519 errs []error) {
520
Colin Cross7ad621c2015-01-07 16:22:45 -0800521 c.dependenciesReady = false
522
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700523 rootDir := filepath.Dir(rootFile)
524
Colin Cross7ad621c2015-01-07 16:22:45 -0800525 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700526
Colin Cross7ad621c2015-01-07 16:22:45 -0800527 // Channels to receive data back from parseBlueprintsFile goroutines
528 blueprintsCh := make(chan stringAndScope)
529 errsCh := make(chan []error)
530 modulesCh := make(chan []*moduleInfo)
531 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700532
Colin Cross7ad621c2015-01-07 16:22:45 -0800533 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
534 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700535
Colin Cross7ad621c2015-01-07 16:22:45 -0800536 // Number of outstanding goroutines to wait for
537 count := 0
538
539 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
540 count++
541 go func() {
542 c.parseBlueprintsFile(filename, scope, rootDir,
543 errsCh, modulesCh, blueprintsCh, depsCh)
544 doneCh <- struct{}{}
545 }()
546 }
547
548 tooManyErrors := false
549
550 startParseBlueprintsFile(rootFile, nil)
551
552loop:
553 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700554 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800555 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700556 }
557
Colin Cross7ad621c2015-01-07 16:22:45 -0800558 select {
559 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700560 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800561 case dep := <-depsCh:
562 deps = append(deps, dep)
563 case modules := <-modulesCh:
564 newErrs := c.addModules(modules)
565 errs = append(errs, newErrs...)
566 case blueprint := <-blueprintsCh:
567 if tooManyErrors {
568 continue
569 }
570 if blueprintsSet[blueprint.string] {
571 continue
572 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700573
Colin Cross7ad621c2015-01-07 16:22:45 -0800574 blueprintsSet[blueprint.string] = true
575 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
576 case <-doneCh:
577 count--
578 if count == 0 {
579 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700580 }
581 }
582 }
583
Colin Cross7ad621c2015-01-07 16:22:45 -0800584 return
585}
586
587// parseBlueprintFile parses a single Blueprints file, returning any errors through
588// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
589// blueprintsCh, and any dependencies on Blueprints files or directories through
590// depsCh.
591func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
592 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
593 depsCh chan<- string) {
594
Colin Cross7ad621c2015-01-07 16:22:45 -0800595 file, err := os.Open(filename)
596 if err != nil {
597 errsCh <- []error{err}
598 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700599 }
600
Colin Cross1fef5362015-04-20 16:50:54 -0700601 modules, subBlueprints, deps, errs := c.parse(rootDir, filename, file, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800602 if len(errs) > 0 {
603 errsCh <- errs
604 }
605
Colin Cross1fef5362015-04-20 16:50:54 -0700606 for _, b := range subBlueprints {
607 blueprintsCh <- b
608 }
609
610 for _, d := range deps {
611 depsCh <- d
612 }
613
Colin Cross7ad621c2015-01-07 16:22:45 -0800614 err = file.Close()
615 if err != nil {
616 errsCh <- []error{err}
617 }
618
619 modulesCh <- modules
Colin Cross1fef5362015-04-20 16:50:54 -0700620}
621
Colin Cross29394222015-04-27 13:18:21 -0700622func (c *Context) findSubdirBlueprints(dir string, subdirs, build []string, subBlueprintsName string,
Colin Cross1fef5362015-04-20 16:50:54 -0700623 subdirsPos, buildPos scanner.Position) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800624
625 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700626 globPattern := filepath.Join(dir, subdir)
627 matches, matchedDirs, err := pathtools.Glob(globPattern)
628 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700629 errs = append(errs, &Error{
630 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
631 Pos: subdirsPos,
632 })
633 continue
634 }
635
636 if len(matches) == 0 {
637 errs = append(errs, &Error{
638 Err: fmt.Errorf("%q: not found", globPattern),
639 Pos: subdirsPos,
640 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700641 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800642
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700643 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700644 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800645
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700646 for _, foundSubdir := range matches {
647 fileInfo, subdirStatErr := os.Stat(foundSubdir)
648 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700649 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700650 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800651 }
652
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700653 // Skip files
654 if !fileInfo.IsDir() {
655 continue
656 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800657
Colin Cross29394222015-04-27 13:18:21 -0700658 var subBlueprints string
659 if subBlueprintsName != "" {
660 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
661 _, err = os.Stat(subBlueprints)
662 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700663
Colin Cross29394222015-04-27 13:18:21 -0700664 if os.IsNotExist(err) || subBlueprints == "" {
665 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
666 _, err = os.Stat(subBlueprints)
667 }
668
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700669 if os.IsNotExist(err) {
670 // There is no Blueprints file in this subdirectory. We
671 // need to add the directory to the list of dependencies
672 // so that if someone adds a Blueprints file in the
673 // future we'll pick it up.
Colin Cross29394222015-04-27 13:18:21 -0700674 deps = append(deps, filepath.Dir(foundSubdir))
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700675 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700676 deps = append(deps, subBlueprints)
677 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800678 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800679 }
680 }
Colin Cross1fef5362015-04-20 16:50:54 -0700681
682 for _, file := range build {
683 globPattern := filepath.Join(dir, file)
684 matches, matchedDirs, err := pathtools.Glob(globPattern)
685 if err != nil {
686 errs = append(errs, &Error{
687 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
688 Pos: buildPos,
689 })
690 continue
691 }
692
693 if len(matches) == 0 {
694 errs = append(errs, &Error{
695 Err: fmt.Errorf("%q: not found", globPattern),
696 Pos: buildPos,
697 })
698 }
699
700 // Depend on all searched directories so we pick up future changes.
701 deps = append(deps, matchedDirs...)
702
703 for _, foundBlueprints := range matches {
704 fileInfo, err := os.Stat(foundBlueprints)
705 if os.IsNotExist(err) {
706 errs = append(errs, &Error{
707 Err: fmt.Errorf("%q not found", foundBlueprints),
708 })
709 continue
710 }
711
712 if fileInfo.IsDir() {
713 errs = append(errs, &Error{
714 Err: fmt.Errorf("%q is a directory", foundBlueprints),
715 })
716 continue
717 }
718
719 blueprints = append(blueprints, foundBlueprints)
720 }
721 }
722
723 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700724}
725
Colin Cross1fef5362015-04-20 16:50:54 -0700726func getStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
727 if assignment, err := scope.Get(v); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700728 switch assignment.Value.Type {
729 case parser.List:
Colin Cross1fef5362015-04-20 16:50:54 -0700730 ret := make([]string, 0, len(assignment.Value.ListValue))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700731
732 for _, value := range assignment.Value.ListValue {
733 if value.Type != parser.String {
734 // The parser should not produce this.
735 panic("non-string value found in list")
736 }
737
Colin Cross1fef5362015-04-20 16:50:54 -0700738 ret = append(ret, value.StringValue)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700739 }
740
Colin Cross1fef5362015-04-20 16:50:54 -0700741 return ret, assignment.Pos, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700742 case parser.Bool, parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700743 return nil, scanner.Position{}, &Error{
744 Err: fmt.Errorf("%q must be a list of strings", v),
745 Pos: assignment.Pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700746 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700747 default:
748 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
749 }
750 }
751
Colin Cross1fef5362015-04-20 16:50:54 -0700752 return nil, scanner.Position{}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700753}
754
Colin Cross29394222015-04-27 13:18:21 -0700755func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
756 if assignment, err := scope.Get(v); err == nil {
757 switch assignment.Value.Type {
758 case parser.String:
759 return assignment.Value.StringValue, assignment.Pos, nil
760 case parser.Bool, parser.List:
761 return "", scanner.Position{}, &Error{
762 Err: fmt.Errorf("%q must be a string", v),
763 Pos: assignment.Pos,
764 }
765 default:
766 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
767 }
768 }
769
770 return "", scanner.Position{}, nil
771}
772
Colin Crossf5e34b92015-03-13 16:02:36 -0700773func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
774 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800775
Colin Crossf4d18a62015-03-18 17:43:15 -0700776 if len(variationNames) == 0 {
777 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400778 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700779 }
780
Colin Crossc9028482014-12-18 16:28:54 -0800781 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800782
Colin Cross174ae052015-03-03 17:37:03 -0800783 var errs []error
784
Colin Crossf5e34b92015-03-13 16:02:36 -0700785 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700786 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800787 factory, ok := c.moduleFactories[typeName]
788 if !ok {
789 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
790 }
791
792 var newLogicModule Module
793 var newProperties []interface{}
794
795 if i == 0 {
796 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700797 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
798 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800799 newLogicModule = origModule.logicModule
800 newProperties = origModule.moduleProperties
801 } else {
802 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700803 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800804 }
805 newLogicModule, newProperties = factory()
806
807 newProperties = append(props, newProperties...)
808
809 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700810 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800811 }
812
813 for i := range newProperties {
814 dst := reflect.ValueOf(newProperties[i]).Elem()
815 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
816
817 proptools.CopyProperties(dst, src)
818 }
819 }
820
Colin Crossf5e34b92015-03-13 16:02:36 -0700821 newVariant := origModule.variant.clone()
822 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800823
Colin Crossed342d92015-03-11 00:57:25 -0700824 m := *origModule
825 newModule := &m
826 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
827 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700828 newModule.variant = newVariant
829 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700830 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800831
Colin Crosse7daa222015-03-11 14:35:41 -0700832 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700833 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700834 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700835 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700836 }
837
Colin Crossc9028482014-12-18 16:28:54 -0800838 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700839
840 // Insert the new variant into the global module map. If this is the first variant then
841 // it reuses logicModule from the original module, which causes this to replace the
842 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800843 c.moduleInfo[newModule.logicModule] = newModule
844
Colin Crossf5e34b92015-03-13 16:02:36 -0700845 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800846 if len(newErrs) > 0 {
847 errs = append(errs, newErrs...)
848 }
Colin Crossc9028482014-12-18 16:28:54 -0800849 }
850
851 // Mark original variant as invalid. Modules that depend on this module will still
852 // depend on origModule, but we'll fix it when the mutator is called on them.
853 origModule.logicModule = nil
854 origModule.splitModules = newModules
855
Colin Cross174ae052015-03-03 17:37:03 -0800856 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800857}
858
Colin Crossf5e34b92015-03-13 16:02:36 -0700859func (c *Context) convertDepsToVariation(module *moduleInfo,
860 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800861
Colin Crossc9028482014-12-18 16:28:54 -0800862 for i, dep := range module.directDeps {
863 if dep.logicModule == nil {
864 var newDep *moduleInfo
865 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700866 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800867 newDep = m
868 break
869 }
870 }
871 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800872 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700873 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
874 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700875 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800876 })
877 continue
Colin Crossc9028482014-12-18 16:28:54 -0800878 }
879 module.directDeps[i] = newDep
880 }
881 }
Colin Cross174ae052015-03-03 17:37:03 -0800882
883 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800884}
885
Colin Crossf5e34b92015-03-13 16:02:36 -0700886func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700887 names := make([]string, 0, len(variant))
888 for _, m := range c.variantMutatorNames {
889 if v, ok := variant[m]; ok {
890 names = append(names, m+":"+v)
891 }
892 }
893
894 return strings.Join(names, ", ")
895}
896
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700897func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800898 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700899
Colin Crossd1facc12015-01-08 14:56:03 -0800900 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700901 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700902 if !ok {
903 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800904 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700905 }
906
Colin Cross7ad621c2015-01-07 16:22:45 -0800907 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700908 &Error{
909 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800910 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700911 },
912 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700913 }
914
Colin Crossbbfa51a2014-12-17 16:12:41 -0800915 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700916
917 module := &moduleInfo{
918 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700919 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700920 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700921 }
922
Jamie Gennis87622922014-09-30 11:38:25 -0700923 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700924 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700925 }
926 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700927 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700928
Jamie Gennis87622922014-09-30 11:38:25 -0700929 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700930 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800931 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700932 }
933
Colin Crossed342d92015-03-11 00:57:25 -0700934 module.pos = moduleDef.Type.Pos
935 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700936 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700937 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700938 }
939
Colin Cross7ad621c2015-01-07 16:22:45 -0800940 return module, nil
941}
942
943func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
944 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700945 name := module.properties.Name
946 c.moduleInfo[module.logicModule] = module
947
948 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800949 errs = append(errs, []error{
950 &Error{
951 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700952 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800953 },
954 &Error{
955 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700956 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800957 },
958 }...)
959 continue
Colin Crossed342d92015-03-11 00:57:25 -0700960 } else {
961 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800962
Colin Crossed342d92015-03-11 00:57:25 -0700963 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
964 // already exists
965 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
966 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
967 }
968
969 c.moduleNinjaNames[ninjaName] = group
970
971 group := &moduleGroup{
972 name: module.properties.Name,
973 ninjaName: ninjaName,
974 modules: []*moduleInfo{module},
975 }
976 module.group = group
977 c.moduleGroups[name] = group
978 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800979 }
980
981 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700982}
983
Jamie Gennisd4e10182014-06-12 20:06:50 -0700984// ResolveDependencies checks that the dependencies specified by all of the
985// modules defined in the parsed Blueprints files are valid. This means that
986// the modules depended upon are defined and that no circular dependencies
987// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700988//
989// The config argument is made available to all of the DynamicDependerModule
990// objects via the Config method on the DynamicDependerModuleContext objects
991// passed to their DynamicDependencies method.
992func (c *Context) ResolveDependencies(config interface{}) []error {
993 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700994 if len(errs) > 0 {
995 return errs
996 }
997
Colin Cross691a60d2015-01-07 18:08:56 -0800998 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700999 if len(errs) > 0 {
1000 return errs
1001 }
1002
1003 c.dependenciesReady = true
1004 return nil
1005}
1006
Colin Cross65569e42015-03-10 20:08:19 -07001007// moduleDeps adds dependencies to a module. If the module implements the
1008// DynamicDependerModule interface then this set consists of the union of those
1009// module names listed in its "deps" property, those returned by its
1010// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001011// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001012// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -07001013func (c *Context) moduleDeps(module *moduleInfo,
1014 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001015
1016 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -08001017 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001018
Colin Crossed342d92015-03-11 00:57:25 -07001019 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001020 if !depNamesSet[depName] {
1021 depNamesSet[depName] = true
1022 depNames = append(depNames, depName)
1023 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001024 }
1025
Colin Cross65569e42015-03-10 20:08:19 -07001026 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001027 if ok {
Colin Cross65569e42015-03-10 20:08:19 -07001028 ddmctx := &dynamicDependerModuleContext{
1029 baseModuleContext: baseModuleContext{
1030 context: c,
1031 config: config,
1032 module: module,
1033 },
1034 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001035 }
1036
1037 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
1038
1039 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -07001040 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001041 }
1042
1043 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -08001044 if !depNamesSet[depName] {
1045 depNamesSet[depName] = true
1046 depNames = append(depNames, depName)
1047 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001048 }
1049 }
1050
Colin Cross65569e42015-03-10 20:08:19 -07001051 for _, depName := range depNames {
1052 newErrs := c.addDependency(module, depName)
1053 if len(newErrs) > 0 {
1054 errs = append(errs, newErrs...)
1055 }
1056 }
1057 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001058}
1059
Colin Cross65569e42015-03-10 20:08:19 -07001060// resolveDependencies populates the directDeps list for every module. In doing so it checks for
1061// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001062func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001063 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -07001064 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -07001065 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1066
1067 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001068 if len(newErrs) > 0 {
1069 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001070 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001071 }
1072 }
1073
1074 return
1075}
1076
Colin Crossc9028482014-12-18 16:28:54 -08001077func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001078 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001079
Colin Crossed342d92015-03-11 00:57:25 -07001080 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001081 return []error{&Error{
1082 Err: fmt.Errorf("%q depends on itself", depName),
1083 Pos: depsPos,
1084 }}
1085 }
1086
1087 depInfo, ok := c.moduleGroups[depName]
1088 if !ok {
1089 return []error{&Error{
1090 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001091 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001092 Pos: depsPos,
1093 }}
1094 }
1095
Colin Cross65569e42015-03-10 20:08:19 -07001096 for _, m := range module.directDeps {
1097 if m.group == depInfo {
1098 return nil
1099 }
Colin Crossc9028482014-12-18 16:28:54 -08001100 }
1101
Colin Cross65569e42015-03-10 20:08:19 -07001102 if len(depInfo.modules) == 1 {
1103 module.directDeps = append(module.directDeps, depInfo.modules[0])
1104 return nil
1105 } else {
1106 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001107 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001108 module.directDeps = append(module.directDeps, m)
1109 return nil
1110 }
1111 }
1112 }
Colin Crossc9028482014-12-18 16:28:54 -08001113
Colin Cross65569e42015-03-10 20:08:19 -07001114 return []error{&Error{
1115 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1116 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001117 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001118 Pos: depsPos,
1119 }}
1120}
1121
Colin Crossf5e34b92015-03-13 16:02:36 -07001122func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross65569e42015-03-10 20:08:19 -07001123 depName string) []error {
1124
1125 depsPos := module.propertyPos["deps"]
1126
1127 depInfo, ok := c.moduleGroups[depName]
1128 if !ok {
1129 return []error{&Error{
1130 Err: fmt.Errorf("%q depends on undefined module %q",
1131 module.properties.Name, depName),
1132 Pos: depsPos,
1133 }}
1134 }
1135
1136 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1137 // compare the strings because the result won't be in mutator registration order.
1138 // Create a new map instead, and then deep compare the maps.
Colin Crossf5e34b92015-03-13 16:02:36 -07001139 newVariant := module.dependencyVariant.clone()
1140 for _, v := range variations {
1141 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001142 }
1143
1144 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001145 if newVariant.equal(m.variant) {
1146 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001147 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001148 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001149 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1150 return []error{&Error{
1151 Err: fmt.Errorf("%q depends on later version of itself", depName),
1152 Pos: depsPos,
1153 }}
1154 }
1155 module.directDeps = append(module.directDeps, m)
1156 return nil
1157 }
1158 }
1159
1160 return []error{&Error{
1161 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1162 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001163 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001164 Pos: depsPos,
1165 }}
Colin Crossc9028482014-12-18 16:28:54 -08001166}
1167
Colin Cross7addea32015-03-11 15:43:52 -07001168func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1169 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001170 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001171 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001172
Colin Cross7addea32015-03-11 15:43:52 -07001173 for _, module := range c.modulesSorted {
1174 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001175 }
1176
Colin Cross7addea32015-03-11 15:43:52 -07001177 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001178 count++
1179 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001180 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001181 if ret {
1182 cancel = true
1183 }
Colin Cross7addea32015-03-11 15:43:52 -07001184 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001185 }()
1186 }
1187
Colin Cross7addea32015-03-11 15:43:52 -07001188 for _, module := range c.modulesSorted {
1189 if module.waitingCount == 0 {
1190 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001191 }
1192 }
1193
Colin Cross11e3b0d2015-02-04 10:41:00 -08001194 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001195 select {
Colin Cross7addea32015-03-11 15:43:52 -07001196 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001197 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001198 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001199 parent.waitingCount--
1200 if parent.waitingCount == 0 {
1201 visitOne(parent)
1202 }
Colin Cross691a60d2015-01-07 18:08:56 -08001203 }
1204 }
1205 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001206 }
1207 }
1208}
1209
1210// updateDependencies recursively walks the module dependency graph and updates
1211// additional fields based on the dependencies. It builds a sorted list of modules
1212// such that dependencies of a module always appear first, and populates reverse
1213// dependency links and counts of total dependencies. It also reports errors when
1214// it encounters dependency cycles. This should called after resolveDependencies,
1215// as well as after any mutator pass has called addDependency
1216func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001217 visited := make(map[*moduleInfo]bool) // modules that were already checked
1218 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001219
Colin Cross7addea32015-03-11 15:43:52 -07001220 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001221
Colin Cross7addea32015-03-11 15:43:52 -07001222 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001223
Colin Cross7addea32015-03-11 15:43:52 -07001224 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001225 // We are the "start" of the cycle, so we're responsible
1226 // for generating the errors. The cycle list is in
1227 // reverse order because all the 'check' calls append
1228 // their own module to the list.
1229 errs = append(errs, &Error{
1230 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001231 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001232 })
1233
1234 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001235 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001236 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001237 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001238 errs = append(errs, &Error{
1239 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001240 curModule.properties.Name,
1241 nextModule.properties.Name),
1242 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001243 })
Colin Cross7addea32015-03-11 15:43:52 -07001244 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001245 }
1246 }
1247
Colin Cross7addea32015-03-11 15:43:52 -07001248 check = func(module *moduleInfo) []*moduleInfo {
1249 visited[module] = true
1250 checking[module] = true
1251 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001252
Colin Cross7addea32015-03-11 15:43:52 -07001253 deps := make(map[*moduleInfo]bool)
1254
1255 // Add an implicit dependency ordering on all earlier modules in the same module group
1256 for _, dep := range module.group.modules {
1257 if dep == module {
1258 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001259 }
Colin Cross7addea32015-03-11 15:43:52 -07001260 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001261 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001262
Colin Cross7addea32015-03-11 15:43:52 -07001263 for _, dep := range module.directDeps {
1264 deps[dep] = true
1265 }
1266
1267 module.reverseDeps = []*moduleInfo{}
1268 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001269
Colin Crossbbfa51a2014-12-17 16:12:41 -08001270 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001271 if checking[dep] {
1272 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001273 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001274 }
1275
1276 if !visited[dep] {
1277 cycle := check(dep)
1278 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001279 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001280 // We are the "start" of the cycle, so we're responsible
1281 // for generating the errors. The cycle list is in
1282 // reverse order because all the 'check' calls append
1283 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001284 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001285
1286 // We can continue processing this module's children to
1287 // find more cycles. Since all the modules that were
1288 // part of the found cycle were marked as visited we
1289 // won't run into that cycle again.
1290 } else {
1291 // We're not the "start" of the cycle, so we just append
1292 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001293 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001294 }
1295 }
1296 }
Colin Cross691a60d2015-01-07 18:08:56 -08001297
Colin Cross7addea32015-03-11 15:43:52 -07001298 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001299 }
1300
Colin Cross7addea32015-03-11 15:43:52 -07001301 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001302
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001303 return nil
1304 }
1305
Colin Cross7addea32015-03-11 15:43:52 -07001306 for _, module := range c.moduleInfo {
1307 if !visited[module] {
1308 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001309 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001310 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001311 panic("inconceivable!")
1312 }
1313 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001314 }
1315 }
1316 }
1317
Colin Cross7addea32015-03-11 15:43:52 -07001318 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001319
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001320 return
1321}
1322
Jamie Gennisd4e10182014-06-12 20:06:50 -07001323// PrepareBuildActions generates an internal representation of all the build
1324// actions that need to be performed. This process involves invoking the
1325// GenerateBuildActions method on each of the Module objects created during the
1326// parse phase and then on each of the registered Singleton objects.
1327//
1328// If the ResolveDependencies method has not already been called it is called
1329// automatically by this method.
1330//
1331// The config argument is made available to all of the Module and Singleton
1332// objects via the Config method on the ModuleContext and SingletonContext
1333// objects passed to GenerateBuildActions. It is also passed to the functions
1334// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1335// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001336//
1337// The returned deps is a list of the ninja files dependencies that were added
1338// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1339// SingletonContext.AddNinjaFileDeps() methods.
1340func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001341 c.buildActionsReady = false
1342
Colin Cross65569e42015-03-10 20:08:19 -07001343 errs = c.runEarlyMutators(config)
1344 if len(errs) > 0 {
1345 return nil, errs
1346 }
1347
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001348 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001349 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001350 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001351 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001352 }
1353 }
1354
Colin Crossc9028482014-12-18 16:28:54 -08001355 errs = c.runMutators(config)
1356 if len(errs) > 0 {
1357 return nil, errs
1358 }
1359
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001360 liveGlobals := newLiveTracker(config)
1361
1362 c.initSpecialVariables()
1363
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001364 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001365 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001366 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001367 }
1368
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001369 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001370 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001371 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001372 }
1373
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001374 deps = append(depsModules, depsSingletons...)
1375
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001376 if c.buildDir != nil {
1377 liveGlobals.addNinjaStringDeps(c.buildDir)
1378 }
1379
1380 pkgNames := c.makeUniquePackageNames(liveGlobals)
1381
1382 // This will panic if it finds a problem since it's a programming error.
1383 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1384
1385 c.pkgNames = pkgNames
1386 c.globalVariables = liveGlobals.variables
1387 c.globalPools = liveGlobals.pools
1388 c.globalRules = liveGlobals.rules
1389
1390 c.buildActionsReady = true
1391
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001392 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001393}
1394
Colin Cross65569e42015-03-10 20:08:19 -07001395func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1396 for _, mutator := range c.earlyMutatorInfo {
1397 for _, group := range c.moduleGroups {
1398 newModules := make([]*moduleInfo, 0, len(group.modules))
1399
1400 for _, module := range group.modules {
1401 mctx := &mutatorContext{
1402 baseModuleContext: baseModuleContext{
1403 context: c,
1404 config: config,
1405 module: module,
1406 },
1407 name: mutator.name,
1408 }
1409 mutator.mutator(mctx)
1410 if len(mctx.errs) > 0 {
1411 errs = append(errs, mctx.errs...)
1412 return errs
1413 }
1414
1415 if module.splitModules != nil {
1416 newModules = append(newModules, module.splitModules...)
1417 } else {
1418 newModules = append(newModules, module)
1419 }
1420 }
1421
1422 group.modules = newModules
1423 }
1424 }
1425
1426 return nil
1427}
1428
Colin Crossc9028482014-12-18 16:28:54 -08001429func (c *Context) runMutators(config interface{}) (errs []error) {
1430 for _, mutator := range c.mutatorInfo {
1431 if mutator.topDownMutator != nil {
1432 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1433 } else if mutator.bottomUpMutator != nil {
1434 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1435 } else {
1436 panic("no mutator set on " + mutator.name)
1437 }
1438 if len(errs) > 0 {
1439 return errs
1440 }
1441 }
1442
1443 return nil
1444}
1445
1446func (c *Context) runTopDownMutator(config interface{},
1447 name string, mutator TopDownMutator) (errs []error) {
1448
Colin Cross7addea32015-03-11 15:43:52 -07001449 for i := 0; i < len(c.modulesSorted); i++ {
1450 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1451 mctx := &mutatorContext{
1452 baseModuleContext: baseModuleContext{
1453 context: c,
1454 config: config,
1455 module: module,
1456 },
1457 name: name,
1458 }
Colin Crossc9028482014-12-18 16:28:54 -08001459
Colin Cross7addea32015-03-11 15:43:52 -07001460 mutator(mctx)
1461 if len(mctx.errs) > 0 {
1462 errs = append(errs, mctx.errs...)
1463 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001464 }
1465 }
1466
1467 return errs
1468}
1469
1470func (c *Context) runBottomUpMutator(config interface{},
1471 name string, mutator BottomUpMutator) (errs []error) {
1472
Colin Cross7addea32015-03-11 15:43:52 -07001473 for _, module := range c.modulesSorted {
1474 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001475
Jamie Gennisc7988252015-04-14 23:28:10 -04001476 if module.splitModules != nil {
1477 panic("split module found in sorted module list")
1478 }
1479
Colin Cross7addea32015-03-11 15:43:52 -07001480 mctx := &mutatorContext{
1481 baseModuleContext: baseModuleContext{
1482 context: c,
1483 config: config,
1484 module: module,
1485 },
1486 name: name,
1487 }
Colin Crossc9028482014-12-18 16:28:54 -08001488
Colin Cross7addea32015-03-11 15:43:52 -07001489 mutator(mctx)
1490 if len(mctx.errs) > 0 {
1491 errs = append(errs, mctx.errs...)
1492 return errs
1493 }
Colin Crossc9028482014-12-18 16:28:54 -08001494
Colin Cross7addea32015-03-11 15:43:52 -07001495 // Fix up any remaining dependencies on modules that were split into variants
1496 // by replacing them with the first variant
1497 for i, dep := range module.directDeps {
1498 if dep.logicModule == nil {
1499 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001500 }
1501 }
1502
Colin Cross7addea32015-03-11 15:43:52 -07001503 if module.splitModules != nil {
1504 newModules = append(newModules, module.splitModules...)
1505 } else {
1506 newModules = append(newModules, module)
1507 }
1508
1509 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001510 }
1511
Jamie Gennisc7988252015-04-14 23:28:10 -04001512 errs = c.updateDependencies()
1513 if len(errs) > 0 {
1514 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001515 }
1516
1517 return errs
1518}
1519
Colin Cross7addea32015-03-11 15:43:52 -07001520func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1521 newModules []*moduleInfo) []*moduleInfo {
1522 for i, m := range modules {
1523 if m == origModule {
1524 return spliceModulesAtIndex(modules, i, newModules)
1525 }
1526 }
1527
1528 panic("failed to find original module to splice")
1529}
1530
1531func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1532 spliceSize := len(newModules)
1533 newLen := len(modules) + spliceSize - 1
1534 var dest []*moduleInfo
1535 if cap(modules) >= len(modules)-1+len(newModules) {
1536 // We can fit the splice in the existing capacity, do everything in place
1537 dest = modules[:newLen]
1538 } else {
1539 dest = make([]*moduleInfo, newLen)
1540 copy(dest, modules[:i])
1541 }
1542
1543 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001544 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001545
1546 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001547 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001548
Colin Cross72bd1932015-03-16 00:13:59 -07001549 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001550}
1551
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001552func (c *Context) initSpecialVariables() {
1553 c.buildDir = nil
1554 c.requiredNinjaMajor = 1
1555 c.requiredNinjaMinor = 1
1556 c.requiredNinjaMicro = 0
1557}
1558
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001559func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001560 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001561
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001562 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001563 var errs []error
1564
Colin Cross691a60d2015-01-07 18:08:56 -08001565 cancelCh := make(chan struct{})
1566 errsCh := make(chan []error)
1567 depsCh := make(chan []string)
1568
1569 go func() {
1570 for {
1571 select {
1572 case <-cancelCh:
1573 close(cancelCh)
1574 return
1575 case newErrs := <-errsCh:
1576 errs = append(errs, newErrs...)
1577 case newDeps := <-depsCh:
1578 deps = append(deps, newDeps...)
1579
1580 }
1581 }
1582 }()
1583
Colin Cross7addea32015-03-11 15:43:52 -07001584 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1585 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1586 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1587 // just set it to nil.
1588 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1589 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001590
Colin Cross7addea32015-03-11 15:43:52 -07001591 mctx := &moduleContext{
1592 baseModuleContext: baseModuleContext{
1593 context: c,
1594 config: config,
1595 module: module,
1596 },
1597 scope: scope,
1598 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001599
Colin Cross7addea32015-03-11 15:43:52 -07001600 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001601
Colin Cross7addea32015-03-11 15:43:52 -07001602 if len(mctx.errs) > 0 {
1603 errsCh <- mctx.errs
1604 return true
1605 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001606
Colin Cross7addea32015-03-11 15:43:52 -07001607 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001608
Colin Crossab6d7902015-03-11 16:17:52 -07001609 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001610 &mctx.actionDefs, liveGlobals)
1611 if len(newErrs) > 0 {
1612 errsCh <- newErrs
1613 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001614 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001615 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001616 })
1617
1618 cancelCh <- struct{}{}
1619 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001620
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001621 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001622}
1623
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001624func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001625 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001626
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001627 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001628 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001629
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001630 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001631 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1632 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1633 // just set it to nil.
1634 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635
1636 sctx := &singletonContext{
1637 context: c,
1638 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001639 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001640 }
1641
1642 info.singleton.GenerateBuildActions(sctx)
1643
1644 if len(sctx.errs) > 0 {
1645 errs = append(errs, sctx.errs...)
1646 if len(errs) > maxErrors {
1647 break
1648 }
1649 continue
1650 }
1651
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001652 deps = append(deps, sctx.ninjaFileDeps...)
1653
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001654 newErrs := c.processLocalBuildActions(&info.actionDefs,
1655 &sctx.actionDefs, liveGlobals)
1656 errs = append(errs, newErrs...)
1657 if len(errs) > maxErrors {
1658 break
1659 }
1660 }
1661
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001662 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001663}
1664
1665func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1666 liveGlobals *liveTracker) []error {
1667
1668 var errs []error
1669
1670 // First we go through and add everything referenced by the module's
1671 // buildDefs to the live globals set. This will end up adding the live
1672 // locals to the set as well, but we'll take them out after.
1673 for _, def := range in.buildDefs {
1674 err := liveGlobals.AddBuildDefDeps(def)
1675 if err != nil {
1676 errs = append(errs, err)
1677 }
1678 }
1679
1680 if len(errs) > 0 {
1681 return errs
1682 }
1683
Colin Crossc9028482014-12-18 16:28:54 -08001684 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001685
1686 // We use the now-incorrect set of live "globals" to determine which local
1687 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001688 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001689 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001690 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001691 if isLive {
1692 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001693 }
1694 }
1695
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001696 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001697 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001698 if isLive {
1699 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001700 }
1701 }
1702
1703 return nil
1704}
1705
Colin Crossbbfa51a2014-12-17 16:12:41 -08001706func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1707 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001708
Colin Crossbbfa51a2014-12-17 16:12:41 -08001709 var walk func(module *moduleInfo)
1710 walk = func(module *moduleInfo) {
1711 visited[module] = true
1712 for _, moduleDep := range module.directDeps {
1713 if !visited[moduleDep] {
1714 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001715 }
1716 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001717
Colin Crossbbfa51a2014-12-17 16:12:41 -08001718 if module != topModule {
1719 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001720 }
1721 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001722
1723 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001724}
1725
Colin Crossbbfa51a2014-12-17 16:12:41 -08001726func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001727 visit func(Module)) {
1728
Colin Crossbbfa51a2014-12-17 16:12:41 -08001729 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001730
Colin Crossbbfa51a2014-12-17 16:12:41 -08001731 var walk func(module *moduleInfo)
1732 walk = func(module *moduleInfo) {
1733 visited[module] = true
1734 for _, moduleDep := range module.directDeps {
1735 if !visited[moduleDep] {
1736 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001737 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001738 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001739
1740 if module != topModule {
1741 if pred(module.logicModule) {
1742 visit(module.logicModule)
1743 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001744 }
1745 }
1746
Colin Crossbbfa51a2014-12-17 16:12:41 -08001747 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001748}
1749
Colin Crossc9028482014-12-18 16:28:54 -08001750func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1751 for _, dep := range module.directDeps {
1752 visit(dep.logicModule)
1753 }
1754}
1755
1756func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1757 visit func(Module)) {
1758
1759 for _, dep := range module.directDeps {
1760 if pred(dep.logicModule) {
1761 visit(dep.logicModule)
1762 }
1763 }
1764}
1765
Jamie Gennisc15544d2014-09-24 20:26:52 -07001766func (c *Context) sortedModuleNames() []string {
1767 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001768 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1769 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001770 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1771 moduleName)
1772 }
1773 sort.Strings(c.cachedSortedModuleNames)
1774 }
1775
1776 return c.cachedSortedModuleNames
1777}
1778
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001779func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001780 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001781 group := c.moduleGroups[moduleName]
1782 for _, module := range group.modules {
1783 visit(module.logicModule)
1784 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001785 }
1786}
1787
1788func (c *Context) visitAllModulesIf(pred func(Module) bool,
1789 visit func(Module)) {
1790
Jamie Gennisc15544d2014-09-24 20:26:52 -07001791 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001792 group := c.moduleGroups[moduleName]
1793 for _, module := range group.modules {
1794 if pred(module.logicModule) {
1795 visit(module.logicModule)
1796 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001797 }
1798 }
1799}
1800
1801func (c *Context) requireNinjaVersion(major, minor, micro int) {
1802 if major != 1 {
1803 panic("ninja version with major version != 1 not supported")
1804 }
1805 if c.requiredNinjaMinor < minor {
1806 c.requiredNinjaMinor = minor
1807 c.requiredNinjaMicro = micro
1808 }
1809 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1810 c.requiredNinjaMicro = micro
1811 }
1812}
1813
1814func (c *Context) setBuildDir(value *ninjaString) {
1815 if c.buildDir != nil {
1816 panic("buildDir set multiple times")
1817 }
1818 c.buildDir = value
1819}
1820
1821func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001822 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001823
Jamie Gennis2fb20952014-10-03 02:49:58 -07001824 pkgs := make(map[string]*PackageContext)
1825 pkgNames := make(map[*PackageContext]string)
1826 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001827
Jamie Gennis2fb20952014-10-03 02:49:58 -07001828 processPackage := func(pctx *PackageContext) {
1829 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001830 // This is a built-in rule and has no package.
1831 return
1832 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001833 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001834 // We've already processed this package.
1835 return
1836 }
1837
Jamie Gennis2fb20952014-10-03 02:49:58 -07001838 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001839 if present {
1840 // Short name collision. Both this package and the one that's
1841 // already there need to use their full names. We leave the short
1842 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001843 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844 longPkgNames[otherPkg] = true
1845 } else {
1846 // No collision so far. Tentatively set the package's name to be
1847 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001848 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07001849 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001850 }
1851 }
1852
1853 // We try to give all packages their short name, but when we get collisions
1854 // we need to use the full unique package name.
1855 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001856 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001857 }
1858 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001859 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001860 }
1861 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001862 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001863 }
1864
1865 // Add the packages that had collisions using their full unique names. This
1866 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001867 for pctx := range longPkgNames {
1868 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001869 }
1870
1871 return pkgNames
1872}
1873
1874func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001875 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001876
1877 visited := make(map[Variable]bool) // variables that were already checked
1878 checking := make(map[Variable]bool) // variables actively being checked
1879
1880 var check func(v Variable) []Variable
1881
1882 check = func(v Variable) []Variable {
1883 visited[v] = true
1884 checking[v] = true
1885 defer delete(checking, v)
1886
1887 value := variables[v]
1888 for _, dep := range value.variables {
1889 if checking[dep] {
1890 // This is a cycle.
1891 return []Variable{dep, v}
1892 }
1893
1894 if !visited[dep] {
1895 cycle := check(dep)
1896 if cycle != nil {
1897 if cycle[0] == v {
1898 // We are the "start" of the cycle, so we're responsible
1899 // for generating the errors. The cycle list is in
1900 // reverse order because all the 'check' calls append
1901 // their own module to the list.
1902 msgs := []string{"detected variable reference cycle:"}
1903
1904 // Iterate backwards through the cycle list.
1905 curName := v.fullName(pkgNames)
1906 curValue := value.Value(pkgNames)
1907 for i := len(cycle) - 1; i >= 0; i-- {
1908 next := cycle[i]
1909 nextName := next.fullName(pkgNames)
1910 nextValue := variables[next].Value(pkgNames)
1911
1912 msgs = append(msgs, fmt.Sprintf(
1913 " %q depends on %q", curName, nextName))
1914 msgs = append(msgs, fmt.Sprintf(
1915 " [%s = %s]", curName, curValue))
1916
1917 curName = nextName
1918 curValue = nextValue
1919 }
1920
1921 // Variable reference cycles are a programming error,
1922 // not the fault of the Blueprint file authors.
1923 panic(strings.Join(msgs, "\n"))
1924 } else {
1925 // We're not the "start" of the cycle, so we just append
1926 // our module to the list and return it.
1927 return append(cycle, v)
1928 }
1929 }
1930 }
1931 }
1932
1933 return nil
1934 }
1935
1936 for v := range variables {
1937 if !visited[v] {
1938 cycle := check(v)
1939 if cycle != nil {
1940 panic("inconceivable!")
1941 }
1942 }
1943 }
1944}
1945
Jamie Gennisaf435562014-10-27 22:34:56 -07001946// AllTargets returns a map all the build target names to the rule used to build
1947// them. This is the same information that is output by running 'ninja -t
1948// targets all'. If this is called before PrepareBuildActions successfully
1949// completes then ErrbuildActionsNotReady is returned.
1950func (c *Context) AllTargets() (map[string]string, error) {
1951 if !c.buildActionsReady {
1952 return nil, ErrBuildActionsNotReady
1953 }
1954
1955 targets := map[string]string{}
1956
1957 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001958 for _, module := range c.moduleInfo {
1959 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001960 ruleName := buildDef.Rule.fullName(c.pkgNames)
1961 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001962 outputValue, err := output.Eval(c.globalVariables)
1963 if err != nil {
1964 return nil, err
1965 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001966 targets[outputValue] = ruleName
1967 }
1968 }
1969 }
1970
1971 // Collect all the singleton build targets.
1972 for _, info := range c.singletonInfo {
1973 for _, buildDef := range info.actionDefs.buildDefs {
1974 ruleName := buildDef.Rule.fullName(c.pkgNames)
1975 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001976 outputValue, err := output.Eval(c.globalVariables)
1977 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001978 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001979 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001980 targets[outputValue] = ruleName
1981 }
1982 }
1983 }
1984
1985 return targets, nil
1986}
1987
Jamie Gennisd4e10182014-06-12 20:06:50 -07001988// WriteBuildFile writes the Ninja manifeset text for the generated build
1989// actions to w. If this is called before PrepareBuildActions successfully
1990// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001991func (c *Context) WriteBuildFile(w io.Writer) error {
1992 if !c.buildActionsReady {
1993 return ErrBuildActionsNotReady
1994 }
1995
1996 nw := newNinjaWriter(w)
1997
1998 err := c.writeBuildFileHeader(nw)
1999 if err != nil {
2000 return err
2001 }
2002
2003 err = c.writeNinjaRequiredVersion(nw)
2004 if err != nil {
2005 return err
2006 }
2007
2008 // TODO: Group the globals by package.
2009
2010 err = c.writeGlobalVariables(nw)
2011 if err != nil {
2012 return err
2013 }
2014
2015 err = c.writeGlobalPools(nw)
2016 if err != nil {
2017 return err
2018 }
2019
2020 err = c.writeBuildDir(nw)
2021 if err != nil {
2022 return err
2023 }
2024
2025 err = c.writeGlobalRules(nw)
2026 if err != nil {
2027 return err
2028 }
2029
2030 err = c.writeAllModuleActions(nw)
2031 if err != nil {
2032 return err
2033 }
2034
2035 err = c.writeAllSingletonActions(nw)
2036 if err != nil {
2037 return err
2038 }
2039
2040 return nil
2041}
2042
Jamie Gennisc15544d2014-09-24 20:26:52 -07002043type pkgAssociation struct {
2044 PkgName string
2045 PkgPath string
2046}
2047
2048type pkgAssociationSorter struct {
2049 pkgs []pkgAssociation
2050}
2051
2052func (s *pkgAssociationSorter) Len() int {
2053 return len(s.pkgs)
2054}
2055
2056func (s *pkgAssociationSorter) Less(i, j int) bool {
2057 iName := s.pkgs[i].PkgName
2058 jName := s.pkgs[j].PkgName
2059 return iName < jName
2060}
2061
2062func (s *pkgAssociationSorter) Swap(i, j int) {
2063 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2064}
2065
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002066func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2067 headerTemplate := template.New("fileHeader")
2068 _, err := headerTemplate.Parse(fileHeaderTemplate)
2069 if err != nil {
2070 // This is a programming error.
2071 panic(err)
2072 }
2073
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002074 var pkgs []pkgAssociation
2075 maxNameLen := 0
2076 for pkg, name := range c.pkgNames {
2077 pkgs = append(pkgs, pkgAssociation{
2078 PkgName: name,
2079 PkgPath: pkg.pkgPath,
2080 })
2081 if len(name) > maxNameLen {
2082 maxNameLen = len(name)
2083 }
2084 }
2085
2086 for i := range pkgs {
2087 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2088 }
2089
Jamie Gennisc15544d2014-09-24 20:26:52 -07002090 sort.Sort(&pkgAssociationSorter{pkgs})
2091
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002092 params := map[string]interface{}{
2093 "Pkgs": pkgs,
2094 }
2095
2096 buf := bytes.NewBuffer(nil)
2097 err = headerTemplate.Execute(buf, params)
2098 if err != nil {
2099 return err
2100 }
2101
2102 return nw.Comment(buf.String())
2103}
2104
2105func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2106 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2107 c.requiredNinjaMicro)
2108
2109 err := nw.Assign("ninja_required_version", value)
2110 if err != nil {
2111 return err
2112 }
2113
2114 return nw.BlankLine()
2115}
2116
2117func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2118 if c.buildDir != nil {
2119 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2120 if err != nil {
2121 return err
2122 }
2123
2124 err = nw.BlankLine()
2125 if err != nil {
2126 return err
2127 }
2128 }
2129 return nil
2130}
2131
Jamie Gennisc15544d2014-09-24 20:26:52 -07002132type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002133 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002134}
2135
Jamie Gennisc15544d2014-09-24 20:26:52 -07002136type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002137 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002138 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002139}
2140
Jamie Gennisc15544d2014-09-24 20:26:52 -07002141func (s *globalEntitySorter) Len() int {
2142 return len(s.entities)
2143}
2144
2145func (s *globalEntitySorter) Less(i, j int) bool {
2146 iName := s.entities[i].fullName(s.pkgNames)
2147 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002148 return iName < jName
2149}
2150
Jamie Gennisc15544d2014-09-24 20:26:52 -07002151func (s *globalEntitySorter) Swap(i, j int) {
2152 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002153}
2154
2155func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2156 visited := make(map[Variable]bool)
2157
2158 var walk func(v Variable) error
2159 walk = func(v Variable) error {
2160 visited[v] = true
2161
2162 // First visit variables on which this variable depends.
2163 value := c.globalVariables[v]
2164 for _, dep := range value.variables {
2165 if !visited[dep] {
2166 err := walk(dep)
2167 if err != nil {
2168 return err
2169 }
2170 }
2171 }
2172
2173 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2174 if err != nil {
2175 return err
2176 }
2177
2178 err = nw.BlankLine()
2179 if err != nil {
2180 return err
2181 }
2182
2183 return nil
2184 }
2185
Jamie Gennisc15544d2014-09-24 20:26:52 -07002186 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2187 for variable := range c.globalVariables {
2188 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002189 }
2190
Jamie Gennisc15544d2014-09-24 20:26:52 -07002191 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002192
Jamie Gennisc15544d2014-09-24 20:26:52 -07002193 for _, entity := range globalVariables {
2194 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002195 if !visited[v] {
2196 err := walk(v)
2197 if err != nil {
2198 return nil
2199 }
2200 }
2201 }
2202
2203 return nil
2204}
2205
2206func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002207 globalPools := make([]globalEntity, 0, len(c.globalPools))
2208 for pool := range c.globalPools {
2209 globalPools = append(globalPools, pool)
2210 }
2211
2212 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2213
2214 for _, entity := range globalPools {
2215 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002216 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002217 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218 err := def.WriteTo(nw, name)
2219 if err != nil {
2220 return err
2221 }
2222
2223 err = nw.BlankLine()
2224 if err != nil {
2225 return err
2226 }
2227 }
2228
2229 return nil
2230}
2231
2232func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002233 globalRules := make([]globalEntity, 0, len(c.globalRules))
2234 for rule := range c.globalRules {
2235 globalRules = append(globalRules, rule)
2236 }
2237
2238 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2239
2240 for _, entity := range globalRules {
2241 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002242 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002243 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002244 err := def.WriteTo(nw, name, c.pkgNames)
2245 if err != nil {
2246 return err
2247 }
2248
2249 err = nw.BlankLine()
2250 if err != nil {
2251 return err
2252 }
2253 }
2254
2255 return nil
2256}
2257
Colin Crossab6d7902015-03-11 16:17:52 -07002258type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002259
Colin Crossab6d7902015-03-11 16:17:52 -07002260func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002261 return len(s)
2262}
2263
Colin Crossab6d7902015-03-11 16:17:52 -07002264func (s moduleSorter) Less(i, j int) bool {
2265 iName := s[i].properties.Name
2266 jName := s[j].properties.Name
2267 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002268 iName = s[i].variantName
2269 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002270 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002271 return iName < jName
2272}
2273
Colin Crossab6d7902015-03-11 16:17:52 -07002274func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002275 s[i], s[j] = s[j], s[i]
2276}
2277
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002278func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2279 headerTemplate := template.New("moduleHeader")
2280 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2281 if err != nil {
2282 // This is a programming error.
2283 panic(err)
2284 }
2285
Colin Crossab6d7902015-03-11 16:17:52 -07002286 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2287 for _, module := range c.moduleInfo {
2288 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002289 }
Colin Crossab6d7902015-03-11 16:17:52 -07002290 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002291
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002292 buf := bytes.NewBuffer(nil)
2293
Colin Crossab6d7902015-03-11 16:17:52 -07002294 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002295 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002296
2297 // In order to make the bootstrap build manifest independent of the
2298 // build dir we need to output the Blueprints file locations in the
2299 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002300 relPos := module.pos
2301 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002302
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002303 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002304 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002305 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2306 factoryName := factoryFunc.Name()
2307
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002308 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002309 "properties": module.properties,
2310 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002311 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002312 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002313 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002314 }
2315 err = headerTemplate.Execute(buf, infoMap)
2316 if err != nil {
2317 return err
2318 }
2319
2320 err = nw.Comment(buf.String())
2321 if err != nil {
2322 return err
2323 }
2324
2325 err = nw.BlankLine()
2326 if err != nil {
2327 return err
2328 }
2329
Colin Crossab6d7902015-03-11 16:17:52 -07002330 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002331 if err != nil {
2332 return err
2333 }
2334
2335 err = nw.BlankLine()
2336 if err != nil {
2337 return err
2338 }
2339 }
2340
2341 return nil
2342}
2343
2344func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2345 headerTemplate := template.New("singletonHeader")
2346 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2347 if err != nil {
2348 // This is a programming error.
2349 panic(err)
2350 }
2351
2352 buf := bytes.NewBuffer(nil)
2353
Jamie Gennis86179fe2014-06-11 16:27:16 -07002354 singletonNames := make([]string, 0, len(c.singletonInfo))
2355 for name := range c.singletonInfo {
2356 singletonNames = append(singletonNames, name)
2357 }
2358 sort.Strings(singletonNames)
2359
2360 for _, name := range singletonNames {
2361 info := c.singletonInfo[name]
2362
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002363 // Get the name of the factory function for the module.
2364 factory := info.factory
2365 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2366 factoryName := factoryFunc.Name()
2367
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002368 buf.Reset()
2369 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002370 "name": name,
2371 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002372 }
2373 err = headerTemplate.Execute(buf, infoMap)
2374 if err != nil {
2375 return err
2376 }
2377
2378 err = nw.Comment(buf.String())
2379 if err != nil {
2380 return err
2381 }
2382
2383 err = nw.BlankLine()
2384 if err != nil {
2385 return err
2386 }
2387
2388 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2389 if err != nil {
2390 return err
2391 }
2392
2393 err = nw.BlankLine()
2394 if err != nil {
2395 return err
2396 }
2397 }
2398
2399 return nil
2400}
2401
2402func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2403 defs *localBuildActions) error {
2404
2405 // Write the local variable assignments.
2406 for _, v := range defs.variables {
2407 // A localVariable doesn't need the package names or config to
2408 // determine its name or value.
2409 name := v.fullName(nil)
2410 value, err := v.value(nil)
2411 if err != nil {
2412 panic(err)
2413 }
2414 err = nw.Assign(name, value.Value(c.pkgNames))
2415 if err != nil {
2416 return err
2417 }
2418 }
2419
2420 if len(defs.variables) > 0 {
2421 err := nw.BlankLine()
2422 if err != nil {
2423 return err
2424 }
2425 }
2426
2427 // Write the local rules.
2428 for _, r := range defs.rules {
2429 // A localRule doesn't need the package names or config to determine
2430 // its name or definition.
2431 name := r.fullName(nil)
2432 def, err := r.def(nil)
2433 if err != nil {
2434 panic(err)
2435 }
2436
2437 err = def.WriteTo(nw, name, c.pkgNames)
2438 if err != nil {
2439 return err
2440 }
2441
2442 err = nw.BlankLine()
2443 if err != nil {
2444 return err
2445 }
2446 }
2447
2448 // Write the build definitions.
2449 for _, buildDef := range defs.buildDefs {
2450 err := buildDef.WriteTo(nw, c.pkgNames)
2451 if err != nil {
2452 return err
2453 }
2454
2455 if len(buildDef.Args) > 0 {
2456 err = nw.BlankLine()
2457 if err != nil {
2458 return err
2459 }
2460 }
2461 }
2462
2463 return nil
2464}
2465
Colin Cross65569e42015-03-10 20:08:19 -07002466func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2467 found := false
2468 for _, l := range list {
2469 if l == a {
2470 found = true
2471 } else if l == b {
2472 return found
2473 }
2474 }
2475
2476 missing := a
2477 if found {
2478 missing = b
2479 }
2480 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2481}
2482
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002483var fileHeaderTemplate = `******************************************************************************
2484*** This file is generated and should not be edited ***
2485******************************************************************************
2486{{if .Pkgs}}
2487This file contains variables, rules, and pools with name prefixes indicating
2488they were generated by the following Go packages:
2489{{range .Pkgs}}
2490 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2491
2492`
2493
2494var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2495Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002496Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002497Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002498Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002499Defined: {{.pos}}
2500`
2501
2502var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2503Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002504Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002505`