blob: f3b5c2cd382f131310f9335ff5f61da907d5a16f [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 Crossbbfa51a2014-12-17 16:12:41 -080065 moduleFactories map[string]ModuleFactory
66 moduleGroups map[string]*moduleGroup
67 moduleInfo map[Module]*moduleInfo
68 moduleGroupsSorted []*moduleGroup
69 singletonInfo map[string]*singletonInfo
Colin Crossc9028482014-12-18 16:28:54 -080070 mutatorInfo []*mutatorInfo
Colin Cross6134a5c2015-02-10 11:26:26 -080071 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
Colin Cross691a60d2015-01-07 18:08:56 -0800114 // set during updateDependencies
115 reverseDeps []*moduleGroup
116 depsCount int
117
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118 // set during PrepareBuildActions
119 actionDefs localBuildActions
Colin Cross691a60d2015-01-07 18:08:56 -0800120
121 // used by parallelVisitAllBottomUp
122 waitingCount int
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700123}
124
Colin Crossbbfa51a2014-12-17 16:12:41 -0800125type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700126 // set during Parse
127 typeName string
128 relBlueprintsFile string
129 pos scanner.Position
130 propertyPos map[string]scanner.Position
131 properties struct {
132 Name string
133 Deps []string
134 }
135
Colin Crossc9028482014-12-18 16:28:54 -0800136 name []subName
137 logicModule Module
138 group *moduleGroup
139 moduleProperties []interface{}
140
141 // set during ResolveDependencies
142 directDeps []*moduleInfo
143
144 // set during each runMutator
145 splitModules []*moduleInfo
146}
147
148type subName struct {
149 mutatorName string
150 variantName string
151}
152
153func (module *moduleInfo) subName() string {
154 names := []string{}
155 for _, subName := range module.name {
156 if subName.variantName != "" {
157 names = append(names, subName.variantName)
158 }
159 }
160 return strings.Join(names, "_")
Colin Crossbbfa51a2014-12-17 16:12:41 -0800161}
162
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700163type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700164 // set during RegisterSingletonType
165 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700166 singleton Singleton
167
168 // set during PrepareBuildActions
169 actionDefs localBuildActions
170}
171
Colin Crossc9028482014-12-18 16:28:54 -0800172type mutatorInfo struct {
173 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800174 topDownMutator TopDownMutator
175 bottomUpMutator BottomUpMutator
176 name string
Colin Crossc9028482014-12-18 16:28:54 -0800177}
178
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700179func (e *Error) Error() string {
180
181 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
182}
183
Jamie Gennisd4e10182014-06-12 20:06:50 -0700184// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700185// no module or singleton factories registered, so the RegisterModuleFactory and
186// RegisterSingletonFactory methods must be called before it can do anything
187// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700188func NewContext() *Context {
189 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800190 moduleFactories: make(map[string]ModuleFactory),
191 moduleGroups: make(map[string]*moduleGroup),
192 moduleInfo: make(map[Module]*moduleInfo),
193 singletonInfo: make(map[string]*singletonInfo),
194 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700195 }
196}
197
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700198// A ModuleFactory function creates a new Module object. See the
199// Context.RegisterModuleType method for details about how a registered
200// ModuleFactory is used by a Context.
201type ModuleFactory func() (m Module, propertyStructs []interface{})
202
Jamie Gennisd4e10182014-06-12 20:06:50 -0700203// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700204// Blueprints file) with a Module factory function. When the given module type
205// name is encountered in a Blueprints file during parsing, the Module factory
206// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800207// generation for the module. If a Mutator splits a module into multiple variants,
208// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700209//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700210// The module type names given here must be unique for the context. The factory
211// function should be a named function so that its package and name can be
212// included in the generated Ninja file for debugging purposes.
213//
214// The factory function returns two values. The first is the newly created
215// Module object. The second is a slice of pointers to that Module object's
216// properties structs. Each properties struct is examined when parsing a module
217// definition of this type in a Blueprints file. Exported fields of the
218// properties structs are automatically set to the property values specified in
219// the Blueprints file. The properties struct field names determine the name of
220// the Blueprints file properties that are used - the Blueprints property name
221// matches that of the properties struct field name with the first letter
222// converted to lower-case.
223//
224// The fields of the properties struct must be either []string, a string, or
225// bool. The Context will panic if a Module gets instantiated with a properties
226// struct containing a field that is not one these supported types.
227//
228// Any properties that appear in the Blueprints files that are not built-in
229// module properties (such as "name" and "deps") and do not have a corresponding
230// field in the returned module properties struct result in an error during the
231// Context's parse phase.
232//
233// As an example, the follow code:
234//
235// type myModule struct {
236// properties struct {
237// Foo string
238// Bar []string
239// }
240// }
241//
242// func NewMyModule() (blueprint.Module, []interface{}) {
243// module := new(myModule)
244// properties := &module.properties
245// return module, []interface{}{properties}
246// }
247//
248// func main() {
249// ctx := blueprint.NewContext()
250// ctx.RegisterModuleType("my_module", NewMyModule)
251// // ...
252// }
253//
254// would support parsing a module defined in a Blueprints file as follows:
255//
256// my_module {
257// name: "myName",
258// foo: "my foo string",
259// bar: ["my", "bar", "strings"],
260// }
261//
Colin Cross7ad621c2015-01-07 16:22:45 -0800262// The factory function may be called from multiple goroutines. Any accesses
263// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700264func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
265 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700266 panic(errors.New("module type name is already registered"))
267 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700268 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700269}
270
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700271// A SingletonFactory function creates a new Singleton object. See the
272// Context.RegisterSingletonType method for details about how a registered
273// SingletonFactory is used by a Context.
274type SingletonFactory func() Singleton
275
276// RegisterSingletonType registers a singleton type that will be invoked to
277// generate build actions. Each registered singleton type is instantiated and
278// and invoked exactly once as part of the generate phase.
279//
280// The singleton type names given here must be unique for the context. The
281// factory function should be a named function so that its package and name can
282// be included in the generated Ninja file for debugging purposes.
283func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700284 if _, present := c.singletonInfo[name]; present {
285 panic(errors.New("singleton name is already registered"))
286 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700287
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700288 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700289 factory: factory,
290 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700291 }
292}
293
294func singletonPkgPath(singleton Singleton) string {
295 typ := reflect.TypeOf(singleton)
296 for typ.Kind() == reflect.Ptr {
297 typ = typ.Elem()
298 }
299 return typ.PkgPath()
300}
301
302func singletonTypeName(singleton Singleton) string {
303 typ := reflect.TypeOf(singleton)
304 for typ.Kind() == reflect.Ptr {
305 typ = typ.Elem()
306 }
307 return typ.PkgPath() + "." + typ.Name()
308}
309
Colin Crossc9028482014-12-18 16:28:54 -0800310// RegisterTopDownMutator registers a mutator that will be invoked to propagate
311// dependency info top-down between Modules. Each registered mutator
312// is invoked once per Module, and is invoked on a module before being invoked
313// on any of its dependencies
314//
315// The mutator type names given here must be unique for the context.
316func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
317 for _, m := range c.mutatorInfo {
318 if m.name == name && m.topDownMutator != nil {
319 panic(fmt.Errorf("mutator name %s is already registered", name))
320 }
321 }
322
323 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
324 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800325 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800326 })
327}
328
329// RegisterBottomUpMutator registers a mutator that will be invoked to split
330// Modules into variants. Each registered mutator is invoked once per Module,
331// and is invoked on dependencies before being invoked on dependers.
332//
333// The mutator type names given here must be unique for the context.
334func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
335 for _, m := range c.mutatorInfo {
336 if m.name == name && m.bottomUpMutator != nil {
337 panic(fmt.Errorf("mutator name %s is already registered", name))
338 }
339 }
340
341 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
342 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800343 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800344 })
345}
346
Jamie Gennisd4e10182014-06-12 20:06:50 -0700347// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
348// where it encounters an unknown module type while parsing Blueprints files. By
349// default, the context will report unknown module types as an error. If this
350// method is called with ignoreUnknownModuleTypes set to true then the context
351// will silently ignore unknown module types.
352//
353// This method should generally not be used. It exists to facilitate the
354// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700355func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
356 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
357}
358
Jamie Gennisd4e10182014-06-12 20:06:50 -0700359// Parse parses a single Blueprints file from r, creating Module objects for
360// each of the module definitions encountered. If the Blueprints file contains
361// an assignment to the "subdirs" variable, then the subdirectories listed are
362// returned in the subdirs first return value.
363//
364// rootDir specifies the path to the root directory of the source tree, while
365// filename specifies the path to the Blueprints file. These paths are used for
366// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800367func (c *Context) parse(rootDir, filename string, r io.Reader,
368 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
369 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700370
Jamie Gennisec701282014-06-12 20:06:31 -0700371 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700372 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800373 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700374 }
375
Colin Crossc0dbc552015-01-02 15:19:28 -0800376 scope = parser.NewScope(scope)
377 scope.Remove("subdirs")
Colin Crossd1facc12015-01-08 14:56:03 -0800378 file, errs := parser.Parse(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700379 if len(errs) > 0 {
380 for i, err := range errs {
381 if parseErr, ok := err.(*parser.ParseError); ok {
382 err = &Error{
383 Err: parseErr.Err,
384 Pos: parseErr.Pos,
385 }
386 errs[i] = err
387 }
388 }
389
390 // If there were any parse errors don't bother trying to interpret the
391 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800392 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700393 }
394
Colin Crossd1facc12015-01-08 14:56:03 -0800395 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700396 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800397 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398 switch def := def.(type) {
399 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800400 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700401
402 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800403 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700404 default:
405 panic("unknown definition type")
406 }
407
408 if len(newErrs) > 0 {
409 errs = append(errs, newErrs...)
410 if len(errs) > maxErrors {
411 break
412 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800413 } else if newModule != nil {
414 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700415 }
416 }
417
Colin Crossc0dbc552015-01-02 15:19:28 -0800418 subdirs, newErrs := c.processSubdirs(scope)
419 if len(newErrs) > 0 {
420 errs = append(errs, newErrs...)
421 }
422
Colin Cross7ad621c2015-01-07 16:22:45 -0800423 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800424}
425
Colin Cross7ad621c2015-01-07 16:22:45 -0800426type stringAndScope struct {
427 string
428 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700429}
430
Jamie Gennisd4e10182014-06-12 20:06:50 -0700431// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
432// at rootFile. When it encounters a Blueprints file with a set of subdirs
433// listed it recursively parses any Blueprints files found in those
434// subdirectories.
435//
436// If no errors are encountered while parsing the files, the list of paths on
437// which the future output will depend is returned. This list will include both
438// Blueprints file paths as well as directory paths for cases where wildcard
439// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700440func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
441 errs []error) {
442
Colin Cross7ad621c2015-01-07 16:22:45 -0800443 c.dependenciesReady = false
444
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700445 rootDir := filepath.Dir(rootFile)
446
Colin Cross7ad621c2015-01-07 16:22:45 -0800447 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700448
Colin Cross7ad621c2015-01-07 16:22:45 -0800449 // Channels to receive data back from parseBlueprintsFile goroutines
450 blueprintsCh := make(chan stringAndScope)
451 errsCh := make(chan []error)
452 modulesCh := make(chan []*moduleInfo)
453 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700454
Colin Cross7ad621c2015-01-07 16:22:45 -0800455 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
456 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700457
Colin Cross7ad621c2015-01-07 16:22:45 -0800458 // Number of outstanding goroutines to wait for
459 count := 0
460
461 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
462 count++
463 go func() {
464 c.parseBlueprintsFile(filename, scope, rootDir,
465 errsCh, modulesCh, blueprintsCh, depsCh)
466 doneCh <- struct{}{}
467 }()
468 }
469
470 tooManyErrors := false
471
472 startParseBlueprintsFile(rootFile, nil)
473
474loop:
475 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700476 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800477 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 }
479
Colin Cross7ad621c2015-01-07 16:22:45 -0800480 select {
481 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700482 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800483 case dep := <-depsCh:
484 deps = append(deps, dep)
485 case modules := <-modulesCh:
486 newErrs := c.addModules(modules)
487 errs = append(errs, newErrs...)
488 case blueprint := <-blueprintsCh:
489 if tooManyErrors {
490 continue
491 }
492 if blueprintsSet[blueprint.string] {
493 continue
494 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700495
Colin Cross7ad621c2015-01-07 16:22:45 -0800496 blueprintsSet[blueprint.string] = true
497 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
498 case <-doneCh:
499 count--
500 if count == 0 {
501 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700502 }
503 }
504 }
505
Colin Cross7ad621c2015-01-07 16:22:45 -0800506 return
507}
508
509// parseBlueprintFile parses a single Blueprints file, returning any errors through
510// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
511// blueprintsCh, and any dependencies on Blueprints files or directories through
512// depsCh.
513func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
514 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
515 depsCh chan<- string) {
516
517 dir := filepath.Dir(filename)
518
519 file, err := os.Open(filename)
520 if err != nil {
521 errsCh <- []error{err}
522 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700523 }
524
Colin Cross7ad621c2015-01-07 16:22:45 -0800525 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
526 if len(errs) > 0 {
527 errsCh <- errs
528 }
529
530 err = file.Close()
531 if err != nil {
532 errsCh <- []error{err}
533 }
534
535 modulesCh <- modules
536
537 for _, subdir := range subdirs {
538 subdir = filepath.Join(dir, subdir)
539
540 dirPart, filePart := filepath.Split(subdir)
541 dirPart = filepath.Clean(dirPart)
542
543 if filePart == "*" {
544 foundSubdirs, err := listSubdirs(dirPart)
545 if err != nil {
546 errsCh <- []error{err}
547 return
548 }
549
550 for _, foundSubdir := range foundSubdirs {
551 subBlueprints := filepath.Join(dirPart, foundSubdir,
552 "Blueprints")
553
554 _, err := os.Stat(subBlueprints)
555 if os.IsNotExist(err) {
556 // There is no Blueprints file in this subdirectory. We
557 // need to add the directory to the list of dependencies
558 // so that if someone adds a Blueprints file in the
559 // future we'll pick it up.
560 depsCh <- filepath.Dir(subBlueprints)
561 } else {
562 depsCh <- subBlueprints
563 blueprintsCh <- stringAndScope{
564 subBlueprints,
565 subScope,
566 }
567 }
568 }
569
570 // We now depend on the directory itself because if any new
571 // subdirectories get added or removed we need to rebuild the
572 // Ninja manifest.
573 depsCh <- dirPart
574 } else {
575 subBlueprints := filepath.Join(subdir, "Blueprints")
576 depsCh <- subBlueprints
577 blueprintsCh <- stringAndScope{
578 subBlueprints,
579 subScope,
580 }
581
582 }
583 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700584}
585
586func listSubdirs(dir string) ([]string, error) {
587 d, err := os.Open(dir)
588 if err != nil {
589 return nil, err
590 }
591 defer d.Close()
592
593 infos, err := d.Readdir(-1)
594 if err != nil {
595 return nil, err
596 }
597
598 var subdirs []string
599 for _, info := range infos {
Jamie Gennis0c35b2d2014-09-25 13:15:10 -0700600 isDotFile := strings.HasPrefix(info.Name(), ".")
601 if info.IsDir() && !isDotFile {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700602 subdirs = append(subdirs, info.Name())
603 }
604 }
605
606 return subdirs, nil
607}
608
Colin Crossc0dbc552015-01-02 15:19:28 -0800609func (c *Context) processSubdirs(
610 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700611
Colin Crossc0dbc552015-01-02 15:19:28 -0800612 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700613 switch assignment.Value.Type {
614 case parser.List:
615 subdirs = make([]string, 0, len(assignment.Value.ListValue))
616
617 for _, value := range assignment.Value.ListValue {
618 if value.Type != parser.String {
619 // The parser should not produce this.
620 panic("non-string value found in list")
621 }
622
623 dirPart, filePart := filepath.Split(value.StringValue)
624 if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
625 strings.ContainsRune(dirPart, '*') {
626
627 errs = append(errs, &Error{
628 Err: fmt.Errorf("subdirs may only wildcard whole " +
629 "directories"),
630 Pos: value.Pos,
631 })
632
633 continue
634 }
635
636 subdirs = append(subdirs, value.StringValue)
637 }
638
639 if len(errs) > 0 {
640 subdirs = nil
641 }
642
643 return
644
645 case parser.Bool, parser.String:
646 errs = []error{
647 &Error{
648 Err: fmt.Errorf("subdirs must be a list of strings"),
649 Pos: assignment.Pos,
650 },
651 }
652
653 return
654
655 default:
656 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
657 }
658 }
659
Colin Crossc0dbc552015-01-02 15:19:28 -0800660 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700661}
662
Colin Crossc9028482014-12-18 16:28:54 -0800663func (c *Context) createVariants(origModule *moduleInfo, mutatorName string,
Colin Cross174ae052015-03-03 17:37:03 -0800664 variantNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800665
666 newModules := []*moduleInfo{}
667 origVariantName := origModule.name
Colin Crossc9028482014-12-18 16:28:54 -0800668
Colin Cross174ae052015-03-03 17:37:03 -0800669 var errs []error
670
Colin Crossc9028482014-12-18 16:28:54 -0800671 for i, variantName := range variantNames {
Colin Crossed342d92015-03-11 00:57:25 -0700672 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800673 factory, ok := c.moduleFactories[typeName]
674 if !ok {
675 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
676 }
677
678 var newLogicModule Module
679 var newProperties []interface{}
680
681 if i == 0 {
682 // Reuse the existing module for the first new variant
683 newLogicModule = origModule.logicModule
684 newProperties = origModule.moduleProperties
685 } else {
686 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700687 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800688 }
689 newLogicModule, newProperties = factory()
690
691 newProperties = append(props, newProperties...)
692
693 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700694 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800695 }
696
697 for i := range newProperties {
698 dst := reflect.ValueOf(newProperties[i]).Elem()
699 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
700
701 proptools.CopyProperties(dst, src)
702 }
703 }
704
705 newVariantName := append([]subName(nil), origVariantName...)
706 newSubName := subName{
707 mutatorName: mutatorName,
708 variantName: variantName,
709 }
710 newVariantName = append(newVariantName, newSubName)
711
Colin Crossed342d92015-03-11 00:57:25 -0700712 m := *origModule
713 newModule := &m
714 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
715 newModule.logicModule = newLogicModule
716 newModule.name = newVariantName
717 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800718
719 newModules = append(newModules, newModule)
720 c.moduleInfo[newModule.logicModule] = newModule
721
Colin Cross174ae052015-03-03 17:37:03 -0800722 newErrs := c.convertDepsToVariant(newModule, newSubName)
723 if len(newErrs) > 0 {
724 errs = append(errs, newErrs...)
725 }
Colin Crossc9028482014-12-18 16:28:54 -0800726 }
727
728 // Mark original variant as invalid. Modules that depend on this module will still
729 // depend on origModule, but we'll fix it when the mutator is called on them.
730 origModule.logicModule = nil
731 origModule.splitModules = newModules
732
Colin Cross174ae052015-03-03 17:37:03 -0800733 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800734}
735
Colin Cross174ae052015-03-03 17:37:03 -0800736func (c *Context) convertDepsToVariant(module *moduleInfo, newSubName subName) (errs []error) {
737
Colin Crossc9028482014-12-18 16:28:54 -0800738 for i, dep := range module.directDeps {
739 if dep.logicModule == nil {
740 var newDep *moduleInfo
741 for _, m := range dep.splitModules {
742 if len(m.name) > 0 && m.name[len(m.name)-1] == newSubName {
743 newDep = m
744 break
745 }
746 }
747 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800748 errs = append(errs, &Error{
749 Err: fmt.Errorf("failed to find variant %q for module %q needed by %q",
Colin Crossed342d92015-03-11 00:57:25 -0700750 newSubName.variantName, dep.properties.Name,
751 module.properties.Name),
752 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800753 })
754 continue
Colin Crossc9028482014-12-18 16:28:54 -0800755 }
756 module.directDeps[i] = newDep
757 }
758 }
Colin Cross174ae052015-03-03 17:37:03 -0800759
760 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800761}
762
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700763func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800764 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700765
Colin Crossd1facc12015-01-08 14:56:03 -0800766 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700767 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700768 if !ok {
769 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800770 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700771 }
772
Colin Cross7ad621c2015-01-07 16:22:45 -0800773 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700774 &Error{
775 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800776 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700777 },
778 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700779 }
780
Colin Crossbbfa51a2014-12-17 16:12:41 -0800781 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700782
783 module := &moduleInfo{
784 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700785 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700786 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700787 }
788
Jamie Gennis87622922014-09-30 11:38:25 -0700789 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700790 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700791 }
792 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700793 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700794
Jamie Gennis87622922014-09-30 11:38:25 -0700795 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700796 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800797 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700798 }
799
Colin Crossed342d92015-03-11 00:57:25 -0700800 module.pos = moduleDef.Type.Pos
801 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700802 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700803 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700804 }
805
Colin Cross7ad621c2015-01-07 16:22:45 -0800806 return module, nil
807}
808
809func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
810 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700811 name := module.properties.Name
812 c.moduleInfo[module.logicModule] = module
813
814 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800815 errs = append(errs, []error{
816 &Error{
817 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700818 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800819 },
820 &Error{
821 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700822 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800823 },
824 }...)
825 continue
Colin Crossed342d92015-03-11 00:57:25 -0700826 } else {
827 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800828
Colin Crossed342d92015-03-11 00:57:25 -0700829 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
830 // already exists
831 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
832 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
833 }
834
835 c.moduleNinjaNames[ninjaName] = group
836
837 group := &moduleGroup{
838 name: module.properties.Name,
839 ninjaName: ninjaName,
840 modules: []*moduleInfo{module},
841 }
842 module.group = group
843 c.moduleGroups[name] = group
844 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800845 }
846
847 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700848}
849
Jamie Gennisd4e10182014-06-12 20:06:50 -0700850// ResolveDependencies checks that the dependencies specified by all of the
851// modules defined in the parsed Blueprints files are valid. This means that
852// the modules depended upon are defined and that no circular dependencies
853// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700854//
855// The config argument is made available to all of the DynamicDependerModule
856// objects via the Config method on the DynamicDependerModuleContext objects
857// passed to their DynamicDependencies method.
858func (c *Context) ResolveDependencies(config interface{}) []error {
859 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700860 if len(errs) > 0 {
861 return errs
862 }
863
Colin Cross691a60d2015-01-07 18:08:56 -0800864 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700865 if len(errs) > 0 {
866 return errs
867 }
868
869 c.dependenciesReady = true
870 return nil
871}
872
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700873// moduleDepNames returns the sorted list of dependency names for a given
874// module. If the module implements the DynamicDependerModule interface then
875// this set consists of the union of those module names listed in its "deps"
876// property and those returned by its DynamicDependencies method. Otherwise it
877// is simply those names listed in its "deps" property.
Colin Crossed342d92015-03-11 00:57:25 -0700878func (c *Context) moduleDepNames(module *moduleInfo,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700879 config interface{}) ([]string, []error) {
880
881 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800882 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700883
Colin Crossed342d92015-03-11 00:57:25 -0700884 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800885 if !depNamesSet[depName] {
886 depNamesSet[depName] = true
887 depNames = append(depNames, depName)
888 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700889 }
890
Colin Crossed342d92015-03-11 00:57:25 -0700891 logicModule := module.logicModule
Colin Crossbbfa51a2014-12-17 16:12:41 -0800892 dynamicDepender, ok := logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700893 if ok {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800894 ddmctx := &baseModuleContext{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700895 context: c,
896 config: config,
Colin Crossed342d92015-03-11 00:57:25 -0700897 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700898 }
899
900 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
901
902 if len(ddmctx.errs) > 0 {
903 return nil, ddmctx.errs
904 }
905
906 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800907 if !depNamesSet[depName] {
908 depNamesSet[depName] = true
909 depNames = append(depNames, depName)
910 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700911 }
912 }
913
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700914 return depNames, nil
915}
916
Colin Crossbbfa51a2014-12-17 16:12:41 -0800917// resolveDependencies populates the moduleGroup.modules[0].directDeps list for every
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700918// module. In doing so it checks for missing dependencies and self-dependant
919// modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700920func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800921 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -0700922 for _, module := range group.modules {
923 depNames, newErrs := c.moduleDepNames(module, config)
Colin Crossc9028482014-12-18 16:28:54 -0800924 if len(newErrs) > 0 {
925 errs = append(errs, newErrs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700926 continue
927 }
Colin Crossed342d92015-03-11 00:57:25 -0700928
929 module.directDeps = make([]*moduleInfo, 0, len(depNames))
930
931 for _, depName := range depNames {
932 newErrs := c.addDependency(module, depName)
933 if len(newErrs) > 0 {
934 errs = append(errs, newErrs...)
935 continue
936 }
937 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700938 }
939 }
940
941 return
942}
943
Colin Crossc9028482014-12-18 16:28:54 -0800944func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -0700945 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -0800946
Colin Crossed342d92015-03-11 00:57:25 -0700947 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -0800948 return []error{&Error{
949 Err: fmt.Errorf("%q depends on itself", depName),
950 Pos: depsPos,
951 }}
952 }
953
954 depInfo, ok := c.moduleGroups[depName]
955 if !ok {
956 return []error{&Error{
957 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -0700958 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -0800959 Pos: depsPos,
960 }}
961 }
962
963 if len(depInfo.modules) != 1 {
964 panic(fmt.Sprintf("cannot add dependency from %s to %s, it already has multiple variants",
Colin Crossed342d92015-03-11 00:57:25 -0700965 module.properties.Name, depInfo.modules[0].properties.Name))
Colin Crossc9028482014-12-18 16:28:54 -0800966 }
967
968 module.directDeps = append(module.directDeps, depInfo.modules[0])
969
970 return nil
971}
972
Colin Cross8900e9b2015-03-02 14:03:01 -0800973func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleGroup) bool) {
Colin Cross691a60d2015-01-07 18:08:56 -0800974 doneCh := make(chan *moduleGroup)
975 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -0800976 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -0800977
978 for _, group := range c.moduleGroupsSorted {
979 group.waitingCount = group.depsCount
980 }
981
982 visitOne := func(group *moduleGroup) {
983 count++
984 go func() {
Colin Cross8900e9b2015-03-02 14:03:01 -0800985 ret := visit(group)
986 if ret {
987 cancel = true
988 }
Colin Cross691a60d2015-01-07 18:08:56 -0800989 doneCh <- group
990 }()
991 }
992
993 for _, group := range c.moduleGroupsSorted {
994 if group.waitingCount == 0 {
995 visitOne(group)
996 }
997 }
998
Colin Cross11e3b0d2015-02-04 10:41:00 -0800999 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001000 select {
1001 case doneGroup := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001002 if !cancel {
1003 for _, parent := range doneGroup.reverseDeps {
1004 parent.waitingCount--
1005 if parent.waitingCount == 0 {
1006 visitOne(parent)
1007 }
Colin Cross691a60d2015-01-07 18:08:56 -08001008 }
1009 }
1010 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001011 }
1012 }
1013}
1014
1015// updateDependencies recursively walks the module dependency graph and updates
1016// additional fields based on the dependencies. It builds a sorted list of modules
1017// such that dependencies of a module always appear first, and populates reverse
1018// dependency links and counts of total dependencies. It also reports errors when
1019// it encounters dependency cycles. This should called after resolveDependencies,
1020// as well as after any mutator pass has called addDependency
1021func (c *Context) updateDependencies() (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001022 visited := make(map[*moduleGroup]bool) // modules that were already checked
1023 checking := make(map[*moduleGroup]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001024
Colin Crossbbfa51a2014-12-17 16:12:41 -08001025 sorted := make([]*moduleGroup, 0, len(c.moduleGroups))
Colin Cross573a2fd2014-12-17 14:16:51 -08001026
Colin Crossbbfa51a2014-12-17 16:12:41 -08001027 var check func(group *moduleGroup) []*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001028
Colin Cross10b54db2015-03-11 14:40:30 -07001029 cycleError := func(cycle []*moduleGroup) {
1030 // We are the "start" of the cycle, so we're responsible
1031 // for generating the errors. The cycle list is in
1032 // reverse order because all the 'check' calls append
1033 // their own module to the list.
1034 errs = append(errs, &Error{
1035 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Crossed342d92015-03-11 00:57:25 -07001036 Pos: cycle[len(cycle)-1].modules[0].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001037 })
1038
1039 // Iterate backwards through the cycle list.
1040 curGroup := cycle[len(cycle)-1]
1041 for i := len(cycle) - 1; i >= 0; i-- {
1042 nextGroup := cycle[i]
1043 errs = append(errs, &Error{
1044 Err: fmt.Errorf(" %q depends on %q",
Colin Crossed342d92015-03-11 00:57:25 -07001045 curGroup.name,
1046 nextGroup.name),
1047 Pos: curGroup.modules[0].propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001048 })
1049 curGroup = nextGroup
1050 }
1051 }
1052
Colin Crossbbfa51a2014-12-17 16:12:41 -08001053 check = func(group *moduleGroup) []*moduleGroup {
1054 visited[group] = true
1055 checking[group] = true
1056 defer delete(checking, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001057
Colin Crossbbfa51a2014-12-17 16:12:41 -08001058 deps := make(map[*moduleGroup]bool)
1059 for _, module := range group.modules {
1060 for _, dep := range module.directDeps {
1061 deps[dep.group] = true
1062 }
1063 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001064
Colin Cross691a60d2015-01-07 18:08:56 -08001065 group.reverseDeps = []*moduleGroup{}
1066 group.depsCount = len(deps)
1067
Colin Crossbbfa51a2014-12-17 16:12:41 -08001068 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001069 if checking[dep] {
1070 // This is a cycle.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001071 return []*moduleGroup{dep, group}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001072 }
1073
1074 if !visited[dep] {
1075 cycle := check(dep)
1076 if cycle != nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001077 if cycle[0] == group {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001078 // We are the "start" of the cycle, so we're responsible
1079 // for generating the errors. The cycle list is in
1080 // reverse order because all the 'check' calls append
1081 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001082 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001083
1084 // We can continue processing this module's children to
1085 // find more cycles. Since all the modules that were
1086 // part of the found cycle were marked as visited we
1087 // won't run into that cycle again.
1088 } else {
1089 // We're not the "start" of the cycle, so we just append
1090 // our module to the list and return it.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001091 return append(cycle, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001092 }
1093 }
1094 }
Colin Cross691a60d2015-01-07 18:08:56 -08001095
1096 dep.reverseDeps = append(dep.reverseDeps, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001097 }
1098
Colin Crossbbfa51a2014-12-17 16:12:41 -08001099 sorted = append(sorted, group)
Colin Cross573a2fd2014-12-17 14:16:51 -08001100
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001101 return nil
1102 }
1103
Colin Crossbbfa51a2014-12-17 16:12:41 -08001104 for _, group := range c.moduleGroups {
1105 if !visited[group] {
1106 cycle := check(group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001107 if cycle != nil {
Colin Cross10b54db2015-03-11 14:40:30 -07001108 if cycle[len(cycle)-1] != group {
1109 panic("inconceivable!")
1110 }
1111 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001112 }
1113 }
1114 }
1115
Colin Crossbbfa51a2014-12-17 16:12:41 -08001116 c.moduleGroupsSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001117
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001118 return
1119}
1120
Jamie Gennisd4e10182014-06-12 20:06:50 -07001121// PrepareBuildActions generates an internal representation of all the build
1122// actions that need to be performed. This process involves invoking the
1123// GenerateBuildActions method on each of the Module objects created during the
1124// parse phase and then on each of the registered Singleton objects.
1125//
1126// If the ResolveDependencies method has not already been called it is called
1127// automatically by this method.
1128//
1129// The config argument is made available to all of the Module and Singleton
1130// objects via the Config method on the ModuleContext and SingletonContext
1131// objects passed to GenerateBuildActions. It is also passed to the functions
1132// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1133// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001134//
1135// The returned deps is a list of the ninja files dependencies that were added
1136// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1137// SingletonContext.AddNinjaFileDeps() methods.
1138func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001139 c.buildActionsReady = false
1140
1141 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001142 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001143 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001144 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001145 }
1146 }
1147
Colin Crossc9028482014-12-18 16:28:54 -08001148 errs = c.runMutators(config)
1149 if len(errs) > 0 {
1150 return nil, errs
1151 }
1152
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001153 liveGlobals := newLiveTracker(config)
1154
1155 c.initSpecialVariables()
1156
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001157 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001158 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001159 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001160 }
1161
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001162 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001163 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001164 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001165 }
1166
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001167 deps = append(depsModules, depsSingletons...)
1168
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001169 if c.buildDir != nil {
1170 liveGlobals.addNinjaStringDeps(c.buildDir)
1171 }
1172
1173 pkgNames := c.makeUniquePackageNames(liveGlobals)
1174
1175 // This will panic if it finds a problem since it's a programming error.
1176 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1177
1178 c.pkgNames = pkgNames
1179 c.globalVariables = liveGlobals.variables
1180 c.globalPools = liveGlobals.pools
1181 c.globalRules = liveGlobals.rules
1182
1183 c.buildActionsReady = true
1184
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001185 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001186}
1187
Colin Crossc9028482014-12-18 16:28:54 -08001188func (c *Context) runMutators(config interface{}) (errs []error) {
1189 for _, mutator := range c.mutatorInfo {
1190 if mutator.topDownMutator != nil {
1191 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1192 } else if mutator.bottomUpMutator != nil {
1193 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1194 } else {
1195 panic("no mutator set on " + mutator.name)
1196 }
1197 if len(errs) > 0 {
1198 return errs
1199 }
1200 }
1201
1202 return nil
1203}
1204
1205func (c *Context) runTopDownMutator(config interface{},
1206 name string, mutator TopDownMutator) (errs []error) {
1207
1208 for i := 0; i < len(c.moduleGroupsSorted); i++ {
1209 group := c.moduleGroupsSorted[len(c.moduleGroupsSorted)-1-i]
1210 for _, module := range group.modules {
1211 mctx := &mutatorContext{
1212 baseModuleContext: baseModuleContext{
1213 context: c,
1214 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001215 module: module,
Colin Crossc9028482014-12-18 16:28:54 -08001216 },
Colin Crossed342d92015-03-11 00:57:25 -07001217 name: name,
Colin Crossc9028482014-12-18 16:28:54 -08001218 }
1219
1220 mutator(mctx)
1221 if len(mctx.errs) > 0 {
1222 errs = append(errs, mctx.errs...)
1223 return errs
1224 }
1225 }
1226 }
1227
1228 return errs
1229}
1230
1231func (c *Context) runBottomUpMutator(config interface{},
1232 name string, mutator BottomUpMutator) (errs []error) {
1233
1234 dependenciesModified := false
1235
1236 for _, group := range c.moduleGroupsSorted {
1237 newModules := make([]*moduleInfo, 0, len(group.modules))
1238
1239 for _, module := range group.modules {
1240 mctx := &mutatorContext{
1241 baseModuleContext: baseModuleContext{
1242 context: c,
1243 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001244 module: module,
Colin Crossc9028482014-12-18 16:28:54 -08001245 },
Colin Crossed342d92015-03-11 00:57:25 -07001246 name: name,
Colin Crossc9028482014-12-18 16:28:54 -08001247 }
1248
1249 mutator(mctx)
1250 if len(mctx.errs) > 0 {
1251 errs = append(errs, mctx.errs...)
1252 return errs
1253 }
1254
1255 // Fix up any remaining dependencies on modules that were split into variants
1256 // by replacing them with the first variant
1257 for i, dep := range module.directDeps {
1258 if dep.logicModule == nil {
1259 module.directDeps[i] = dep.splitModules[0]
1260 }
1261 }
1262
1263 if mctx.dependenciesModified {
1264 dependenciesModified = true
1265 }
1266
1267 if module.splitModules != nil {
1268 newModules = append(newModules, module.splitModules...)
1269 } else {
1270 newModules = append(newModules, module)
1271 }
1272 }
1273
1274 group.modules = newModules
1275 }
1276
1277 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001278 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001279 if len(errs) > 0 {
1280 return errs
1281 }
1282 }
1283
1284 return errs
1285}
1286
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001287func (c *Context) initSpecialVariables() {
1288 c.buildDir = nil
1289 c.requiredNinjaMajor = 1
1290 c.requiredNinjaMinor = 1
1291 c.requiredNinjaMicro = 0
1292}
1293
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001294func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001295 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001296
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001297 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001298 var errs []error
1299
Colin Cross691a60d2015-01-07 18:08:56 -08001300 cancelCh := make(chan struct{})
1301 errsCh := make(chan []error)
1302 depsCh := make(chan []string)
1303
1304 go func() {
1305 for {
1306 select {
1307 case <-cancelCh:
1308 close(cancelCh)
1309 return
1310 case newErrs := <-errsCh:
1311 errs = append(errs, newErrs...)
1312 case newDeps := <-depsCh:
1313 deps = append(deps, newDeps...)
1314
1315 }
1316 }
1317 }()
1318
Colin Cross8900e9b2015-03-02 14:03:01 -08001319 c.parallelVisitAllBottomUp(func(group *moduleGroup) bool {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001320 for _, module := range group.modules {
Colin Cross6134a5c2015-02-10 11:26:26 -08001321 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1322 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1323 // just set it to nil.
1324 prefix := moduleNamespacePrefix(group.ninjaName + "_" + module.subName())
1325 scope := newLocalScope(nil, prefix)
1326
Colin Crossbbfa51a2014-12-17 16:12:41 -08001327 mctx := &moduleContext{
Colin Cross1455a0f2014-12-17 13:23:56 -08001328 baseModuleContext: baseModuleContext{
1329 context: c,
1330 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001331 module: module,
Colin Crossb2e7b5d2014-11-11 14:18:53 -08001332 },
Colin Crossed342d92015-03-11 00:57:25 -07001333 scope: scope,
Colin Crossbbfa51a2014-12-17 16:12:41 -08001334 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001335
Colin Crossbbfa51a2014-12-17 16:12:41 -08001336 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001337
Colin Crossbbfa51a2014-12-17 16:12:41 -08001338 if len(mctx.errs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001339 errsCh <- mctx.errs
Colin Cross8900e9b2015-03-02 14:03:01 -08001340 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001341 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001342
Colin Cross691a60d2015-01-07 18:08:56 -08001343 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001344
Colin Crossbbfa51a2014-12-17 16:12:41 -08001345 newErrs := c.processLocalBuildActions(&group.actionDefs,
1346 &mctx.actionDefs, liveGlobals)
1347 if len(newErrs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001348 errsCh <- newErrs
Colin Cross8900e9b2015-03-02 14:03:01 -08001349 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001350 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001351 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001352 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001353 })
1354
1355 cancelCh <- struct{}{}
1356 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001357
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001358 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001359}
1360
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001361func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001362 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001363
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001364 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001365 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001366
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001367 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001368 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1369 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1370 // just set it to nil.
1371 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001372
1373 sctx := &singletonContext{
1374 context: c,
1375 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001376 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001377 }
1378
1379 info.singleton.GenerateBuildActions(sctx)
1380
1381 if len(sctx.errs) > 0 {
1382 errs = append(errs, sctx.errs...)
1383 if len(errs) > maxErrors {
1384 break
1385 }
1386 continue
1387 }
1388
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001389 deps = append(deps, sctx.ninjaFileDeps...)
1390
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001391 newErrs := c.processLocalBuildActions(&info.actionDefs,
1392 &sctx.actionDefs, liveGlobals)
1393 errs = append(errs, newErrs...)
1394 if len(errs) > maxErrors {
1395 break
1396 }
1397 }
1398
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001399 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001400}
1401
1402func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1403 liveGlobals *liveTracker) []error {
1404
1405 var errs []error
1406
1407 // First we go through and add everything referenced by the module's
1408 // buildDefs to the live globals set. This will end up adding the live
1409 // locals to the set as well, but we'll take them out after.
1410 for _, def := range in.buildDefs {
1411 err := liveGlobals.AddBuildDefDeps(def)
1412 if err != nil {
1413 errs = append(errs, err)
1414 }
1415 }
1416
1417 if len(errs) > 0 {
1418 return errs
1419 }
1420
Colin Crossc9028482014-12-18 16:28:54 -08001421 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001422
1423 // We use the now-incorrect set of live "globals" to determine which local
1424 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001425 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001426 for _, v := range in.variables {
1427 _, isLive := liveGlobals.variables[v]
1428 if isLive {
1429 out.variables = append(out.variables, v)
1430 delete(liveGlobals.variables, v)
1431 }
1432 }
1433
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001434 for _, r := range in.rules {
1435 _, isLive := liveGlobals.rules[r]
1436 if isLive {
1437 out.rules = append(out.rules, r)
1438 delete(liveGlobals.rules, r)
1439 }
1440 }
1441
1442 return nil
1443}
1444
Colin Crossbbfa51a2014-12-17 16:12:41 -08001445func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1446 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001447
Colin Crossbbfa51a2014-12-17 16:12:41 -08001448 var walk func(module *moduleInfo)
1449 walk = func(module *moduleInfo) {
1450 visited[module] = true
1451 for _, moduleDep := range module.directDeps {
1452 if !visited[moduleDep] {
1453 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001454 }
1455 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001456
Colin Crossbbfa51a2014-12-17 16:12:41 -08001457 if module != topModule {
1458 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459 }
1460 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001461
1462 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001463}
1464
Colin Crossbbfa51a2014-12-17 16:12:41 -08001465func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001466 visit func(Module)) {
1467
Colin Crossbbfa51a2014-12-17 16:12:41 -08001468 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469
Colin Crossbbfa51a2014-12-17 16:12:41 -08001470 var walk func(module *moduleInfo)
1471 walk = func(module *moduleInfo) {
1472 visited[module] = true
1473 for _, moduleDep := range module.directDeps {
1474 if !visited[moduleDep] {
1475 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001476 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001477 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001478
1479 if module != topModule {
1480 if pred(module.logicModule) {
1481 visit(module.logicModule)
1482 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001483 }
1484 }
1485
Colin Crossbbfa51a2014-12-17 16:12:41 -08001486 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001487}
1488
Colin Crossc9028482014-12-18 16:28:54 -08001489func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1490 for _, dep := range module.directDeps {
1491 visit(dep.logicModule)
1492 }
1493}
1494
1495func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1496 visit func(Module)) {
1497
1498 for _, dep := range module.directDeps {
1499 if pred(dep.logicModule) {
1500 visit(dep.logicModule)
1501 }
1502 }
1503}
1504
Jamie Gennisc15544d2014-09-24 20:26:52 -07001505func (c *Context) sortedModuleNames() []string {
1506 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001507 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1508 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001509 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1510 moduleName)
1511 }
1512 sort.Strings(c.cachedSortedModuleNames)
1513 }
1514
1515 return c.cachedSortedModuleNames
1516}
1517
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001518func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001519 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001520 group := c.moduleGroups[moduleName]
1521 for _, module := range group.modules {
1522 visit(module.logicModule)
1523 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001524 }
1525}
1526
1527func (c *Context) visitAllModulesIf(pred func(Module) bool,
1528 visit func(Module)) {
1529
Jamie Gennisc15544d2014-09-24 20:26:52 -07001530 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001531 group := c.moduleGroups[moduleName]
1532 for _, module := range group.modules {
1533 if pred(module.logicModule) {
1534 visit(module.logicModule)
1535 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001536 }
1537 }
1538}
1539
1540func (c *Context) requireNinjaVersion(major, minor, micro int) {
1541 if major != 1 {
1542 panic("ninja version with major version != 1 not supported")
1543 }
1544 if c.requiredNinjaMinor < minor {
1545 c.requiredNinjaMinor = minor
1546 c.requiredNinjaMicro = micro
1547 }
1548 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1549 c.requiredNinjaMicro = micro
1550 }
1551}
1552
1553func (c *Context) setBuildDir(value *ninjaString) {
1554 if c.buildDir != nil {
1555 panic("buildDir set multiple times")
1556 }
1557 c.buildDir = value
1558}
1559
1560func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001561 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001562
Jamie Gennis2fb20952014-10-03 02:49:58 -07001563 pkgs := make(map[string]*PackageContext)
1564 pkgNames := make(map[*PackageContext]string)
1565 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001566
Jamie Gennis2fb20952014-10-03 02:49:58 -07001567 processPackage := func(pctx *PackageContext) {
1568 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001569 // This is a built-in rule and has no package.
1570 return
1571 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001572 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001573 // We've already processed this package.
1574 return
1575 }
1576
Jamie Gennis2fb20952014-10-03 02:49:58 -07001577 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001578 if present {
1579 // Short name collision. Both this package and the one that's
1580 // already there need to use their full names. We leave the short
1581 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001582 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001583 longPkgNames[otherPkg] = true
1584 } else {
1585 // No collision so far. Tentatively set the package's name to be
1586 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001587 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001588 }
1589 }
1590
1591 // We try to give all packages their short name, but when we get collisions
1592 // we need to use the full unique package name.
1593 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001594 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001595 }
1596 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001597 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001598 }
1599 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001600 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001601 }
1602
1603 // Add the packages that had collisions using their full unique names. This
1604 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001605 for pctx := range longPkgNames {
1606 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001607 }
1608
1609 return pkgNames
1610}
1611
1612func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001613 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001614
1615 visited := make(map[Variable]bool) // variables that were already checked
1616 checking := make(map[Variable]bool) // variables actively being checked
1617
1618 var check func(v Variable) []Variable
1619
1620 check = func(v Variable) []Variable {
1621 visited[v] = true
1622 checking[v] = true
1623 defer delete(checking, v)
1624
1625 value := variables[v]
1626 for _, dep := range value.variables {
1627 if checking[dep] {
1628 // This is a cycle.
1629 return []Variable{dep, v}
1630 }
1631
1632 if !visited[dep] {
1633 cycle := check(dep)
1634 if cycle != nil {
1635 if cycle[0] == v {
1636 // We are the "start" of the cycle, so we're responsible
1637 // for generating the errors. The cycle list is in
1638 // reverse order because all the 'check' calls append
1639 // their own module to the list.
1640 msgs := []string{"detected variable reference cycle:"}
1641
1642 // Iterate backwards through the cycle list.
1643 curName := v.fullName(pkgNames)
1644 curValue := value.Value(pkgNames)
1645 for i := len(cycle) - 1; i >= 0; i-- {
1646 next := cycle[i]
1647 nextName := next.fullName(pkgNames)
1648 nextValue := variables[next].Value(pkgNames)
1649
1650 msgs = append(msgs, fmt.Sprintf(
1651 " %q depends on %q", curName, nextName))
1652 msgs = append(msgs, fmt.Sprintf(
1653 " [%s = %s]", curName, curValue))
1654
1655 curName = nextName
1656 curValue = nextValue
1657 }
1658
1659 // Variable reference cycles are a programming error,
1660 // not the fault of the Blueprint file authors.
1661 panic(strings.Join(msgs, "\n"))
1662 } else {
1663 // We're not the "start" of the cycle, so we just append
1664 // our module to the list and return it.
1665 return append(cycle, v)
1666 }
1667 }
1668 }
1669 }
1670
1671 return nil
1672 }
1673
1674 for v := range variables {
1675 if !visited[v] {
1676 cycle := check(v)
1677 if cycle != nil {
1678 panic("inconceivable!")
1679 }
1680 }
1681 }
1682}
1683
Jamie Gennisaf435562014-10-27 22:34:56 -07001684// AllTargets returns a map all the build target names to the rule used to build
1685// them. This is the same information that is output by running 'ninja -t
1686// targets all'. If this is called before PrepareBuildActions successfully
1687// completes then ErrbuildActionsNotReady is returned.
1688func (c *Context) AllTargets() (map[string]string, error) {
1689 if !c.buildActionsReady {
1690 return nil, ErrBuildActionsNotReady
1691 }
1692
1693 targets := map[string]string{}
1694
1695 // Collect all the module build targets.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001696 for _, info := range c.moduleGroups {
Jamie Gennisaf435562014-10-27 22:34:56 -07001697 for _, buildDef := range info.actionDefs.buildDefs {
1698 ruleName := buildDef.Rule.fullName(c.pkgNames)
1699 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001700 outputValue, err := output.Eval(c.globalVariables)
1701 if err != nil {
1702 return nil, err
1703 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001704 targets[outputValue] = ruleName
1705 }
1706 }
1707 }
1708
1709 // Collect all the singleton build targets.
1710 for _, info := range c.singletonInfo {
1711 for _, buildDef := range info.actionDefs.buildDefs {
1712 ruleName := buildDef.Rule.fullName(c.pkgNames)
1713 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001714 outputValue, err := output.Eval(c.globalVariables)
1715 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001716 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001717 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001718 targets[outputValue] = ruleName
1719 }
1720 }
1721 }
1722
1723 return targets, nil
1724}
1725
Jamie Gennisd4e10182014-06-12 20:06:50 -07001726// WriteBuildFile writes the Ninja manifeset text for the generated build
1727// actions to w. If this is called before PrepareBuildActions successfully
1728// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001729func (c *Context) WriteBuildFile(w io.Writer) error {
1730 if !c.buildActionsReady {
1731 return ErrBuildActionsNotReady
1732 }
1733
1734 nw := newNinjaWriter(w)
1735
1736 err := c.writeBuildFileHeader(nw)
1737 if err != nil {
1738 return err
1739 }
1740
1741 err = c.writeNinjaRequiredVersion(nw)
1742 if err != nil {
1743 return err
1744 }
1745
1746 // TODO: Group the globals by package.
1747
1748 err = c.writeGlobalVariables(nw)
1749 if err != nil {
1750 return err
1751 }
1752
1753 err = c.writeGlobalPools(nw)
1754 if err != nil {
1755 return err
1756 }
1757
1758 err = c.writeBuildDir(nw)
1759 if err != nil {
1760 return err
1761 }
1762
1763 err = c.writeGlobalRules(nw)
1764 if err != nil {
1765 return err
1766 }
1767
1768 err = c.writeAllModuleActions(nw)
1769 if err != nil {
1770 return err
1771 }
1772
1773 err = c.writeAllSingletonActions(nw)
1774 if err != nil {
1775 return err
1776 }
1777
1778 return nil
1779}
1780
Jamie Gennisc15544d2014-09-24 20:26:52 -07001781type pkgAssociation struct {
1782 PkgName string
1783 PkgPath string
1784}
1785
1786type pkgAssociationSorter struct {
1787 pkgs []pkgAssociation
1788}
1789
1790func (s *pkgAssociationSorter) Len() int {
1791 return len(s.pkgs)
1792}
1793
1794func (s *pkgAssociationSorter) Less(i, j int) bool {
1795 iName := s.pkgs[i].PkgName
1796 jName := s.pkgs[j].PkgName
1797 return iName < jName
1798}
1799
1800func (s *pkgAssociationSorter) Swap(i, j int) {
1801 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1802}
1803
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001804func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1805 headerTemplate := template.New("fileHeader")
1806 _, err := headerTemplate.Parse(fileHeaderTemplate)
1807 if err != nil {
1808 // This is a programming error.
1809 panic(err)
1810 }
1811
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001812 var pkgs []pkgAssociation
1813 maxNameLen := 0
1814 for pkg, name := range c.pkgNames {
1815 pkgs = append(pkgs, pkgAssociation{
1816 PkgName: name,
1817 PkgPath: pkg.pkgPath,
1818 })
1819 if len(name) > maxNameLen {
1820 maxNameLen = len(name)
1821 }
1822 }
1823
1824 for i := range pkgs {
1825 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1826 }
1827
Jamie Gennisc15544d2014-09-24 20:26:52 -07001828 sort.Sort(&pkgAssociationSorter{pkgs})
1829
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001830 params := map[string]interface{}{
1831 "Pkgs": pkgs,
1832 }
1833
1834 buf := bytes.NewBuffer(nil)
1835 err = headerTemplate.Execute(buf, params)
1836 if err != nil {
1837 return err
1838 }
1839
1840 return nw.Comment(buf.String())
1841}
1842
1843func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1844 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1845 c.requiredNinjaMicro)
1846
1847 err := nw.Assign("ninja_required_version", value)
1848 if err != nil {
1849 return err
1850 }
1851
1852 return nw.BlankLine()
1853}
1854
1855func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1856 if c.buildDir != nil {
1857 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1858 if err != nil {
1859 return err
1860 }
1861
1862 err = nw.BlankLine()
1863 if err != nil {
1864 return err
1865 }
1866 }
1867 return nil
1868}
1869
Jamie Gennisc15544d2014-09-24 20:26:52 -07001870type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001871 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001872}
1873
Jamie Gennisc15544d2014-09-24 20:26:52 -07001874type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001875 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001876 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001877}
1878
Jamie Gennisc15544d2014-09-24 20:26:52 -07001879func (s *globalEntitySorter) Len() int {
1880 return len(s.entities)
1881}
1882
1883func (s *globalEntitySorter) Less(i, j int) bool {
1884 iName := s.entities[i].fullName(s.pkgNames)
1885 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001886 return iName < jName
1887}
1888
Jamie Gennisc15544d2014-09-24 20:26:52 -07001889func (s *globalEntitySorter) Swap(i, j int) {
1890 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001891}
1892
1893func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1894 visited := make(map[Variable]bool)
1895
1896 var walk func(v Variable) error
1897 walk = func(v Variable) error {
1898 visited[v] = true
1899
1900 // First visit variables on which this variable depends.
1901 value := c.globalVariables[v]
1902 for _, dep := range value.variables {
1903 if !visited[dep] {
1904 err := walk(dep)
1905 if err != nil {
1906 return err
1907 }
1908 }
1909 }
1910
1911 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1912 if err != nil {
1913 return err
1914 }
1915
1916 err = nw.BlankLine()
1917 if err != nil {
1918 return err
1919 }
1920
1921 return nil
1922 }
1923
Jamie Gennisc15544d2014-09-24 20:26:52 -07001924 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1925 for variable := range c.globalVariables {
1926 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001927 }
1928
Jamie Gennisc15544d2014-09-24 20:26:52 -07001929 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930
Jamie Gennisc15544d2014-09-24 20:26:52 -07001931 for _, entity := range globalVariables {
1932 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001933 if !visited[v] {
1934 err := walk(v)
1935 if err != nil {
1936 return nil
1937 }
1938 }
1939 }
1940
1941 return nil
1942}
1943
1944func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001945 globalPools := make([]globalEntity, 0, len(c.globalPools))
1946 for pool := range c.globalPools {
1947 globalPools = append(globalPools, pool)
1948 }
1949
1950 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1951
1952 for _, entity := range globalPools {
1953 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001954 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001955 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001956 err := def.WriteTo(nw, name)
1957 if err != nil {
1958 return err
1959 }
1960
1961 err = nw.BlankLine()
1962 if err != nil {
1963 return err
1964 }
1965 }
1966
1967 return nil
1968}
1969
1970func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001971 globalRules := make([]globalEntity, 0, len(c.globalRules))
1972 for rule := range c.globalRules {
1973 globalRules = append(globalRules, rule)
1974 }
1975
1976 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
1977
1978 for _, entity := range globalRules {
1979 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001980 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001981 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001982 err := def.WriteTo(nw, name, c.pkgNames)
1983 if err != nil {
1984 return err
1985 }
1986
1987 err = nw.BlankLine()
1988 if err != nil {
1989 return err
1990 }
1991 }
1992
1993 return nil
1994}
1995
Colin Crossbbfa51a2014-12-17 16:12:41 -08001996type moduleGroupSorter []*moduleGroup
Jamie Gennis86179fe2014-06-11 16:27:16 -07001997
Colin Crossbbfa51a2014-12-17 16:12:41 -08001998func (s moduleGroupSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001999 return len(s)
2000}
2001
Colin Crossbbfa51a2014-12-17 16:12:41 -08002002func (s moduleGroupSorter) Less(i, j int) bool {
Colin Crossed342d92015-03-11 00:57:25 -07002003 iName := s[i].name
2004 jName := s[j].name
Jamie Gennis86179fe2014-06-11 16:27:16 -07002005 return iName < jName
2006}
2007
Colin Crossbbfa51a2014-12-17 16:12:41 -08002008func (s moduleGroupSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002009 s[i], s[j] = s[j], s[i]
2010}
2011
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002012func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2013 headerTemplate := template.New("moduleHeader")
2014 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2015 if err != nil {
2016 // This is a programming error.
2017 panic(err)
2018 }
2019
Colin Crossbbfa51a2014-12-17 16:12:41 -08002020 infos := make([]*moduleGroup, 0, len(c.moduleGroups))
2021 for _, info := range c.moduleGroups {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002022 infos = append(infos, info)
2023 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002024 sort.Sort(moduleGroupSorter(infos))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002025
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002026 buf := bytes.NewBuffer(nil)
2027
Jamie Gennis86179fe2014-06-11 16:27:16 -07002028 for _, info := range infos {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002029 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002030
2031 // In order to make the bootstrap build manifest independent of the
2032 // build dir we need to output the Blueprints file locations in the
2033 // comments as paths relative to the source directory.
Colin Crossed342d92015-03-11 00:57:25 -07002034 relPos := info.modules[0].pos
2035 relPos.Filename = info.modules[0].relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002036
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002037 // Get the name and location of the factory function for the module.
Colin Crossed342d92015-03-11 00:57:25 -07002038 factory := c.moduleFactories[info.modules[0].typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002039 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2040 factoryName := factoryFunc.Name()
2041
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002042 infoMap := map[string]interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07002043 "properties": info.modules[0].properties,
2044 "typeName": info.modules[0].typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002045 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002046 "pos": relPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002047 }
2048 err = headerTemplate.Execute(buf, infoMap)
2049 if err != nil {
2050 return err
2051 }
2052
2053 err = nw.Comment(buf.String())
2054 if err != nil {
2055 return err
2056 }
2057
2058 err = nw.BlankLine()
2059 if err != nil {
2060 return err
2061 }
2062
2063 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2064 if err != nil {
2065 return err
2066 }
2067
2068 err = nw.BlankLine()
2069 if err != nil {
2070 return err
2071 }
2072 }
2073
2074 return nil
2075}
2076
2077func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2078 headerTemplate := template.New("singletonHeader")
2079 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2080 if err != nil {
2081 // This is a programming error.
2082 panic(err)
2083 }
2084
2085 buf := bytes.NewBuffer(nil)
2086
Jamie Gennis86179fe2014-06-11 16:27:16 -07002087 singletonNames := make([]string, 0, len(c.singletonInfo))
2088 for name := range c.singletonInfo {
2089 singletonNames = append(singletonNames, name)
2090 }
2091 sort.Strings(singletonNames)
2092
2093 for _, name := range singletonNames {
2094 info := c.singletonInfo[name]
2095
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002096 // Get the name of the factory function for the module.
2097 factory := info.factory
2098 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2099 factoryName := factoryFunc.Name()
2100
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002101 buf.Reset()
2102 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002103 "name": name,
2104 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002105 }
2106 err = headerTemplate.Execute(buf, infoMap)
2107 if err != nil {
2108 return err
2109 }
2110
2111 err = nw.Comment(buf.String())
2112 if err != nil {
2113 return err
2114 }
2115
2116 err = nw.BlankLine()
2117 if err != nil {
2118 return err
2119 }
2120
2121 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2122 if err != nil {
2123 return err
2124 }
2125
2126 err = nw.BlankLine()
2127 if err != nil {
2128 return err
2129 }
2130 }
2131
2132 return nil
2133}
2134
2135func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2136 defs *localBuildActions) error {
2137
2138 // Write the local variable assignments.
2139 for _, v := range defs.variables {
2140 // A localVariable doesn't need the package names or config to
2141 // determine its name or value.
2142 name := v.fullName(nil)
2143 value, err := v.value(nil)
2144 if err != nil {
2145 panic(err)
2146 }
2147 err = nw.Assign(name, value.Value(c.pkgNames))
2148 if err != nil {
2149 return err
2150 }
2151 }
2152
2153 if len(defs.variables) > 0 {
2154 err := nw.BlankLine()
2155 if err != nil {
2156 return err
2157 }
2158 }
2159
2160 // Write the local rules.
2161 for _, r := range defs.rules {
2162 // A localRule doesn't need the package names or config to determine
2163 // its name or definition.
2164 name := r.fullName(nil)
2165 def, err := r.def(nil)
2166 if err != nil {
2167 panic(err)
2168 }
2169
2170 err = def.WriteTo(nw, name, c.pkgNames)
2171 if err != nil {
2172 return err
2173 }
2174
2175 err = nw.BlankLine()
2176 if err != nil {
2177 return err
2178 }
2179 }
2180
2181 // Write the build definitions.
2182 for _, buildDef := range defs.buildDefs {
2183 err := buildDef.WriteTo(nw, c.pkgNames)
2184 if err != nil {
2185 return err
2186 }
2187
2188 if len(buildDef.Args) > 0 {
2189 err = nw.BlankLine()
2190 if err != nil {
2191 return err
2192 }
2193 }
2194 }
2195
2196 return nil
2197}
2198
2199var fileHeaderTemplate = `******************************************************************************
2200*** This file is generated and should not be edited ***
2201******************************************************************************
2202{{if .Pkgs}}
2203This file contains variables, rules, and pools with name prefixes indicating
2204they were generated by the following Go packages:
2205{{range .Pkgs}}
2206 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2207
2208`
2209
2210var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2211Module: {{.properties.Name}}
2212Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002213Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002214Defined: {{.pos}}
2215`
2216
2217var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2218Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002219Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002220`