blob: 0d18f76018dc61134992547a91437ed09575a4a1 [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 Cross7addea32015-03-11 15:43:52 -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 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070072
73 dependenciesReady bool // set to true on a successful ResolveDependencies
74 buildActionsReady bool // set to true on a successful PrepareBuildActions
75
76 // set by SetIgnoreUnknownModuleTypes
77 ignoreUnknownModuleTypes bool
78
79 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070080 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070081 globalVariables map[Variable]*ninjaString
82 globalPools map[Pool]*poolDef
83 globalRules map[Rule]*ruleDef
84
85 // set during PrepareBuildActions
86 buildDir *ninjaString // The builddir special Ninja variable
87 requiredNinjaMajor int // For the ninja_required_version variable
88 requiredNinjaMinor int // For the ninja_required_version variable
89 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070090
91 // set lazily by sortedModuleNames
92 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070093}
94
Jamie Gennisd4e10182014-06-12 20:06:50 -070095// An Error describes a problem that was encountered that is related to a
96// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -070098 Err error // the error that occurred
99 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100}
101
102type localBuildActions struct {
103 variables []*localVariable
104 rules []*localRule
105 buildDefs []*buildDef
106}
107
Colin Crossbbfa51a2014-12-17 16:12:41 -0800108type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700109 name string
110 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700111
Colin Crossbbfa51a2014-12-17 16:12:41 -0800112 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700113
114 // set during PrepareBuildActions
115 actionDefs localBuildActions
116}
117
Colin Crossbbfa51a2014-12-17 16:12:41 -0800118type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700119 // set during Parse
120 typeName string
121 relBlueprintsFile string
122 pos scanner.Position
123 propertyPos map[string]scanner.Position
124 properties struct {
125 Name string
126 Deps []string
127 }
128
Colin Crosse7daa222015-03-11 14:35:41 -0700129 variantName string
130 variants variantMap
131
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
148}
149
Colin Crosse7daa222015-03-11 14:35:41 -0700150type variantMap map[string]string
151
152func (vm variantMap) clone() variantMap {
153 newVm := make(variantMap)
154 for k, v := range vm {
155 newVm[k] = v
156 }
157
158 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800159}
160
Colin Crosse7daa222015-03-11 14:35:41 -0700161func (vm variantMap) equal(other variantMap) bool {
162 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800163}
164
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700165type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700166 // set during RegisterSingletonType
167 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700168 singleton Singleton
169
170 // set during PrepareBuildActions
171 actionDefs localBuildActions
172}
173
Colin Crossc9028482014-12-18 16:28:54 -0800174type mutatorInfo struct {
175 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800176 topDownMutator TopDownMutator
177 bottomUpMutator BottomUpMutator
178 name string
Colin Crossc9028482014-12-18 16:28:54 -0800179}
180
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700181func (e *Error) Error() string {
182
183 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
184}
185
Jamie Gennisd4e10182014-06-12 20:06:50 -0700186// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700187// no module or singleton factories registered, so the RegisterModuleFactory and
188// RegisterSingletonFactory methods must be called before it can do anything
189// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700190func NewContext() *Context {
191 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800192 moduleFactories: make(map[string]ModuleFactory),
193 moduleGroups: make(map[string]*moduleGroup),
194 moduleInfo: make(map[Module]*moduleInfo),
195 singletonInfo: make(map[string]*singletonInfo),
196 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700197 }
198}
199
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700200// A ModuleFactory function creates a new Module object. See the
201// Context.RegisterModuleType method for details about how a registered
202// ModuleFactory is used by a Context.
203type ModuleFactory func() (m Module, propertyStructs []interface{})
204
Jamie Gennisd4e10182014-06-12 20:06:50 -0700205// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700206// Blueprints file) with a Module factory function. When the given module type
207// name is encountered in a Blueprints file during parsing, the Module factory
208// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800209// generation for the module. If a Mutator splits a module into multiple variants,
210// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700211//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700212// The module type names given here must be unique for the context. The factory
213// function should be a named function so that its package and name can be
214// included in the generated Ninja file for debugging purposes.
215//
216// The factory function returns two values. The first is the newly created
217// Module object. The second is a slice of pointers to that Module object's
218// properties structs. Each properties struct is examined when parsing a module
219// definition of this type in a Blueprints file. Exported fields of the
220// properties structs are automatically set to the property values specified in
221// the Blueprints file. The properties struct field names determine the name of
222// the Blueprints file properties that are used - the Blueprints property name
223// matches that of the properties struct field name with the first letter
224// converted to lower-case.
225//
226// The fields of the properties struct must be either []string, a string, or
227// bool. The Context will panic if a Module gets instantiated with a properties
228// struct containing a field that is not one these supported types.
229//
230// Any properties that appear in the Blueprints files that are not built-in
231// module properties (such as "name" and "deps") and do not have a corresponding
232// field in the returned module properties struct result in an error during the
233// Context's parse phase.
234//
235// As an example, the follow code:
236//
237// type myModule struct {
238// properties struct {
239// Foo string
240// Bar []string
241// }
242// }
243//
244// func NewMyModule() (blueprint.Module, []interface{}) {
245// module := new(myModule)
246// properties := &module.properties
247// return module, []interface{}{properties}
248// }
249//
250// func main() {
251// ctx := blueprint.NewContext()
252// ctx.RegisterModuleType("my_module", NewMyModule)
253// // ...
254// }
255//
256// would support parsing a module defined in a Blueprints file as follows:
257//
258// my_module {
259// name: "myName",
260// foo: "my foo string",
261// bar: ["my", "bar", "strings"],
262// }
263//
Colin Cross7ad621c2015-01-07 16:22:45 -0800264// The factory function may be called from multiple goroutines. Any accesses
265// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700266func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
267 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700268 panic(errors.New("module type name is already registered"))
269 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700270 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700271}
272
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700273// A SingletonFactory function creates a new Singleton object. See the
274// Context.RegisterSingletonType method for details about how a registered
275// SingletonFactory is used by a Context.
276type SingletonFactory func() Singleton
277
278// RegisterSingletonType registers a singleton type that will be invoked to
279// generate build actions. Each registered singleton type is instantiated and
280// and invoked exactly once as part of the generate phase.
281//
282// The singleton type names given here must be unique for the context. The
283// factory function should be a named function so that its package and name can
284// be included in the generated Ninja file for debugging purposes.
285func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700286 if _, present := c.singletonInfo[name]; present {
287 panic(errors.New("singleton name is already registered"))
288 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700289
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700290 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700291 factory: factory,
292 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700293 }
294}
295
296func singletonPkgPath(singleton Singleton) string {
297 typ := reflect.TypeOf(singleton)
298 for typ.Kind() == reflect.Ptr {
299 typ = typ.Elem()
300 }
301 return typ.PkgPath()
302}
303
304func singletonTypeName(singleton Singleton) string {
305 typ := reflect.TypeOf(singleton)
306 for typ.Kind() == reflect.Ptr {
307 typ = typ.Elem()
308 }
309 return typ.PkgPath() + "." + typ.Name()
310}
311
Colin Crossc9028482014-12-18 16:28:54 -0800312// RegisterTopDownMutator registers a mutator that will be invoked to propagate
313// dependency info top-down between Modules. Each registered mutator
314// is invoked once per Module, and is invoked on a module before being invoked
315// on any of its dependencies
316//
317// The mutator type names given here must be unique for the context.
318func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
319 for _, m := range c.mutatorInfo {
320 if m.name == name && m.topDownMutator != nil {
321 panic(fmt.Errorf("mutator name %s is already registered", name))
322 }
323 }
324
325 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
326 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800327 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800328 })
329}
330
331// RegisterBottomUpMutator registers a mutator that will be invoked to split
332// Modules into variants. Each registered mutator is invoked once per Module,
333// and is invoked on dependencies before being invoked on dependers.
334//
335// The mutator type names given here must be unique for the context.
336func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
337 for _, m := range c.mutatorInfo {
338 if m.name == name && m.bottomUpMutator != nil {
339 panic(fmt.Errorf("mutator name %s is already registered", name))
340 }
341 }
342
343 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
344 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800345 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800346 })
347}
348
Jamie Gennisd4e10182014-06-12 20:06:50 -0700349// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
350// where it encounters an unknown module type while parsing Blueprints files. By
351// default, the context will report unknown module types as an error. If this
352// method is called with ignoreUnknownModuleTypes set to true then the context
353// will silently ignore unknown module types.
354//
355// This method should generally not be used. It exists to facilitate the
356// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700357func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
358 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
359}
360
Jamie Gennisd4e10182014-06-12 20:06:50 -0700361// Parse parses a single Blueprints file from r, creating Module objects for
362// each of the module definitions encountered. If the Blueprints file contains
363// an assignment to the "subdirs" variable, then the subdirectories listed are
364// returned in the subdirs first return value.
365//
366// rootDir specifies the path to the root directory of the source tree, while
367// filename specifies the path to the Blueprints file. These paths are used for
368// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800369func (c *Context) parse(rootDir, filename string, r io.Reader,
370 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
371 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700372
Jamie Gennisec701282014-06-12 20:06:31 -0700373 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700374 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800375 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700376 }
377
Colin Crossc0dbc552015-01-02 15:19:28 -0800378 scope = parser.NewScope(scope)
379 scope.Remove("subdirs")
Colin Crossd1facc12015-01-08 14:56:03 -0800380 file, errs := parser.Parse(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700381 if len(errs) > 0 {
382 for i, err := range errs {
383 if parseErr, ok := err.(*parser.ParseError); ok {
384 err = &Error{
385 Err: parseErr.Err,
386 Pos: parseErr.Pos,
387 }
388 errs[i] = err
389 }
390 }
391
392 // If there were any parse errors don't bother trying to interpret the
393 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800394 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700395 }
396
Colin Crossd1facc12015-01-08 14:56:03 -0800397 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800399 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700400 switch def := def.(type) {
401 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800402 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700403
404 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800405 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700406 default:
407 panic("unknown definition type")
408 }
409
410 if len(newErrs) > 0 {
411 errs = append(errs, newErrs...)
412 if len(errs) > maxErrors {
413 break
414 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800415 } else if newModule != nil {
416 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700417 }
418 }
419
Colin Crossc0dbc552015-01-02 15:19:28 -0800420 subdirs, newErrs := c.processSubdirs(scope)
421 if len(newErrs) > 0 {
422 errs = append(errs, newErrs...)
423 }
424
Colin Cross7ad621c2015-01-07 16:22:45 -0800425 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800426}
427
Colin Cross7ad621c2015-01-07 16:22:45 -0800428type stringAndScope struct {
429 string
430 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700431}
432
Jamie Gennisd4e10182014-06-12 20:06:50 -0700433// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
434// at rootFile. When it encounters a Blueprints file with a set of subdirs
435// listed it recursively parses any Blueprints files found in those
436// subdirectories.
437//
438// If no errors are encountered while parsing the files, the list of paths on
439// which the future output will depend is returned. This list will include both
440// Blueprints file paths as well as directory paths for cases where wildcard
441// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700442func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
443 errs []error) {
444
Colin Cross7ad621c2015-01-07 16:22:45 -0800445 c.dependenciesReady = false
446
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700447 rootDir := filepath.Dir(rootFile)
448
Colin Cross7ad621c2015-01-07 16:22:45 -0800449 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700450
Colin Cross7ad621c2015-01-07 16:22:45 -0800451 // Channels to receive data back from parseBlueprintsFile goroutines
452 blueprintsCh := make(chan stringAndScope)
453 errsCh := make(chan []error)
454 modulesCh := make(chan []*moduleInfo)
455 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700456
Colin Cross7ad621c2015-01-07 16:22:45 -0800457 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
458 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700459
Colin Cross7ad621c2015-01-07 16:22:45 -0800460 // Number of outstanding goroutines to wait for
461 count := 0
462
463 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
464 count++
465 go func() {
466 c.parseBlueprintsFile(filename, scope, rootDir,
467 errsCh, modulesCh, blueprintsCh, depsCh)
468 doneCh <- struct{}{}
469 }()
470 }
471
472 tooManyErrors := false
473
474 startParseBlueprintsFile(rootFile, nil)
475
476loop:
477 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800479 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700480 }
481
Colin Cross7ad621c2015-01-07 16:22:45 -0800482 select {
483 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700484 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800485 case dep := <-depsCh:
486 deps = append(deps, dep)
487 case modules := <-modulesCh:
488 newErrs := c.addModules(modules)
489 errs = append(errs, newErrs...)
490 case blueprint := <-blueprintsCh:
491 if tooManyErrors {
492 continue
493 }
494 if blueprintsSet[blueprint.string] {
495 continue
496 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497
Colin Cross7ad621c2015-01-07 16:22:45 -0800498 blueprintsSet[blueprint.string] = true
499 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
500 case <-doneCh:
501 count--
502 if count == 0 {
503 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700504 }
505 }
506 }
507
Colin Cross7ad621c2015-01-07 16:22:45 -0800508 return
509}
510
511// parseBlueprintFile parses a single Blueprints file, returning any errors through
512// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
513// blueprintsCh, and any dependencies on Blueprints files or directories through
514// depsCh.
515func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
516 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
517 depsCh chan<- string) {
518
519 dir := filepath.Dir(filename)
520
521 file, err := os.Open(filename)
522 if err != nil {
523 errsCh <- []error{err}
524 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700525 }
526
Colin Cross7ad621c2015-01-07 16:22:45 -0800527 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
528 if len(errs) > 0 {
529 errsCh <- errs
530 }
531
532 err = file.Close()
533 if err != nil {
534 errsCh <- []error{err}
535 }
536
537 modulesCh <- modules
538
539 for _, subdir := range subdirs {
540 subdir = filepath.Join(dir, subdir)
541
542 dirPart, filePart := filepath.Split(subdir)
543 dirPart = filepath.Clean(dirPart)
544
545 if filePart == "*" {
546 foundSubdirs, err := listSubdirs(dirPart)
547 if err != nil {
548 errsCh <- []error{err}
549 return
550 }
551
552 for _, foundSubdir := range foundSubdirs {
553 subBlueprints := filepath.Join(dirPart, foundSubdir,
554 "Blueprints")
555
556 _, err := os.Stat(subBlueprints)
557 if os.IsNotExist(err) {
558 // There is no Blueprints file in this subdirectory. We
559 // need to add the directory to the list of dependencies
560 // so that if someone adds a Blueprints file in the
561 // future we'll pick it up.
562 depsCh <- filepath.Dir(subBlueprints)
563 } else {
564 depsCh <- subBlueprints
565 blueprintsCh <- stringAndScope{
566 subBlueprints,
567 subScope,
568 }
569 }
570 }
571
572 // We now depend on the directory itself because if any new
573 // subdirectories get added or removed we need to rebuild the
574 // Ninja manifest.
575 depsCh <- dirPart
576 } else {
577 subBlueprints := filepath.Join(subdir, "Blueprints")
578 depsCh <- subBlueprints
579 blueprintsCh <- stringAndScope{
580 subBlueprints,
581 subScope,
582 }
583
584 }
585 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700586}
587
588func listSubdirs(dir string) ([]string, error) {
589 d, err := os.Open(dir)
590 if err != nil {
591 return nil, err
592 }
593 defer d.Close()
594
595 infos, err := d.Readdir(-1)
596 if err != nil {
597 return nil, err
598 }
599
600 var subdirs []string
601 for _, info := range infos {
Jamie Gennis0c35b2d2014-09-25 13:15:10 -0700602 isDotFile := strings.HasPrefix(info.Name(), ".")
603 if info.IsDir() && !isDotFile {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700604 subdirs = append(subdirs, info.Name())
605 }
606 }
607
608 return subdirs, nil
609}
610
Colin Crossc0dbc552015-01-02 15:19:28 -0800611func (c *Context) processSubdirs(
612 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700613
Colin Crossc0dbc552015-01-02 15:19:28 -0800614 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700615 switch assignment.Value.Type {
616 case parser.List:
617 subdirs = make([]string, 0, len(assignment.Value.ListValue))
618
619 for _, value := range assignment.Value.ListValue {
620 if value.Type != parser.String {
621 // The parser should not produce this.
622 panic("non-string value found in list")
623 }
624
625 dirPart, filePart := filepath.Split(value.StringValue)
626 if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
627 strings.ContainsRune(dirPart, '*') {
628
629 errs = append(errs, &Error{
630 Err: fmt.Errorf("subdirs may only wildcard whole " +
631 "directories"),
632 Pos: value.Pos,
633 })
634
635 continue
636 }
637
638 subdirs = append(subdirs, value.StringValue)
639 }
640
641 if len(errs) > 0 {
642 subdirs = nil
643 }
644
645 return
646
647 case parser.Bool, parser.String:
648 errs = []error{
649 &Error{
650 Err: fmt.Errorf("subdirs must be a list of strings"),
651 Pos: assignment.Pos,
652 },
653 }
654
655 return
656
657 default:
658 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
659 }
660 }
661
Colin Crossc0dbc552015-01-02 15:19:28 -0800662 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700663}
664
Colin Crossc9028482014-12-18 16:28:54 -0800665func (c *Context) createVariants(origModule *moduleInfo, mutatorName string,
Colin Cross174ae052015-03-03 17:37:03 -0800666 variantNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800667
668 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800669
Colin Cross174ae052015-03-03 17:37:03 -0800670 var errs []error
671
Colin Crossc9028482014-12-18 16:28:54 -0800672 for i, variantName := range variantNames {
Colin Crossed342d92015-03-11 00:57:25 -0700673 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800674 factory, ok := c.moduleFactories[typeName]
675 if !ok {
676 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
677 }
678
679 var newLogicModule Module
680 var newProperties []interface{}
681
682 if i == 0 {
683 // Reuse the existing module for the first new variant
684 newLogicModule = origModule.logicModule
685 newProperties = origModule.moduleProperties
686 } else {
687 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700688 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800689 }
690 newLogicModule, newProperties = factory()
691
692 newProperties = append(props, newProperties...)
693
694 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700695 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800696 }
697
698 for i := range newProperties {
699 dst := reflect.ValueOf(newProperties[i]).Elem()
700 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
701
702 proptools.CopyProperties(dst, src)
703 }
704 }
705
Colin Crosse7daa222015-03-11 14:35:41 -0700706 newVariants := origModule.variants.clone()
707 newVariants[mutatorName] = variantName
Colin Crossc9028482014-12-18 16:28:54 -0800708
Colin Crossed342d92015-03-11 00:57:25 -0700709 m := *origModule
710 newModule := &m
711 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
712 newModule.logicModule = newLogicModule
Colin Crosse7daa222015-03-11 14:35:41 -0700713 newModule.variants = newVariants
Colin Crossed342d92015-03-11 00:57:25 -0700714 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800715
Colin Crosse7daa222015-03-11 14:35:41 -0700716 if newModule.variantName == "" {
717 newModule.variantName = variantName
718 } else {
719 newModule.variantName += "_" + variantName
720 }
721
Colin Crossc9028482014-12-18 16:28:54 -0800722 newModules = append(newModules, newModule)
723 c.moduleInfo[newModule.logicModule] = newModule
724
Colin Crosse7daa222015-03-11 14:35:41 -0700725 newErrs := c.convertDepsToVariant(newModule, mutatorName, variantName)
Colin Cross174ae052015-03-03 17:37:03 -0800726 if len(newErrs) > 0 {
727 errs = append(errs, newErrs...)
728 }
Colin Crossc9028482014-12-18 16:28:54 -0800729 }
730
731 // Mark original variant as invalid. Modules that depend on this module will still
732 // depend on origModule, but we'll fix it when the mutator is called on them.
733 origModule.logicModule = nil
734 origModule.splitModules = newModules
735
Colin Cross174ae052015-03-03 17:37:03 -0800736 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800737}
738
Colin Crosse7daa222015-03-11 14:35:41 -0700739func (c *Context) convertDepsToVariant(module *moduleInfo,
740 mutatorName, variantName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800741
Colin Crossc9028482014-12-18 16:28:54 -0800742 for i, dep := range module.directDeps {
743 if dep.logicModule == nil {
744 var newDep *moduleInfo
745 for _, m := range dep.splitModules {
Colin Crosse7daa222015-03-11 14:35:41 -0700746 if m.variants[mutatorName] == variantName {
Colin Crossc9028482014-12-18 16:28:54 -0800747 newDep = m
748 break
749 }
750 }
751 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800752 errs = append(errs, &Error{
753 Err: fmt.Errorf("failed to find variant %q for module %q needed by %q",
Colin Crosse7daa222015-03-11 14:35:41 -0700754 variantName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700755 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800756 })
757 continue
Colin Crossc9028482014-12-18 16:28:54 -0800758 }
759 module.directDeps[i] = newDep
760 }
761 }
Colin Cross174ae052015-03-03 17:37:03 -0800762
763 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800764}
765
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700766func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800767 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700768
Colin Crossd1facc12015-01-08 14:56:03 -0800769 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700770 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700771 if !ok {
772 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800773 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700774 }
775
Colin Cross7ad621c2015-01-07 16:22:45 -0800776 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700777 &Error{
778 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800779 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700780 },
781 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700782 }
783
Colin Crossbbfa51a2014-12-17 16:12:41 -0800784 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700785
786 module := &moduleInfo{
787 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700788 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700789 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700790 }
791
Jamie Gennis87622922014-09-30 11:38:25 -0700792 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700793 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700794 }
795 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700796 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700797
Jamie Gennis87622922014-09-30 11:38:25 -0700798 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700799 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800800 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700801 }
802
Colin Crossed342d92015-03-11 00:57:25 -0700803 module.pos = moduleDef.Type.Pos
804 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700805 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700806 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700807 }
808
Colin Cross7ad621c2015-01-07 16:22:45 -0800809 return module, nil
810}
811
812func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
813 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700814 name := module.properties.Name
815 c.moduleInfo[module.logicModule] = module
816
817 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800818 errs = append(errs, []error{
819 &Error{
820 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700821 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800822 },
823 &Error{
824 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700825 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800826 },
827 }...)
828 continue
Colin Crossed342d92015-03-11 00:57:25 -0700829 } else {
830 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800831
Colin Crossed342d92015-03-11 00:57:25 -0700832 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
833 // already exists
834 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
835 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
836 }
837
838 c.moduleNinjaNames[ninjaName] = group
839
840 group := &moduleGroup{
841 name: module.properties.Name,
842 ninjaName: ninjaName,
843 modules: []*moduleInfo{module},
844 }
845 module.group = group
846 c.moduleGroups[name] = group
847 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800848 }
849
850 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700851}
852
Jamie Gennisd4e10182014-06-12 20:06:50 -0700853// ResolveDependencies checks that the dependencies specified by all of the
854// modules defined in the parsed Blueprints files are valid. This means that
855// the modules depended upon are defined and that no circular dependencies
856// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700857//
858// The config argument is made available to all of the DynamicDependerModule
859// objects via the Config method on the DynamicDependerModuleContext objects
860// passed to their DynamicDependencies method.
861func (c *Context) ResolveDependencies(config interface{}) []error {
862 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700863 if len(errs) > 0 {
864 return errs
865 }
866
Colin Cross691a60d2015-01-07 18:08:56 -0800867 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700868 if len(errs) > 0 {
869 return errs
870 }
871
872 c.dependenciesReady = true
873 return nil
874}
875
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700876// moduleDepNames returns the sorted list of dependency names for a given
877// module. If the module implements the DynamicDependerModule interface then
878// this set consists of the union of those module names listed in its "deps"
879// property and those returned by its DynamicDependencies method. Otherwise it
880// is simply those names listed in its "deps" property.
Colin Crossed342d92015-03-11 00:57:25 -0700881func (c *Context) moduleDepNames(module *moduleInfo,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700882 config interface{}) ([]string, []error) {
883
884 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800885 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700886
Colin Crossed342d92015-03-11 00:57:25 -0700887 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800888 if !depNamesSet[depName] {
889 depNamesSet[depName] = true
890 depNames = append(depNames, depName)
891 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700892 }
893
Colin Crossed342d92015-03-11 00:57:25 -0700894 logicModule := module.logicModule
Colin Crossbbfa51a2014-12-17 16:12:41 -0800895 dynamicDepender, ok := logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700896 if ok {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800897 ddmctx := &baseModuleContext{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700898 context: c,
899 config: config,
Colin Crossed342d92015-03-11 00:57:25 -0700900 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700901 }
902
903 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
904
905 if len(ddmctx.errs) > 0 {
906 return nil, ddmctx.errs
907 }
908
909 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800910 if !depNamesSet[depName] {
911 depNamesSet[depName] = true
912 depNames = append(depNames, depName)
913 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700914 }
915 }
916
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700917 return depNames, nil
918}
919
Colin Crossbbfa51a2014-12-17 16:12:41 -0800920// resolveDependencies populates the moduleGroup.modules[0].directDeps list for every
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700921// module. In doing so it checks for missing dependencies and self-dependant
922// modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700923func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800924 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -0700925 for _, module := range group.modules {
926 depNames, newErrs := c.moduleDepNames(module, config)
Colin Crossc9028482014-12-18 16:28:54 -0800927 if len(newErrs) > 0 {
928 errs = append(errs, newErrs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700929 continue
930 }
Colin Crossed342d92015-03-11 00:57:25 -0700931
932 module.directDeps = make([]*moduleInfo, 0, len(depNames))
933
934 for _, depName := range depNames {
935 newErrs := c.addDependency(module, depName)
936 if len(newErrs) > 0 {
937 errs = append(errs, newErrs...)
938 continue
939 }
940 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700941 }
942 }
943
944 return
945}
946
Colin Crossc9028482014-12-18 16:28:54 -0800947func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -0700948 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -0800949
Colin Crossed342d92015-03-11 00:57:25 -0700950 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -0800951 return []error{&Error{
952 Err: fmt.Errorf("%q depends on itself", depName),
953 Pos: depsPos,
954 }}
955 }
956
957 depInfo, ok := c.moduleGroups[depName]
958 if !ok {
959 return []error{&Error{
960 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -0700961 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -0800962 Pos: depsPos,
963 }}
964 }
965
966 if len(depInfo.modules) != 1 {
967 panic(fmt.Sprintf("cannot add dependency from %s to %s, it already has multiple variants",
Colin Crossed342d92015-03-11 00:57:25 -0700968 module.properties.Name, depInfo.modules[0].properties.Name))
Colin Crossc9028482014-12-18 16:28:54 -0800969 }
970
971 module.directDeps = append(module.directDeps, depInfo.modules[0])
972
973 return nil
974}
975
Colin Cross7addea32015-03-11 15:43:52 -0700976func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
977 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -0800978 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -0800979 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -0800980
Colin Cross7addea32015-03-11 15:43:52 -0700981 for _, module := range c.modulesSorted {
982 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -0800983 }
984
Colin Cross7addea32015-03-11 15:43:52 -0700985 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -0800986 count++
987 go func() {
Colin Cross7addea32015-03-11 15:43:52 -0700988 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -0800989 if ret {
990 cancel = true
991 }
Colin Cross7addea32015-03-11 15:43:52 -0700992 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -0800993 }()
994 }
995
Colin Cross7addea32015-03-11 15:43:52 -0700996 for _, module := range c.modulesSorted {
997 if module.waitingCount == 0 {
998 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -0800999 }
1000 }
1001
Colin Cross11e3b0d2015-02-04 10:41:00 -08001002 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001003 select {
Colin Cross7addea32015-03-11 15:43:52 -07001004 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001005 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001006 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001007 parent.waitingCount--
1008 if parent.waitingCount == 0 {
1009 visitOne(parent)
1010 }
Colin Cross691a60d2015-01-07 18:08:56 -08001011 }
1012 }
1013 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001014 }
1015 }
1016}
1017
1018// updateDependencies recursively walks the module dependency graph and updates
1019// additional fields based on the dependencies. It builds a sorted list of modules
1020// such that dependencies of a module always appear first, and populates reverse
1021// dependency links and counts of total dependencies. It also reports errors when
1022// it encounters dependency cycles. This should called after resolveDependencies,
1023// as well as after any mutator pass has called addDependency
1024func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001025 visited := make(map[*moduleInfo]bool) // modules that were already checked
1026 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001027
Colin Cross7addea32015-03-11 15:43:52 -07001028 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001029
Colin Cross7addea32015-03-11 15:43:52 -07001030 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001031
Colin Cross7addea32015-03-11 15:43:52 -07001032 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001033 // We are the "start" of the cycle, so we're responsible
1034 // for generating the errors. The cycle list is in
1035 // reverse order because all the 'check' calls append
1036 // their own module to the list.
1037 errs = append(errs, &Error{
1038 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001039 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001040 })
1041
1042 // Iterate backwards through the cycle list.
Colin Cross7addea32015-03-11 15:43:52 -07001043 curModule := cycle[len(cycle)-1]
Colin Cross10b54db2015-03-11 14:40:30 -07001044 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001045 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001046 errs = append(errs, &Error{
1047 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001048 curModule.properties.Name,
1049 nextModule.properties.Name),
1050 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001051 })
Colin Cross7addea32015-03-11 15:43:52 -07001052 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001053 }
1054 }
1055
Colin Cross7addea32015-03-11 15:43:52 -07001056 check = func(module *moduleInfo) []*moduleInfo {
1057 visited[module] = true
1058 checking[module] = true
1059 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001060
Colin Cross7addea32015-03-11 15:43:52 -07001061 deps := make(map[*moduleInfo]bool)
1062
1063 // Add an implicit dependency ordering on all earlier modules in the same module group
1064 for _, dep := range module.group.modules {
1065 if dep == module {
1066 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001067 }
Colin Cross7addea32015-03-11 15:43:52 -07001068 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001069 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001070
Colin Cross7addea32015-03-11 15:43:52 -07001071 for _, dep := range module.directDeps {
1072 deps[dep] = true
1073 }
1074
1075 module.reverseDeps = []*moduleInfo{}
1076 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001077
Colin Crossbbfa51a2014-12-17 16:12:41 -08001078 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001079 if checking[dep] {
1080 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001081 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001082 }
1083
1084 if !visited[dep] {
1085 cycle := check(dep)
1086 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001087 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001088 // We are the "start" of the cycle, so we're responsible
1089 // for generating the errors. The cycle list is in
1090 // reverse order because all the 'check' calls append
1091 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001092 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001093
1094 // We can continue processing this module's children to
1095 // find more cycles. Since all the modules that were
1096 // part of the found cycle were marked as visited we
1097 // won't run into that cycle again.
1098 } else {
1099 // We're not the "start" of the cycle, so we just append
1100 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001101 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001102 }
1103 }
1104 }
Colin Cross691a60d2015-01-07 18:08:56 -08001105
Colin Cross7addea32015-03-11 15:43:52 -07001106 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001107 }
1108
Colin Cross7addea32015-03-11 15:43:52 -07001109 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001110
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001111 return nil
1112 }
1113
Colin Cross7addea32015-03-11 15:43:52 -07001114 for _, module := range c.moduleInfo {
1115 if !visited[module] {
1116 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001117 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001118 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001119 panic("inconceivable!")
1120 }
1121 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001122 }
1123 }
1124 }
1125
Colin Cross7addea32015-03-11 15:43:52 -07001126 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001127
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001128 return
1129}
1130
Jamie Gennisd4e10182014-06-12 20:06:50 -07001131// PrepareBuildActions generates an internal representation of all the build
1132// actions that need to be performed. This process involves invoking the
1133// GenerateBuildActions method on each of the Module objects created during the
1134// parse phase and then on each of the registered Singleton objects.
1135//
1136// If the ResolveDependencies method has not already been called it is called
1137// automatically by this method.
1138//
1139// The config argument is made available to all of the Module and Singleton
1140// objects via the Config method on the ModuleContext and SingletonContext
1141// objects passed to GenerateBuildActions. It is also passed to the functions
1142// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1143// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001144//
1145// The returned deps is a list of the ninja files dependencies that were added
1146// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1147// SingletonContext.AddNinjaFileDeps() methods.
1148func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001149 c.buildActionsReady = false
1150
1151 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001152 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001153 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001154 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001155 }
1156 }
1157
Colin Crossc9028482014-12-18 16:28:54 -08001158 errs = c.runMutators(config)
1159 if len(errs) > 0 {
1160 return nil, errs
1161 }
1162
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001163 liveGlobals := newLiveTracker(config)
1164
1165 c.initSpecialVariables()
1166
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001167 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001168 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001169 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001170 }
1171
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001172 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001173 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001174 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001175 }
1176
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001177 deps = append(depsModules, depsSingletons...)
1178
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001179 if c.buildDir != nil {
1180 liveGlobals.addNinjaStringDeps(c.buildDir)
1181 }
1182
1183 pkgNames := c.makeUniquePackageNames(liveGlobals)
1184
1185 // This will panic if it finds a problem since it's a programming error.
1186 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1187
1188 c.pkgNames = pkgNames
1189 c.globalVariables = liveGlobals.variables
1190 c.globalPools = liveGlobals.pools
1191 c.globalRules = liveGlobals.rules
1192
1193 c.buildActionsReady = true
1194
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001195 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001196}
1197
Colin Crossc9028482014-12-18 16:28:54 -08001198func (c *Context) runMutators(config interface{}) (errs []error) {
1199 for _, mutator := range c.mutatorInfo {
1200 if mutator.topDownMutator != nil {
1201 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1202 } else if mutator.bottomUpMutator != nil {
1203 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1204 } else {
1205 panic("no mutator set on " + mutator.name)
1206 }
1207 if len(errs) > 0 {
1208 return errs
1209 }
1210 }
1211
1212 return nil
1213}
1214
1215func (c *Context) runTopDownMutator(config interface{},
1216 name string, mutator TopDownMutator) (errs []error) {
1217
Colin Cross7addea32015-03-11 15:43:52 -07001218 for i := 0; i < len(c.modulesSorted); i++ {
1219 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1220 mctx := &mutatorContext{
1221 baseModuleContext: baseModuleContext{
1222 context: c,
1223 config: config,
1224 module: module,
1225 },
1226 name: name,
1227 }
Colin Crossc9028482014-12-18 16:28:54 -08001228
Colin Cross7addea32015-03-11 15:43:52 -07001229 mutator(mctx)
1230 if len(mctx.errs) > 0 {
1231 errs = append(errs, mctx.errs...)
1232 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001233 }
1234 }
1235
1236 return errs
1237}
1238
1239func (c *Context) runBottomUpMutator(config interface{},
1240 name string, mutator BottomUpMutator) (errs []error) {
1241
1242 dependenciesModified := false
1243
Colin Cross7addea32015-03-11 15:43:52 -07001244 for _, module := range c.modulesSorted {
1245 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001246
Colin Cross7addea32015-03-11 15:43:52 -07001247 mctx := &mutatorContext{
1248 baseModuleContext: baseModuleContext{
1249 context: c,
1250 config: config,
1251 module: module,
1252 },
1253 name: name,
1254 }
Colin Crossc9028482014-12-18 16:28:54 -08001255
Colin Cross7addea32015-03-11 15:43:52 -07001256 mutator(mctx)
1257 if len(mctx.errs) > 0 {
1258 errs = append(errs, mctx.errs...)
1259 return errs
1260 }
Colin Crossc9028482014-12-18 16:28:54 -08001261
Colin Cross7addea32015-03-11 15:43:52 -07001262 // Fix up any remaining dependencies on modules that were split into variants
1263 // by replacing them with the first variant
1264 for i, dep := range module.directDeps {
1265 if dep.logicModule == nil {
1266 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001267 }
1268 }
1269
Colin Cross7addea32015-03-11 15:43:52 -07001270 if mctx.dependenciesModified {
1271 dependenciesModified = true
1272 }
1273
1274 if module.splitModules != nil {
1275 newModules = append(newModules, module.splitModules...)
1276 } else {
1277 newModules = append(newModules, module)
1278 }
1279
1280 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001281 }
1282
1283 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001284 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001285 if len(errs) > 0 {
1286 return errs
1287 }
1288 }
1289
1290 return errs
1291}
1292
Colin Cross7addea32015-03-11 15:43:52 -07001293func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1294 newModules []*moduleInfo) []*moduleInfo {
1295 for i, m := range modules {
1296 if m == origModule {
1297 return spliceModulesAtIndex(modules, i, newModules)
1298 }
1299 }
1300
1301 panic("failed to find original module to splice")
1302}
1303
1304func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1305 spliceSize := len(newModules)
1306 newLen := len(modules) + spliceSize - 1
1307 var dest []*moduleInfo
1308 if cap(modules) >= len(modules)-1+len(newModules) {
1309 // We can fit the splice in the existing capacity, do everything in place
1310 dest = modules[:newLen]
1311 } else {
1312 dest = make([]*moduleInfo, newLen)
1313 copy(dest, modules[:i])
1314 }
1315
1316 // Move the end of the slice over by spliceSize-1
1317 copy(modules[i+spliceSize:], modules[i+1:])
1318
1319 // Copy the new modules into the slice
1320 copy(modules[i:], newModules)
1321
1322 return modules
1323}
1324
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001325func (c *Context) initSpecialVariables() {
1326 c.buildDir = nil
1327 c.requiredNinjaMajor = 1
1328 c.requiredNinjaMinor = 1
1329 c.requiredNinjaMicro = 0
1330}
1331
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001332func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001333 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001334
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001335 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001336 var errs []error
1337
Colin Cross691a60d2015-01-07 18:08:56 -08001338 cancelCh := make(chan struct{})
1339 errsCh := make(chan []error)
1340 depsCh := make(chan []string)
1341
1342 go func() {
1343 for {
1344 select {
1345 case <-cancelCh:
1346 close(cancelCh)
1347 return
1348 case newErrs := <-errsCh:
1349 errs = append(errs, newErrs...)
1350 case newDeps := <-depsCh:
1351 deps = append(deps, newDeps...)
1352
1353 }
1354 }
1355 }()
1356
Colin Cross7addea32015-03-11 15:43:52 -07001357 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1358 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1359 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1360 // just set it to nil.
1361 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1362 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001363
Colin Cross7addea32015-03-11 15:43:52 -07001364 mctx := &moduleContext{
1365 baseModuleContext: baseModuleContext{
1366 context: c,
1367 config: config,
1368 module: module,
1369 },
1370 scope: scope,
1371 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001372
Colin Cross7addea32015-03-11 15:43:52 -07001373 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001374
Colin Cross7addea32015-03-11 15:43:52 -07001375 if len(mctx.errs) > 0 {
1376 errsCh <- mctx.errs
1377 return true
1378 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001379
Colin Cross7addea32015-03-11 15:43:52 -07001380 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001381
Colin Cross7addea32015-03-11 15:43:52 -07001382 newErrs := c.processLocalBuildActions(&module.group.actionDefs,
1383 &mctx.actionDefs, liveGlobals)
1384 if len(newErrs) > 0 {
1385 errsCh <- newErrs
1386 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001387 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001388 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001389 })
1390
1391 cancelCh <- struct{}{}
1392 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001393
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001394 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001395}
1396
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001397func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001398 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001399
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001400 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001401 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001402
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001403 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001404 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1405 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1406 // just set it to nil.
1407 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001408
1409 sctx := &singletonContext{
1410 context: c,
1411 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001412 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001413 }
1414
1415 info.singleton.GenerateBuildActions(sctx)
1416
1417 if len(sctx.errs) > 0 {
1418 errs = append(errs, sctx.errs...)
1419 if len(errs) > maxErrors {
1420 break
1421 }
1422 continue
1423 }
1424
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001425 deps = append(deps, sctx.ninjaFileDeps...)
1426
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001427 newErrs := c.processLocalBuildActions(&info.actionDefs,
1428 &sctx.actionDefs, liveGlobals)
1429 errs = append(errs, newErrs...)
1430 if len(errs) > maxErrors {
1431 break
1432 }
1433 }
1434
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001435 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001436}
1437
1438func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1439 liveGlobals *liveTracker) []error {
1440
1441 var errs []error
1442
1443 // First we go through and add everything referenced by the module's
1444 // buildDefs to the live globals set. This will end up adding the live
1445 // locals to the set as well, but we'll take them out after.
1446 for _, def := range in.buildDefs {
1447 err := liveGlobals.AddBuildDefDeps(def)
1448 if err != nil {
1449 errs = append(errs, err)
1450 }
1451 }
1452
1453 if len(errs) > 0 {
1454 return errs
1455 }
1456
Colin Crossc9028482014-12-18 16:28:54 -08001457 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001458
1459 // We use the now-incorrect set of live "globals" to determine which local
1460 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001461 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001462 for _, v := range in.variables {
1463 _, isLive := liveGlobals.variables[v]
1464 if isLive {
1465 out.variables = append(out.variables, v)
1466 delete(liveGlobals.variables, v)
1467 }
1468 }
1469
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001470 for _, r := range in.rules {
1471 _, isLive := liveGlobals.rules[r]
1472 if isLive {
1473 out.rules = append(out.rules, r)
1474 delete(liveGlobals.rules, r)
1475 }
1476 }
1477
1478 return nil
1479}
1480
Colin Crossbbfa51a2014-12-17 16:12:41 -08001481func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1482 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001483
Colin Crossbbfa51a2014-12-17 16:12:41 -08001484 var walk func(module *moduleInfo)
1485 walk = func(module *moduleInfo) {
1486 visited[module] = true
1487 for _, moduleDep := range module.directDeps {
1488 if !visited[moduleDep] {
1489 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001490 }
1491 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001492
Colin Crossbbfa51a2014-12-17 16:12:41 -08001493 if module != topModule {
1494 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001495 }
1496 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001497
1498 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001499}
1500
Colin Crossbbfa51a2014-12-17 16:12:41 -08001501func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001502 visit func(Module)) {
1503
Colin Crossbbfa51a2014-12-17 16:12:41 -08001504 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001505
Colin Crossbbfa51a2014-12-17 16:12:41 -08001506 var walk func(module *moduleInfo)
1507 walk = func(module *moduleInfo) {
1508 visited[module] = true
1509 for _, moduleDep := range module.directDeps {
1510 if !visited[moduleDep] {
1511 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001512 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001513 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001514
1515 if module != topModule {
1516 if pred(module.logicModule) {
1517 visit(module.logicModule)
1518 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001519 }
1520 }
1521
Colin Crossbbfa51a2014-12-17 16:12:41 -08001522 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001523}
1524
Colin Crossc9028482014-12-18 16:28:54 -08001525func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1526 for _, dep := range module.directDeps {
1527 visit(dep.logicModule)
1528 }
1529}
1530
1531func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1532 visit func(Module)) {
1533
1534 for _, dep := range module.directDeps {
1535 if pred(dep.logicModule) {
1536 visit(dep.logicModule)
1537 }
1538 }
1539}
1540
Jamie Gennisc15544d2014-09-24 20:26:52 -07001541func (c *Context) sortedModuleNames() []string {
1542 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001543 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1544 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001545 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1546 moduleName)
1547 }
1548 sort.Strings(c.cachedSortedModuleNames)
1549 }
1550
1551 return c.cachedSortedModuleNames
1552}
1553
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001554func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001555 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001556 group := c.moduleGroups[moduleName]
1557 for _, module := range group.modules {
1558 visit(module.logicModule)
1559 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001560 }
1561}
1562
1563func (c *Context) visitAllModulesIf(pred func(Module) bool,
1564 visit func(Module)) {
1565
Jamie Gennisc15544d2014-09-24 20:26:52 -07001566 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001567 group := c.moduleGroups[moduleName]
1568 for _, module := range group.modules {
1569 if pred(module.logicModule) {
1570 visit(module.logicModule)
1571 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001572 }
1573 }
1574}
1575
1576func (c *Context) requireNinjaVersion(major, minor, micro int) {
1577 if major != 1 {
1578 panic("ninja version with major version != 1 not supported")
1579 }
1580 if c.requiredNinjaMinor < minor {
1581 c.requiredNinjaMinor = minor
1582 c.requiredNinjaMicro = micro
1583 }
1584 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1585 c.requiredNinjaMicro = micro
1586 }
1587}
1588
1589func (c *Context) setBuildDir(value *ninjaString) {
1590 if c.buildDir != nil {
1591 panic("buildDir set multiple times")
1592 }
1593 c.buildDir = value
1594}
1595
1596func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001597 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001598
Jamie Gennis2fb20952014-10-03 02:49:58 -07001599 pkgs := make(map[string]*PackageContext)
1600 pkgNames := make(map[*PackageContext]string)
1601 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001602
Jamie Gennis2fb20952014-10-03 02:49:58 -07001603 processPackage := func(pctx *PackageContext) {
1604 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001605 // This is a built-in rule and has no package.
1606 return
1607 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001608 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001609 // We've already processed this package.
1610 return
1611 }
1612
Jamie Gennis2fb20952014-10-03 02:49:58 -07001613 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001614 if present {
1615 // Short name collision. Both this package and the one that's
1616 // already there need to use their full names. We leave the short
1617 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001618 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001619 longPkgNames[otherPkg] = true
1620 } else {
1621 // No collision so far. Tentatively set the package's name to be
1622 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001623 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001624 }
1625 }
1626
1627 // We try to give all packages their short name, but when we get collisions
1628 // we need to use the full unique package name.
1629 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001630 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001631 }
1632 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001633 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001634 }
1635 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001636 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001637 }
1638
1639 // Add the packages that had collisions using their full unique names. This
1640 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001641 for pctx := range longPkgNames {
1642 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001643 }
1644
1645 return pkgNames
1646}
1647
1648func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001649 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001650
1651 visited := make(map[Variable]bool) // variables that were already checked
1652 checking := make(map[Variable]bool) // variables actively being checked
1653
1654 var check func(v Variable) []Variable
1655
1656 check = func(v Variable) []Variable {
1657 visited[v] = true
1658 checking[v] = true
1659 defer delete(checking, v)
1660
1661 value := variables[v]
1662 for _, dep := range value.variables {
1663 if checking[dep] {
1664 // This is a cycle.
1665 return []Variable{dep, v}
1666 }
1667
1668 if !visited[dep] {
1669 cycle := check(dep)
1670 if cycle != nil {
1671 if cycle[0] == v {
1672 // We are the "start" of the cycle, so we're responsible
1673 // for generating the errors. The cycle list is in
1674 // reverse order because all the 'check' calls append
1675 // their own module to the list.
1676 msgs := []string{"detected variable reference cycle:"}
1677
1678 // Iterate backwards through the cycle list.
1679 curName := v.fullName(pkgNames)
1680 curValue := value.Value(pkgNames)
1681 for i := len(cycle) - 1; i >= 0; i-- {
1682 next := cycle[i]
1683 nextName := next.fullName(pkgNames)
1684 nextValue := variables[next].Value(pkgNames)
1685
1686 msgs = append(msgs, fmt.Sprintf(
1687 " %q depends on %q", curName, nextName))
1688 msgs = append(msgs, fmt.Sprintf(
1689 " [%s = %s]", curName, curValue))
1690
1691 curName = nextName
1692 curValue = nextValue
1693 }
1694
1695 // Variable reference cycles are a programming error,
1696 // not the fault of the Blueprint file authors.
1697 panic(strings.Join(msgs, "\n"))
1698 } else {
1699 // We're not the "start" of the cycle, so we just append
1700 // our module to the list and return it.
1701 return append(cycle, v)
1702 }
1703 }
1704 }
1705 }
1706
1707 return nil
1708 }
1709
1710 for v := range variables {
1711 if !visited[v] {
1712 cycle := check(v)
1713 if cycle != nil {
1714 panic("inconceivable!")
1715 }
1716 }
1717 }
1718}
1719
Jamie Gennisaf435562014-10-27 22:34:56 -07001720// AllTargets returns a map all the build target names to the rule used to build
1721// them. This is the same information that is output by running 'ninja -t
1722// targets all'. If this is called before PrepareBuildActions successfully
1723// completes then ErrbuildActionsNotReady is returned.
1724func (c *Context) AllTargets() (map[string]string, error) {
1725 if !c.buildActionsReady {
1726 return nil, ErrBuildActionsNotReady
1727 }
1728
1729 targets := map[string]string{}
1730
1731 // Collect all the module build targets.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001732 for _, info := range c.moduleGroups {
Jamie Gennisaf435562014-10-27 22:34:56 -07001733 for _, buildDef := range info.actionDefs.buildDefs {
1734 ruleName := buildDef.Rule.fullName(c.pkgNames)
1735 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001736 outputValue, err := output.Eval(c.globalVariables)
1737 if err != nil {
1738 return nil, err
1739 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001740 targets[outputValue] = ruleName
1741 }
1742 }
1743 }
1744
1745 // Collect all the singleton build targets.
1746 for _, info := range c.singletonInfo {
1747 for _, buildDef := range info.actionDefs.buildDefs {
1748 ruleName := buildDef.Rule.fullName(c.pkgNames)
1749 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001750 outputValue, err := output.Eval(c.globalVariables)
1751 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001752 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001753 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001754 targets[outputValue] = ruleName
1755 }
1756 }
1757 }
1758
1759 return targets, nil
1760}
1761
Jamie Gennisd4e10182014-06-12 20:06:50 -07001762// WriteBuildFile writes the Ninja manifeset text for the generated build
1763// actions to w. If this is called before PrepareBuildActions successfully
1764// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001765func (c *Context) WriteBuildFile(w io.Writer) error {
1766 if !c.buildActionsReady {
1767 return ErrBuildActionsNotReady
1768 }
1769
1770 nw := newNinjaWriter(w)
1771
1772 err := c.writeBuildFileHeader(nw)
1773 if err != nil {
1774 return err
1775 }
1776
1777 err = c.writeNinjaRequiredVersion(nw)
1778 if err != nil {
1779 return err
1780 }
1781
1782 // TODO: Group the globals by package.
1783
1784 err = c.writeGlobalVariables(nw)
1785 if err != nil {
1786 return err
1787 }
1788
1789 err = c.writeGlobalPools(nw)
1790 if err != nil {
1791 return err
1792 }
1793
1794 err = c.writeBuildDir(nw)
1795 if err != nil {
1796 return err
1797 }
1798
1799 err = c.writeGlobalRules(nw)
1800 if err != nil {
1801 return err
1802 }
1803
1804 err = c.writeAllModuleActions(nw)
1805 if err != nil {
1806 return err
1807 }
1808
1809 err = c.writeAllSingletonActions(nw)
1810 if err != nil {
1811 return err
1812 }
1813
1814 return nil
1815}
1816
Jamie Gennisc15544d2014-09-24 20:26:52 -07001817type pkgAssociation struct {
1818 PkgName string
1819 PkgPath string
1820}
1821
1822type pkgAssociationSorter struct {
1823 pkgs []pkgAssociation
1824}
1825
1826func (s *pkgAssociationSorter) Len() int {
1827 return len(s.pkgs)
1828}
1829
1830func (s *pkgAssociationSorter) Less(i, j int) bool {
1831 iName := s.pkgs[i].PkgName
1832 jName := s.pkgs[j].PkgName
1833 return iName < jName
1834}
1835
1836func (s *pkgAssociationSorter) Swap(i, j int) {
1837 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1838}
1839
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001840func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1841 headerTemplate := template.New("fileHeader")
1842 _, err := headerTemplate.Parse(fileHeaderTemplate)
1843 if err != nil {
1844 // This is a programming error.
1845 panic(err)
1846 }
1847
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001848 var pkgs []pkgAssociation
1849 maxNameLen := 0
1850 for pkg, name := range c.pkgNames {
1851 pkgs = append(pkgs, pkgAssociation{
1852 PkgName: name,
1853 PkgPath: pkg.pkgPath,
1854 })
1855 if len(name) > maxNameLen {
1856 maxNameLen = len(name)
1857 }
1858 }
1859
1860 for i := range pkgs {
1861 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1862 }
1863
Jamie Gennisc15544d2014-09-24 20:26:52 -07001864 sort.Sort(&pkgAssociationSorter{pkgs})
1865
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001866 params := map[string]interface{}{
1867 "Pkgs": pkgs,
1868 }
1869
1870 buf := bytes.NewBuffer(nil)
1871 err = headerTemplate.Execute(buf, params)
1872 if err != nil {
1873 return err
1874 }
1875
1876 return nw.Comment(buf.String())
1877}
1878
1879func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1880 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1881 c.requiredNinjaMicro)
1882
1883 err := nw.Assign("ninja_required_version", value)
1884 if err != nil {
1885 return err
1886 }
1887
1888 return nw.BlankLine()
1889}
1890
1891func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1892 if c.buildDir != nil {
1893 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1894 if err != nil {
1895 return err
1896 }
1897
1898 err = nw.BlankLine()
1899 if err != nil {
1900 return err
1901 }
1902 }
1903 return nil
1904}
1905
Jamie Gennisc15544d2014-09-24 20:26:52 -07001906type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001907 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001908}
1909
Jamie Gennisc15544d2014-09-24 20:26:52 -07001910type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001911 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001912 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001913}
1914
Jamie Gennisc15544d2014-09-24 20:26:52 -07001915func (s *globalEntitySorter) Len() int {
1916 return len(s.entities)
1917}
1918
1919func (s *globalEntitySorter) Less(i, j int) bool {
1920 iName := s.entities[i].fullName(s.pkgNames)
1921 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001922 return iName < jName
1923}
1924
Jamie Gennisc15544d2014-09-24 20:26:52 -07001925func (s *globalEntitySorter) Swap(i, j int) {
1926 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927}
1928
1929func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1930 visited := make(map[Variable]bool)
1931
1932 var walk func(v Variable) error
1933 walk = func(v Variable) error {
1934 visited[v] = true
1935
1936 // First visit variables on which this variable depends.
1937 value := c.globalVariables[v]
1938 for _, dep := range value.variables {
1939 if !visited[dep] {
1940 err := walk(dep)
1941 if err != nil {
1942 return err
1943 }
1944 }
1945 }
1946
1947 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1948 if err != nil {
1949 return err
1950 }
1951
1952 err = nw.BlankLine()
1953 if err != nil {
1954 return err
1955 }
1956
1957 return nil
1958 }
1959
Jamie Gennisc15544d2014-09-24 20:26:52 -07001960 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1961 for variable := range c.globalVariables {
1962 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001963 }
1964
Jamie Gennisc15544d2014-09-24 20:26:52 -07001965 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001966
Jamie Gennisc15544d2014-09-24 20:26:52 -07001967 for _, entity := range globalVariables {
1968 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001969 if !visited[v] {
1970 err := walk(v)
1971 if err != nil {
1972 return nil
1973 }
1974 }
1975 }
1976
1977 return nil
1978}
1979
1980func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001981 globalPools := make([]globalEntity, 0, len(c.globalPools))
1982 for pool := range c.globalPools {
1983 globalPools = append(globalPools, pool)
1984 }
1985
1986 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1987
1988 for _, entity := range globalPools {
1989 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001990 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001991 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001992 err := def.WriteTo(nw, name)
1993 if err != nil {
1994 return err
1995 }
1996
1997 err = nw.BlankLine()
1998 if err != nil {
1999 return err
2000 }
2001 }
2002
2003 return nil
2004}
2005
2006func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002007 globalRules := make([]globalEntity, 0, len(c.globalRules))
2008 for rule := range c.globalRules {
2009 globalRules = append(globalRules, rule)
2010 }
2011
2012 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2013
2014 for _, entity := range globalRules {
2015 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002016 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002017 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002018 err := def.WriteTo(nw, name, c.pkgNames)
2019 if err != nil {
2020 return err
2021 }
2022
2023 err = nw.BlankLine()
2024 if err != nil {
2025 return err
2026 }
2027 }
2028
2029 return nil
2030}
2031
Colin Crossbbfa51a2014-12-17 16:12:41 -08002032type moduleGroupSorter []*moduleGroup
Jamie Gennis86179fe2014-06-11 16:27:16 -07002033
Colin Crossbbfa51a2014-12-17 16:12:41 -08002034func (s moduleGroupSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002035 return len(s)
2036}
2037
Colin Crossbbfa51a2014-12-17 16:12:41 -08002038func (s moduleGroupSorter) Less(i, j int) bool {
Colin Crossed342d92015-03-11 00:57:25 -07002039 iName := s[i].name
2040 jName := s[j].name
Jamie Gennis86179fe2014-06-11 16:27:16 -07002041 return iName < jName
2042}
2043
Colin Crossbbfa51a2014-12-17 16:12:41 -08002044func (s moduleGroupSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002045 s[i], s[j] = s[j], s[i]
2046}
2047
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002048func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2049 headerTemplate := template.New("moduleHeader")
2050 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2051 if err != nil {
2052 // This is a programming error.
2053 panic(err)
2054 }
2055
Colin Crossbbfa51a2014-12-17 16:12:41 -08002056 infos := make([]*moduleGroup, 0, len(c.moduleGroups))
2057 for _, info := range c.moduleGroups {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002058 infos = append(infos, info)
2059 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002060 sort.Sort(moduleGroupSorter(infos))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002061
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002062 buf := bytes.NewBuffer(nil)
2063
Jamie Gennis86179fe2014-06-11 16:27:16 -07002064 for _, info := range infos {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002065 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002066
2067 // In order to make the bootstrap build manifest independent of the
2068 // build dir we need to output the Blueprints file locations in the
2069 // comments as paths relative to the source directory.
Colin Crossed342d92015-03-11 00:57:25 -07002070 relPos := info.modules[0].pos
2071 relPos.Filename = info.modules[0].relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002072
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002073 // Get the name and location of the factory function for the module.
Colin Crossed342d92015-03-11 00:57:25 -07002074 factory := c.moduleFactories[info.modules[0].typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002075 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2076 factoryName := factoryFunc.Name()
2077
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002078 infoMap := map[string]interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07002079 "properties": info.modules[0].properties,
2080 "typeName": info.modules[0].typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002081 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002082 "pos": relPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002083 }
2084 err = headerTemplate.Execute(buf, infoMap)
2085 if err != nil {
2086 return err
2087 }
2088
2089 err = nw.Comment(buf.String())
2090 if err != nil {
2091 return err
2092 }
2093
2094 err = nw.BlankLine()
2095 if err != nil {
2096 return err
2097 }
2098
2099 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2100 if err != nil {
2101 return err
2102 }
2103
2104 err = nw.BlankLine()
2105 if err != nil {
2106 return err
2107 }
2108 }
2109
2110 return nil
2111}
2112
2113func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2114 headerTemplate := template.New("singletonHeader")
2115 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2116 if err != nil {
2117 // This is a programming error.
2118 panic(err)
2119 }
2120
2121 buf := bytes.NewBuffer(nil)
2122
Jamie Gennis86179fe2014-06-11 16:27:16 -07002123 singletonNames := make([]string, 0, len(c.singletonInfo))
2124 for name := range c.singletonInfo {
2125 singletonNames = append(singletonNames, name)
2126 }
2127 sort.Strings(singletonNames)
2128
2129 for _, name := range singletonNames {
2130 info := c.singletonInfo[name]
2131
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002132 // Get the name of the factory function for the module.
2133 factory := info.factory
2134 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2135 factoryName := factoryFunc.Name()
2136
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002137 buf.Reset()
2138 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002139 "name": name,
2140 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002141 }
2142 err = headerTemplate.Execute(buf, infoMap)
2143 if err != nil {
2144 return err
2145 }
2146
2147 err = nw.Comment(buf.String())
2148 if err != nil {
2149 return err
2150 }
2151
2152 err = nw.BlankLine()
2153 if err != nil {
2154 return err
2155 }
2156
2157 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2158 if err != nil {
2159 return err
2160 }
2161
2162 err = nw.BlankLine()
2163 if err != nil {
2164 return err
2165 }
2166 }
2167
2168 return nil
2169}
2170
2171func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2172 defs *localBuildActions) error {
2173
2174 // Write the local variable assignments.
2175 for _, v := range defs.variables {
2176 // A localVariable doesn't need the package names or config to
2177 // determine its name or value.
2178 name := v.fullName(nil)
2179 value, err := v.value(nil)
2180 if err != nil {
2181 panic(err)
2182 }
2183 err = nw.Assign(name, value.Value(c.pkgNames))
2184 if err != nil {
2185 return err
2186 }
2187 }
2188
2189 if len(defs.variables) > 0 {
2190 err := nw.BlankLine()
2191 if err != nil {
2192 return err
2193 }
2194 }
2195
2196 // Write the local rules.
2197 for _, r := range defs.rules {
2198 // A localRule doesn't need the package names or config to determine
2199 // its name or definition.
2200 name := r.fullName(nil)
2201 def, err := r.def(nil)
2202 if err != nil {
2203 panic(err)
2204 }
2205
2206 err = def.WriteTo(nw, name, c.pkgNames)
2207 if err != nil {
2208 return err
2209 }
2210
2211 err = nw.BlankLine()
2212 if err != nil {
2213 return err
2214 }
2215 }
2216
2217 // Write the build definitions.
2218 for _, buildDef := range defs.buildDefs {
2219 err := buildDef.WriteTo(nw, c.pkgNames)
2220 if err != nil {
2221 return err
2222 }
2223
2224 if len(buildDef.Args) > 0 {
2225 err = nw.BlankLine()
2226 if err != nil {
2227 return err
2228 }
2229 }
2230 }
2231
2232 return nil
2233}
2234
2235var fileHeaderTemplate = `******************************************************************************
2236*** This file is generated and should not be edited ***
2237******************************************************************************
2238{{if .Pkgs}}
2239This file contains variables, rules, and pools with name prefixes indicating
2240they were generated by the following Go packages:
2241{{range .Pkgs}}
2242 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2243
2244`
2245
2246var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2247Module: {{.properties.Name}}
2248Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002249Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002250Defined: {{.pos}}
2251`
2252
2253var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2254Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002255Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002256`