blob: 08fbc138d19ec606f538c8d9346173c7d4159f28 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "errors"
20 "fmt"
Jamie Gennis6cafc2c2015-03-20 22:39:29 -040021 "github.com/google/blueprint/parser"
22 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070023 "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 Cross96e56702015-03-19 17:28:06 -0700433 file, errs := parser.ParseAndEval(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
Colin Crossf4d18a62015-03-18 17:43:15 -0700721 if len(variationNames) == 0 {
722 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400723 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700724 }
725
Colin Crossc9028482014-12-18 16:28:54 -0800726 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800727
Colin Cross174ae052015-03-03 17:37:03 -0800728 var errs []error
729
Colin Crossf5e34b92015-03-13 16:02:36 -0700730 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700731 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800732 factory, ok := c.moduleFactories[typeName]
733 if !ok {
734 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
735 }
736
737 var newLogicModule Module
738 var newProperties []interface{}
739
740 if i == 0 {
741 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700742 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
743 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800744 newLogicModule = origModule.logicModule
745 newProperties = origModule.moduleProperties
746 } else {
747 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700748 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800749 }
750 newLogicModule, newProperties = factory()
751
752 newProperties = append(props, newProperties...)
753
754 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700755 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800756 }
757
758 for i := range newProperties {
759 dst := reflect.ValueOf(newProperties[i]).Elem()
760 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
761
762 proptools.CopyProperties(dst, src)
763 }
764 }
765
Colin Crossf5e34b92015-03-13 16:02:36 -0700766 newVariant := origModule.variant.clone()
767 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800768
Colin Crossed342d92015-03-11 00:57:25 -0700769 m := *origModule
770 newModule := &m
771 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
772 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700773 newModule.variant = newVariant
774 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700775 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800776
Colin Crosse7daa222015-03-11 14:35:41 -0700777 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700778 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700779 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700780 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700781 }
782
Colin Crossc9028482014-12-18 16:28:54 -0800783 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700784
785 // Insert the new variant into the global module map. If this is the first variant then
786 // it reuses logicModule from the original module, which causes this to replace the
787 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800788 c.moduleInfo[newModule.logicModule] = newModule
789
Colin Crossf5e34b92015-03-13 16:02:36 -0700790 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800791 if len(newErrs) > 0 {
792 errs = append(errs, newErrs...)
793 }
Colin Crossc9028482014-12-18 16:28:54 -0800794 }
795
796 // Mark original variant as invalid. Modules that depend on this module will still
797 // depend on origModule, but we'll fix it when the mutator is called on them.
798 origModule.logicModule = nil
799 origModule.splitModules = newModules
800
Colin Cross174ae052015-03-03 17:37:03 -0800801 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800802}
803
Colin Crossf5e34b92015-03-13 16:02:36 -0700804func (c *Context) convertDepsToVariation(module *moduleInfo,
805 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800806
Colin Crossc9028482014-12-18 16:28:54 -0800807 for i, dep := range module.directDeps {
808 if dep.logicModule == nil {
809 var newDep *moduleInfo
810 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700811 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800812 newDep = m
813 break
814 }
815 }
816 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800817 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700818 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
819 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700820 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800821 })
822 continue
Colin Crossc9028482014-12-18 16:28:54 -0800823 }
824 module.directDeps[i] = newDep
825 }
826 }
Colin Cross174ae052015-03-03 17:37:03 -0800827
828 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800829}
830
Colin Crossf5e34b92015-03-13 16:02:36 -0700831func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700832 names := make([]string, 0, len(variant))
833 for _, m := range c.variantMutatorNames {
834 if v, ok := variant[m]; ok {
835 names = append(names, m+":"+v)
836 }
837 }
838
839 return strings.Join(names, ", ")
840}
841
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700842func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800843 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700844
Colin Crossd1facc12015-01-08 14:56:03 -0800845 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700846 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700847 if !ok {
848 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800849 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700850 }
851
Colin Cross7ad621c2015-01-07 16:22:45 -0800852 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700853 &Error{
854 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800855 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700856 },
857 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700858 }
859
Colin Crossbbfa51a2014-12-17 16:12:41 -0800860 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700861
862 module := &moduleInfo{
863 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700864 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700865 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700866 }
867
Jamie Gennis87622922014-09-30 11:38:25 -0700868 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700869 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700870 }
871 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700872 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700873
Jamie Gennis87622922014-09-30 11:38:25 -0700874 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700875 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800876 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700877 }
878
Colin Crossed342d92015-03-11 00:57:25 -0700879 module.pos = moduleDef.Type.Pos
880 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700881 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700882 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700883 }
884
Colin Cross7ad621c2015-01-07 16:22:45 -0800885 return module, nil
886}
887
888func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
889 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700890 name := module.properties.Name
891 c.moduleInfo[module.logicModule] = module
892
893 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800894 errs = append(errs, []error{
895 &Error{
896 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700897 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800898 },
899 &Error{
900 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700901 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800902 },
903 }...)
904 continue
Colin Crossed342d92015-03-11 00:57:25 -0700905 } else {
906 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800907
Colin Crossed342d92015-03-11 00:57:25 -0700908 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
909 // already exists
910 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
911 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
912 }
913
914 c.moduleNinjaNames[ninjaName] = group
915
916 group := &moduleGroup{
917 name: module.properties.Name,
918 ninjaName: ninjaName,
919 modules: []*moduleInfo{module},
920 }
921 module.group = group
922 c.moduleGroups[name] = group
923 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800924 }
925
926 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700927}
928
Jamie Gennisd4e10182014-06-12 20:06:50 -0700929// ResolveDependencies checks that the dependencies specified by all of the
930// modules defined in the parsed Blueprints files are valid. This means that
931// the modules depended upon are defined and that no circular dependencies
932// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700933//
934// The config argument is made available to all of the DynamicDependerModule
935// objects via the Config method on the DynamicDependerModuleContext objects
936// passed to their DynamicDependencies method.
937func (c *Context) ResolveDependencies(config interface{}) []error {
938 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700939 if len(errs) > 0 {
940 return errs
941 }
942
Colin Cross691a60d2015-01-07 18:08:56 -0800943 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700944 if len(errs) > 0 {
945 return errs
946 }
947
948 c.dependenciesReady = true
949 return nil
950}
951
Colin Cross65569e42015-03-10 20:08:19 -0700952// moduleDeps adds dependencies to a module. If the module implements the
953// DynamicDependerModule interface then this set consists of the union of those
954// module names listed in its "deps" property, those returned by its
955// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -0700956// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700957// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -0700958func (c *Context) moduleDeps(module *moduleInfo,
959 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700960
961 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800962 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700963
Colin Crossed342d92015-03-11 00:57:25 -0700964 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800965 if !depNamesSet[depName] {
966 depNamesSet[depName] = true
967 depNames = append(depNames, depName)
968 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700969 }
970
Colin Cross65569e42015-03-10 20:08:19 -0700971 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700972 if ok {
Colin Cross65569e42015-03-10 20:08:19 -0700973 ddmctx := &dynamicDependerModuleContext{
974 baseModuleContext: baseModuleContext{
975 context: c,
976 config: config,
977 module: module,
978 },
979 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700980 }
981
982 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
983
984 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -0700985 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700986 }
987
988 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800989 if !depNamesSet[depName] {
990 depNamesSet[depName] = true
991 depNames = append(depNames, depName)
992 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700993 }
994 }
995
Colin Cross65569e42015-03-10 20:08:19 -0700996 for _, depName := range depNames {
997 newErrs := c.addDependency(module, depName)
998 if len(newErrs) > 0 {
999 errs = append(errs, newErrs...)
1000 }
1001 }
1002 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001003}
1004
Colin Cross65569e42015-03-10 20:08:19 -07001005// resolveDependencies populates the directDeps list for every module. In doing so it checks for
1006// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001007func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001008 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -07001009 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -07001010 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1011
1012 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001013 if len(newErrs) > 0 {
1014 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001015 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001016 }
1017 }
1018
1019 return
1020}
1021
Colin Crossc9028482014-12-18 16:28:54 -08001022func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001023 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001024
Colin Crossed342d92015-03-11 00:57:25 -07001025 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001026 return []error{&Error{
1027 Err: fmt.Errorf("%q depends on itself", depName),
1028 Pos: depsPos,
1029 }}
1030 }
1031
1032 depInfo, ok := c.moduleGroups[depName]
1033 if !ok {
1034 return []error{&Error{
1035 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001036 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001037 Pos: depsPos,
1038 }}
1039 }
1040
Colin Cross65569e42015-03-10 20:08:19 -07001041 for _, m := range module.directDeps {
1042 if m.group == depInfo {
1043 return nil
1044 }
Colin Crossc9028482014-12-18 16:28:54 -08001045 }
1046
Colin Cross65569e42015-03-10 20:08:19 -07001047 if len(depInfo.modules) == 1 {
1048 module.directDeps = append(module.directDeps, depInfo.modules[0])
1049 return nil
1050 } else {
1051 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001052 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001053 module.directDeps = append(module.directDeps, m)
1054 return nil
1055 }
1056 }
1057 }
Colin Crossc9028482014-12-18 16:28:54 -08001058
Colin Cross65569e42015-03-10 20:08:19 -07001059 return []error{&Error{
1060 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1061 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001062 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001063 Pos: depsPos,
1064 }}
1065}
1066
Colin Crossf5e34b92015-03-13 16:02:36 -07001067func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross65569e42015-03-10 20:08:19 -07001068 depName string) []error {
1069
1070 depsPos := module.propertyPos["deps"]
1071
1072 depInfo, ok := c.moduleGroups[depName]
1073 if !ok {
1074 return []error{&Error{
1075 Err: fmt.Errorf("%q depends on undefined module %q",
1076 module.properties.Name, depName),
1077 Pos: depsPos,
1078 }}
1079 }
1080
1081 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1082 // compare the strings because the result won't be in mutator registration order.
1083 // Create a new map instead, and then deep compare the maps.
Colin Crossf5e34b92015-03-13 16:02:36 -07001084 newVariant := module.dependencyVariant.clone()
1085 for _, v := range variations {
1086 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001087 }
1088
1089 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001090 if newVariant.equal(m.variant) {
1091 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001092 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001093 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001094 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1095 return []error{&Error{
1096 Err: fmt.Errorf("%q depends on later version of itself", depName),
1097 Pos: depsPos,
1098 }}
1099 }
1100 module.directDeps = append(module.directDeps, m)
1101 return nil
1102 }
1103 }
1104
1105 return []error{&Error{
1106 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1107 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001108 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001109 Pos: depsPos,
1110 }}
Colin Crossc9028482014-12-18 16:28:54 -08001111}
1112
Colin Cross7addea32015-03-11 15:43:52 -07001113func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1114 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001115 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001116 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001117
Colin Cross7addea32015-03-11 15:43:52 -07001118 for _, module := range c.modulesSorted {
1119 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001120 }
1121
Colin Cross7addea32015-03-11 15:43:52 -07001122 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001123 count++
1124 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001125 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001126 if ret {
1127 cancel = true
1128 }
Colin Cross7addea32015-03-11 15:43:52 -07001129 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001130 }()
1131 }
1132
Colin Cross7addea32015-03-11 15:43:52 -07001133 for _, module := range c.modulesSorted {
1134 if module.waitingCount == 0 {
1135 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001136 }
1137 }
1138
Colin Cross11e3b0d2015-02-04 10:41:00 -08001139 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001140 select {
Colin Cross7addea32015-03-11 15:43:52 -07001141 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001142 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001143 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001144 parent.waitingCount--
1145 if parent.waitingCount == 0 {
1146 visitOne(parent)
1147 }
Colin Cross691a60d2015-01-07 18:08:56 -08001148 }
1149 }
1150 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001151 }
1152 }
1153}
1154
1155// updateDependencies recursively walks the module dependency graph and updates
1156// additional fields based on the dependencies. It builds a sorted list of modules
1157// such that dependencies of a module always appear first, and populates reverse
1158// dependency links and counts of total dependencies. It also reports errors when
1159// it encounters dependency cycles. This should called after resolveDependencies,
1160// as well as after any mutator pass has called addDependency
1161func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001162 visited := make(map[*moduleInfo]bool) // modules that were already checked
1163 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001164
Colin Cross7addea32015-03-11 15:43:52 -07001165 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001166
Colin Cross7addea32015-03-11 15:43:52 -07001167 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001168
Colin Cross7addea32015-03-11 15:43:52 -07001169 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001170 // We are the "start" of the cycle, so we're responsible
1171 // for generating the errors. The cycle list is in
1172 // reverse order because all the 'check' calls append
1173 // their own module to the list.
1174 errs = append(errs, &Error{
1175 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001176 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001177 })
1178
1179 // Iterate backwards through the cycle list.
Colin Cross7addea32015-03-11 15:43:52 -07001180 curModule := cycle[len(cycle)-1]
Colin Cross10b54db2015-03-11 14:40:30 -07001181 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001182 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001183 errs = append(errs, &Error{
1184 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001185 curModule.properties.Name,
1186 nextModule.properties.Name),
1187 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001188 })
Colin Cross7addea32015-03-11 15:43:52 -07001189 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001190 }
1191 }
1192
Colin Cross7addea32015-03-11 15:43:52 -07001193 check = func(module *moduleInfo) []*moduleInfo {
1194 visited[module] = true
1195 checking[module] = true
1196 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001197
Colin Cross7addea32015-03-11 15:43:52 -07001198 deps := make(map[*moduleInfo]bool)
1199
1200 // Add an implicit dependency ordering on all earlier modules in the same module group
1201 for _, dep := range module.group.modules {
1202 if dep == module {
1203 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001204 }
Colin Cross7addea32015-03-11 15:43:52 -07001205 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001206 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001207
Colin Cross7addea32015-03-11 15:43:52 -07001208 for _, dep := range module.directDeps {
1209 deps[dep] = true
1210 }
1211
1212 module.reverseDeps = []*moduleInfo{}
1213 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001214
Colin Crossbbfa51a2014-12-17 16:12:41 -08001215 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001216 if checking[dep] {
1217 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001218 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001219 }
1220
1221 if !visited[dep] {
1222 cycle := check(dep)
1223 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001224 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001225 // We are the "start" of the cycle, so we're responsible
1226 // for generating the errors. The cycle list is in
1227 // reverse order because all the 'check' calls append
1228 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001229 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001230
1231 // We can continue processing this module's children to
1232 // find more cycles. Since all the modules that were
1233 // part of the found cycle were marked as visited we
1234 // won't run into that cycle again.
1235 } else {
1236 // We're not the "start" of the cycle, so we just append
1237 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001238 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001239 }
1240 }
1241 }
Colin Cross691a60d2015-01-07 18:08:56 -08001242
Colin Cross7addea32015-03-11 15:43:52 -07001243 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001244 }
1245
Colin Cross7addea32015-03-11 15:43:52 -07001246 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001247
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001248 return nil
1249 }
1250
Colin Cross7addea32015-03-11 15:43:52 -07001251 for _, module := range c.moduleInfo {
1252 if !visited[module] {
1253 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001254 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001255 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001256 panic("inconceivable!")
1257 }
1258 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001259 }
1260 }
1261 }
1262
Colin Cross7addea32015-03-11 15:43:52 -07001263 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001264
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001265 return
1266}
1267
Jamie Gennisd4e10182014-06-12 20:06:50 -07001268// PrepareBuildActions generates an internal representation of all the build
1269// actions that need to be performed. This process involves invoking the
1270// GenerateBuildActions method on each of the Module objects created during the
1271// parse phase and then on each of the registered Singleton objects.
1272//
1273// If the ResolveDependencies method has not already been called it is called
1274// automatically by this method.
1275//
1276// The config argument is made available to all of the Module and Singleton
1277// objects via the Config method on the ModuleContext and SingletonContext
1278// objects passed to GenerateBuildActions. It is also passed to the functions
1279// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1280// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001281//
1282// The returned deps is a list of the ninja files dependencies that were added
1283// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1284// SingletonContext.AddNinjaFileDeps() methods.
1285func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001286 c.buildActionsReady = false
1287
Colin Cross65569e42015-03-10 20:08:19 -07001288 errs = c.runEarlyMutators(config)
1289 if len(errs) > 0 {
1290 return nil, errs
1291 }
1292
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001293 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001294 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001295 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001296 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001297 }
1298 }
1299
Colin Crossc9028482014-12-18 16:28:54 -08001300 errs = c.runMutators(config)
1301 if len(errs) > 0 {
1302 return nil, errs
1303 }
1304
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001305 liveGlobals := newLiveTracker(config)
1306
1307 c.initSpecialVariables()
1308
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001309 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001310 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001311 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001312 }
1313
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001314 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001315 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001316 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001317 }
1318
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001319 deps = append(depsModules, depsSingletons...)
1320
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001321 if c.buildDir != nil {
1322 liveGlobals.addNinjaStringDeps(c.buildDir)
1323 }
1324
1325 pkgNames := c.makeUniquePackageNames(liveGlobals)
1326
1327 // This will panic if it finds a problem since it's a programming error.
1328 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1329
1330 c.pkgNames = pkgNames
1331 c.globalVariables = liveGlobals.variables
1332 c.globalPools = liveGlobals.pools
1333 c.globalRules = liveGlobals.rules
1334
1335 c.buildActionsReady = true
1336
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001337 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001338}
1339
Colin Cross65569e42015-03-10 20:08:19 -07001340func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1341 for _, mutator := range c.earlyMutatorInfo {
1342 for _, group := range c.moduleGroups {
1343 newModules := make([]*moduleInfo, 0, len(group.modules))
1344
1345 for _, module := range group.modules {
1346 mctx := &mutatorContext{
1347 baseModuleContext: baseModuleContext{
1348 context: c,
1349 config: config,
1350 module: module,
1351 },
1352 name: mutator.name,
1353 }
1354 mutator.mutator(mctx)
1355 if len(mctx.errs) > 0 {
1356 errs = append(errs, mctx.errs...)
1357 return errs
1358 }
1359
1360 if module.splitModules != nil {
1361 newModules = append(newModules, module.splitModules...)
1362 } else {
1363 newModules = append(newModules, module)
1364 }
1365 }
1366
1367 group.modules = newModules
1368 }
1369 }
1370
1371 return nil
1372}
1373
Colin Crossc9028482014-12-18 16:28:54 -08001374func (c *Context) runMutators(config interface{}) (errs []error) {
1375 for _, mutator := range c.mutatorInfo {
1376 if mutator.topDownMutator != nil {
1377 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1378 } else if mutator.bottomUpMutator != nil {
1379 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1380 } else {
1381 panic("no mutator set on " + mutator.name)
1382 }
1383 if len(errs) > 0 {
1384 return errs
1385 }
1386 }
1387
1388 return nil
1389}
1390
1391func (c *Context) runTopDownMutator(config interface{},
1392 name string, mutator TopDownMutator) (errs []error) {
1393
Colin Cross7addea32015-03-11 15:43:52 -07001394 for i := 0; i < len(c.modulesSorted); i++ {
1395 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1396 mctx := &mutatorContext{
1397 baseModuleContext: baseModuleContext{
1398 context: c,
1399 config: config,
1400 module: module,
1401 },
1402 name: name,
1403 }
Colin Crossc9028482014-12-18 16:28:54 -08001404
Colin Cross7addea32015-03-11 15:43:52 -07001405 mutator(mctx)
1406 if len(mctx.errs) > 0 {
1407 errs = append(errs, mctx.errs...)
1408 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001409 }
1410 }
1411
1412 return errs
1413}
1414
1415func (c *Context) runBottomUpMutator(config interface{},
1416 name string, mutator BottomUpMutator) (errs []error) {
1417
1418 dependenciesModified := false
1419
Colin Cross7addea32015-03-11 15:43:52 -07001420 for _, module := range c.modulesSorted {
1421 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001422
Colin Cross7addea32015-03-11 15:43:52 -07001423 mctx := &mutatorContext{
1424 baseModuleContext: baseModuleContext{
1425 context: c,
1426 config: config,
1427 module: module,
1428 },
1429 name: name,
1430 }
Colin Crossc9028482014-12-18 16:28:54 -08001431
Colin Cross7addea32015-03-11 15:43:52 -07001432 mutator(mctx)
1433 if len(mctx.errs) > 0 {
1434 errs = append(errs, mctx.errs...)
1435 return errs
1436 }
Colin Crossc9028482014-12-18 16:28:54 -08001437
Colin Cross7addea32015-03-11 15:43:52 -07001438 // Fix up any remaining dependencies on modules that were split into variants
1439 // by replacing them with the first variant
1440 for i, dep := range module.directDeps {
1441 if dep.logicModule == nil {
1442 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001443 }
1444 }
1445
Colin Cross7addea32015-03-11 15:43:52 -07001446 if mctx.dependenciesModified {
1447 dependenciesModified = true
1448 }
1449
1450 if module.splitModules != nil {
1451 newModules = append(newModules, module.splitModules...)
1452 } else {
1453 newModules = append(newModules, module)
1454 }
1455
1456 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001457 }
1458
1459 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001460 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001461 if len(errs) > 0 {
1462 return errs
1463 }
1464 }
1465
1466 return errs
1467}
1468
Colin Cross7addea32015-03-11 15:43:52 -07001469func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1470 newModules []*moduleInfo) []*moduleInfo {
1471 for i, m := range modules {
1472 if m == origModule {
1473 return spliceModulesAtIndex(modules, i, newModules)
1474 }
1475 }
1476
1477 panic("failed to find original module to splice")
1478}
1479
1480func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1481 spliceSize := len(newModules)
1482 newLen := len(modules) + spliceSize - 1
1483 var dest []*moduleInfo
1484 if cap(modules) >= len(modules)-1+len(newModules) {
1485 // We can fit the splice in the existing capacity, do everything in place
1486 dest = modules[:newLen]
1487 } else {
1488 dest = make([]*moduleInfo, newLen)
1489 copy(dest, modules[:i])
1490 }
1491
1492 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001493 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001494
1495 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001496 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001497
Colin Cross72bd1932015-03-16 00:13:59 -07001498 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001499}
1500
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001501func (c *Context) initSpecialVariables() {
1502 c.buildDir = nil
1503 c.requiredNinjaMajor = 1
1504 c.requiredNinjaMinor = 1
1505 c.requiredNinjaMicro = 0
1506}
1507
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001508func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001509 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001510
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001511 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001512 var errs []error
1513
Colin Cross691a60d2015-01-07 18:08:56 -08001514 cancelCh := make(chan struct{})
1515 errsCh := make(chan []error)
1516 depsCh := make(chan []string)
1517
1518 go func() {
1519 for {
1520 select {
1521 case <-cancelCh:
1522 close(cancelCh)
1523 return
1524 case newErrs := <-errsCh:
1525 errs = append(errs, newErrs...)
1526 case newDeps := <-depsCh:
1527 deps = append(deps, newDeps...)
1528
1529 }
1530 }
1531 }()
1532
Colin Cross7addea32015-03-11 15:43:52 -07001533 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1534 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1535 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1536 // just set it to nil.
1537 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1538 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001539
Colin Cross7addea32015-03-11 15:43:52 -07001540 mctx := &moduleContext{
1541 baseModuleContext: baseModuleContext{
1542 context: c,
1543 config: config,
1544 module: module,
1545 },
1546 scope: scope,
1547 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001548
Colin Cross7addea32015-03-11 15:43:52 -07001549 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001550
Colin Cross7addea32015-03-11 15:43:52 -07001551 if len(mctx.errs) > 0 {
1552 errsCh <- mctx.errs
1553 return true
1554 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001555
Colin Cross7addea32015-03-11 15:43:52 -07001556 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001557
Colin Crossab6d7902015-03-11 16:17:52 -07001558 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001559 &mctx.actionDefs, liveGlobals)
1560 if len(newErrs) > 0 {
1561 errsCh <- newErrs
1562 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001563 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001564 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001565 })
1566
1567 cancelCh <- struct{}{}
1568 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001569
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001570 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001571}
1572
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001573func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001574 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001575
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001576 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001577 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001578
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001579 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001580 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1581 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1582 // just set it to nil.
1583 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001584
1585 sctx := &singletonContext{
1586 context: c,
1587 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001588 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001589 }
1590
1591 info.singleton.GenerateBuildActions(sctx)
1592
1593 if len(sctx.errs) > 0 {
1594 errs = append(errs, sctx.errs...)
1595 if len(errs) > maxErrors {
1596 break
1597 }
1598 continue
1599 }
1600
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001601 deps = append(deps, sctx.ninjaFileDeps...)
1602
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001603 newErrs := c.processLocalBuildActions(&info.actionDefs,
1604 &sctx.actionDefs, liveGlobals)
1605 errs = append(errs, newErrs...)
1606 if len(errs) > maxErrors {
1607 break
1608 }
1609 }
1610
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001611 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001612}
1613
1614func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1615 liveGlobals *liveTracker) []error {
1616
1617 var errs []error
1618
1619 // First we go through and add everything referenced by the module's
1620 // buildDefs to the live globals set. This will end up adding the live
1621 // locals to the set as well, but we'll take them out after.
1622 for _, def := range in.buildDefs {
1623 err := liveGlobals.AddBuildDefDeps(def)
1624 if err != nil {
1625 errs = append(errs, err)
1626 }
1627 }
1628
1629 if len(errs) > 0 {
1630 return errs
1631 }
1632
Colin Crossc9028482014-12-18 16:28:54 -08001633 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001634
1635 // We use the now-incorrect set of live "globals" to determine which local
1636 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001637 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001638 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001639 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001640 if isLive {
1641 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001642 }
1643 }
1644
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001645 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001646 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001647 if isLive {
1648 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001649 }
1650 }
1651
1652 return nil
1653}
1654
Colin Crossbbfa51a2014-12-17 16:12:41 -08001655func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1656 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001657
Colin Crossbbfa51a2014-12-17 16:12:41 -08001658 var walk func(module *moduleInfo)
1659 walk = func(module *moduleInfo) {
1660 visited[module] = true
1661 for _, moduleDep := range module.directDeps {
1662 if !visited[moduleDep] {
1663 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001664 }
1665 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001666
Colin Crossbbfa51a2014-12-17 16:12:41 -08001667 if module != topModule {
1668 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001669 }
1670 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001671
1672 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001673}
1674
Colin Crossbbfa51a2014-12-17 16:12:41 -08001675func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001676 visit func(Module)) {
1677
Colin Crossbbfa51a2014-12-17 16:12:41 -08001678 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001679
Colin Crossbbfa51a2014-12-17 16:12:41 -08001680 var walk func(module *moduleInfo)
1681 walk = func(module *moduleInfo) {
1682 visited[module] = true
1683 for _, moduleDep := range module.directDeps {
1684 if !visited[moduleDep] {
1685 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001686 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001687 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001688
1689 if module != topModule {
1690 if pred(module.logicModule) {
1691 visit(module.logicModule)
1692 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001693 }
1694 }
1695
Colin Crossbbfa51a2014-12-17 16:12:41 -08001696 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001697}
1698
Colin Crossc9028482014-12-18 16:28:54 -08001699func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1700 for _, dep := range module.directDeps {
1701 visit(dep.logicModule)
1702 }
1703}
1704
1705func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1706 visit func(Module)) {
1707
1708 for _, dep := range module.directDeps {
1709 if pred(dep.logicModule) {
1710 visit(dep.logicModule)
1711 }
1712 }
1713}
1714
Jamie Gennisc15544d2014-09-24 20:26:52 -07001715func (c *Context) sortedModuleNames() []string {
1716 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001717 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1718 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001719 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1720 moduleName)
1721 }
1722 sort.Strings(c.cachedSortedModuleNames)
1723 }
1724
1725 return c.cachedSortedModuleNames
1726}
1727
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001728func (c *Context) visitAllModules(visit func(Module)) {
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 visit(module.logicModule)
1733 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001734 }
1735}
1736
1737func (c *Context) visitAllModulesIf(pred func(Module) bool,
1738 visit func(Module)) {
1739
Jamie Gennisc15544d2014-09-24 20:26:52 -07001740 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001741 group := c.moduleGroups[moduleName]
1742 for _, module := range group.modules {
1743 if pred(module.logicModule) {
1744 visit(module.logicModule)
1745 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001746 }
1747 }
1748}
1749
1750func (c *Context) requireNinjaVersion(major, minor, micro int) {
1751 if major != 1 {
1752 panic("ninja version with major version != 1 not supported")
1753 }
1754 if c.requiredNinjaMinor < minor {
1755 c.requiredNinjaMinor = minor
1756 c.requiredNinjaMicro = micro
1757 }
1758 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1759 c.requiredNinjaMicro = micro
1760 }
1761}
1762
1763func (c *Context) setBuildDir(value *ninjaString) {
1764 if c.buildDir != nil {
1765 panic("buildDir set multiple times")
1766 }
1767 c.buildDir = value
1768}
1769
1770func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001771 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001772
Jamie Gennis2fb20952014-10-03 02:49:58 -07001773 pkgs := make(map[string]*PackageContext)
1774 pkgNames := make(map[*PackageContext]string)
1775 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001776
Jamie Gennis2fb20952014-10-03 02:49:58 -07001777 processPackage := func(pctx *PackageContext) {
1778 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001779 // This is a built-in rule and has no package.
1780 return
1781 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001782 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001783 // We've already processed this package.
1784 return
1785 }
1786
Jamie Gennis2fb20952014-10-03 02:49:58 -07001787 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001788 if present {
1789 // Short name collision. Both this package and the one that's
1790 // already there need to use their full names. We leave the short
1791 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001792 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001793 longPkgNames[otherPkg] = true
1794 } else {
1795 // No collision so far. Tentatively set the package's name to be
1796 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001797 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 }
1799 }
1800
1801 // We try to give all packages their short name, but when we get collisions
1802 // we need to use the full unique package name.
1803 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001804 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001805 }
1806 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001807 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001808 }
1809 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001810 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001811 }
1812
1813 // Add the packages that had collisions using their full unique names. This
1814 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001815 for pctx := range longPkgNames {
1816 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001817 }
1818
1819 return pkgNames
1820}
1821
1822func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001823 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001824
1825 visited := make(map[Variable]bool) // variables that were already checked
1826 checking := make(map[Variable]bool) // variables actively being checked
1827
1828 var check func(v Variable) []Variable
1829
1830 check = func(v Variable) []Variable {
1831 visited[v] = true
1832 checking[v] = true
1833 defer delete(checking, v)
1834
1835 value := variables[v]
1836 for _, dep := range value.variables {
1837 if checking[dep] {
1838 // This is a cycle.
1839 return []Variable{dep, v}
1840 }
1841
1842 if !visited[dep] {
1843 cycle := check(dep)
1844 if cycle != nil {
1845 if cycle[0] == v {
1846 // We are the "start" of the cycle, so we're responsible
1847 // for generating the errors. The cycle list is in
1848 // reverse order because all the 'check' calls append
1849 // their own module to the list.
1850 msgs := []string{"detected variable reference cycle:"}
1851
1852 // Iterate backwards through the cycle list.
1853 curName := v.fullName(pkgNames)
1854 curValue := value.Value(pkgNames)
1855 for i := len(cycle) - 1; i >= 0; i-- {
1856 next := cycle[i]
1857 nextName := next.fullName(pkgNames)
1858 nextValue := variables[next].Value(pkgNames)
1859
1860 msgs = append(msgs, fmt.Sprintf(
1861 " %q depends on %q", curName, nextName))
1862 msgs = append(msgs, fmt.Sprintf(
1863 " [%s = %s]", curName, curValue))
1864
1865 curName = nextName
1866 curValue = nextValue
1867 }
1868
1869 // Variable reference cycles are a programming error,
1870 // not the fault of the Blueprint file authors.
1871 panic(strings.Join(msgs, "\n"))
1872 } else {
1873 // We're not the "start" of the cycle, so we just append
1874 // our module to the list and return it.
1875 return append(cycle, v)
1876 }
1877 }
1878 }
1879 }
1880
1881 return nil
1882 }
1883
1884 for v := range variables {
1885 if !visited[v] {
1886 cycle := check(v)
1887 if cycle != nil {
1888 panic("inconceivable!")
1889 }
1890 }
1891 }
1892}
1893
Jamie Gennisaf435562014-10-27 22:34:56 -07001894// AllTargets returns a map all the build target names to the rule used to build
1895// them. This is the same information that is output by running 'ninja -t
1896// targets all'. If this is called before PrepareBuildActions successfully
1897// completes then ErrbuildActionsNotReady is returned.
1898func (c *Context) AllTargets() (map[string]string, error) {
1899 if !c.buildActionsReady {
1900 return nil, ErrBuildActionsNotReady
1901 }
1902
1903 targets := map[string]string{}
1904
1905 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001906 for _, module := range c.moduleInfo {
1907 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001908 ruleName := buildDef.Rule.fullName(c.pkgNames)
1909 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001910 outputValue, err := output.Eval(c.globalVariables)
1911 if err != nil {
1912 return nil, err
1913 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001914 targets[outputValue] = ruleName
1915 }
1916 }
1917 }
1918
1919 // Collect all the singleton build targets.
1920 for _, info := range c.singletonInfo {
1921 for _, buildDef := range info.actionDefs.buildDefs {
1922 ruleName := buildDef.Rule.fullName(c.pkgNames)
1923 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001924 outputValue, err := output.Eval(c.globalVariables)
1925 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001926 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001927 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001928 targets[outputValue] = ruleName
1929 }
1930 }
1931 }
1932
1933 return targets, nil
1934}
1935
Jamie Gennisd4e10182014-06-12 20:06:50 -07001936// WriteBuildFile writes the Ninja manifeset text for the generated build
1937// actions to w. If this is called before PrepareBuildActions successfully
1938// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001939func (c *Context) WriteBuildFile(w io.Writer) error {
1940 if !c.buildActionsReady {
1941 return ErrBuildActionsNotReady
1942 }
1943
1944 nw := newNinjaWriter(w)
1945
1946 err := c.writeBuildFileHeader(nw)
1947 if err != nil {
1948 return err
1949 }
1950
1951 err = c.writeNinjaRequiredVersion(nw)
1952 if err != nil {
1953 return err
1954 }
1955
1956 // TODO: Group the globals by package.
1957
1958 err = c.writeGlobalVariables(nw)
1959 if err != nil {
1960 return err
1961 }
1962
1963 err = c.writeGlobalPools(nw)
1964 if err != nil {
1965 return err
1966 }
1967
1968 err = c.writeBuildDir(nw)
1969 if err != nil {
1970 return err
1971 }
1972
1973 err = c.writeGlobalRules(nw)
1974 if err != nil {
1975 return err
1976 }
1977
1978 err = c.writeAllModuleActions(nw)
1979 if err != nil {
1980 return err
1981 }
1982
1983 err = c.writeAllSingletonActions(nw)
1984 if err != nil {
1985 return err
1986 }
1987
1988 return nil
1989}
1990
Jamie Gennisc15544d2014-09-24 20:26:52 -07001991type pkgAssociation struct {
1992 PkgName string
1993 PkgPath string
1994}
1995
1996type pkgAssociationSorter struct {
1997 pkgs []pkgAssociation
1998}
1999
2000func (s *pkgAssociationSorter) Len() int {
2001 return len(s.pkgs)
2002}
2003
2004func (s *pkgAssociationSorter) Less(i, j int) bool {
2005 iName := s.pkgs[i].PkgName
2006 jName := s.pkgs[j].PkgName
2007 return iName < jName
2008}
2009
2010func (s *pkgAssociationSorter) Swap(i, j int) {
2011 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2012}
2013
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002014func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2015 headerTemplate := template.New("fileHeader")
2016 _, err := headerTemplate.Parse(fileHeaderTemplate)
2017 if err != nil {
2018 // This is a programming error.
2019 panic(err)
2020 }
2021
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002022 var pkgs []pkgAssociation
2023 maxNameLen := 0
2024 for pkg, name := range c.pkgNames {
2025 pkgs = append(pkgs, pkgAssociation{
2026 PkgName: name,
2027 PkgPath: pkg.pkgPath,
2028 })
2029 if len(name) > maxNameLen {
2030 maxNameLen = len(name)
2031 }
2032 }
2033
2034 for i := range pkgs {
2035 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2036 }
2037
Jamie Gennisc15544d2014-09-24 20:26:52 -07002038 sort.Sort(&pkgAssociationSorter{pkgs})
2039
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002040 params := map[string]interface{}{
2041 "Pkgs": pkgs,
2042 }
2043
2044 buf := bytes.NewBuffer(nil)
2045 err = headerTemplate.Execute(buf, params)
2046 if err != nil {
2047 return err
2048 }
2049
2050 return nw.Comment(buf.String())
2051}
2052
2053func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2054 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2055 c.requiredNinjaMicro)
2056
2057 err := nw.Assign("ninja_required_version", value)
2058 if err != nil {
2059 return err
2060 }
2061
2062 return nw.BlankLine()
2063}
2064
2065func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2066 if c.buildDir != nil {
2067 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2068 if err != nil {
2069 return err
2070 }
2071
2072 err = nw.BlankLine()
2073 if err != nil {
2074 return err
2075 }
2076 }
2077 return nil
2078}
2079
Jamie Gennisc15544d2014-09-24 20:26:52 -07002080type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002081 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002082}
2083
Jamie Gennisc15544d2014-09-24 20:26:52 -07002084type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002085 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002086 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002087}
2088
Jamie Gennisc15544d2014-09-24 20:26:52 -07002089func (s *globalEntitySorter) Len() int {
2090 return len(s.entities)
2091}
2092
2093func (s *globalEntitySorter) Less(i, j int) bool {
2094 iName := s.entities[i].fullName(s.pkgNames)
2095 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002096 return iName < jName
2097}
2098
Jamie Gennisc15544d2014-09-24 20:26:52 -07002099func (s *globalEntitySorter) Swap(i, j int) {
2100 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002101}
2102
2103func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2104 visited := make(map[Variable]bool)
2105
2106 var walk func(v Variable) error
2107 walk = func(v Variable) error {
2108 visited[v] = true
2109
2110 // First visit variables on which this variable depends.
2111 value := c.globalVariables[v]
2112 for _, dep := range value.variables {
2113 if !visited[dep] {
2114 err := walk(dep)
2115 if err != nil {
2116 return err
2117 }
2118 }
2119 }
2120
2121 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2122 if err != nil {
2123 return err
2124 }
2125
2126 err = nw.BlankLine()
2127 if err != nil {
2128 return err
2129 }
2130
2131 return nil
2132 }
2133
Jamie Gennisc15544d2014-09-24 20:26:52 -07002134 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2135 for variable := range c.globalVariables {
2136 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002137 }
2138
Jamie Gennisc15544d2014-09-24 20:26:52 -07002139 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002140
Jamie Gennisc15544d2014-09-24 20:26:52 -07002141 for _, entity := range globalVariables {
2142 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002143 if !visited[v] {
2144 err := walk(v)
2145 if err != nil {
2146 return nil
2147 }
2148 }
2149 }
2150
2151 return nil
2152}
2153
2154func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002155 globalPools := make([]globalEntity, 0, len(c.globalPools))
2156 for pool := range c.globalPools {
2157 globalPools = append(globalPools, pool)
2158 }
2159
2160 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2161
2162 for _, entity := range globalPools {
2163 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002164 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002165 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002166 err := def.WriteTo(nw, name)
2167 if err != nil {
2168 return err
2169 }
2170
2171 err = nw.BlankLine()
2172 if err != nil {
2173 return err
2174 }
2175 }
2176
2177 return nil
2178}
2179
2180func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002181 globalRules := make([]globalEntity, 0, len(c.globalRules))
2182 for rule := range c.globalRules {
2183 globalRules = append(globalRules, rule)
2184 }
2185
2186 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2187
2188 for _, entity := range globalRules {
2189 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002190 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002191 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002192 err := def.WriteTo(nw, name, c.pkgNames)
2193 if err != nil {
2194 return err
2195 }
2196
2197 err = nw.BlankLine()
2198 if err != nil {
2199 return err
2200 }
2201 }
2202
2203 return nil
2204}
2205
Colin Crossab6d7902015-03-11 16:17:52 -07002206type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002207
Colin Crossab6d7902015-03-11 16:17:52 -07002208func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002209 return len(s)
2210}
2211
Colin Crossab6d7902015-03-11 16:17:52 -07002212func (s moduleSorter) Less(i, j int) bool {
2213 iName := s[i].properties.Name
2214 jName := s[j].properties.Name
2215 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002216 iName = s[i].variantName
2217 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002218 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002219 return iName < jName
2220}
2221
Colin Crossab6d7902015-03-11 16:17:52 -07002222func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002223 s[i], s[j] = s[j], s[i]
2224}
2225
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002226func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2227 headerTemplate := template.New("moduleHeader")
2228 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2229 if err != nil {
2230 // This is a programming error.
2231 panic(err)
2232 }
2233
Colin Crossab6d7902015-03-11 16:17:52 -07002234 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2235 for _, module := range c.moduleInfo {
2236 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002237 }
Colin Crossab6d7902015-03-11 16:17:52 -07002238 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002239
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002240 buf := bytes.NewBuffer(nil)
2241
Colin Crossab6d7902015-03-11 16:17:52 -07002242 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002243 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002244
2245 // In order to make the bootstrap build manifest independent of the
2246 // build dir we need to output the Blueprints file locations in the
2247 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002248 relPos := module.pos
2249 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002250
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002251 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002252 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002253 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2254 factoryName := factoryFunc.Name()
2255
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002256 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002257 "properties": module.properties,
2258 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002259 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002260 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002261 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002262 }
2263 err = headerTemplate.Execute(buf, infoMap)
2264 if err != nil {
2265 return err
2266 }
2267
2268 err = nw.Comment(buf.String())
2269 if err != nil {
2270 return err
2271 }
2272
2273 err = nw.BlankLine()
2274 if err != nil {
2275 return err
2276 }
2277
Colin Crossab6d7902015-03-11 16:17:52 -07002278 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002279 if err != nil {
2280 return err
2281 }
2282
2283 err = nw.BlankLine()
2284 if err != nil {
2285 return err
2286 }
2287 }
2288
2289 return nil
2290}
2291
2292func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2293 headerTemplate := template.New("singletonHeader")
2294 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2295 if err != nil {
2296 // This is a programming error.
2297 panic(err)
2298 }
2299
2300 buf := bytes.NewBuffer(nil)
2301
Jamie Gennis86179fe2014-06-11 16:27:16 -07002302 singletonNames := make([]string, 0, len(c.singletonInfo))
2303 for name := range c.singletonInfo {
2304 singletonNames = append(singletonNames, name)
2305 }
2306 sort.Strings(singletonNames)
2307
2308 for _, name := range singletonNames {
2309 info := c.singletonInfo[name]
2310
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002311 // Get the name of the factory function for the module.
2312 factory := info.factory
2313 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2314 factoryName := factoryFunc.Name()
2315
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002316 buf.Reset()
2317 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002318 "name": name,
2319 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002320 }
2321 err = headerTemplate.Execute(buf, infoMap)
2322 if err != nil {
2323 return err
2324 }
2325
2326 err = nw.Comment(buf.String())
2327 if err != nil {
2328 return err
2329 }
2330
2331 err = nw.BlankLine()
2332 if err != nil {
2333 return err
2334 }
2335
2336 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2337 if err != nil {
2338 return err
2339 }
2340
2341 err = nw.BlankLine()
2342 if err != nil {
2343 return err
2344 }
2345 }
2346
2347 return nil
2348}
2349
2350func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2351 defs *localBuildActions) error {
2352
2353 // Write the local variable assignments.
2354 for _, v := range defs.variables {
2355 // A localVariable doesn't need the package names or config to
2356 // determine its name or value.
2357 name := v.fullName(nil)
2358 value, err := v.value(nil)
2359 if err != nil {
2360 panic(err)
2361 }
2362 err = nw.Assign(name, value.Value(c.pkgNames))
2363 if err != nil {
2364 return err
2365 }
2366 }
2367
2368 if len(defs.variables) > 0 {
2369 err := nw.BlankLine()
2370 if err != nil {
2371 return err
2372 }
2373 }
2374
2375 // Write the local rules.
2376 for _, r := range defs.rules {
2377 // A localRule doesn't need the package names or config to determine
2378 // its name or definition.
2379 name := r.fullName(nil)
2380 def, err := r.def(nil)
2381 if err != nil {
2382 panic(err)
2383 }
2384
2385 err = def.WriteTo(nw, name, c.pkgNames)
2386 if err != nil {
2387 return err
2388 }
2389
2390 err = nw.BlankLine()
2391 if err != nil {
2392 return err
2393 }
2394 }
2395
2396 // Write the build definitions.
2397 for _, buildDef := range defs.buildDefs {
2398 err := buildDef.WriteTo(nw, c.pkgNames)
2399 if err != nil {
2400 return err
2401 }
2402
2403 if len(buildDef.Args) > 0 {
2404 err = nw.BlankLine()
2405 if err != nil {
2406 return err
2407 }
2408 }
2409 }
2410
2411 return nil
2412}
2413
Colin Cross65569e42015-03-10 20:08:19 -07002414func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2415 found := false
2416 for _, l := range list {
2417 if l == a {
2418 found = true
2419 } else if l == b {
2420 return found
2421 }
2422 }
2423
2424 missing := a
2425 if found {
2426 missing = b
2427 }
2428 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2429}
2430
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002431var fileHeaderTemplate = `******************************************************************************
2432*** This file is generated and should not be edited ***
2433******************************************************************************
2434{{if .Pkgs}}
2435This file contains variables, rules, and pools with name prefixes indicating
2436they were generated by the following Go packages:
2437{{range .Pkgs}}
2438 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2439
2440`
2441
2442var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2443Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002444Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002445Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002446Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002447Defined: {{.pos}}
2448`
2449
2450var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2451Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002452Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002453`