blob: 4437dedf1e496e4669f238ff51c5801071bb6450 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
18 "blueprint/parser"
Colin Crossc9028482014-12-18 16:28:54 -080019 "blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "bytes"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080029 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "strings"
31 "text/scanner"
32 "text/template"
33)
34
35var ErrBuildActionsNotReady = errors.New("build actions are not ready")
36
37const maxErrors = 10
38
Jamie Gennisd4e10182014-06-12 20:06:50 -070039// A Context contains all the state needed to parse a set of Blueprints files
40// and generate a Ninja file. The process of generating a Ninja file proceeds
41// through a series of four phases. Each phase corresponds with a some methods
42// on the Context object
43//
44// Phase Methods
45// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070046// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070047//
48// 2. Parse ParseBlueprintsFiles, Parse
49//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070050// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070051//
52// 4. Write WriteBuildFile
53//
54// The registration phase prepares the context to process Blueprints files
55// containing various types of modules. The parse phase reads in one or more
56// Blueprints files and validates their contents against the module types that
57// have been registered. The generate phase then analyzes the parsed Blueprints
58// contents to create an internal representation for the build actions that must
59// be performed. This phase also performs validation of the module dependencies
60// and property values defined in the parsed Blueprints files. Finally, the
61// write phase generates the Ninja manifest text based on the generated build
62// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070063type Context struct {
64 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070065 moduleFactories map[string]ModuleFactory
66 moduleGroups map[string]*moduleGroup
67 moduleInfo map[Module]*moduleInfo
68 modulesSorted []*moduleInfo
69 singletonInfo map[string]*singletonInfo
70 mutatorInfo []*mutatorInfo
71 earlyMutatorInfo []*earlyMutatorInfo
72 variantMutatorNames []string
73 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074
75 dependenciesReady bool // set to true on a successful ResolveDependencies
76 buildActionsReady bool // set to true on a successful PrepareBuildActions
77
78 // set by SetIgnoreUnknownModuleTypes
79 ignoreUnknownModuleTypes bool
80
81 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070082 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070083 globalVariables map[Variable]*ninjaString
84 globalPools map[Pool]*poolDef
85 globalRules map[Rule]*ruleDef
86
87 // set during PrepareBuildActions
88 buildDir *ninjaString // The builddir special Ninja variable
89 requiredNinjaMajor int // For the ninja_required_version variable
90 requiredNinjaMinor int // For the ninja_required_version variable
91 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070092
93 // set lazily by sortedModuleNames
94 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095}
96
Jamie Gennisd4e10182014-06-12 20:06:50 -070097// An Error describes a problem that was encountered that is related to a
98// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700100 Err error // the error that occurred
101 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102}
103
104type localBuildActions struct {
105 variables []*localVariable
106 rules []*localRule
107 buildDefs []*buildDef
108}
109
Colin Crossbbfa51a2014-12-17 16:12:41 -0800110type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700111 name string
112 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700113
Colin Crossbbfa51a2014-12-17 16:12:41 -0800114 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115}
116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700118 // set during Parse
119 typeName string
120 relBlueprintsFile string
121 pos scanner.Position
122 propertyPos map[string]scanner.Position
123 properties struct {
124 Name string
125 Deps []string
126 }
127
Colin Crossf5e34b92015-03-13 16:02:36 -0700128 variantName string
129 variant variationMap
130 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700131
Colin Crossc9028482014-12-18 16:28:54 -0800132 logicModule Module
133 group *moduleGroup
134 moduleProperties []interface{}
135
136 // set during ResolveDependencies
137 directDeps []*moduleInfo
138
Colin Cross7addea32015-03-11 15:43:52 -0700139 // set during updateDependencies
140 reverseDeps []*moduleInfo
141 depsCount int
142
143 // used by parallelVisitAllBottomUp
144 waitingCount int
145
Colin Crossc9028482014-12-18 16:28:54 -0800146 // set during each runMutator
147 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700148
149 // set during PrepareBuildActions
150 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800151}
152
Colin Crossf5e34b92015-03-13 16:02:36 -0700153// A Variation is a way that a variant of a module differs from other variants of the same module.
154// For example, two variants of the same module might have Variation{"arch","arm"} and
155// Variation{"arch","arm64"}
156type Variation struct {
157 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700158 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700159 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
160 // "shared" or "static" for link.
161 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700162}
163
Colin Crossf5e34b92015-03-13 16:02:36 -0700164// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
165type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700166
Colin Crossf5e34b92015-03-13 16:02:36 -0700167func (vm variationMap) clone() variationMap {
168 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700169 for k, v := range vm {
170 newVm[k] = v
171 }
172
173 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800174}
175
Colin Crossf5e34b92015-03-13 16:02:36 -0700176func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700177 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800178}
179
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700180type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700181 // set during RegisterSingletonType
182 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700183 singleton Singleton
184
185 // set during PrepareBuildActions
186 actionDefs localBuildActions
187}
188
Colin Crossc9028482014-12-18 16:28:54 -0800189type mutatorInfo struct {
190 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800191 topDownMutator TopDownMutator
192 bottomUpMutator BottomUpMutator
193 name string
Colin Crossc9028482014-12-18 16:28:54 -0800194}
195
Colin Cross65569e42015-03-10 20:08:19 -0700196type earlyMutatorInfo struct {
197 // set during RegisterEarlyMutator
198 mutator EarlyMutator
199 name string
200}
201
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700202func (e *Error) Error() string {
203
204 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
205}
206
Jamie Gennisd4e10182014-06-12 20:06:50 -0700207// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700208// no module or singleton factories registered, so the RegisterModuleFactory and
209// RegisterSingletonFactory methods must be called before it can do anything
210// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700211func NewContext() *Context {
212 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800213 moduleFactories: make(map[string]ModuleFactory),
214 moduleGroups: make(map[string]*moduleGroup),
215 moduleInfo: make(map[Module]*moduleInfo),
216 singletonInfo: make(map[string]*singletonInfo),
217 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700218 }
219}
220
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700221// A ModuleFactory function creates a new Module object. See the
222// Context.RegisterModuleType method for details about how a registered
223// ModuleFactory is used by a Context.
224type ModuleFactory func() (m Module, propertyStructs []interface{})
225
Jamie Gennisd4e10182014-06-12 20:06:50 -0700226// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700227// Blueprints file) with a Module factory function. When the given module type
228// name is encountered in a Blueprints file during parsing, the Module factory
229// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800230// generation for the module. If a Mutator splits a module into multiple variants,
231// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700232//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700233// The module type names given here must be unique for the context. The factory
234// function should be a named function so that its package and name can be
235// included in the generated Ninja file for debugging purposes.
236//
237// The factory function returns two values. The first is the newly created
238// Module object. The second is a slice of pointers to that Module object's
239// properties structs. Each properties struct is examined when parsing a module
240// definition of this type in a Blueprints file. Exported fields of the
241// properties structs are automatically set to the property values specified in
242// the Blueprints file. The properties struct field names determine the name of
243// the Blueprints file properties that are used - the Blueprints property name
244// matches that of the properties struct field name with the first letter
245// converted to lower-case.
246//
247// The fields of the properties struct must be either []string, a string, or
248// bool. The Context will panic if a Module gets instantiated with a properties
249// struct containing a field that is not one these supported types.
250//
251// Any properties that appear in the Blueprints files that are not built-in
252// module properties (such as "name" and "deps") and do not have a corresponding
253// field in the returned module properties struct result in an error during the
254// Context's parse phase.
255//
256// As an example, the follow code:
257//
258// type myModule struct {
259// properties struct {
260// Foo string
261// Bar []string
262// }
263// }
264//
265// func NewMyModule() (blueprint.Module, []interface{}) {
266// module := new(myModule)
267// properties := &module.properties
268// return module, []interface{}{properties}
269// }
270//
271// func main() {
272// ctx := blueprint.NewContext()
273// ctx.RegisterModuleType("my_module", NewMyModule)
274// // ...
275// }
276//
277// would support parsing a module defined in a Blueprints file as follows:
278//
279// my_module {
280// name: "myName",
281// foo: "my foo string",
282// bar: ["my", "bar", "strings"],
283// }
284//
Colin Cross7ad621c2015-01-07 16:22:45 -0800285// The factory function may be called from multiple goroutines. Any accesses
286// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700287func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
288 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700289 panic(errors.New("module type name is already registered"))
290 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700291 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700292}
293
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700294// A SingletonFactory function creates a new Singleton object. See the
295// Context.RegisterSingletonType method for details about how a registered
296// SingletonFactory is used by a Context.
297type SingletonFactory func() Singleton
298
299// RegisterSingletonType registers a singleton type that will be invoked to
300// generate build actions. Each registered singleton type is instantiated and
301// and invoked exactly once as part of the generate phase.
302//
303// The singleton type names given here must be unique for the context. The
304// factory function should be a named function so that its package and name can
305// be included in the generated Ninja file for debugging purposes.
306func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700307 if _, present := c.singletonInfo[name]; present {
308 panic(errors.New("singleton name is already registered"))
309 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700310
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700311 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312 factory: factory,
313 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700314 }
315}
316
317func singletonPkgPath(singleton Singleton) string {
318 typ := reflect.TypeOf(singleton)
319 for typ.Kind() == reflect.Ptr {
320 typ = typ.Elem()
321 }
322 return typ.PkgPath()
323}
324
325func singletonTypeName(singleton Singleton) string {
326 typ := reflect.TypeOf(singleton)
327 for typ.Kind() == reflect.Ptr {
328 typ = typ.Elem()
329 }
330 return typ.PkgPath() + "." + typ.Name()
331}
332
Colin Crossc9028482014-12-18 16:28:54 -0800333// RegisterTopDownMutator registers a mutator that will be invoked to propagate
334// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700335// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
336// once per Module, and is invoked on a module before being invoked on any of its
337// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800338//
Colin Cross65569e42015-03-10 20:08:19 -0700339// The mutator type names given here must be unique to all top down mutators in
340// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800341func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
342 for _, m := range c.mutatorInfo {
343 if m.name == name && m.topDownMutator != nil {
344 panic(fmt.Errorf("mutator name %s is already registered", name))
345 }
346 }
347
348 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
349 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800350 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800351 })
352}
353
354// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700355// Modules into variants. Each registered mutator is invoked in registration
356// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
357// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800358//
Colin Cross65569e42015-03-10 20:08:19 -0700359// The mutator type names given here must be unique to all bottom up or early
360// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800361func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700362 for _, m := range c.variantMutatorNames {
363 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800364 panic(fmt.Errorf("mutator name %s is already registered", name))
365 }
366 }
367
368 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
369 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800370 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800371 })
Colin Cross65569e42015-03-10 20:08:19 -0700372
373 c.variantMutatorNames = append(c.variantMutatorNames, name)
374}
375
376// RegisterEarlyMutator registers a mutator that will be invoked to split
377// Modules into multiple variant Modules before any dependencies have been
378// created. Each registered mutator is invoked in registration order once
379// per Module (including each variant from previous early mutators). Module
380// order is unpredictable.
381//
382// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700383// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700384//
385// The mutator type names given here must be unique to all bottom up or early
386// mutators in the Context.
387func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
388 for _, m := range c.variantMutatorNames {
389 if m == name {
390 panic(fmt.Errorf("mutator name %s is already registered", name))
391 }
392 }
393
394 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
395 mutator: mutator,
396 name: name,
397 })
398
399 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800400}
401
Jamie Gennisd4e10182014-06-12 20:06:50 -0700402// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
403// where it encounters an unknown module type while parsing Blueprints files. By
404// default, the context will report unknown module types as an error. If this
405// method is called with ignoreUnknownModuleTypes set to true then the context
406// will silently ignore unknown module types.
407//
408// This method should generally not be used. It exists to facilitate the
409// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700410func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
411 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
412}
413
Jamie Gennisd4e10182014-06-12 20:06:50 -0700414// Parse parses a single Blueprints file from r, creating Module objects for
415// each of the module definitions encountered. If the Blueprints file contains
416// an assignment to the "subdirs" variable, then the subdirectories listed are
417// returned in the subdirs first return value.
418//
419// rootDir specifies the path to the root directory of the source tree, while
420// filename specifies the path to the Blueprints file. These paths are used for
421// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800422func (c *Context) parse(rootDir, filename string, r io.Reader,
423 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
424 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700425
Jamie Gennisec701282014-06-12 20:06:31 -0700426 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700427 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800428 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700429 }
430
Colin Crossc0dbc552015-01-02 15:19:28 -0800431 scope = parser.NewScope(scope)
432 scope.Remove("subdirs")
Colin 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
721 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800722
Colin Cross174ae052015-03-03 17:37:03 -0800723 var errs []error
724
Colin Crossf5e34b92015-03-13 16:02:36 -0700725 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700726 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800727 factory, ok := c.moduleFactories[typeName]
728 if !ok {
729 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
730 }
731
732 var newLogicModule Module
733 var newProperties []interface{}
734
735 if i == 0 {
736 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700737 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
738 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800739 newLogicModule = origModule.logicModule
740 newProperties = origModule.moduleProperties
741 } else {
742 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700743 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800744 }
745 newLogicModule, newProperties = factory()
746
747 newProperties = append(props, newProperties...)
748
749 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700750 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800751 }
752
753 for i := range newProperties {
754 dst := reflect.ValueOf(newProperties[i]).Elem()
755 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
756
757 proptools.CopyProperties(dst, src)
758 }
759 }
760
Colin Crossf5e34b92015-03-13 16:02:36 -0700761 newVariant := origModule.variant.clone()
762 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800763
Colin Crossed342d92015-03-11 00:57:25 -0700764 m := *origModule
765 newModule := &m
766 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
767 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700768 newModule.variant = newVariant
769 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700770 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800771
Colin Crosse7daa222015-03-11 14:35:41 -0700772 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700773 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700774 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700775 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700776 }
777
Colin Crossc9028482014-12-18 16:28:54 -0800778 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700779
780 // Insert the new variant into the global module map. If this is the first variant then
781 // it reuses logicModule from the original module, which causes this to replace the
782 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800783 c.moduleInfo[newModule.logicModule] = newModule
784
Colin Crossf5e34b92015-03-13 16:02:36 -0700785 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800786 if len(newErrs) > 0 {
787 errs = append(errs, newErrs...)
788 }
Colin Crossc9028482014-12-18 16:28:54 -0800789 }
790
791 // Mark original variant as invalid. Modules that depend on this module will still
792 // depend on origModule, but we'll fix it when the mutator is called on them.
793 origModule.logicModule = nil
794 origModule.splitModules = newModules
795
Colin Cross174ae052015-03-03 17:37:03 -0800796 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800797}
798
Colin Crossf5e34b92015-03-13 16:02:36 -0700799func (c *Context) convertDepsToVariation(module *moduleInfo,
800 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800801
Colin Crossc9028482014-12-18 16:28:54 -0800802 for i, dep := range module.directDeps {
803 if dep.logicModule == nil {
804 var newDep *moduleInfo
805 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700806 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800807 newDep = m
808 break
809 }
810 }
811 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800812 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700813 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
814 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700815 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800816 })
817 continue
Colin Crossc9028482014-12-18 16:28:54 -0800818 }
819 module.directDeps[i] = newDep
820 }
821 }
Colin Cross174ae052015-03-03 17:37:03 -0800822
823 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800824}
825
Colin Crossf5e34b92015-03-13 16:02:36 -0700826func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700827 names := make([]string, 0, len(variant))
828 for _, m := range c.variantMutatorNames {
829 if v, ok := variant[m]; ok {
830 names = append(names, m+":"+v)
831 }
832 }
833
834 return strings.Join(names, ", ")
835}
836
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700837func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800838 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700839
Colin Crossd1facc12015-01-08 14:56:03 -0800840 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700841 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700842 if !ok {
843 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800844 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700845 }
846
Colin Cross7ad621c2015-01-07 16:22:45 -0800847 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700848 &Error{
849 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800850 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700851 },
852 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700853 }
854
Colin Crossbbfa51a2014-12-17 16:12:41 -0800855 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700856
857 module := &moduleInfo{
858 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700859 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700860 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700861 }
862
Jamie Gennis87622922014-09-30 11:38:25 -0700863 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700864 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700865 }
866 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700867 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700868
Jamie Gennis87622922014-09-30 11:38:25 -0700869 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700870 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800871 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700872 }
873
Colin Crossed342d92015-03-11 00:57:25 -0700874 module.pos = moduleDef.Type.Pos
875 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700876 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700877 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700878 }
879
Colin Cross7ad621c2015-01-07 16:22:45 -0800880 return module, nil
881}
882
883func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
884 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700885 name := module.properties.Name
886 c.moduleInfo[module.logicModule] = module
887
888 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800889 errs = append(errs, []error{
890 &Error{
891 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700892 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800893 },
894 &Error{
895 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700896 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800897 },
898 }...)
899 continue
Colin Crossed342d92015-03-11 00:57:25 -0700900 } else {
901 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800902
Colin Crossed342d92015-03-11 00:57:25 -0700903 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
904 // already exists
905 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
906 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
907 }
908
909 c.moduleNinjaNames[ninjaName] = group
910
911 group := &moduleGroup{
912 name: module.properties.Name,
913 ninjaName: ninjaName,
914 modules: []*moduleInfo{module},
915 }
916 module.group = group
917 c.moduleGroups[name] = group
918 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800919 }
920
921 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700922}
923
Jamie Gennisd4e10182014-06-12 20:06:50 -0700924// ResolveDependencies checks that the dependencies specified by all of the
925// modules defined in the parsed Blueprints files are valid. This means that
926// the modules depended upon are defined and that no circular dependencies
927// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700928//
929// The config argument is made available to all of the DynamicDependerModule
930// objects via the Config method on the DynamicDependerModuleContext objects
931// passed to their DynamicDependencies method.
932func (c *Context) ResolveDependencies(config interface{}) []error {
933 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700934 if len(errs) > 0 {
935 return errs
936 }
937
Colin Cross691a60d2015-01-07 18:08:56 -0800938 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700939 if len(errs) > 0 {
940 return errs
941 }
942
943 c.dependenciesReady = true
944 return nil
945}
946
Colin Cross65569e42015-03-10 20:08:19 -0700947// moduleDeps adds dependencies to a module. If the module implements the
948// DynamicDependerModule interface then this set consists of the union of those
949// module names listed in its "deps" property, those returned by its
950// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -0700951// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700952// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -0700953func (c *Context) moduleDeps(module *moduleInfo,
954 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700955
956 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800957 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700958
Colin Crossed342d92015-03-11 00:57:25 -0700959 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800960 if !depNamesSet[depName] {
961 depNamesSet[depName] = true
962 depNames = append(depNames, depName)
963 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700964 }
965
Colin Cross65569e42015-03-10 20:08:19 -0700966 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700967 if ok {
Colin Cross65569e42015-03-10 20:08:19 -0700968 ddmctx := &dynamicDependerModuleContext{
969 baseModuleContext: baseModuleContext{
970 context: c,
971 config: config,
972 module: module,
973 },
974 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700975 }
976
977 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
978
979 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -0700980 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700981 }
982
983 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800984 if !depNamesSet[depName] {
985 depNamesSet[depName] = true
986 depNames = append(depNames, depName)
987 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700988 }
989 }
990
Colin Cross65569e42015-03-10 20:08:19 -0700991 for _, depName := range depNames {
992 newErrs := c.addDependency(module, depName)
993 if len(newErrs) > 0 {
994 errs = append(errs, newErrs...)
995 }
996 }
997 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700998}
999
Colin Cross65569e42015-03-10 20:08:19 -07001000// resolveDependencies populates the directDeps list for every module. In doing so it checks for
1001// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001002func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001003 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -07001004 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -07001005 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
1006
1007 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -08001008 if len(newErrs) > 0 {
1009 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -07001010 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001011 }
1012 }
1013
1014 return
1015}
1016
Colin Crossc9028482014-12-18 16:28:54 -08001017func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001018 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -08001019
Colin Crossed342d92015-03-11 00:57:25 -07001020 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001021 return []error{&Error{
1022 Err: fmt.Errorf("%q depends on itself", depName),
1023 Pos: depsPos,
1024 }}
1025 }
1026
1027 depInfo, ok := c.moduleGroups[depName]
1028 if !ok {
1029 return []error{&Error{
1030 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001031 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -08001032 Pos: depsPos,
1033 }}
1034 }
1035
Colin Cross65569e42015-03-10 20:08:19 -07001036 for _, m := range module.directDeps {
1037 if m.group == depInfo {
1038 return nil
1039 }
Colin Crossc9028482014-12-18 16:28:54 -08001040 }
1041
Colin Cross65569e42015-03-10 20:08:19 -07001042 if len(depInfo.modules) == 1 {
1043 module.directDeps = append(module.directDeps, depInfo.modules[0])
1044 return nil
1045 } else {
1046 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001047 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001048 module.directDeps = append(module.directDeps, m)
1049 return nil
1050 }
1051 }
1052 }
Colin Crossc9028482014-12-18 16:28:54 -08001053
Colin Cross65569e42015-03-10 20:08:19 -07001054 return []error{&Error{
1055 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1056 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001057 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001058 Pos: depsPos,
1059 }}
1060}
1061
Colin Crossf5e34b92015-03-13 16:02:36 -07001062func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross65569e42015-03-10 20:08:19 -07001063 depName string) []error {
1064
1065 depsPos := module.propertyPos["deps"]
1066
1067 depInfo, ok := c.moduleGroups[depName]
1068 if !ok {
1069 return []error{&Error{
1070 Err: fmt.Errorf("%q depends on undefined module %q",
1071 module.properties.Name, depName),
1072 Pos: depsPos,
1073 }}
1074 }
1075
1076 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1077 // compare the strings because the result won't be in mutator registration order.
1078 // Create a new map instead, and then deep compare the maps.
Colin Crossf5e34b92015-03-13 16:02:36 -07001079 newVariant := module.dependencyVariant.clone()
1080 for _, v := range variations {
1081 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001082 }
1083
1084 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001085 if newVariant.equal(m.variant) {
1086 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001087 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001088 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001089 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1090 return []error{&Error{
1091 Err: fmt.Errorf("%q depends on later version of itself", depName),
1092 Pos: depsPos,
1093 }}
1094 }
1095 module.directDeps = append(module.directDeps, m)
1096 return nil
1097 }
1098 }
1099
1100 return []error{&Error{
1101 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1102 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001103 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001104 Pos: depsPos,
1105 }}
Colin Crossc9028482014-12-18 16:28:54 -08001106}
1107
Colin Cross7addea32015-03-11 15:43:52 -07001108func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1109 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001110 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001111 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001112
Colin Cross7addea32015-03-11 15:43:52 -07001113 for _, module := range c.modulesSorted {
1114 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001115 }
1116
Colin Cross7addea32015-03-11 15:43:52 -07001117 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001118 count++
1119 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001120 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001121 if ret {
1122 cancel = true
1123 }
Colin Cross7addea32015-03-11 15:43:52 -07001124 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001125 }()
1126 }
1127
Colin Cross7addea32015-03-11 15:43:52 -07001128 for _, module := range c.modulesSorted {
1129 if module.waitingCount == 0 {
1130 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001131 }
1132 }
1133
Colin Cross11e3b0d2015-02-04 10:41:00 -08001134 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001135 select {
Colin Cross7addea32015-03-11 15:43:52 -07001136 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001137 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001138 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001139 parent.waitingCount--
1140 if parent.waitingCount == 0 {
1141 visitOne(parent)
1142 }
Colin Cross691a60d2015-01-07 18:08:56 -08001143 }
1144 }
1145 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001146 }
1147 }
1148}
1149
1150// updateDependencies recursively walks the module dependency graph and updates
1151// additional fields based on the dependencies. It builds a sorted list of modules
1152// such that dependencies of a module always appear first, and populates reverse
1153// dependency links and counts of total dependencies. It also reports errors when
1154// it encounters dependency cycles. This should called after resolveDependencies,
1155// as well as after any mutator pass has called addDependency
1156func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001157 visited := make(map[*moduleInfo]bool) // modules that were already checked
1158 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001159
Colin Cross7addea32015-03-11 15:43:52 -07001160 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001161
Colin Cross7addea32015-03-11 15:43:52 -07001162 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001163
Colin Cross7addea32015-03-11 15:43:52 -07001164 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001165 // We are the "start" of the cycle, so we're responsible
1166 // for generating the errors. The cycle list is in
1167 // reverse order because all the 'check' calls append
1168 // their own module to the list.
1169 errs = append(errs, &Error{
1170 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001171 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001172 })
1173
1174 // Iterate backwards through the cycle list.
Colin Cross7addea32015-03-11 15:43:52 -07001175 curModule := cycle[len(cycle)-1]
Colin Cross10b54db2015-03-11 14:40:30 -07001176 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001177 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001178 errs = append(errs, &Error{
1179 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001180 curModule.properties.Name,
1181 nextModule.properties.Name),
1182 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001183 })
Colin Cross7addea32015-03-11 15:43:52 -07001184 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001185 }
1186 }
1187
Colin Cross7addea32015-03-11 15:43:52 -07001188 check = func(module *moduleInfo) []*moduleInfo {
1189 visited[module] = true
1190 checking[module] = true
1191 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001192
Colin Cross7addea32015-03-11 15:43:52 -07001193 deps := make(map[*moduleInfo]bool)
1194
1195 // Add an implicit dependency ordering on all earlier modules in the same module group
1196 for _, dep := range module.group.modules {
1197 if dep == module {
1198 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001199 }
Colin Cross7addea32015-03-11 15:43:52 -07001200 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001201 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001202
Colin Cross7addea32015-03-11 15:43:52 -07001203 for _, dep := range module.directDeps {
1204 deps[dep] = true
1205 }
1206
1207 module.reverseDeps = []*moduleInfo{}
1208 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001209
Colin Crossbbfa51a2014-12-17 16:12:41 -08001210 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001211 if checking[dep] {
1212 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001213 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001214 }
1215
1216 if !visited[dep] {
1217 cycle := check(dep)
1218 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001219 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001220 // We are the "start" of the cycle, so we're responsible
1221 // for generating the errors. The cycle list is in
1222 // reverse order because all the 'check' calls append
1223 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001224 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001225
1226 // We can continue processing this module's children to
1227 // find more cycles. Since all the modules that were
1228 // part of the found cycle were marked as visited we
1229 // won't run into that cycle again.
1230 } else {
1231 // We're not the "start" of the cycle, so we just append
1232 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001233 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001234 }
1235 }
1236 }
Colin Cross691a60d2015-01-07 18:08:56 -08001237
Colin Cross7addea32015-03-11 15:43:52 -07001238 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001239 }
1240
Colin Cross7addea32015-03-11 15:43:52 -07001241 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001242
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001243 return nil
1244 }
1245
Colin Cross7addea32015-03-11 15:43:52 -07001246 for _, module := range c.moduleInfo {
1247 if !visited[module] {
1248 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001249 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001250 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001251 panic("inconceivable!")
1252 }
1253 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001254 }
1255 }
1256 }
1257
Colin Cross7addea32015-03-11 15:43:52 -07001258 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001259
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001260 return
1261}
1262
Jamie Gennisd4e10182014-06-12 20:06:50 -07001263// PrepareBuildActions generates an internal representation of all the build
1264// actions that need to be performed. This process involves invoking the
1265// GenerateBuildActions method on each of the Module objects created during the
1266// parse phase and then on each of the registered Singleton objects.
1267//
1268// If the ResolveDependencies method has not already been called it is called
1269// automatically by this method.
1270//
1271// The config argument is made available to all of the Module and Singleton
1272// objects via the Config method on the ModuleContext and SingletonContext
1273// objects passed to GenerateBuildActions. It is also passed to the functions
1274// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1275// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001276//
1277// The returned deps is a list of the ninja files dependencies that were added
1278// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1279// SingletonContext.AddNinjaFileDeps() methods.
1280func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001281 c.buildActionsReady = false
1282
Colin Cross65569e42015-03-10 20:08:19 -07001283 errs = c.runEarlyMutators(config)
1284 if len(errs) > 0 {
1285 return nil, errs
1286 }
1287
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001288 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001289 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001290 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001291 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001292 }
1293 }
1294
Colin Crossc9028482014-12-18 16:28:54 -08001295 errs = c.runMutators(config)
1296 if len(errs) > 0 {
1297 return nil, errs
1298 }
1299
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001300 liveGlobals := newLiveTracker(config)
1301
1302 c.initSpecialVariables()
1303
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001304 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001305 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001306 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001307 }
1308
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001309 depsSingletons, errs := c.generateSingletonBuildActions(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 deps = append(depsModules, depsSingletons...)
1315
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001316 if c.buildDir != nil {
1317 liveGlobals.addNinjaStringDeps(c.buildDir)
1318 }
1319
1320 pkgNames := c.makeUniquePackageNames(liveGlobals)
1321
1322 // This will panic if it finds a problem since it's a programming error.
1323 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1324
1325 c.pkgNames = pkgNames
1326 c.globalVariables = liveGlobals.variables
1327 c.globalPools = liveGlobals.pools
1328 c.globalRules = liveGlobals.rules
1329
1330 c.buildActionsReady = true
1331
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001332 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001333}
1334
Colin Cross65569e42015-03-10 20:08:19 -07001335func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1336 for _, mutator := range c.earlyMutatorInfo {
1337 for _, group := range c.moduleGroups {
1338 newModules := make([]*moduleInfo, 0, len(group.modules))
1339
1340 for _, module := range group.modules {
1341 mctx := &mutatorContext{
1342 baseModuleContext: baseModuleContext{
1343 context: c,
1344 config: config,
1345 module: module,
1346 },
1347 name: mutator.name,
1348 }
1349 mutator.mutator(mctx)
1350 if len(mctx.errs) > 0 {
1351 errs = append(errs, mctx.errs...)
1352 return errs
1353 }
1354
1355 if module.splitModules != nil {
1356 newModules = append(newModules, module.splitModules...)
1357 } else {
1358 newModules = append(newModules, module)
1359 }
1360 }
1361
1362 group.modules = newModules
1363 }
1364 }
1365
1366 return nil
1367}
1368
Colin Crossc9028482014-12-18 16:28:54 -08001369func (c *Context) runMutators(config interface{}) (errs []error) {
1370 for _, mutator := range c.mutatorInfo {
1371 if mutator.topDownMutator != nil {
1372 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1373 } else if mutator.bottomUpMutator != nil {
1374 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1375 } else {
1376 panic("no mutator set on " + mutator.name)
1377 }
1378 if len(errs) > 0 {
1379 return errs
1380 }
1381 }
1382
1383 return nil
1384}
1385
1386func (c *Context) runTopDownMutator(config interface{},
1387 name string, mutator TopDownMutator) (errs []error) {
1388
Colin Cross7addea32015-03-11 15:43:52 -07001389 for i := 0; i < len(c.modulesSorted); i++ {
1390 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1391 mctx := &mutatorContext{
1392 baseModuleContext: baseModuleContext{
1393 context: c,
1394 config: config,
1395 module: module,
1396 },
1397 name: name,
1398 }
Colin Crossc9028482014-12-18 16:28:54 -08001399
Colin Cross7addea32015-03-11 15:43:52 -07001400 mutator(mctx)
1401 if len(mctx.errs) > 0 {
1402 errs = append(errs, mctx.errs...)
1403 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001404 }
1405 }
1406
1407 return errs
1408}
1409
1410func (c *Context) runBottomUpMutator(config interface{},
1411 name string, mutator BottomUpMutator) (errs []error) {
1412
1413 dependenciesModified := false
1414
Colin Cross7addea32015-03-11 15:43:52 -07001415 for _, module := range c.modulesSorted {
1416 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001417
Colin Cross7addea32015-03-11 15:43:52 -07001418 mctx := &mutatorContext{
1419 baseModuleContext: baseModuleContext{
1420 context: c,
1421 config: config,
1422 module: module,
1423 },
1424 name: name,
1425 }
Colin Crossc9028482014-12-18 16:28:54 -08001426
Colin Cross7addea32015-03-11 15:43:52 -07001427 mutator(mctx)
1428 if len(mctx.errs) > 0 {
1429 errs = append(errs, mctx.errs...)
1430 return errs
1431 }
Colin Crossc9028482014-12-18 16:28:54 -08001432
Colin Cross7addea32015-03-11 15:43:52 -07001433 // Fix up any remaining dependencies on modules that were split into variants
1434 // by replacing them with the first variant
1435 for i, dep := range module.directDeps {
1436 if dep.logicModule == nil {
1437 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001438 }
1439 }
1440
Colin Cross7addea32015-03-11 15:43:52 -07001441 if mctx.dependenciesModified {
1442 dependenciesModified = true
1443 }
1444
1445 if module.splitModules != nil {
1446 newModules = append(newModules, module.splitModules...)
1447 } else {
1448 newModules = append(newModules, module)
1449 }
1450
1451 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001452 }
1453
1454 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001455 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001456 if len(errs) > 0 {
1457 return errs
1458 }
1459 }
1460
1461 return errs
1462}
1463
Colin Cross7addea32015-03-11 15:43:52 -07001464func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1465 newModules []*moduleInfo) []*moduleInfo {
1466 for i, m := range modules {
1467 if m == origModule {
1468 return spliceModulesAtIndex(modules, i, newModules)
1469 }
1470 }
1471
1472 panic("failed to find original module to splice")
1473}
1474
1475func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1476 spliceSize := len(newModules)
1477 newLen := len(modules) + spliceSize - 1
1478 var dest []*moduleInfo
1479 if cap(modules) >= len(modules)-1+len(newModules) {
1480 // We can fit the splice in the existing capacity, do everything in place
1481 dest = modules[:newLen]
1482 } else {
1483 dest = make([]*moduleInfo, newLen)
1484 copy(dest, modules[:i])
1485 }
1486
1487 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001488 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001489
1490 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001491 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001492
Colin Cross72bd1932015-03-16 00:13:59 -07001493 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001494}
1495
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001496func (c *Context) initSpecialVariables() {
1497 c.buildDir = nil
1498 c.requiredNinjaMajor = 1
1499 c.requiredNinjaMinor = 1
1500 c.requiredNinjaMicro = 0
1501}
1502
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001503func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001504 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001505
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001506 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001507 var errs []error
1508
Colin Cross691a60d2015-01-07 18:08:56 -08001509 cancelCh := make(chan struct{})
1510 errsCh := make(chan []error)
1511 depsCh := make(chan []string)
1512
1513 go func() {
1514 for {
1515 select {
1516 case <-cancelCh:
1517 close(cancelCh)
1518 return
1519 case newErrs := <-errsCh:
1520 errs = append(errs, newErrs...)
1521 case newDeps := <-depsCh:
1522 deps = append(deps, newDeps...)
1523
1524 }
1525 }
1526 }()
1527
Colin Cross7addea32015-03-11 15:43:52 -07001528 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1529 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1530 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1531 // just set it to nil.
1532 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1533 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001534
Colin Cross7addea32015-03-11 15:43:52 -07001535 mctx := &moduleContext{
1536 baseModuleContext: baseModuleContext{
1537 context: c,
1538 config: config,
1539 module: module,
1540 },
1541 scope: scope,
1542 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001543
Colin Cross7addea32015-03-11 15:43:52 -07001544 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001545
Colin Cross7addea32015-03-11 15:43:52 -07001546 if len(mctx.errs) > 0 {
1547 errsCh <- mctx.errs
1548 return true
1549 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001550
Colin Cross7addea32015-03-11 15:43:52 -07001551 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001552
Colin Crossab6d7902015-03-11 16:17:52 -07001553 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001554 &mctx.actionDefs, liveGlobals)
1555 if len(newErrs) > 0 {
1556 errsCh <- newErrs
1557 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001558 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001559 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001560 })
1561
1562 cancelCh <- struct{}{}
1563 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001564
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001565 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001566}
1567
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001568func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001569 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001570
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001571 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001572 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001573
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001574 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001575 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1576 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1577 // just set it to nil.
1578 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001579
1580 sctx := &singletonContext{
1581 context: c,
1582 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001583 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001584 }
1585
1586 info.singleton.GenerateBuildActions(sctx)
1587
1588 if len(sctx.errs) > 0 {
1589 errs = append(errs, sctx.errs...)
1590 if len(errs) > maxErrors {
1591 break
1592 }
1593 continue
1594 }
1595
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001596 deps = append(deps, sctx.ninjaFileDeps...)
1597
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001598 newErrs := c.processLocalBuildActions(&info.actionDefs,
1599 &sctx.actionDefs, liveGlobals)
1600 errs = append(errs, newErrs...)
1601 if len(errs) > maxErrors {
1602 break
1603 }
1604 }
1605
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001606 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001607}
1608
1609func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1610 liveGlobals *liveTracker) []error {
1611
1612 var errs []error
1613
1614 // First we go through and add everything referenced by the module's
1615 // buildDefs to the live globals set. This will end up adding the live
1616 // locals to the set as well, but we'll take them out after.
1617 for _, def := range in.buildDefs {
1618 err := liveGlobals.AddBuildDefDeps(def)
1619 if err != nil {
1620 errs = append(errs, err)
1621 }
1622 }
1623
1624 if len(errs) > 0 {
1625 return errs
1626 }
1627
Colin Crossc9028482014-12-18 16:28:54 -08001628 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001629
1630 // We use the now-incorrect set of live "globals" to determine which local
1631 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001632 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001633 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001634 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635 if isLive {
1636 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001637 }
1638 }
1639
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001640 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001641 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001642 if isLive {
1643 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001644 }
1645 }
1646
1647 return nil
1648}
1649
Colin Crossbbfa51a2014-12-17 16:12:41 -08001650func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1651 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001652
Colin Crossbbfa51a2014-12-17 16:12:41 -08001653 var walk func(module *moduleInfo)
1654 walk = func(module *moduleInfo) {
1655 visited[module] = true
1656 for _, moduleDep := range module.directDeps {
1657 if !visited[moduleDep] {
1658 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001659 }
1660 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001661
Colin Crossbbfa51a2014-12-17 16:12:41 -08001662 if module != topModule {
1663 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001664 }
1665 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001666
1667 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001668}
1669
Colin Crossbbfa51a2014-12-17 16:12:41 -08001670func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001671 visit func(Module)) {
1672
Colin Crossbbfa51a2014-12-17 16:12:41 -08001673 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001674
Colin Crossbbfa51a2014-12-17 16:12:41 -08001675 var walk func(module *moduleInfo)
1676 walk = func(module *moduleInfo) {
1677 visited[module] = true
1678 for _, moduleDep := range module.directDeps {
1679 if !visited[moduleDep] {
1680 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001681 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001682 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001683
1684 if module != topModule {
1685 if pred(module.logicModule) {
1686 visit(module.logicModule)
1687 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001688 }
1689 }
1690
Colin Crossbbfa51a2014-12-17 16:12:41 -08001691 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001692}
1693
Colin Crossc9028482014-12-18 16:28:54 -08001694func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1695 for _, dep := range module.directDeps {
1696 visit(dep.logicModule)
1697 }
1698}
1699
1700func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1701 visit func(Module)) {
1702
1703 for _, dep := range module.directDeps {
1704 if pred(dep.logicModule) {
1705 visit(dep.logicModule)
1706 }
1707 }
1708}
1709
Jamie Gennisc15544d2014-09-24 20:26:52 -07001710func (c *Context) sortedModuleNames() []string {
1711 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001712 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1713 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001714 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1715 moduleName)
1716 }
1717 sort.Strings(c.cachedSortedModuleNames)
1718 }
1719
1720 return c.cachedSortedModuleNames
1721}
1722
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001723func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001724 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001725 group := c.moduleGroups[moduleName]
1726 for _, module := range group.modules {
1727 visit(module.logicModule)
1728 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001729 }
1730}
1731
1732func (c *Context) visitAllModulesIf(pred func(Module) bool,
1733 visit func(Module)) {
1734
Jamie Gennisc15544d2014-09-24 20:26:52 -07001735 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001736 group := c.moduleGroups[moduleName]
1737 for _, module := range group.modules {
1738 if pred(module.logicModule) {
1739 visit(module.logicModule)
1740 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001741 }
1742 }
1743}
1744
1745func (c *Context) requireNinjaVersion(major, minor, micro int) {
1746 if major != 1 {
1747 panic("ninja version with major version != 1 not supported")
1748 }
1749 if c.requiredNinjaMinor < minor {
1750 c.requiredNinjaMinor = minor
1751 c.requiredNinjaMicro = micro
1752 }
1753 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1754 c.requiredNinjaMicro = micro
1755 }
1756}
1757
1758func (c *Context) setBuildDir(value *ninjaString) {
1759 if c.buildDir != nil {
1760 panic("buildDir set multiple times")
1761 }
1762 c.buildDir = value
1763}
1764
1765func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001766 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001767
Jamie Gennis2fb20952014-10-03 02:49:58 -07001768 pkgs := make(map[string]*PackageContext)
1769 pkgNames := make(map[*PackageContext]string)
1770 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001771
Jamie Gennis2fb20952014-10-03 02:49:58 -07001772 processPackage := func(pctx *PackageContext) {
1773 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001774 // This is a built-in rule and has no package.
1775 return
1776 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001777 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001778 // We've already processed this package.
1779 return
1780 }
1781
Jamie Gennis2fb20952014-10-03 02:49:58 -07001782 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001783 if present {
1784 // Short name collision. Both this package and the one that's
1785 // already there need to use their full names. We leave the short
1786 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001787 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001788 longPkgNames[otherPkg] = true
1789 } else {
1790 // No collision so far. Tentatively set the package's name to be
1791 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001792 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001793 }
1794 }
1795
1796 // We try to give all packages their short name, but when we get collisions
1797 // we need to use the full unique package name.
1798 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001799 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001800 }
1801 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001802 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001803 }
1804 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001805 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001806 }
1807
1808 // Add the packages that had collisions using their full unique names. This
1809 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001810 for pctx := range longPkgNames {
1811 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001812 }
1813
1814 return pkgNames
1815}
1816
1817func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001818 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001819
1820 visited := make(map[Variable]bool) // variables that were already checked
1821 checking := make(map[Variable]bool) // variables actively being checked
1822
1823 var check func(v Variable) []Variable
1824
1825 check = func(v Variable) []Variable {
1826 visited[v] = true
1827 checking[v] = true
1828 defer delete(checking, v)
1829
1830 value := variables[v]
1831 for _, dep := range value.variables {
1832 if checking[dep] {
1833 // This is a cycle.
1834 return []Variable{dep, v}
1835 }
1836
1837 if !visited[dep] {
1838 cycle := check(dep)
1839 if cycle != nil {
1840 if cycle[0] == v {
1841 // We are the "start" of the cycle, so we're responsible
1842 // for generating the errors. The cycle list is in
1843 // reverse order because all the 'check' calls append
1844 // their own module to the list.
1845 msgs := []string{"detected variable reference cycle:"}
1846
1847 // Iterate backwards through the cycle list.
1848 curName := v.fullName(pkgNames)
1849 curValue := value.Value(pkgNames)
1850 for i := len(cycle) - 1; i >= 0; i-- {
1851 next := cycle[i]
1852 nextName := next.fullName(pkgNames)
1853 nextValue := variables[next].Value(pkgNames)
1854
1855 msgs = append(msgs, fmt.Sprintf(
1856 " %q depends on %q", curName, nextName))
1857 msgs = append(msgs, fmt.Sprintf(
1858 " [%s = %s]", curName, curValue))
1859
1860 curName = nextName
1861 curValue = nextValue
1862 }
1863
1864 // Variable reference cycles are a programming error,
1865 // not the fault of the Blueprint file authors.
1866 panic(strings.Join(msgs, "\n"))
1867 } else {
1868 // We're not the "start" of the cycle, so we just append
1869 // our module to the list and return it.
1870 return append(cycle, v)
1871 }
1872 }
1873 }
1874 }
1875
1876 return nil
1877 }
1878
1879 for v := range variables {
1880 if !visited[v] {
1881 cycle := check(v)
1882 if cycle != nil {
1883 panic("inconceivable!")
1884 }
1885 }
1886 }
1887}
1888
Jamie Gennisaf435562014-10-27 22:34:56 -07001889// AllTargets returns a map all the build target names to the rule used to build
1890// them. This is the same information that is output by running 'ninja -t
1891// targets all'. If this is called before PrepareBuildActions successfully
1892// completes then ErrbuildActionsNotReady is returned.
1893func (c *Context) AllTargets() (map[string]string, error) {
1894 if !c.buildActionsReady {
1895 return nil, ErrBuildActionsNotReady
1896 }
1897
1898 targets := map[string]string{}
1899
1900 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001901 for _, module := range c.moduleInfo {
1902 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001903 ruleName := buildDef.Rule.fullName(c.pkgNames)
1904 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001905 outputValue, err := output.Eval(c.globalVariables)
1906 if err != nil {
1907 return nil, err
1908 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001909 targets[outputValue] = ruleName
1910 }
1911 }
1912 }
1913
1914 // Collect all the singleton build targets.
1915 for _, info := range c.singletonInfo {
1916 for _, buildDef := range info.actionDefs.buildDefs {
1917 ruleName := buildDef.Rule.fullName(c.pkgNames)
1918 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001919 outputValue, err := output.Eval(c.globalVariables)
1920 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001921 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001922 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001923 targets[outputValue] = ruleName
1924 }
1925 }
1926 }
1927
1928 return targets, nil
1929}
1930
Jamie Gennisd4e10182014-06-12 20:06:50 -07001931// WriteBuildFile writes the Ninja manifeset text for the generated build
1932// actions to w. If this is called before PrepareBuildActions successfully
1933// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001934func (c *Context) WriteBuildFile(w io.Writer) error {
1935 if !c.buildActionsReady {
1936 return ErrBuildActionsNotReady
1937 }
1938
1939 nw := newNinjaWriter(w)
1940
1941 err := c.writeBuildFileHeader(nw)
1942 if err != nil {
1943 return err
1944 }
1945
1946 err = c.writeNinjaRequiredVersion(nw)
1947 if err != nil {
1948 return err
1949 }
1950
1951 // TODO: Group the globals by package.
1952
1953 err = c.writeGlobalVariables(nw)
1954 if err != nil {
1955 return err
1956 }
1957
1958 err = c.writeGlobalPools(nw)
1959 if err != nil {
1960 return err
1961 }
1962
1963 err = c.writeBuildDir(nw)
1964 if err != nil {
1965 return err
1966 }
1967
1968 err = c.writeGlobalRules(nw)
1969 if err != nil {
1970 return err
1971 }
1972
1973 err = c.writeAllModuleActions(nw)
1974 if err != nil {
1975 return err
1976 }
1977
1978 err = c.writeAllSingletonActions(nw)
1979 if err != nil {
1980 return err
1981 }
1982
1983 return nil
1984}
1985
Jamie Gennisc15544d2014-09-24 20:26:52 -07001986type pkgAssociation struct {
1987 PkgName string
1988 PkgPath string
1989}
1990
1991type pkgAssociationSorter struct {
1992 pkgs []pkgAssociation
1993}
1994
1995func (s *pkgAssociationSorter) Len() int {
1996 return len(s.pkgs)
1997}
1998
1999func (s *pkgAssociationSorter) Less(i, j int) bool {
2000 iName := s.pkgs[i].PkgName
2001 jName := s.pkgs[j].PkgName
2002 return iName < jName
2003}
2004
2005func (s *pkgAssociationSorter) Swap(i, j int) {
2006 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2007}
2008
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002009func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2010 headerTemplate := template.New("fileHeader")
2011 _, err := headerTemplate.Parse(fileHeaderTemplate)
2012 if err != nil {
2013 // This is a programming error.
2014 panic(err)
2015 }
2016
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002017 var pkgs []pkgAssociation
2018 maxNameLen := 0
2019 for pkg, name := range c.pkgNames {
2020 pkgs = append(pkgs, pkgAssociation{
2021 PkgName: name,
2022 PkgPath: pkg.pkgPath,
2023 })
2024 if len(name) > maxNameLen {
2025 maxNameLen = len(name)
2026 }
2027 }
2028
2029 for i := range pkgs {
2030 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2031 }
2032
Jamie Gennisc15544d2014-09-24 20:26:52 -07002033 sort.Sort(&pkgAssociationSorter{pkgs})
2034
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002035 params := map[string]interface{}{
2036 "Pkgs": pkgs,
2037 }
2038
2039 buf := bytes.NewBuffer(nil)
2040 err = headerTemplate.Execute(buf, params)
2041 if err != nil {
2042 return err
2043 }
2044
2045 return nw.Comment(buf.String())
2046}
2047
2048func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2049 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2050 c.requiredNinjaMicro)
2051
2052 err := nw.Assign("ninja_required_version", value)
2053 if err != nil {
2054 return err
2055 }
2056
2057 return nw.BlankLine()
2058}
2059
2060func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2061 if c.buildDir != nil {
2062 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2063 if err != nil {
2064 return err
2065 }
2066
2067 err = nw.BlankLine()
2068 if err != nil {
2069 return err
2070 }
2071 }
2072 return nil
2073}
2074
Jamie Gennisc15544d2014-09-24 20:26:52 -07002075type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002076 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002077}
2078
Jamie Gennisc15544d2014-09-24 20:26:52 -07002079type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002080 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002081 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002082}
2083
Jamie Gennisc15544d2014-09-24 20:26:52 -07002084func (s *globalEntitySorter) Len() int {
2085 return len(s.entities)
2086}
2087
2088func (s *globalEntitySorter) Less(i, j int) bool {
2089 iName := s.entities[i].fullName(s.pkgNames)
2090 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002091 return iName < jName
2092}
2093
Jamie Gennisc15544d2014-09-24 20:26:52 -07002094func (s *globalEntitySorter) Swap(i, j int) {
2095 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002096}
2097
2098func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2099 visited := make(map[Variable]bool)
2100
2101 var walk func(v Variable) error
2102 walk = func(v Variable) error {
2103 visited[v] = true
2104
2105 // First visit variables on which this variable depends.
2106 value := c.globalVariables[v]
2107 for _, dep := range value.variables {
2108 if !visited[dep] {
2109 err := walk(dep)
2110 if err != nil {
2111 return err
2112 }
2113 }
2114 }
2115
2116 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2117 if err != nil {
2118 return err
2119 }
2120
2121 err = nw.BlankLine()
2122 if err != nil {
2123 return err
2124 }
2125
2126 return nil
2127 }
2128
Jamie Gennisc15544d2014-09-24 20:26:52 -07002129 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2130 for variable := range c.globalVariables {
2131 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002132 }
2133
Jamie Gennisc15544d2014-09-24 20:26:52 -07002134 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002135
Jamie Gennisc15544d2014-09-24 20:26:52 -07002136 for _, entity := range globalVariables {
2137 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002138 if !visited[v] {
2139 err := walk(v)
2140 if err != nil {
2141 return nil
2142 }
2143 }
2144 }
2145
2146 return nil
2147}
2148
2149func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002150 globalPools := make([]globalEntity, 0, len(c.globalPools))
2151 for pool := range c.globalPools {
2152 globalPools = append(globalPools, pool)
2153 }
2154
2155 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2156
2157 for _, entity := range globalPools {
2158 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002159 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002160 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002161 err := def.WriteTo(nw, name)
2162 if err != nil {
2163 return err
2164 }
2165
2166 err = nw.BlankLine()
2167 if err != nil {
2168 return err
2169 }
2170 }
2171
2172 return nil
2173}
2174
2175func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002176 globalRules := make([]globalEntity, 0, len(c.globalRules))
2177 for rule := range c.globalRules {
2178 globalRules = append(globalRules, rule)
2179 }
2180
2181 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2182
2183 for _, entity := range globalRules {
2184 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002185 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002186 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002187 err := def.WriteTo(nw, name, c.pkgNames)
2188 if err != nil {
2189 return err
2190 }
2191
2192 err = nw.BlankLine()
2193 if err != nil {
2194 return err
2195 }
2196 }
2197
2198 return nil
2199}
2200
Colin Crossab6d7902015-03-11 16:17:52 -07002201type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002202
Colin Crossab6d7902015-03-11 16:17:52 -07002203func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002204 return len(s)
2205}
2206
Colin Crossab6d7902015-03-11 16:17:52 -07002207func (s moduleSorter) Less(i, j int) bool {
2208 iName := s[i].properties.Name
2209 jName := s[j].properties.Name
2210 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002211 iName = s[i].variantName
2212 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002213 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002214 return iName < jName
2215}
2216
Colin Crossab6d7902015-03-11 16:17:52 -07002217func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002218 s[i], s[j] = s[j], s[i]
2219}
2220
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002221func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2222 headerTemplate := template.New("moduleHeader")
2223 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2224 if err != nil {
2225 // This is a programming error.
2226 panic(err)
2227 }
2228
Colin Crossab6d7902015-03-11 16:17:52 -07002229 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2230 for _, module := range c.moduleInfo {
2231 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002232 }
Colin Crossab6d7902015-03-11 16:17:52 -07002233 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002234
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002235 buf := bytes.NewBuffer(nil)
2236
Colin Crossab6d7902015-03-11 16:17:52 -07002237 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002238 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002239
2240 // In order to make the bootstrap build manifest independent of the
2241 // build dir we need to output the Blueprints file locations in the
2242 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002243 relPos := module.pos
2244 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002245
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002246 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002247 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002248 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2249 factoryName := factoryFunc.Name()
2250
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002251 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002252 "properties": module.properties,
2253 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002254 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002255 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002256 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002257 }
2258 err = headerTemplate.Execute(buf, infoMap)
2259 if err != nil {
2260 return err
2261 }
2262
2263 err = nw.Comment(buf.String())
2264 if err != nil {
2265 return err
2266 }
2267
2268 err = nw.BlankLine()
2269 if err != nil {
2270 return err
2271 }
2272
Colin Crossab6d7902015-03-11 16:17:52 -07002273 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002274 if err != nil {
2275 return err
2276 }
2277
2278 err = nw.BlankLine()
2279 if err != nil {
2280 return err
2281 }
2282 }
2283
2284 return nil
2285}
2286
2287func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2288 headerTemplate := template.New("singletonHeader")
2289 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2290 if err != nil {
2291 // This is a programming error.
2292 panic(err)
2293 }
2294
2295 buf := bytes.NewBuffer(nil)
2296
Jamie Gennis86179fe2014-06-11 16:27:16 -07002297 singletonNames := make([]string, 0, len(c.singletonInfo))
2298 for name := range c.singletonInfo {
2299 singletonNames = append(singletonNames, name)
2300 }
2301 sort.Strings(singletonNames)
2302
2303 for _, name := range singletonNames {
2304 info := c.singletonInfo[name]
2305
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002306 // Get the name of the factory function for the module.
2307 factory := info.factory
2308 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2309 factoryName := factoryFunc.Name()
2310
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002311 buf.Reset()
2312 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002313 "name": name,
2314 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002315 }
2316 err = headerTemplate.Execute(buf, infoMap)
2317 if err != nil {
2318 return err
2319 }
2320
2321 err = nw.Comment(buf.String())
2322 if err != nil {
2323 return err
2324 }
2325
2326 err = nw.BlankLine()
2327 if err != nil {
2328 return err
2329 }
2330
2331 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2332 if err != nil {
2333 return err
2334 }
2335
2336 err = nw.BlankLine()
2337 if err != nil {
2338 return err
2339 }
2340 }
2341
2342 return nil
2343}
2344
2345func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2346 defs *localBuildActions) error {
2347
2348 // Write the local variable assignments.
2349 for _, v := range defs.variables {
2350 // A localVariable doesn't need the package names or config to
2351 // determine its name or value.
2352 name := v.fullName(nil)
2353 value, err := v.value(nil)
2354 if err != nil {
2355 panic(err)
2356 }
2357 err = nw.Assign(name, value.Value(c.pkgNames))
2358 if err != nil {
2359 return err
2360 }
2361 }
2362
2363 if len(defs.variables) > 0 {
2364 err := nw.BlankLine()
2365 if err != nil {
2366 return err
2367 }
2368 }
2369
2370 // Write the local rules.
2371 for _, r := range defs.rules {
2372 // A localRule doesn't need the package names or config to determine
2373 // its name or definition.
2374 name := r.fullName(nil)
2375 def, err := r.def(nil)
2376 if err != nil {
2377 panic(err)
2378 }
2379
2380 err = def.WriteTo(nw, name, c.pkgNames)
2381 if err != nil {
2382 return err
2383 }
2384
2385 err = nw.BlankLine()
2386 if err != nil {
2387 return err
2388 }
2389 }
2390
2391 // Write the build definitions.
2392 for _, buildDef := range defs.buildDefs {
2393 err := buildDef.WriteTo(nw, c.pkgNames)
2394 if err != nil {
2395 return err
2396 }
2397
2398 if len(buildDef.Args) > 0 {
2399 err = nw.BlankLine()
2400 if err != nil {
2401 return err
2402 }
2403 }
2404 }
2405
2406 return nil
2407}
2408
Colin Cross65569e42015-03-10 20:08:19 -07002409func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2410 found := false
2411 for _, l := range list {
2412 if l == a {
2413 found = true
2414 } else if l == b {
2415 return found
2416 }
2417 }
2418
2419 missing := a
2420 if found {
2421 missing = b
2422 }
2423 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2424}
2425
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002426var fileHeaderTemplate = `******************************************************************************
2427*** This file is generated and should not be edited ***
2428******************************************************************************
2429{{if .Pkgs}}
2430This file contains variables, rules, and pools with name prefixes indicating
2431they were generated by the following Go packages:
2432{{range .Pkgs}}
2433 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2434
2435`
2436
2437var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2438Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002439Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002440Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002441Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002442Defined: {{.pos}}
2443`
2444
2445var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2446Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002447Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002448`