blob: cee434c5ac4afaf7def7b94b5dc3926b37521013 [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 (
18 "blueprint/parser"
Colin Crossc9028482014-12-18 16:28:54 -080019 "blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "bytes"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080029 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "strings"
31 "text/scanner"
32 "text/template"
33)
34
35var ErrBuildActionsNotReady = errors.New("build actions are not ready")
36
37const maxErrors = 10
38
Jamie Gennisd4e10182014-06-12 20:06:50 -070039// A Context contains all the state needed to parse a set of Blueprints files
40// and generate a Ninja file. The process of generating a Ninja file proceeds
41// through a series of four phases. Each phase corresponds with a some methods
42// on the Context object
43//
44// Phase Methods
45// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070046// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070047//
48// 2. Parse ParseBlueprintsFiles, Parse
49//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070050// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070051//
52// 4. Write WriteBuildFile
53//
54// The registration phase prepares the context to process Blueprints files
55// containing various types of modules. The parse phase reads in one or more
56// Blueprints files and validates their contents against the module types that
57// have been registered. The generate phase then analyzes the parsed Blueprints
58// contents to create an internal representation for the build actions that must
59// be performed. This phase also performs validation of the module dependencies
60// and property values defined in the parsed Blueprints files. Finally, the
61// write phase generates the Ninja manifest text based on the generated build
62// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070063type Context struct {
64 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070065 moduleFactories map[string]ModuleFactory
66 moduleGroups map[string]*moduleGroup
67 moduleInfo map[Module]*moduleInfo
68 modulesSorted []*moduleInfo
69 singletonInfo map[string]*singletonInfo
70 mutatorInfo []*mutatorInfo
71 earlyMutatorInfo []*earlyMutatorInfo
72 variantMutatorNames []string
73 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074
75 dependenciesReady bool // set to true on a successful ResolveDependencies
76 buildActionsReady bool // set to true on a successful PrepareBuildActions
77
78 // set by SetIgnoreUnknownModuleTypes
79 ignoreUnknownModuleTypes bool
80
81 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070082 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070083 globalVariables map[Variable]*ninjaString
84 globalPools map[Pool]*poolDef
85 globalRules map[Rule]*ruleDef
86
87 // set during PrepareBuildActions
88 buildDir *ninjaString // The builddir special Ninja variable
89 requiredNinjaMajor int // For the ninja_required_version variable
90 requiredNinjaMinor int // For the ninja_required_version variable
91 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070092
93 // set lazily by sortedModuleNames
94 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095}
96
Jamie Gennisd4e10182014-06-12 20:06:50 -070097// An Error describes a problem that was encountered that is related to a
98// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700100 Err error // the error that occurred
101 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102}
103
104type localBuildActions struct {
105 variables []*localVariable
106 rules []*localRule
107 buildDefs []*buildDef
108}
109
Colin Crossbbfa51a2014-12-17 16:12:41 -0800110type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700111 name string
112 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700113
Colin Crossbbfa51a2014-12-17 16:12:41 -0800114 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115}
116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700118 // set during Parse
119 typeName string
120 relBlueprintsFile string
121 pos scanner.Position
122 propertyPos map[string]scanner.Position
123 properties struct {
124 Name string
125 Deps []string
126 }
127
Colin Crossf5e34b92015-03-13 16:02:36 -0700128 variantName string
129 variant variationMap
130 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700131
Colin Crossc9028482014-12-18 16:28:54 -0800132 logicModule Module
133 group *moduleGroup
134 moduleProperties []interface{}
135
136 // set during ResolveDependencies
137 directDeps []*moduleInfo
138
Colin Cross7addea32015-03-11 15:43:52 -0700139 // set during updateDependencies
140 reverseDeps []*moduleInfo
141 depsCount int
142
143 // used by parallelVisitAllBottomUp
144 waitingCount int
145
Colin Crossc9028482014-12-18 16:28:54 -0800146 // set during each runMutator
147 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700148
149 // set during PrepareBuildActions
150 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800151}
152
Colin Crossf5e34b92015-03-13 16:02:36 -0700153// A Variation is a way that a variant of a module differs from other variants of the same module.
154// For example, two variants of the same module might have Variation{"arch","arm"} and
155// Variation{"arch","arm64"}
156type Variation struct {
157 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700158 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700159 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
160 // "shared" or "static" for link.
161 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700162}
163
Colin Crossf5e34b92015-03-13 16:02:36 -0700164// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
165type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700166
Colin Crossf5e34b92015-03-13 16:02:36 -0700167func (vm variationMap) clone() variationMap {
168 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700169 for k, v := range vm {
170 newVm[k] = v
171 }
172
173 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800174}
175
Colin Crossf5e34b92015-03-13 16:02:36 -0700176func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700177 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800178}
179
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700180type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700181 // set during RegisterSingletonType
182 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700183 singleton Singleton
184
185 // set during PrepareBuildActions
186 actionDefs localBuildActions
187}
188
Colin Crossc9028482014-12-18 16:28:54 -0800189type mutatorInfo struct {
190 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800191 topDownMutator TopDownMutator
192 bottomUpMutator BottomUpMutator
193 name string
Colin Crossc9028482014-12-18 16:28:54 -0800194}
195
Colin Cross65569e42015-03-10 20:08:19 -0700196type earlyMutatorInfo struct {
197 // set during RegisterEarlyMutator
198 mutator EarlyMutator
199 name string
200}
201
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700202func (e *Error) Error() string {
203
204 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
205}
206
Jamie Gennisd4e10182014-06-12 20:06:50 -0700207// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700208// no module or singleton factories registered, so the RegisterModuleFactory and
209// RegisterSingletonFactory methods must be called before it can do anything
210// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700211func NewContext() *Context {
212 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800213 moduleFactories: make(map[string]ModuleFactory),
214 moduleGroups: make(map[string]*moduleGroup),
215 moduleInfo: make(map[Module]*moduleInfo),
216 singletonInfo: make(map[string]*singletonInfo),
217 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700218 }
219}
220
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700221// A ModuleFactory function creates a new Module object. See the
222// Context.RegisterModuleType method for details about how a registered
223// ModuleFactory is used by a Context.
224type ModuleFactory func() (m Module, propertyStructs []interface{})
225
Jamie Gennisd4e10182014-06-12 20:06:50 -0700226// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700227// Blueprints file) with a Module factory function. When the given module type
228// name is encountered in a Blueprints file during parsing, the Module factory
229// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800230// generation for the module. If a Mutator splits a module into multiple variants,
231// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700232//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700233// The module type names given here must be unique for the context. The factory
234// function should be a named function so that its package and name can be
235// included in the generated Ninja file for debugging purposes.
236//
237// The factory function returns two values. The first is the newly created
238// Module object. The second is a slice of pointers to that Module object's
239// properties structs. Each properties struct is examined when parsing a module
240// definition of this type in a Blueprints file. Exported fields of the
241// properties structs are automatically set to the property values specified in
242// the Blueprints file. The properties struct field names determine the name of
243// the Blueprints file properties that are used - the Blueprints property name
244// matches that of the properties struct field name with the first letter
245// converted to lower-case.
246//
247// The fields of the properties struct must be either []string, a string, or
248// bool. The Context will panic if a Module gets instantiated with a properties
249// struct containing a field that is not one these supported types.
250//
251// Any properties that appear in the Blueprints files that are not built-in
252// module properties (such as "name" and "deps") and do not have a corresponding
253// field in the returned module properties struct result in an error during the
254// Context's parse phase.
255//
256// As an example, the follow code:
257//
258// type myModule struct {
259// properties struct {
260// Foo string
261// Bar []string
262// }
263// }
264//
265// func NewMyModule() (blueprint.Module, []interface{}) {
266// module := new(myModule)
267// properties := &module.properties
268// return module, []interface{}{properties}
269// }
270//
271// func main() {
272// ctx := blueprint.NewContext()
273// ctx.RegisterModuleType("my_module", NewMyModule)
274// // ...
275// }
276//
277// would support parsing a module defined in a Blueprints file as follows:
278//
279// my_module {
280// name: "myName",
281// foo: "my foo string",
282// bar: ["my", "bar", "strings"],
283// }
284//
Colin Cross7ad621c2015-01-07 16:22:45 -0800285// The factory function may be called from multiple goroutines. Any accesses
286// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700287func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
288 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700289 panic(errors.New("module type name is already registered"))
290 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700291 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700292}
293
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700294// A SingletonFactory function creates a new Singleton object. See the
295// Context.RegisterSingletonType method for details about how a registered
296// SingletonFactory is used by a Context.
297type SingletonFactory func() Singleton
298
299// RegisterSingletonType registers a singleton type that will be invoked to
300// generate build actions. Each registered singleton type is instantiated and
301// and invoked exactly once as part of the generate phase.
302//
303// The singleton type names given here must be unique for the context. The
304// factory function should be a named function so that its package and name can
305// be included in the generated Ninja file for debugging purposes.
306func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700307 if _, present := c.singletonInfo[name]; present {
308 panic(errors.New("singleton name is already registered"))
309 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700310
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700311 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312 factory: factory,
313 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700314 }
315}
316
317func singletonPkgPath(singleton Singleton) string {
318 typ := reflect.TypeOf(singleton)
319 for typ.Kind() == reflect.Ptr {
320 typ = typ.Elem()
321 }
322 return typ.PkgPath()
323}
324
325func singletonTypeName(singleton Singleton) string {
326 typ := reflect.TypeOf(singleton)
327 for typ.Kind() == reflect.Ptr {
328 typ = typ.Elem()
329 }
330 return typ.PkgPath() + "." + typ.Name()
331}
332
Colin Crossc9028482014-12-18 16:28:54 -0800333// RegisterTopDownMutator registers a mutator that will be invoked to propagate
334// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700335// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
336// once per Module, and is invoked on a module before being invoked on any of its
337// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800338//
Colin Cross65569e42015-03-10 20:08:19 -0700339// The mutator type names given here must be unique to all top down mutators in
340// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800341func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
342 for _, m := range c.mutatorInfo {
343 if m.name == name && m.topDownMutator != nil {
344 panic(fmt.Errorf("mutator name %s is already registered", name))
345 }
346 }
347
348 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
349 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800350 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800351 })
352}
353
354// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700355// Modules into variants. Each registered mutator is invoked in registration
356// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
357// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800358//
Colin Cross65569e42015-03-10 20:08:19 -0700359// The mutator type names given here must be unique to all bottom up or early
360// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800361func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700362 for _, m := range c.variantMutatorNames {
363 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800364 panic(fmt.Errorf("mutator name %s is already registered", name))
365 }
366 }
367
368 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
369 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800370 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800371 })
Colin Cross65569e42015-03-10 20:08:19 -0700372
373 c.variantMutatorNames = append(c.variantMutatorNames, name)
374}
375
376// RegisterEarlyMutator registers a mutator that will be invoked to split
377// Modules into multiple variant Modules before any dependencies have been
378// created. Each registered mutator is invoked in registration order once
379// per Module (including each variant from previous early mutators). Module
380// order is unpredictable.
381//
382// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700383// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700384//
385// The mutator type names given here must be unique to all bottom up or early
386// mutators in the Context.
387func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
388 for _, m := range c.variantMutatorNames {
389 if m == name {
390 panic(fmt.Errorf("mutator name %s is already registered", name))
391 }
392 }
393
394 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
395 mutator: mutator,
396 name: name,
397 })
398
399 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800400}
401
Jamie Gennisd4e10182014-06-12 20:06:50 -0700402// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
403// where it encounters an unknown module type while parsing Blueprints files. By
404// default, the context will report unknown module types as an error. If this
405// method is called with ignoreUnknownModuleTypes set to true then the context
406// will silently ignore unknown module types.
407//
408// This method should generally not be used. It exists to facilitate the
409// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700410func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
411 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
412}
413
Jamie Gennisd4e10182014-06-12 20:06:50 -0700414// Parse parses a single Blueprints file from r, creating Module objects for
415// each of the module definitions encountered. If the Blueprints file contains
416// an assignment to the "subdirs" variable, then the subdirectories listed are
417// returned in the subdirs first return value.
418//
419// rootDir specifies the path to the root directory of the source tree, while
420// filename specifies the path to the Blueprints file. These paths are used for
421// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800422func (c *Context) parse(rootDir, filename string, r io.Reader,
423 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
424 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700425
Jamie Gennisec701282014-06-12 20:06:31 -0700426 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700427 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800428 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700429 }
430
Colin Crossc0dbc552015-01-02 15:19:28 -0800431 scope = parser.NewScope(scope)
432 scope.Remove("subdirs")
Colin Crossd1facc12015-01-08 14:56:03 -0800433 file, errs := parser.Parse(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700434 if len(errs) > 0 {
435 for i, err := range errs {
436 if parseErr, ok := err.(*parser.ParseError); ok {
437 err = &Error{
438 Err: parseErr.Err,
439 Pos: parseErr.Pos,
440 }
441 errs[i] = err
442 }
443 }
444
445 // If there were any parse errors don't bother trying to interpret the
446 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800447 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700448 }
449
Colin Crossd1facc12015-01-08 14:56:03 -0800450 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700451 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800452 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700453 switch def := def.(type) {
454 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800455 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700456
457 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800458 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700459 default:
460 panic("unknown definition type")
461 }
462
463 if len(newErrs) > 0 {
464 errs = append(errs, newErrs...)
465 if len(errs) > maxErrors {
466 break
467 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800468 } else if newModule != nil {
469 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700470 }
471 }
472
Colin Crossc0dbc552015-01-02 15:19:28 -0800473 subdirs, newErrs := c.processSubdirs(scope)
474 if len(newErrs) > 0 {
475 errs = append(errs, newErrs...)
476 }
477
Colin Cross7ad621c2015-01-07 16:22:45 -0800478 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800479}
480
Colin Cross7ad621c2015-01-07 16:22:45 -0800481type stringAndScope struct {
482 string
483 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700484}
485
Jamie Gennisd4e10182014-06-12 20:06:50 -0700486// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
487// at rootFile. When it encounters a Blueprints file with a set of subdirs
488// listed it recursively parses any Blueprints files found in those
489// subdirectories.
490//
491// If no errors are encountered while parsing the files, the list of paths on
492// which the future output will depend is returned. This list will include both
493// Blueprints file paths as well as directory paths for cases where wildcard
494// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700495func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
496 errs []error) {
497
Colin Cross7ad621c2015-01-07 16:22:45 -0800498 c.dependenciesReady = false
499
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700500 rootDir := filepath.Dir(rootFile)
501
Colin Cross7ad621c2015-01-07 16:22:45 -0800502 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700503
Colin Cross7ad621c2015-01-07 16:22:45 -0800504 // Channels to receive data back from parseBlueprintsFile goroutines
505 blueprintsCh := make(chan stringAndScope)
506 errsCh := make(chan []error)
507 modulesCh := make(chan []*moduleInfo)
508 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700509
Colin Cross7ad621c2015-01-07 16:22:45 -0800510 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
511 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700512
Colin Cross7ad621c2015-01-07 16:22:45 -0800513 // Number of outstanding goroutines to wait for
514 count := 0
515
516 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
517 count++
518 go func() {
519 c.parseBlueprintsFile(filename, scope, rootDir,
520 errsCh, modulesCh, blueprintsCh, depsCh)
521 doneCh <- struct{}{}
522 }()
523 }
524
525 tooManyErrors := false
526
527 startParseBlueprintsFile(rootFile, nil)
528
529loop:
530 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700531 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800532 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700533 }
534
Colin Cross7ad621c2015-01-07 16:22:45 -0800535 select {
536 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700537 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800538 case dep := <-depsCh:
539 deps = append(deps, dep)
540 case modules := <-modulesCh:
541 newErrs := c.addModules(modules)
542 errs = append(errs, newErrs...)
543 case blueprint := <-blueprintsCh:
544 if tooManyErrors {
545 continue
546 }
547 if blueprintsSet[blueprint.string] {
548 continue
549 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700550
Colin Cross7ad621c2015-01-07 16:22:45 -0800551 blueprintsSet[blueprint.string] = true
552 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
553 case <-doneCh:
554 count--
555 if count == 0 {
556 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700557 }
558 }
559 }
560
Colin Cross7ad621c2015-01-07 16:22:45 -0800561 return
562}
563
564// parseBlueprintFile parses a single Blueprints file, returning any errors through
565// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
566// blueprintsCh, and any dependencies on Blueprints files or directories through
567// depsCh.
568func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
569 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
570 depsCh chan<- string) {
571
572 dir := filepath.Dir(filename)
573
574 file, err := os.Open(filename)
575 if err != nil {
576 errsCh <- []error{err}
577 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700578 }
579
Colin Cross7ad621c2015-01-07 16:22:45 -0800580 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
581 if len(errs) > 0 {
582 errsCh <- errs
583 }
584
585 err = file.Close()
586 if err != nil {
587 errsCh <- []error{err}
588 }
589
590 modulesCh <- modules
591
592 for _, subdir := range subdirs {
593 subdir = filepath.Join(dir, subdir)
594
595 dirPart, filePart := filepath.Split(subdir)
596 dirPart = filepath.Clean(dirPart)
597
598 if filePart == "*" {
599 foundSubdirs, err := listSubdirs(dirPart)
600 if err != nil {
601 errsCh <- []error{err}
602 return
603 }
604
605 for _, foundSubdir := range foundSubdirs {
606 subBlueprints := filepath.Join(dirPart, foundSubdir,
607 "Blueprints")
608
609 _, err := os.Stat(subBlueprints)
610 if os.IsNotExist(err) {
611 // There is no Blueprints file in this subdirectory. We
612 // need to add the directory to the list of dependencies
613 // so that if someone adds a Blueprints file in the
614 // future we'll pick it up.
615 depsCh <- filepath.Dir(subBlueprints)
616 } else {
617 depsCh <- subBlueprints
618 blueprintsCh <- stringAndScope{
619 subBlueprints,
620 subScope,
621 }
622 }
623 }
624
625 // We now depend on the directory itself because if any new
626 // subdirectories get added or removed we need to rebuild the
627 // Ninja manifest.
628 depsCh <- dirPart
629 } else {
630 subBlueprints := filepath.Join(subdir, "Blueprints")
631 depsCh <- subBlueprints
632 blueprintsCh <- stringAndScope{
633 subBlueprints,
634 subScope,
635 }
636
637 }
638 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700639}
640
641func listSubdirs(dir string) ([]string, error) {
642 d, err := os.Open(dir)
643 if err != nil {
644 return nil, err
645 }
646 defer d.Close()
647
648 infos, err := d.Readdir(-1)
649 if err != nil {
650 return nil, err
651 }
652
653 var subdirs []string
654 for _, info := range infos {
Jamie Gennis0c35b2d2014-09-25 13:15:10 -0700655 isDotFile := strings.HasPrefix(info.Name(), ".")
656 if info.IsDir() && !isDotFile {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700657 subdirs = append(subdirs, info.Name())
658 }
659 }
660
661 return subdirs, nil
662}
663
Colin Crossc0dbc552015-01-02 15:19:28 -0800664func (c *Context) processSubdirs(
665 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700666
Colin Crossc0dbc552015-01-02 15:19:28 -0800667 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700668 switch assignment.Value.Type {
669 case parser.List:
670 subdirs = make([]string, 0, len(assignment.Value.ListValue))
671
672 for _, value := range assignment.Value.ListValue {
673 if value.Type != parser.String {
674 // The parser should not produce this.
675 panic("non-string value found in list")
676 }
677
678 dirPart, filePart := filepath.Split(value.StringValue)
679 if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
680 strings.ContainsRune(dirPart, '*') {
681
682 errs = append(errs, &Error{
683 Err: fmt.Errorf("subdirs may only wildcard whole " +
684 "directories"),
685 Pos: value.Pos,
686 })
687
688 continue
689 }
690
691 subdirs = append(subdirs, value.StringValue)
692 }
693
694 if len(errs) > 0 {
695 subdirs = nil
696 }
697
698 return
699
700 case parser.Bool, parser.String:
701 errs = []error{
702 &Error{
703 Err: fmt.Errorf("subdirs must be a list of strings"),
704 Pos: assignment.Pos,
705 },
706 }
707
708 return
709
710 default:
711 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
712 }
713 }
714
Colin Crossc0dbc552015-01-02 15:19:28 -0800715 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700716}
717
Colin Crossf5e34b92015-03-13 16:02:36 -0700718func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
719 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800720
721 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800722
Colin Cross174ae052015-03-03 17:37:03 -0800723 var errs []error
724
Colin Crossf5e34b92015-03-13 16:02:36 -0700725 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700726 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800727 factory, ok := c.moduleFactories[typeName]
728 if !ok {
729 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
730 }
731
732 var newLogicModule Module
733 var newProperties []interface{}
734
735 if i == 0 {
736 // Reuse the existing module for the first new variant
737 newLogicModule = origModule.logicModule
738 newProperties = origModule.moduleProperties
739 } else {
740 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700741 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800742 }
743 newLogicModule, newProperties = factory()
744
745 newProperties = append(props, newProperties...)
746
747 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700748 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800749 }
750
751 for i := range newProperties {
752 dst := reflect.ValueOf(newProperties[i]).Elem()
753 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
754
755 proptools.CopyProperties(dst, src)
756 }
757 }
758
Colin Crossf5e34b92015-03-13 16:02:36 -0700759 newVariant := origModule.variant.clone()
760 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800761
Colin Crossed342d92015-03-11 00:57:25 -0700762 m := *origModule
763 newModule := &m
764 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
765 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700766 newModule.variant = newVariant
767 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700768 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800769
Colin Crosse7daa222015-03-11 14:35:41 -0700770 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700771 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700772 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700773 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700774 }
775
Colin Crossc9028482014-12-18 16:28:54 -0800776 newModules = append(newModules, newModule)
777 c.moduleInfo[newModule.logicModule] = newModule
778
Colin Crossf5e34b92015-03-13 16:02:36 -0700779 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800780 if len(newErrs) > 0 {
781 errs = append(errs, newErrs...)
782 }
Colin Crossc9028482014-12-18 16:28:54 -0800783 }
784
785 // Mark original variant as invalid. Modules that depend on this module will still
786 // depend on origModule, but we'll fix it when the mutator is called on them.
787 origModule.logicModule = nil
788 origModule.splitModules = newModules
789
Colin Cross174ae052015-03-03 17:37:03 -0800790 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800791}
792
Colin Crossf5e34b92015-03-13 16:02:36 -0700793func (c *Context) convertDepsToVariation(module *moduleInfo,
794 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800795
Colin Crossc9028482014-12-18 16:28:54 -0800796 for i, dep := range module.directDeps {
797 if dep.logicModule == nil {
798 var newDep *moduleInfo
799 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700800 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800801 newDep = m
802 break
803 }
804 }
805 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800806 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700807 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
808 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700809 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800810 })
811 continue
Colin Crossc9028482014-12-18 16:28:54 -0800812 }
813 module.directDeps[i] = newDep
814 }
815 }
Colin Cross174ae052015-03-03 17:37:03 -0800816
817 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800818}
819
Colin Crossf5e34b92015-03-13 16:02:36 -0700820func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700821 names := make([]string, 0, len(variant))
822 for _, m := range c.variantMutatorNames {
823 if v, ok := variant[m]; ok {
824 names = append(names, m+":"+v)
825 }
826 }
827
828 return strings.Join(names, ", ")
829}
830
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700831func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800832 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700833
Colin Crossd1facc12015-01-08 14:56:03 -0800834 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700835 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700836 if !ok {
837 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800838 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700839 }
840
Colin Cross7ad621c2015-01-07 16:22:45 -0800841 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700842 &Error{
843 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800844 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700845 },
846 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700847 }
848
Colin Crossbbfa51a2014-12-17 16:12:41 -0800849 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700850
851 module := &moduleInfo{
852 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700853 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700854 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700855 }
856
Jamie Gennis87622922014-09-30 11:38:25 -0700857 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700858 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700859 }
860 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700861 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700862
Jamie Gennis87622922014-09-30 11:38:25 -0700863 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700864 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800865 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700866 }
867
Colin Crossed342d92015-03-11 00:57:25 -0700868 module.pos = moduleDef.Type.Pos
869 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700870 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700871 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700872 }
873
Colin Cross7ad621c2015-01-07 16:22:45 -0800874 return module, nil
875}
876
877func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
878 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700879 name := module.properties.Name
880 c.moduleInfo[module.logicModule] = module
881
882 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800883 errs = append(errs, []error{
884 &Error{
885 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700886 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800887 },
888 &Error{
889 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700890 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800891 },
892 }...)
893 continue
Colin Crossed342d92015-03-11 00:57:25 -0700894 } else {
895 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800896
Colin Crossed342d92015-03-11 00:57:25 -0700897 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
898 // already exists
899 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
900 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
901 }
902
903 c.moduleNinjaNames[ninjaName] = group
904
905 group := &moduleGroup{
906 name: module.properties.Name,
907 ninjaName: ninjaName,
908 modules: []*moduleInfo{module},
909 }
910 module.group = group
911 c.moduleGroups[name] = group
912 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800913 }
914
915 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700916}
917
Jamie Gennisd4e10182014-06-12 20:06:50 -0700918// ResolveDependencies checks that the dependencies specified by all of the
919// modules defined in the parsed Blueprints files are valid. This means that
920// the modules depended upon are defined and that no circular dependencies
921// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700922//
923// The config argument is made available to all of the DynamicDependerModule
924// objects via the Config method on the DynamicDependerModuleContext objects
925// passed to their DynamicDependencies method.
926func (c *Context) ResolveDependencies(config interface{}) []error {
927 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700928 if len(errs) > 0 {
929 return errs
930 }
931
Colin Cross691a60d2015-01-07 18:08:56 -0800932 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700933 if len(errs) > 0 {
934 return errs
935 }
936
937 c.dependenciesReady = true
938 return nil
939}
940
Colin Cross65569e42015-03-10 20:08:19 -0700941// moduleDeps adds dependencies to a module. If the module implements the
942// DynamicDependerModule interface then this set consists of the union of those
943// module names listed in its "deps" property, those returned by its
944// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -0700945// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700946// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -0700947func (c *Context) moduleDeps(module *moduleInfo,
948 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700949
950 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800951 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700952
Colin Crossed342d92015-03-11 00:57:25 -0700953 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800954 if !depNamesSet[depName] {
955 depNamesSet[depName] = true
956 depNames = append(depNames, depName)
957 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700958 }
959
Colin Cross65569e42015-03-10 20:08:19 -0700960 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700961 if ok {
Colin Cross65569e42015-03-10 20:08:19 -0700962 ddmctx := &dynamicDependerModuleContext{
963 baseModuleContext: baseModuleContext{
964 context: c,
965 config: config,
966 module: module,
967 },
968 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700969 }
970
971 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
972
973 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -0700974 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700975 }
976
977 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800978 if !depNamesSet[depName] {
979 depNamesSet[depName] = true
980 depNames = append(depNames, depName)
981 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700982 }
983 }
984
Colin Cross65569e42015-03-10 20:08:19 -0700985 for _, depName := range depNames {
986 newErrs := c.addDependency(module, depName)
987 if len(newErrs) > 0 {
988 errs = append(errs, newErrs...)
989 }
990 }
991 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700992}
993
Colin Cross65569e42015-03-10 20:08:19 -0700994// resolveDependencies populates the directDeps list for every module. In doing so it checks for
995// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700996func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800997 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -0700998 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -0700999 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1000
1001 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001002 if len(newErrs) > 0 {
1003 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001004 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001005 }
1006 }
1007
1008 return
1009}
1010
Colin Crossc9028482014-12-18 16:28:54 -08001011func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001012 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001013
Colin Crossed342d92015-03-11 00:57:25 -07001014 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001015 return []error{&Error{
1016 Err: fmt.Errorf("%q depends on itself", depName),
1017 Pos: depsPos,
1018 }}
1019 }
1020
1021 depInfo, ok := c.moduleGroups[depName]
1022 if !ok {
1023 return []error{&Error{
1024 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001025 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001026 Pos: depsPos,
1027 }}
1028 }
1029
Colin Cross65569e42015-03-10 20:08:19 -07001030 for _, m := range module.directDeps {
1031 if m.group == depInfo {
1032 return nil
1033 }
Colin Crossc9028482014-12-18 16:28:54 -08001034 }
1035
Colin Cross65569e42015-03-10 20:08:19 -07001036 if len(depInfo.modules) == 1 {
1037 module.directDeps = append(module.directDeps, depInfo.modules[0])
1038 return nil
1039 } else {
1040 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001041 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001042 module.directDeps = append(module.directDeps, m)
1043 return nil
1044 }
1045 }
1046 }
Colin Crossc9028482014-12-18 16:28:54 -08001047
Colin Cross65569e42015-03-10 20:08:19 -07001048 return []error{&Error{
1049 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1050 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001051 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001052 Pos: depsPos,
1053 }}
1054}
1055
Colin Crossf5e34b92015-03-13 16:02:36 -07001056func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross65569e42015-03-10 20:08:19 -07001057 depName string) []error {
1058
1059 depsPos := module.propertyPos["deps"]
1060
1061 depInfo, ok := c.moduleGroups[depName]
1062 if !ok {
1063 return []error{&Error{
1064 Err: fmt.Errorf("%q depends on undefined module %q",
1065 module.properties.Name, depName),
1066 Pos: depsPos,
1067 }}
1068 }
1069
1070 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1071 // compare the strings because the result won't be in mutator registration order.
1072 // Create a new map instead, and then deep compare the maps.
Colin Crossf5e34b92015-03-13 16:02:36 -07001073 newVariant := module.dependencyVariant.clone()
1074 for _, v := range variations {
1075 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001076 }
1077
1078 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001079 if newVariant.equal(m.variant) {
1080 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001081 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001082 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001083 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1084 return []error{&Error{
1085 Err: fmt.Errorf("%q depends on later version of itself", depName),
1086 Pos: depsPos,
1087 }}
1088 }
1089 module.directDeps = append(module.directDeps, m)
1090 return nil
1091 }
1092 }
1093
1094 return []error{&Error{
1095 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1096 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001097 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001098 Pos: depsPos,
1099 }}
Colin Crossc9028482014-12-18 16:28:54 -08001100}
1101
Colin Cross7addea32015-03-11 15:43:52 -07001102func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1103 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001104 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001105 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001106
Colin Cross7addea32015-03-11 15:43:52 -07001107 for _, module := range c.modulesSorted {
1108 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001109 }
1110
Colin Cross7addea32015-03-11 15:43:52 -07001111 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001112 count++
1113 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001114 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001115 if ret {
1116 cancel = true
1117 }
Colin Cross7addea32015-03-11 15:43:52 -07001118 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001119 }()
1120 }
1121
Colin Cross7addea32015-03-11 15:43:52 -07001122 for _, module := range c.modulesSorted {
1123 if module.waitingCount == 0 {
1124 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001125 }
1126 }
1127
Colin Cross11e3b0d2015-02-04 10:41:00 -08001128 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001129 select {
Colin Cross7addea32015-03-11 15:43:52 -07001130 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001131 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001132 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001133 parent.waitingCount--
1134 if parent.waitingCount == 0 {
1135 visitOne(parent)
1136 }
Colin Cross691a60d2015-01-07 18:08:56 -08001137 }
1138 }
1139 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001140 }
1141 }
1142}
1143
1144// updateDependencies recursively walks the module dependency graph and updates
1145// additional fields based on the dependencies. It builds a sorted list of modules
1146// such that dependencies of a module always appear first, and populates reverse
1147// dependency links and counts of total dependencies. It also reports errors when
1148// it encounters dependency cycles. This should called after resolveDependencies,
1149// as well as after any mutator pass has called addDependency
1150func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001151 visited := make(map[*moduleInfo]bool) // modules that were already checked
1152 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001153
Colin Cross7addea32015-03-11 15:43:52 -07001154 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001155
Colin Cross7addea32015-03-11 15:43:52 -07001156 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001157
Colin Cross7addea32015-03-11 15:43:52 -07001158 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001159 // We are the "start" of the cycle, so we're responsible
1160 // for generating the errors. The cycle list is in
1161 // reverse order because all the 'check' calls append
1162 // their own module to the list.
1163 errs = append(errs, &Error{
1164 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001165 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001166 })
1167
1168 // Iterate backwards through the cycle list.
Colin Cross7addea32015-03-11 15:43:52 -07001169 curModule := cycle[len(cycle)-1]
Colin Cross10b54db2015-03-11 14:40:30 -07001170 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001171 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001172 errs = append(errs, &Error{
1173 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001174 curModule.properties.Name,
1175 nextModule.properties.Name),
1176 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001177 })
Colin Cross7addea32015-03-11 15:43:52 -07001178 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001179 }
1180 }
1181
Colin Cross7addea32015-03-11 15:43:52 -07001182 check = func(module *moduleInfo) []*moduleInfo {
1183 visited[module] = true
1184 checking[module] = true
1185 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001186
Colin Cross7addea32015-03-11 15:43:52 -07001187 deps := make(map[*moduleInfo]bool)
1188
1189 // Add an implicit dependency ordering on all earlier modules in the same module group
1190 for _, dep := range module.group.modules {
1191 if dep == module {
1192 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001193 }
Colin Cross7addea32015-03-11 15:43:52 -07001194 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001195 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001196
Colin Cross7addea32015-03-11 15:43:52 -07001197 for _, dep := range module.directDeps {
1198 deps[dep] = true
1199 }
1200
1201 module.reverseDeps = []*moduleInfo{}
1202 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001203
Colin Crossbbfa51a2014-12-17 16:12:41 -08001204 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001205 if checking[dep] {
1206 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001207 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001208 }
1209
1210 if !visited[dep] {
1211 cycle := check(dep)
1212 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001213 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001214 // We are the "start" of the cycle, so we're responsible
1215 // for generating the errors. The cycle list is in
1216 // reverse order because all the 'check' calls append
1217 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001218 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001219
1220 // We can continue processing this module's children to
1221 // find more cycles. Since all the modules that were
1222 // part of the found cycle were marked as visited we
1223 // won't run into that cycle again.
1224 } else {
1225 // We're not the "start" of the cycle, so we just append
1226 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001227 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001228 }
1229 }
1230 }
Colin Cross691a60d2015-01-07 18:08:56 -08001231
Colin Cross7addea32015-03-11 15:43:52 -07001232 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001233 }
1234
Colin Cross7addea32015-03-11 15:43:52 -07001235 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001236
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001237 return nil
1238 }
1239
Colin Cross7addea32015-03-11 15:43:52 -07001240 for _, module := range c.moduleInfo {
1241 if !visited[module] {
1242 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001243 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001244 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001245 panic("inconceivable!")
1246 }
1247 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001248 }
1249 }
1250 }
1251
Colin Cross7addea32015-03-11 15:43:52 -07001252 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001253
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001254 return
1255}
1256
Jamie Gennisd4e10182014-06-12 20:06:50 -07001257// PrepareBuildActions generates an internal representation of all the build
1258// actions that need to be performed. This process involves invoking the
1259// GenerateBuildActions method on each of the Module objects created during the
1260// parse phase and then on each of the registered Singleton objects.
1261//
1262// If the ResolveDependencies method has not already been called it is called
1263// automatically by this method.
1264//
1265// The config argument is made available to all of the Module and Singleton
1266// objects via the Config method on the ModuleContext and SingletonContext
1267// objects passed to GenerateBuildActions. It is also passed to the functions
1268// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1269// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001270//
1271// The returned deps is a list of the ninja files dependencies that were added
1272// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1273// SingletonContext.AddNinjaFileDeps() methods.
1274func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001275 c.buildActionsReady = false
1276
Colin Cross65569e42015-03-10 20:08:19 -07001277 errs = c.runEarlyMutators(config)
1278 if len(errs) > 0 {
1279 return nil, errs
1280 }
1281
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001282 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001283 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001284 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001285 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001286 }
1287 }
1288
Colin Crossc9028482014-12-18 16:28:54 -08001289 errs = c.runMutators(config)
1290 if len(errs) > 0 {
1291 return nil, errs
1292 }
1293
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001294 liveGlobals := newLiveTracker(config)
1295
1296 c.initSpecialVariables()
1297
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001298 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001299 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001300 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001301 }
1302
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001303 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001304 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001305 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001306 }
1307
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001308 deps = append(depsModules, depsSingletons...)
1309
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001310 if c.buildDir != nil {
1311 liveGlobals.addNinjaStringDeps(c.buildDir)
1312 }
1313
1314 pkgNames := c.makeUniquePackageNames(liveGlobals)
1315
1316 // This will panic if it finds a problem since it's a programming error.
1317 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1318
1319 c.pkgNames = pkgNames
1320 c.globalVariables = liveGlobals.variables
1321 c.globalPools = liveGlobals.pools
1322 c.globalRules = liveGlobals.rules
1323
1324 c.buildActionsReady = true
1325
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001326 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001327}
1328
Colin Cross65569e42015-03-10 20:08:19 -07001329func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1330 for _, mutator := range c.earlyMutatorInfo {
1331 for _, group := range c.moduleGroups {
1332 newModules := make([]*moduleInfo, 0, len(group.modules))
1333
1334 for _, module := range group.modules {
1335 mctx := &mutatorContext{
1336 baseModuleContext: baseModuleContext{
1337 context: c,
1338 config: config,
1339 module: module,
1340 },
1341 name: mutator.name,
1342 }
1343 mutator.mutator(mctx)
1344 if len(mctx.errs) > 0 {
1345 errs = append(errs, mctx.errs...)
1346 return errs
1347 }
1348
1349 if module.splitModules != nil {
1350 newModules = append(newModules, module.splitModules...)
1351 } else {
1352 newModules = append(newModules, module)
1353 }
1354 }
1355
1356 group.modules = newModules
1357 }
1358 }
1359
1360 return nil
1361}
1362
Colin Crossc9028482014-12-18 16:28:54 -08001363func (c *Context) runMutators(config interface{}) (errs []error) {
1364 for _, mutator := range c.mutatorInfo {
1365 if mutator.topDownMutator != nil {
1366 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1367 } else if mutator.bottomUpMutator != nil {
1368 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1369 } else {
1370 panic("no mutator set on " + mutator.name)
1371 }
1372 if len(errs) > 0 {
1373 return errs
1374 }
1375 }
1376
1377 return nil
1378}
1379
1380func (c *Context) runTopDownMutator(config interface{},
1381 name string, mutator TopDownMutator) (errs []error) {
1382
Colin Cross7addea32015-03-11 15:43:52 -07001383 for i := 0; i < len(c.modulesSorted); i++ {
1384 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1385 mctx := &mutatorContext{
1386 baseModuleContext: baseModuleContext{
1387 context: c,
1388 config: config,
1389 module: module,
1390 },
1391 name: name,
1392 }
Colin Crossc9028482014-12-18 16:28:54 -08001393
Colin Cross7addea32015-03-11 15:43:52 -07001394 mutator(mctx)
1395 if len(mctx.errs) > 0 {
1396 errs = append(errs, mctx.errs...)
1397 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001398 }
1399 }
1400
1401 return errs
1402}
1403
1404func (c *Context) runBottomUpMutator(config interface{},
1405 name string, mutator BottomUpMutator) (errs []error) {
1406
1407 dependenciesModified := false
1408
Colin Cross7addea32015-03-11 15:43:52 -07001409 for _, module := range c.modulesSorted {
1410 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001411
Colin Cross7addea32015-03-11 15:43:52 -07001412 mctx := &mutatorContext{
1413 baseModuleContext: baseModuleContext{
1414 context: c,
1415 config: config,
1416 module: module,
1417 },
1418 name: name,
1419 }
Colin Crossc9028482014-12-18 16:28:54 -08001420
Colin Cross7addea32015-03-11 15:43:52 -07001421 mutator(mctx)
1422 if len(mctx.errs) > 0 {
1423 errs = append(errs, mctx.errs...)
1424 return errs
1425 }
Colin Crossc9028482014-12-18 16:28:54 -08001426
Colin Cross7addea32015-03-11 15:43:52 -07001427 // Fix up any remaining dependencies on modules that were split into variants
1428 // by replacing them with the first variant
1429 for i, dep := range module.directDeps {
1430 if dep.logicModule == nil {
1431 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001432 }
1433 }
1434
Colin Cross7addea32015-03-11 15:43:52 -07001435 if mctx.dependenciesModified {
1436 dependenciesModified = true
1437 }
1438
1439 if module.splitModules != nil {
1440 newModules = append(newModules, module.splitModules...)
1441 } else {
1442 newModules = append(newModules, module)
1443 }
1444
1445 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001446 }
1447
1448 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001449 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001450 if len(errs) > 0 {
1451 return errs
1452 }
1453 }
1454
1455 return errs
1456}
1457
Colin Cross7addea32015-03-11 15:43:52 -07001458func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1459 newModules []*moduleInfo) []*moduleInfo {
1460 for i, m := range modules {
1461 if m == origModule {
1462 return spliceModulesAtIndex(modules, i, newModules)
1463 }
1464 }
1465
1466 panic("failed to find original module to splice")
1467}
1468
1469func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1470 spliceSize := len(newModules)
1471 newLen := len(modules) + spliceSize - 1
1472 var dest []*moduleInfo
1473 if cap(modules) >= len(modules)-1+len(newModules) {
1474 // We can fit the splice in the existing capacity, do everything in place
1475 dest = modules[:newLen]
1476 } else {
1477 dest = make([]*moduleInfo, newLen)
1478 copy(dest, modules[:i])
1479 }
1480
1481 // Move the end of the slice over by spliceSize-1
1482 copy(modules[i+spliceSize:], modules[i+1:])
1483
1484 // Copy the new modules into the slice
1485 copy(modules[i:], newModules)
1486
1487 return modules
1488}
1489
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001490func (c *Context) initSpecialVariables() {
1491 c.buildDir = nil
1492 c.requiredNinjaMajor = 1
1493 c.requiredNinjaMinor = 1
1494 c.requiredNinjaMicro = 0
1495}
1496
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001497func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001498 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001499
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001500 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001501 var errs []error
1502
Colin Cross691a60d2015-01-07 18:08:56 -08001503 cancelCh := make(chan struct{})
1504 errsCh := make(chan []error)
1505 depsCh := make(chan []string)
1506
1507 go func() {
1508 for {
1509 select {
1510 case <-cancelCh:
1511 close(cancelCh)
1512 return
1513 case newErrs := <-errsCh:
1514 errs = append(errs, newErrs...)
1515 case newDeps := <-depsCh:
1516 deps = append(deps, newDeps...)
1517
1518 }
1519 }
1520 }()
1521
Colin Cross7addea32015-03-11 15:43:52 -07001522 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1523 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1524 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1525 // just set it to nil.
1526 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1527 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001528
Colin Cross7addea32015-03-11 15:43:52 -07001529 mctx := &moduleContext{
1530 baseModuleContext: baseModuleContext{
1531 context: c,
1532 config: config,
1533 module: module,
1534 },
1535 scope: scope,
1536 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001537
Colin Cross7addea32015-03-11 15:43:52 -07001538 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001539
Colin Cross7addea32015-03-11 15:43:52 -07001540 if len(mctx.errs) > 0 {
1541 errsCh <- mctx.errs
1542 return true
1543 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001544
Colin Cross7addea32015-03-11 15:43:52 -07001545 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001546
Colin Crossab6d7902015-03-11 16:17:52 -07001547 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001548 &mctx.actionDefs, liveGlobals)
1549 if len(newErrs) > 0 {
1550 errsCh <- newErrs
1551 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001552 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001553 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001554 })
1555
1556 cancelCh <- struct{}{}
1557 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001558
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001559 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001560}
1561
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001562func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001563 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001564
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001565 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001566 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001567
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001568 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001569 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1570 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1571 // just set it to nil.
1572 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001573
1574 sctx := &singletonContext{
1575 context: c,
1576 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001577 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001578 }
1579
1580 info.singleton.GenerateBuildActions(sctx)
1581
1582 if len(sctx.errs) > 0 {
1583 errs = append(errs, sctx.errs...)
1584 if len(errs) > maxErrors {
1585 break
1586 }
1587 continue
1588 }
1589
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001590 deps = append(deps, sctx.ninjaFileDeps...)
1591
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001592 newErrs := c.processLocalBuildActions(&info.actionDefs,
1593 &sctx.actionDefs, liveGlobals)
1594 errs = append(errs, newErrs...)
1595 if len(errs) > maxErrors {
1596 break
1597 }
1598 }
1599
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001600 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001601}
1602
1603func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1604 liveGlobals *liveTracker) []error {
1605
1606 var errs []error
1607
1608 // First we go through and add everything referenced by the module's
1609 // buildDefs to the live globals set. This will end up adding the live
1610 // locals to the set as well, but we'll take them out after.
1611 for _, def := range in.buildDefs {
1612 err := liveGlobals.AddBuildDefDeps(def)
1613 if err != nil {
1614 errs = append(errs, err)
1615 }
1616 }
1617
1618 if len(errs) > 0 {
1619 return errs
1620 }
1621
Colin Crossc9028482014-12-18 16:28:54 -08001622 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001623
1624 // We use the now-incorrect set of live "globals" to determine which local
1625 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001626 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001627 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001628 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001629 if isLive {
1630 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001631 }
1632 }
1633
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001634 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001635 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001636 if isLive {
1637 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001638 }
1639 }
1640
1641 return nil
1642}
1643
Colin Crossbbfa51a2014-12-17 16:12:41 -08001644func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1645 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001646
Colin Crossbbfa51a2014-12-17 16:12:41 -08001647 var walk func(module *moduleInfo)
1648 walk = func(module *moduleInfo) {
1649 visited[module] = true
1650 for _, moduleDep := range module.directDeps {
1651 if !visited[moduleDep] {
1652 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001653 }
1654 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001655
Colin Crossbbfa51a2014-12-17 16:12:41 -08001656 if module != topModule {
1657 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001658 }
1659 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001660
1661 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001662}
1663
Colin Crossbbfa51a2014-12-17 16:12:41 -08001664func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001665 visit func(Module)) {
1666
Colin Crossbbfa51a2014-12-17 16:12:41 -08001667 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001668
Colin Crossbbfa51a2014-12-17 16:12:41 -08001669 var walk func(module *moduleInfo)
1670 walk = func(module *moduleInfo) {
1671 visited[module] = true
1672 for _, moduleDep := range module.directDeps {
1673 if !visited[moduleDep] {
1674 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001675 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001676 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001677
1678 if module != topModule {
1679 if pred(module.logicModule) {
1680 visit(module.logicModule)
1681 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001682 }
1683 }
1684
Colin Crossbbfa51a2014-12-17 16:12:41 -08001685 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001686}
1687
Colin Crossc9028482014-12-18 16:28:54 -08001688func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1689 for _, dep := range module.directDeps {
1690 visit(dep.logicModule)
1691 }
1692}
1693
1694func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1695 visit func(Module)) {
1696
1697 for _, dep := range module.directDeps {
1698 if pred(dep.logicModule) {
1699 visit(dep.logicModule)
1700 }
1701 }
1702}
1703
Jamie Gennisc15544d2014-09-24 20:26:52 -07001704func (c *Context) sortedModuleNames() []string {
1705 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001706 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1707 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001708 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1709 moduleName)
1710 }
1711 sort.Strings(c.cachedSortedModuleNames)
1712 }
1713
1714 return c.cachedSortedModuleNames
1715}
1716
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001717func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001718 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001719 group := c.moduleGroups[moduleName]
1720 for _, module := range group.modules {
1721 visit(module.logicModule)
1722 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001723 }
1724}
1725
1726func (c *Context) visitAllModulesIf(pred func(Module) bool,
1727 visit func(Module)) {
1728
Jamie Gennisc15544d2014-09-24 20:26:52 -07001729 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001730 group := c.moduleGroups[moduleName]
1731 for _, module := range group.modules {
1732 if pred(module.logicModule) {
1733 visit(module.logicModule)
1734 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001735 }
1736 }
1737}
1738
1739func (c *Context) requireNinjaVersion(major, minor, micro int) {
1740 if major != 1 {
1741 panic("ninja version with major version != 1 not supported")
1742 }
1743 if c.requiredNinjaMinor < minor {
1744 c.requiredNinjaMinor = minor
1745 c.requiredNinjaMicro = micro
1746 }
1747 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1748 c.requiredNinjaMicro = micro
1749 }
1750}
1751
1752func (c *Context) setBuildDir(value *ninjaString) {
1753 if c.buildDir != nil {
1754 panic("buildDir set multiple times")
1755 }
1756 c.buildDir = value
1757}
1758
1759func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001760 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001761
Jamie Gennis2fb20952014-10-03 02:49:58 -07001762 pkgs := make(map[string]*PackageContext)
1763 pkgNames := make(map[*PackageContext]string)
1764 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001765
Jamie Gennis2fb20952014-10-03 02:49:58 -07001766 processPackage := func(pctx *PackageContext) {
1767 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001768 // This is a built-in rule and has no package.
1769 return
1770 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001771 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001772 // We've already processed this package.
1773 return
1774 }
1775
Jamie Gennis2fb20952014-10-03 02:49:58 -07001776 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001777 if present {
1778 // Short name collision. Both this package and the one that's
1779 // already there need to use their full names. We leave the short
1780 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001781 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001782 longPkgNames[otherPkg] = true
1783 } else {
1784 // No collision so far. Tentatively set the package's name to be
1785 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001786 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001787 }
1788 }
1789
1790 // We try to give all packages their short name, but when we get collisions
1791 // we need to use the full unique package name.
1792 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001793 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001794 }
1795 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001796 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001797 }
1798 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001799 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001800 }
1801
1802 // Add the packages that had collisions using their full unique names. This
1803 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001804 for pctx := range longPkgNames {
1805 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001806 }
1807
1808 return pkgNames
1809}
1810
1811func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001812 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001813
1814 visited := make(map[Variable]bool) // variables that were already checked
1815 checking := make(map[Variable]bool) // variables actively being checked
1816
1817 var check func(v Variable) []Variable
1818
1819 check = func(v Variable) []Variable {
1820 visited[v] = true
1821 checking[v] = true
1822 defer delete(checking, v)
1823
1824 value := variables[v]
1825 for _, dep := range value.variables {
1826 if checking[dep] {
1827 // This is a cycle.
1828 return []Variable{dep, v}
1829 }
1830
1831 if !visited[dep] {
1832 cycle := check(dep)
1833 if cycle != nil {
1834 if cycle[0] == v {
1835 // We are the "start" of the cycle, so we're responsible
1836 // for generating the errors. The cycle list is in
1837 // reverse order because all the 'check' calls append
1838 // their own module to the list.
1839 msgs := []string{"detected variable reference cycle:"}
1840
1841 // Iterate backwards through the cycle list.
1842 curName := v.fullName(pkgNames)
1843 curValue := value.Value(pkgNames)
1844 for i := len(cycle) - 1; i >= 0; i-- {
1845 next := cycle[i]
1846 nextName := next.fullName(pkgNames)
1847 nextValue := variables[next].Value(pkgNames)
1848
1849 msgs = append(msgs, fmt.Sprintf(
1850 " %q depends on %q", curName, nextName))
1851 msgs = append(msgs, fmt.Sprintf(
1852 " [%s = %s]", curName, curValue))
1853
1854 curName = nextName
1855 curValue = nextValue
1856 }
1857
1858 // Variable reference cycles are a programming error,
1859 // not the fault of the Blueprint file authors.
1860 panic(strings.Join(msgs, "\n"))
1861 } else {
1862 // We're not the "start" of the cycle, so we just append
1863 // our module to the list and return it.
1864 return append(cycle, v)
1865 }
1866 }
1867 }
1868 }
1869
1870 return nil
1871 }
1872
1873 for v := range variables {
1874 if !visited[v] {
1875 cycle := check(v)
1876 if cycle != nil {
1877 panic("inconceivable!")
1878 }
1879 }
1880 }
1881}
1882
Jamie Gennisaf435562014-10-27 22:34:56 -07001883// AllTargets returns a map all the build target names to the rule used to build
1884// them. This is the same information that is output by running 'ninja -t
1885// targets all'. If this is called before PrepareBuildActions successfully
1886// completes then ErrbuildActionsNotReady is returned.
1887func (c *Context) AllTargets() (map[string]string, error) {
1888 if !c.buildActionsReady {
1889 return nil, ErrBuildActionsNotReady
1890 }
1891
1892 targets := map[string]string{}
1893
1894 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001895 for _, module := range c.moduleInfo {
1896 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001897 ruleName := buildDef.Rule.fullName(c.pkgNames)
1898 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001899 outputValue, err := output.Eval(c.globalVariables)
1900 if err != nil {
1901 return nil, err
1902 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001903 targets[outputValue] = ruleName
1904 }
1905 }
1906 }
1907
1908 // Collect all the singleton build targets.
1909 for _, info := range c.singletonInfo {
1910 for _, buildDef := range info.actionDefs.buildDefs {
1911 ruleName := buildDef.Rule.fullName(c.pkgNames)
1912 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001913 outputValue, err := output.Eval(c.globalVariables)
1914 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001915 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001916 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001917 targets[outputValue] = ruleName
1918 }
1919 }
1920 }
1921
1922 return targets, nil
1923}
1924
Jamie Gennisd4e10182014-06-12 20:06:50 -07001925// WriteBuildFile writes the Ninja manifeset text for the generated build
1926// actions to w. If this is called before PrepareBuildActions successfully
1927// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001928func (c *Context) WriteBuildFile(w io.Writer) error {
1929 if !c.buildActionsReady {
1930 return ErrBuildActionsNotReady
1931 }
1932
1933 nw := newNinjaWriter(w)
1934
1935 err := c.writeBuildFileHeader(nw)
1936 if err != nil {
1937 return err
1938 }
1939
1940 err = c.writeNinjaRequiredVersion(nw)
1941 if err != nil {
1942 return err
1943 }
1944
1945 // TODO: Group the globals by package.
1946
1947 err = c.writeGlobalVariables(nw)
1948 if err != nil {
1949 return err
1950 }
1951
1952 err = c.writeGlobalPools(nw)
1953 if err != nil {
1954 return err
1955 }
1956
1957 err = c.writeBuildDir(nw)
1958 if err != nil {
1959 return err
1960 }
1961
1962 err = c.writeGlobalRules(nw)
1963 if err != nil {
1964 return err
1965 }
1966
1967 err = c.writeAllModuleActions(nw)
1968 if err != nil {
1969 return err
1970 }
1971
1972 err = c.writeAllSingletonActions(nw)
1973 if err != nil {
1974 return err
1975 }
1976
1977 return nil
1978}
1979
Jamie Gennisc15544d2014-09-24 20:26:52 -07001980type pkgAssociation struct {
1981 PkgName string
1982 PkgPath string
1983}
1984
1985type pkgAssociationSorter struct {
1986 pkgs []pkgAssociation
1987}
1988
1989func (s *pkgAssociationSorter) Len() int {
1990 return len(s.pkgs)
1991}
1992
1993func (s *pkgAssociationSorter) Less(i, j int) bool {
1994 iName := s.pkgs[i].PkgName
1995 jName := s.pkgs[j].PkgName
1996 return iName < jName
1997}
1998
1999func (s *pkgAssociationSorter) Swap(i, j int) {
2000 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2001}
2002
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002003func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2004 headerTemplate := template.New("fileHeader")
2005 _, err := headerTemplate.Parse(fileHeaderTemplate)
2006 if err != nil {
2007 // This is a programming error.
2008 panic(err)
2009 }
2010
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002011 var pkgs []pkgAssociation
2012 maxNameLen := 0
2013 for pkg, name := range c.pkgNames {
2014 pkgs = append(pkgs, pkgAssociation{
2015 PkgName: name,
2016 PkgPath: pkg.pkgPath,
2017 })
2018 if len(name) > maxNameLen {
2019 maxNameLen = len(name)
2020 }
2021 }
2022
2023 for i := range pkgs {
2024 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2025 }
2026
Jamie Gennisc15544d2014-09-24 20:26:52 -07002027 sort.Sort(&pkgAssociationSorter{pkgs})
2028
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002029 params := map[string]interface{}{
2030 "Pkgs": pkgs,
2031 }
2032
2033 buf := bytes.NewBuffer(nil)
2034 err = headerTemplate.Execute(buf, params)
2035 if err != nil {
2036 return err
2037 }
2038
2039 return nw.Comment(buf.String())
2040}
2041
2042func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2043 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2044 c.requiredNinjaMicro)
2045
2046 err := nw.Assign("ninja_required_version", value)
2047 if err != nil {
2048 return err
2049 }
2050
2051 return nw.BlankLine()
2052}
2053
2054func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2055 if c.buildDir != nil {
2056 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2057 if err != nil {
2058 return err
2059 }
2060
2061 err = nw.BlankLine()
2062 if err != nil {
2063 return err
2064 }
2065 }
2066 return nil
2067}
2068
Jamie Gennisc15544d2014-09-24 20:26:52 -07002069type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002070 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002071}
2072
Jamie Gennisc15544d2014-09-24 20:26:52 -07002073type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002074 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002075 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002076}
2077
Jamie Gennisc15544d2014-09-24 20:26:52 -07002078func (s *globalEntitySorter) Len() int {
2079 return len(s.entities)
2080}
2081
2082func (s *globalEntitySorter) Less(i, j int) bool {
2083 iName := s.entities[i].fullName(s.pkgNames)
2084 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002085 return iName < jName
2086}
2087
Jamie Gennisc15544d2014-09-24 20:26:52 -07002088func (s *globalEntitySorter) Swap(i, j int) {
2089 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002090}
2091
2092func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2093 visited := make(map[Variable]bool)
2094
2095 var walk func(v Variable) error
2096 walk = func(v Variable) error {
2097 visited[v] = true
2098
2099 // First visit variables on which this variable depends.
2100 value := c.globalVariables[v]
2101 for _, dep := range value.variables {
2102 if !visited[dep] {
2103 err := walk(dep)
2104 if err != nil {
2105 return err
2106 }
2107 }
2108 }
2109
2110 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2111 if err != nil {
2112 return err
2113 }
2114
2115 err = nw.BlankLine()
2116 if err != nil {
2117 return err
2118 }
2119
2120 return nil
2121 }
2122
Jamie Gennisc15544d2014-09-24 20:26:52 -07002123 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2124 for variable := range c.globalVariables {
2125 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002126 }
2127
Jamie Gennisc15544d2014-09-24 20:26:52 -07002128 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002129
Jamie Gennisc15544d2014-09-24 20:26:52 -07002130 for _, entity := range globalVariables {
2131 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002132 if !visited[v] {
2133 err := walk(v)
2134 if err != nil {
2135 return nil
2136 }
2137 }
2138 }
2139
2140 return nil
2141}
2142
2143func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002144 globalPools := make([]globalEntity, 0, len(c.globalPools))
2145 for pool := range c.globalPools {
2146 globalPools = append(globalPools, pool)
2147 }
2148
2149 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2150
2151 for _, entity := range globalPools {
2152 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002153 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002154 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002155 err := def.WriteTo(nw, name)
2156 if err != nil {
2157 return err
2158 }
2159
2160 err = nw.BlankLine()
2161 if err != nil {
2162 return err
2163 }
2164 }
2165
2166 return nil
2167}
2168
2169func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002170 globalRules := make([]globalEntity, 0, len(c.globalRules))
2171 for rule := range c.globalRules {
2172 globalRules = append(globalRules, rule)
2173 }
2174
2175 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2176
2177 for _, entity := range globalRules {
2178 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002179 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002180 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002181 err := def.WriteTo(nw, name, c.pkgNames)
2182 if err != nil {
2183 return err
2184 }
2185
2186 err = nw.BlankLine()
2187 if err != nil {
2188 return err
2189 }
2190 }
2191
2192 return nil
2193}
2194
Colin Crossab6d7902015-03-11 16:17:52 -07002195type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002196
Colin Crossab6d7902015-03-11 16:17:52 -07002197func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002198 return len(s)
2199}
2200
Colin Crossab6d7902015-03-11 16:17:52 -07002201func (s moduleSorter) Less(i, j int) bool {
2202 iName := s[i].properties.Name
2203 jName := s[j].properties.Name
2204 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002205 iName = s[i].variantName
2206 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002207 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002208 return iName < jName
2209}
2210
Colin Crossab6d7902015-03-11 16:17:52 -07002211func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002212 s[i], s[j] = s[j], s[i]
2213}
2214
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002215func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2216 headerTemplate := template.New("moduleHeader")
2217 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2218 if err != nil {
2219 // This is a programming error.
2220 panic(err)
2221 }
2222
Colin Crossab6d7902015-03-11 16:17:52 -07002223 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2224 for _, module := range c.moduleInfo {
2225 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002226 }
Colin Crossab6d7902015-03-11 16:17:52 -07002227 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002228
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002229 buf := bytes.NewBuffer(nil)
2230
Colin Crossab6d7902015-03-11 16:17:52 -07002231 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002232 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002233
2234 // In order to make the bootstrap build manifest independent of the
2235 // build dir we need to output the Blueprints file locations in the
2236 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002237 relPos := module.pos
2238 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002239
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002240 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002241 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002242 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2243 factoryName := factoryFunc.Name()
2244
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002245 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002246 "properties": module.properties,
2247 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002248 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002249 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002250 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002251 }
2252 err = headerTemplate.Execute(buf, infoMap)
2253 if err != nil {
2254 return err
2255 }
2256
2257 err = nw.Comment(buf.String())
2258 if err != nil {
2259 return err
2260 }
2261
2262 err = nw.BlankLine()
2263 if err != nil {
2264 return err
2265 }
2266
Colin Crossab6d7902015-03-11 16:17:52 -07002267 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002268 if err != nil {
2269 return err
2270 }
2271
2272 err = nw.BlankLine()
2273 if err != nil {
2274 return err
2275 }
2276 }
2277
2278 return nil
2279}
2280
2281func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2282 headerTemplate := template.New("singletonHeader")
2283 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2284 if err != nil {
2285 // This is a programming error.
2286 panic(err)
2287 }
2288
2289 buf := bytes.NewBuffer(nil)
2290
Jamie Gennis86179fe2014-06-11 16:27:16 -07002291 singletonNames := make([]string, 0, len(c.singletonInfo))
2292 for name := range c.singletonInfo {
2293 singletonNames = append(singletonNames, name)
2294 }
2295 sort.Strings(singletonNames)
2296
2297 for _, name := range singletonNames {
2298 info := c.singletonInfo[name]
2299
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002300 // Get the name of the factory function for the module.
2301 factory := info.factory
2302 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2303 factoryName := factoryFunc.Name()
2304
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002305 buf.Reset()
2306 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002307 "name": name,
2308 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002309 }
2310 err = headerTemplate.Execute(buf, infoMap)
2311 if err != nil {
2312 return err
2313 }
2314
2315 err = nw.Comment(buf.String())
2316 if err != nil {
2317 return err
2318 }
2319
2320 err = nw.BlankLine()
2321 if err != nil {
2322 return err
2323 }
2324
2325 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2326 if err != nil {
2327 return err
2328 }
2329
2330 err = nw.BlankLine()
2331 if err != nil {
2332 return err
2333 }
2334 }
2335
2336 return nil
2337}
2338
2339func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2340 defs *localBuildActions) error {
2341
2342 // Write the local variable assignments.
2343 for _, v := range defs.variables {
2344 // A localVariable doesn't need the package names or config to
2345 // determine its name or value.
2346 name := v.fullName(nil)
2347 value, err := v.value(nil)
2348 if err != nil {
2349 panic(err)
2350 }
2351 err = nw.Assign(name, value.Value(c.pkgNames))
2352 if err != nil {
2353 return err
2354 }
2355 }
2356
2357 if len(defs.variables) > 0 {
2358 err := nw.BlankLine()
2359 if err != nil {
2360 return err
2361 }
2362 }
2363
2364 // Write the local rules.
2365 for _, r := range defs.rules {
2366 // A localRule doesn't need the package names or config to determine
2367 // its name or definition.
2368 name := r.fullName(nil)
2369 def, err := r.def(nil)
2370 if err != nil {
2371 panic(err)
2372 }
2373
2374 err = def.WriteTo(nw, name, c.pkgNames)
2375 if err != nil {
2376 return err
2377 }
2378
2379 err = nw.BlankLine()
2380 if err != nil {
2381 return err
2382 }
2383 }
2384
2385 // Write the build definitions.
2386 for _, buildDef := range defs.buildDefs {
2387 err := buildDef.WriteTo(nw, c.pkgNames)
2388 if err != nil {
2389 return err
2390 }
2391
2392 if len(buildDef.Args) > 0 {
2393 err = nw.BlankLine()
2394 if err != nil {
2395 return err
2396 }
2397 }
2398 }
2399
2400 return nil
2401}
2402
Colin Cross65569e42015-03-10 20:08:19 -07002403func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2404 found := false
2405 for _, l := range list {
2406 if l == a {
2407 found = true
2408 } else if l == b {
2409 return found
2410 }
2411 }
2412
2413 missing := a
2414 if found {
2415 missing = b
2416 }
2417 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2418}
2419
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002420var fileHeaderTemplate = `******************************************************************************
2421*** This file is generated and should not be edited ***
2422******************************************************************************
2423{{if .Pkgs}}
2424This file contains variables, rules, and pools with name prefixes indicating
2425they were generated by the following Go packages:
2426{{range .Pkgs}}
2427 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2428
2429`
2430
2431var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2432Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002433Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002434Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002435Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002436Defined: {{.pos}}
2437`
2438
2439var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2440Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002441Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002442`