blob: 8f5cedbd80f2aae256a160844c3d207cf8c255b7 [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
Colin Crossbbfa51a2014-12-17 16:12:41 -0800115type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700116 // set during Parse
117 typeName string
118 relBlueprintsFile string
119 pos scanner.Position
120 propertyPos map[string]scanner.Position
121 properties struct {
122 Name string
123 Deps []string
124 }
125
Colin Crosse7daa222015-03-11 14:35:41 -0700126 variantName string
127 variants variantMap
128
Colin Crossc9028482014-12-18 16:28:54 -0800129 logicModule Module
130 group *moduleGroup
131 moduleProperties []interface{}
132
133 // set during ResolveDependencies
134 directDeps []*moduleInfo
135
Colin Cross7addea32015-03-11 15:43:52 -0700136 // set during updateDependencies
137 reverseDeps []*moduleInfo
138 depsCount int
139
140 // used by parallelVisitAllBottomUp
141 waitingCount int
142
Colin Crossc9028482014-12-18 16:28:54 -0800143 // set during each runMutator
144 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700145
146 // set during PrepareBuildActions
147 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800148}
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 Crossab6d7902015-03-11 16:17:52 -07001382 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001383 &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 {
Colin Crossab6d7902015-03-11 16:17:52 -07001463 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001464 if isLive {
1465 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001466 }
1467 }
1468
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001470 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001471 if isLive {
1472 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001473 }
1474 }
1475
1476 return nil
1477}
1478
Colin Crossbbfa51a2014-12-17 16:12:41 -08001479func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1480 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001481
Colin Crossbbfa51a2014-12-17 16:12:41 -08001482 var walk func(module *moduleInfo)
1483 walk = func(module *moduleInfo) {
1484 visited[module] = true
1485 for _, moduleDep := range module.directDeps {
1486 if !visited[moduleDep] {
1487 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001488 }
1489 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001490
Colin Crossbbfa51a2014-12-17 16:12:41 -08001491 if module != topModule {
1492 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001493 }
1494 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001495
1496 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001497}
1498
Colin Crossbbfa51a2014-12-17 16:12:41 -08001499func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001500 visit func(Module)) {
1501
Colin Crossbbfa51a2014-12-17 16:12:41 -08001502 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001503
Colin Crossbbfa51a2014-12-17 16:12:41 -08001504 var walk func(module *moduleInfo)
1505 walk = func(module *moduleInfo) {
1506 visited[module] = true
1507 for _, moduleDep := range module.directDeps {
1508 if !visited[moduleDep] {
1509 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001510 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001511 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001512
1513 if module != topModule {
1514 if pred(module.logicModule) {
1515 visit(module.logicModule)
1516 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001517 }
1518 }
1519
Colin Crossbbfa51a2014-12-17 16:12:41 -08001520 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001521}
1522
Colin Crossc9028482014-12-18 16:28:54 -08001523func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1524 for _, dep := range module.directDeps {
1525 visit(dep.logicModule)
1526 }
1527}
1528
1529func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1530 visit func(Module)) {
1531
1532 for _, dep := range module.directDeps {
1533 if pred(dep.logicModule) {
1534 visit(dep.logicModule)
1535 }
1536 }
1537}
1538
Jamie Gennisc15544d2014-09-24 20:26:52 -07001539func (c *Context) sortedModuleNames() []string {
1540 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001541 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1542 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001543 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1544 moduleName)
1545 }
1546 sort.Strings(c.cachedSortedModuleNames)
1547 }
1548
1549 return c.cachedSortedModuleNames
1550}
1551
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001552func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001553 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001554 group := c.moduleGroups[moduleName]
1555 for _, module := range group.modules {
1556 visit(module.logicModule)
1557 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001558 }
1559}
1560
1561func (c *Context) visitAllModulesIf(pred func(Module) bool,
1562 visit func(Module)) {
1563
Jamie Gennisc15544d2014-09-24 20:26:52 -07001564 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001565 group := c.moduleGroups[moduleName]
1566 for _, module := range group.modules {
1567 if pred(module.logicModule) {
1568 visit(module.logicModule)
1569 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001570 }
1571 }
1572}
1573
1574func (c *Context) requireNinjaVersion(major, minor, micro int) {
1575 if major != 1 {
1576 panic("ninja version with major version != 1 not supported")
1577 }
1578 if c.requiredNinjaMinor < minor {
1579 c.requiredNinjaMinor = minor
1580 c.requiredNinjaMicro = micro
1581 }
1582 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1583 c.requiredNinjaMicro = micro
1584 }
1585}
1586
1587func (c *Context) setBuildDir(value *ninjaString) {
1588 if c.buildDir != nil {
1589 panic("buildDir set multiple times")
1590 }
1591 c.buildDir = value
1592}
1593
1594func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001595 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001596
Jamie Gennis2fb20952014-10-03 02:49:58 -07001597 pkgs := make(map[string]*PackageContext)
1598 pkgNames := make(map[*PackageContext]string)
1599 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001600
Jamie Gennis2fb20952014-10-03 02:49:58 -07001601 processPackage := func(pctx *PackageContext) {
1602 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001603 // This is a built-in rule and has no package.
1604 return
1605 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001606 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001607 // We've already processed this package.
1608 return
1609 }
1610
Jamie Gennis2fb20952014-10-03 02:49:58 -07001611 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001612 if present {
1613 // Short name collision. Both this package and the one that's
1614 // already there need to use their full names. We leave the short
1615 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001616 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001617 longPkgNames[otherPkg] = true
1618 } else {
1619 // No collision so far. Tentatively set the package's name to be
1620 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001621 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001622 }
1623 }
1624
1625 // We try to give all packages their short name, but when we get collisions
1626 // we need to use the full unique package name.
1627 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001628 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001629 }
1630 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001631 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001632 }
1633 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001634 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635 }
1636
1637 // Add the packages that had collisions using their full unique names. This
1638 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001639 for pctx := range longPkgNames {
1640 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001641 }
1642
1643 return pkgNames
1644}
1645
1646func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001647 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001648
1649 visited := make(map[Variable]bool) // variables that were already checked
1650 checking := make(map[Variable]bool) // variables actively being checked
1651
1652 var check func(v Variable) []Variable
1653
1654 check = func(v Variable) []Variable {
1655 visited[v] = true
1656 checking[v] = true
1657 defer delete(checking, v)
1658
1659 value := variables[v]
1660 for _, dep := range value.variables {
1661 if checking[dep] {
1662 // This is a cycle.
1663 return []Variable{dep, v}
1664 }
1665
1666 if !visited[dep] {
1667 cycle := check(dep)
1668 if cycle != nil {
1669 if cycle[0] == v {
1670 // We are the "start" of the cycle, so we're responsible
1671 // for generating the errors. The cycle list is in
1672 // reverse order because all the 'check' calls append
1673 // their own module to the list.
1674 msgs := []string{"detected variable reference cycle:"}
1675
1676 // Iterate backwards through the cycle list.
1677 curName := v.fullName(pkgNames)
1678 curValue := value.Value(pkgNames)
1679 for i := len(cycle) - 1; i >= 0; i-- {
1680 next := cycle[i]
1681 nextName := next.fullName(pkgNames)
1682 nextValue := variables[next].Value(pkgNames)
1683
1684 msgs = append(msgs, fmt.Sprintf(
1685 " %q depends on %q", curName, nextName))
1686 msgs = append(msgs, fmt.Sprintf(
1687 " [%s = %s]", curName, curValue))
1688
1689 curName = nextName
1690 curValue = nextValue
1691 }
1692
1693 // Variable reference cycles are a programming error,
1694 // not the fault of the Blueprint file authors.
1695 panic(strings.Join(msgs, "\n"))
1696 } else {
1697 // We're not the "start" of the cycle, so we just append
1698 // our module to the list and return it.
1699 return append(cycle, v)
1700 }
1701 }
1702 }
1703 }
1704
1705 return nil
1706 }
1707
1708 for v := range variables {
1709 if !visited[v] {
1710 cycle := check(v)
1711 if cycle != nil {
1712 panic("inconceivable!")
1713 }
1714 }
1715 }
1716}
1717
Jamie Gennisaf435562014-10-27 22:34:56 -07001718// AllTargets returns a map all the build target names to the rule used to build
1719// them. This is the same information that is output by running 'ninja -t
1720// targets all'. If this is called before PrepareBuildActions successfully
1721// completes then ErrbuildActionsNotReady is returned.
1722func (c *Context) AllTargets() (map[string]string, error) {
1723 if !c.buildActionsReady {
1724 return nil, ErrBuildActionsNotReady
1725 }
1726
1727 targets := map[string]string{}
1728
1729 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001730 for _, module := range c.moduleInfo {
1731 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001732 ruleName := buildDef.Rule.fullName(c.pkgNames)
1733 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001734 outputValue, err := output.Eval(c.globalVariables)
1735 if err != nil {
1736 return nil, err
1737 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001738 targets[outputValue] = ruleName
1739 }
1740 }
1741 }
1742
1743 // Collect all the singleton build targets.
1744 for _, info := range c.singletonInfo {
1745 for _, buildDef := range info.actionDefs.buildDefs {
1746 ruleName := buildDef.Rule.fullName(c.pkgNames)
1747 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001748 outputValue, err := output.Eval(c.globalVariables)
1749 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001750 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001751 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001752 targets[outputValue] = ruleName
1753 }
1754 }
1755 }
1756
1757 return targets, nil
1758}
1759
Jamie Gennisd4e10182014-06-12 20:06:50 -07001760// WriteBuildFile writes the Ninja manifeset text for the generated build
1761// actions to w. If this is called before PrepareBuildActions successfully
1762// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001763func (c *Context) WriteBuildFile(w io.Writer) error {
1764 if !c.buildActionsReady {
1765 return ErrBuildActionsNotReady
1766 }
1767
1768 nw := newNinjaWriter(w)
1769
1770 err := c.writeBuildFileHeader(nw)
1771 if err != nil {
1772 return err
1773 }
1774
1775 err = c.writeNinjaRequiredVersion(nw)
1776 if err != nil {
1777 return err
1778 }
1779
1780 // TODO: Group the globals by package.
1781
1782 err = c.writeGlobalVariables(nw)
1783 if err != nil {
1784 return err
1785 }
1786
1787 err = c.writeGlobalPools(nw)
1788 if err != nil {
1789 return err
1790 }
1791
1792 err = c.writeBuildDir(nw)
1793 if err != nil {
1794 return err
1795 }
1796
1797 err = c.writeGlobalRules(nw)
1798 if err != nil {
1799 return err
1800 }
1801
1802 err = c.writeAllModuleActions(nw)
1803 if err != nil {
1804 return err
1805 }
1806
1807 err = c.writeAllSingletonActions(nw)
1808 if err != nil {
1809 return err
1810 }
1811
1812 return nil
1813}
1814
Jamie Gennisc15544d2014-09-24 20:26:52 -07001815type pkgAssociation struct {
1816 PkgName string
1817 PkgPath string
1818}
1819
1820type pkgAssociationSorter struct {
1821 pkgs []pkgAssociation
1822}
1823
1824func (s *pkgAssociationSorter) Len() int {
1825 return len(s.pkgs)
1826}
1827
1828func (s *pkgAssociationSorter) Less(i, j int) bool {
1829 iName := s.pkgs[i].PkgName
1830 jName := s.pkgs[j].PkgName
1831 return iName < jName
1832}
1833
1834func (s *pkgAssociationSorter) Swap(i, j int) {
1835 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1836}
1837
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001838func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1839 headerTemplate := template.New("fileHeader")
1840 _, err := headerTemplate.Parse(fileHeaderTemplate)
1841 if err != nil {
1842 // This is a programming error.
1843 panic(err)
1844 }
1845
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001846 var pkgs []pkgAssociation
1847 maxNameLen := 0
1848 for pkg, name := range c.pkgNames {
1849 pkgs = append(pkgs, pkgAssociation{
1850 PkgName: name,
1851 PkgPath: pkg.pkgPath,
1852 })
1853 if len(name) > maxNameLen {
1854 maxNameLen = len(name)
1855 }
1856 }
1857
1858 for i := range pkgs {
1859 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1860 }
1861
Jamie Gennisc15544d2014-09-24 20:26:52 -07001862 sort.Sort(&pkgAssociationSorter{pkgs})
1863
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001864 params := map[string]interface{}{
1865 "Pkgs": pkgs,
1866 }
1867
1868 buf := bytes.NewBuffer(nil)
1869 err = headerTemplate.Execute(buf, params)
1870 if err != nil {
1871 return err
1872 }
1873
1874 return nw.Comment(buf.String())
1875}
1876
1877func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1878 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1879 c.requiredNinjaMicro)
1880
1881 err := nw.Assign("ninja_required_version", value)
1882 if err != nil {
1883 return err
1884 }
1885
1886 return nw.BlankLine()
1887}
1888
1889func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1890 if c.buildDir != nil {
1891 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1892 if err != nil {
1893 return err
1894 }
1895
1896 err = nw.BlankLine()
1897 if err != nil {
1898 return err
1899 }
1900 }
1901 return nil
1902}
1903
Jamie Gennisc15544d2014-09-24 20:26:52 -07001904type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001905 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001906}
1907
Jamie Gennisc15544d2014-09-24 20:26:52 -07001908type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001909 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001910 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001911}
1912
Jamie Gennisc15544d2014-09-24 20:26:52 -07001913func (s *globalEntitySorter) Len() int {
1914 return len(s.entities)
1915}
1916
1917func (s *globalEntitySorter) Less(i, j int) bool {
1918 iName := s.entities[i].fullName(s.pkgNames)
1919 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001920 return iName < jName
1921}
1922
Jamie Gennisc15544d2014-09-24 20:26:52 -07001923func (s *globalEntitySorter) Swap(i, j int) {
1924 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001925}
1926
1927func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1928 visited := make(map[Variable]bool)
1929
1930 var walk func(v Variable) error
1931 walk = func(v Variable) error {
1932 visited[v] = true
1933
1934 // First visit variables on which this variable depends.
1935 value := c.globalVariables[v]
1936 for _, dep := range value.variables {
1937 if !visited[dep] {
1938 err := walk(dep)
1939 if err != nil {
1940 return err
1941 }
1942 }
1943 }
1944
1945 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1946 if err != nil {
1947 return err
1948 }
1949
1950 err = nw.BlankLine()
1951 if err != nil {
1952 return err
1953 }
1954
1955 return nil
1956 }
1957
Jamie Gennisc15544d2014-09-24 20:26:52 -07001958 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1959 for variable := range c.globalVariables {
1960 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001961 }
1962
Jamie Gennisc15544d2014-09-24 20:26:52 -07001963 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001964
Jamie Gennisc15544d2014-09-24 20:26:52 -07001965 for _, entity := range globalVariables {
1966 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001967 if !visited[v] {
1968 err := walk(v)
1969 if err != nil {
1970 return nil
1971 }
1972 }
1973 }
1974
1975 return nil
1976}
1977
1978func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001979 globalPools := make([]globalEntity, 0, len(c.globalPools))
1980 for pool := range c.globalPools {
1981 globalPools = append(globalPools, pool)
1982 }
1983
1984 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1985
1986 for _, entity := range globalPools {
1987 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001988 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001989 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001990 err := def.WriteTo(nw, name)
1991 if err != nil {
1992 return err
1993 }
1994
1995 err = nw.BlankLine()
1996 if err != nil {
1997 return err
1998 }
1999 }
2000
2001 return nil
2002}
2003
2004func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002005 globalRules := make([]globalEntity, 0, len(c.globalRules))
2006 for rule := range c.globalRules {
2007 globalRules = append(globalRules, rule)
2008 }
2009
2010 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2011
2012 for _, entity := range globalRules {
2013 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002014 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002015 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002016 err := def.WriteTo(nw, name, c.pkgNames)
2017 if err != nil {
2018 return err
2019 }
2020
2021 err = nw.BlankLine()
2022 if err != nil {
2023 return err
2024 }
2025 }
2026
2027 return nil
2028}
2029
Colin Crossab6d7902015-03-11 16:17:52 -07002030type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002031
Colin Crossab6d7902015-03-11 16:17:52 -07002032func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002033 return len(s)
2034}
2035
Colin Crossab6d7902015-03-11 16:17:52 -07002036func (s moduleSorter) Less(i, j int) bool {
2037 iName := s[i].properties.Name
2038 jName := s[j].properties.Name
2039 if iName == jName {
2040 iName = s[i].subName()
2041 jName = s[j].subName()
2042 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002043 return iName < jName
2044}
2045
Colin Crossab6d7902015-03-11 16:17:52 -07002046func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002047 s[i], s[j] = s[j], s[i]
2048}
2049
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002050func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2051 headerTemplate := template.New("moduleHeader")
2052 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2053 if err != nil {
2054 // This is a programming error.
2055 panic(err)
2056 }
2057
Colin Crossab6d7902015-03-11 16:17:52 -07002058 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2059 for _, module := range c.moduleInfo {
2060 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002061 }
Colin Crossab6d7902015-03-11 16:17:52 -07002062 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002063
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002064 buf := bytes.NewBuffer(nil)
2065
Colin Crossab6d7902015-03-11 16:17:52 -07002066 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002067 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002068
2069 // In order to make the bootstrap build manifest independent of the
2070 // build dir we need to output the Blueprints file locations in the
2071 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002072 relPos := module.pos
2073 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002074
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002075 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002076 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002077 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2078 factoryName := factoryFunc.Name()
2079
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002080 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002081 "properties": module.properties,
2082 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002083 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002084 "pos": relPos,
Colin Crossab6d7902015-03-11 16:17:52 -07002085 "variant": module.subName(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002086 }
2087 err = headerTemplate.Execute(buf, infoMap)
2088 if err != nil {
2089 return err
2090 }
2091
2092 err = nw.Comment(buf.String())
2093 if err != nil {
2094 return err
2095 }
2096
2097 err = nw.BlankLine()
2098 if err != nil {
2099 return err
2100 }
2101
Colin Crossab6d7902015-03-11 16:17:52 -07002102 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002103 if err != nil {
2104 return err
2105 }
2106
2107 err = nw.BlankLine()
2108 if err != nil {
2109 return err
2110 }
2111 }
2112
2113 return nil
2114}
2115
2116func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2117 headerTemplate := template.New("singletonHeader")
2118 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2119 if err != nil {
2120 // This is a programming error.
2121 panic(err)
2122 }
2123
2124 buf := bytes.NewBuffer(nil)
2125
Jamie Gennis86179fe2014-06-11 16:27:16 -07002126 singletonNames := make([]string, 0, len(c.singletonInfo))
2127 for name := range c.singletonInfo {
2128 singletonNames = append(singletonNames, name)
2129 }
2130 sort.Strings(singletonNames)
2131
2132 for _, name := range singletonNames {
2133 info := c.singletonInfo[name]
2134
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002135 // Get the name of the factory function for the module.
2136 factory := info.factory
2137 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2138 factoryName := factoryFunc.Name()
2139
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002140 buf.Reset()
2141 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002142 "name": name,
2143 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002144 }
2145 err = headerTemplate.Execute(buf, infoMap)
2146 if err != nil {
2147 return err
2148 }
2149
2150 err = nw.Comment(buf.String())
2151 if err != nil {
2152 return err
2153 }
2154
2155 err = nw.BlankLine()
2156 if err != nil {
2157 return err
2158 }
2159
2160 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2161 if err != nil {
2162 return err
2163 }
2164
2165 err = nw.BlankLine()
2166 if err != nil {
2167 return err
2168 }
2169 }
2170
2171 return nil
2172}
2173
2174func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2175 defs *localBuildActions) error {
2176
2177 // Write the local variable assignments.
2178 for _, v := range defs.variables {
2179 // A localVariable doesn't need the package names or config to
2180 // determine its name or value.
2181 name := v.fullName(nil)
2182 value, err := v.value(nil)
2183 if err != nil {
2184 panic(err)
2185 }
2186 err = nw.Assign(name, value.Value(c.pkgNames))
2187 if err != nil {
2188 return err
2189 }
2190 }
2191
2192 if len(defs.variables) > 0 {
2193 err := nw.BlankLine()
2194 if err != nil {
2195 return err
2196 }
2197 }
2198
2199 // Write the local rules.
2200 for _, r := range defs.rules {
2201 // A localRule doesn't need the package names or config to determine
2202 // its name or definition.
2203 name := r.fullName(nil)
2204 def, err := r.def(nil)
2205 if err != nil {
2206 panic(err)
2207 }
2208
2209 err = def.WriteTo(nw, name, c.pkgNames)
2210 if err != nil {
2211 return err
2212 }
2213
2214 err = nw.BlankLine()
2215 if err != nil {
2216 return err
2217 }
2218 }
2219
2220 // Write the build definitions.
2221 for _, buildDef := range defs.buildDefs {
2222 err := buildDef.WriteTo(nw, c.pkgNames)
2223 if err != nil {
2224 return err
2225 }
2226
2227 if len(buildDef.Args) > 0 {
2228 err = nw.BlankLine()
2229 if err != nil {
2230 return err
2231 }
2232 }
2233 }
2234
2235 return nil
2236}
2237
2238var fileHeaderTemplate = `******************************************************************************
2239*** This file is generated and should not be edited ***
2240******************************************************************************
2241{{if .Pkgs}}
2242This file contains variables, rules, and pools with name prefixes indicating
2243they were generated by the following Go packages:
2244{{range .Pkgs}}
2245 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2246
2247`
2248
2249var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2250Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002251Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002252Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002253Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002254Defined: {{.pos}}
2255`
2256
2257var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2258Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002259Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002260`