blob: eb313d2ddad572215dfe143b12097633b296e27f [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 Crosse7daa222015-03-11 14:35:41 -0700136 variantName string
137 variants variantMap
138
Colin Crossc9028482014-12-18 16:28:54 -0800139 logicModule Module
140 group *moduleGroup
141 moduleProperties []interface{}
142
143 // set during ResolveDependencies
144 directDeps []*moduleInfo
145
146 // set during each runMutator
147 splitModules []*moduleInfo
148}
149
Colin Crosse7daa222015-03-11 14:35:41 -0700150type variantMap map[string]string
151
152func (vm variantMap) clone() variantMap {
153 newVm := make(variantMap)
154 for k, v := range vm {
155 newVm[k] = v
156 }
157
158 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800159}
160
Colin Crosse7daa222015-03-11 14:35:41 -0700161func (vm variantMap) equal(other variantMap) bool {
162 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800163}
164
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700165type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700166 // set during RegisterSingletonType
167 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700168 singleton Singleton
169
170 // set during PrepareBuildActions
171 actionDefs localBuildActions
172}
173
Colin Crossc9028482014-12-18 16:28:54 -0800174type mutatorInfo struct {
175 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800176 topDownMutator TopDownMutator
177 bottomUpMutator BottomUpMutator
178 name string
Colin Crossc9028482014-12-18 16:28:54 -0800179}
180
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700181func (e *Error) Error() string {
182
183 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
184}
185
Jamie Gennisd4e10182014-06-12 20:06:50 -0700186// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700187// no module or singleton factories registered, so the RegisterModuleFactory and
188// RegisterSingletonFactory methods must be called before it can do anything
189// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700190func NewContext() *Context {
191 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800192 moduleFactories: make(map[string]ModuleFactory),
193 moduleGroups: make(map[string]*moduleGroup),
194 moduleInfo: make(map[Module]*moduleInfo),
195 singletonInfo: make(map[string]*singletonInfo),
196 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700197 }
198}
199
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700200// A ModuleFactory function creates a new Module object. See the
201// Context.RegisterModuleType method for details about how a registered
202// ModuleFactory is used by a Context.
203type ModuleFactory func() (m Module, propertyStructs []interface{})
204
Jamie Gennisd4e10182014-06-12 20:06:50 -0700205// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700206// Blueprints file) with a Module factory function. When the given module type
207// name is encountered in a Blueprints file during parsing, the Module factory
208// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800209// generation for the module. If a Mutator splits a module into multiple variants,
210// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700211//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700212// The module type names given here must be unique for the context. The factory
213// function should be a named function so that its package and name can be
214// included in the generated Ninja file for debugging purposes.
215//
216// The factory function returns two values. The first is the newly created
217// Module object. The second is a slice of pointers to that Module object's
218// properties structs. Each properties struct is examined when parsing a module
219// definition of this type in a Blueprints file. Exported fields of the
220// properties structs are automatically set to the property values specified in
221// the Blueprints file. The properties struct field names determine the name of
222// the Blueprints file properties that are used - the Blueprints property name
223// matches that of the properties struct field name with the first letter
224// converted to lower-case.
225//
226// The fields of the properties struct must be either []string, a string, or
227// bool. The Context will panic if a Module gets instantiated with a properties
228// struct containing a field that is not one these supported types.
229//
230// Any properties that appear in the Blueprints files that are not built-in
231// module properties (such as "name" and "deps") and do not have a corresponding
232// field in the returned module properties struct result in an error during the
233// Context's parse phase.
234//
235// As an example, the follow code:
236//
237// type myModule struct {
238// properties struct {
239// Foo string
240// Bar []string
241// }
242// }
243//
244// func NewMyModule() (blueprint.Module, []interface{}) {
245// module := new(myModule)
246// properties := &module.properties
247// return module, []interface{}{properties}
248// }
249//
250// func main() {
251// ctx := blueprint.NewContext()
252// ctx.RegisterModuleType("my_module", NewMyModule)
253// // ...
254// }
255//
256// would support parsing a module defined in a Blueprints file as follows:
257//
258// my_module {
259// name: "myName",
260// foo: "my foo string",
261// bar: ["my", "bar", "strings"],
262// }
263//
Colin Cross7ad621c2015-01-07 16:22:45 -0800264// The factory function may be called from multiple goroutines. Any accesses
265// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700266func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
267 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700268 panic(errors.New("module type name is already registered"))
269 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700270 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700271}
272
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700273// A SingletonFactory function creates a new Singleton object. See the
274// Context.RegisterSingletonType method for details about how a registered
275// SingletonFactory is used by a Context.
276type SingletonFactory func() Singleton
277
278// RegisterSingletonType registers a singleton type that will be invoked to
279// generate build actions. Each registered singleton type is instantiated and
280// and invoked exactly once as part of the generate phase.
281//
282// The singleton type names given here must be unique for the context. The
283// factory function should be a named function so that its package and name can
284// be included in the generated Ninja file for debugging purposes.
285func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700286 if _, present := c.singletonInfo[name]; present {
287 panic(errors.New("singleton name is already registered"))
288 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700289
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700290 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700291 factory: factory,
292 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700293 }
294}
295
296func singletonPkgPath(singleton Singleton) string {
297 typ := reflect.TypeOf(singleton)
298 for typ.Kind() == reflect.Ptr {
299 typ = typ.Elem()
300 }
301 return typ.PkgPath()
302}
303
304func singletonTypeName(singleton Singleton) string {
305 typ := reflect.TypeOf(singleton)
306 for typ.Kind() == reflect.Ptr {
307 typ = typ.Elem()
308 }
309 return typ.PkgPath() + "." + typ.Name()
310}
311
Colin Crossc9028482014-12-18 16:28:54 -0800312// RegisterTopDownMutator registers a mutator that will be invoked to propagate
313// dependency info top-down between Modules. Each registered mutator
314// is invoked once per Module, and is invoked on a module before being invoked
315// on any of its dependencies
316//
317// The mutator type names given here must be unique for the context.
318func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
319 for _, m := range c.mutatorInfo {
320 if m.name == name && m.topDownMutator != nil {
321 panic(fmt.Errorf("mutator name %s is already registered", name))
322 }
323 }
324
325 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
326 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800327 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800328 })
329}
330
331// RegisterBottomUpMutator registers a mutator that will be invoked to split
332// Modules into variants. Each registered mutator is invoked once per Module,
333// and is invoked on dependencies before being invoked on dependers.
334//
335// The mutator type names given here must be unique for the context.
336func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
337 for _, m := range c.mutatorInfo {
338 if m.name == name && m.bottomUpMutator != nil {
339 panic(fmt.Errorf("mutator name %s is already registered", name))
340 }
341 }
342
343 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
344 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800345 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800346 })
347}
348
Jamie Gennisd4e10182014-06-12 20:06:50 -0700349// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
350// where it encounters an unknown module type while parsing Blueprints files. By
351// default, the context will report unknown module types as an error. If this
352// method is called with ignoreUnknownModuleTypes set to true then the context
353// will silently ignore unknown module types.
354//
355// This method should generally not be used. It exists to facilitate the
356// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700357func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
358 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
359}
360
Jamie Gennisd4e10182014-06-12 20:06:50 -0700361// Parse parses a single Blueprints file from r, creating Module objects for
362// each of the module definitions encountered. If the Blueprints file contains
363// an assignment to the "subdirs" variable, then the subdirectories listed are
364// returned in the subdirs first return value.
365//
366// rootDir specifies the path to the root directory of the source tree, while
367// filename specifies the path to the Blueprints file. These paths are used for
368// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800369func (c *Context) parse(rootDir, filename string, r io.Reader,
370 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
371 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700372
Jamie Gennisec701282014-06-12 20:06:31 -0700373 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700374 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800375 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700376 }
377
Colin Crossc0dbc552015-01-02 15:19:28 -0800378 scope = parser.NewScope(scope)
379 scope.Remove("subdirs")
Colin Crossd1facc12015-01-08 14:56:03 -0800380 file, errs := parser.Parse(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700381 if len(errs) > 0 {
382 for i, err := range errs {
383 if parseErr, ok := err.(*parser.ParseError); ok {
384 err = &Error{
385 Err: parseErr.Err,
386 Pos: parseErr.Pos,
387 }
388 errs[i] = err
389 }
390 }
391
392 // If there were any parse errors don't bother trying to interpret the
393 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800394 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700395 }
396
Colin Crossd1facc12015-01-08 14:56:03 -0800397 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800399 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700400 switch def := def.(type) {
401 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800402 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700403
404 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800405 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700406 default:
407 panic("unknown definition type")
408 }
409
410 if len(newErrs) > 0 {
411 errs = append(errs, newErrs...)
412 if len(errs) > maxErrors {
413 break
414 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800415 } else if newModule != nil {
416 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700417 }
418 }
419
Colin Crossc0dbc552015-01-02 15:19:28 -0800420 subdirs, newErrs := c.processSubdirs(scope)
421 if len(newErrs) > 0 {
422 errs = append(errs, newErrs...)
423 }
424
Colin Cross7ad621c2015-01-07 16:22:45 -0800425 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800426}
427
Colin Cross7ad621c2015-01-07 16:22:45 -0800428type stringAndScope struct {
429 string
430 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700431}
432
Jamie Gennisd4e10182014-06-12 20:06:50 -0700433// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
434// at rootFile. When it encounters a Blueprints file with a set of subdirs
435// listed it recursively parses any Blueprints files found in those
436// subdirectories.
437//
438// If no errors are encountered while parsing the files, the list of paths on
439// which the future output will depend is returned. This list will include both
440// Blueprints file paths as well as directory paths for cases where wildcard
441// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700442func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
443 errs []error) {
444
Colin Cross7ad621c2015-01-07 16:22:45 -0800445 c.dependenciesReady = false
446
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700447 rootDir := filepath.Dir(rootFile)
448
Colin Cross7ad621c2015-01-07 16:22:45 -0800449 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700450
Colin Cross7ad621c2015-01-07 16:22:45 -0800451 // Channels to receive data back from parseBlueprintsFile goroutines
452 blueprintsCh := make(chan stringAndScope)
453 errsCh := make(chan []error)
454 modulesCh := make(chan []*moduleInfo)
455 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700456
Colin Cross7ad621c2015-01-07 16:22:45 -0800457 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
458 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700459
Colin Cross7ad621c2015-01-07 16:22:45 -0800460 // Number of outstanding goroutines to wait for
461 count := 0
462
463 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
464 count++
465 go func() {
466 c.parseBlueprintsFile(filename, scope, rootDir,
467 errsCh, modulesCh, blueprintsCh, depsCh)
468 doneCh <- struct{}{}
469 }()
470 }
471
472 tooManyErrors := false
473
474 startParseBlueprintsFile(rootFile, nil)
475
476loop:
477 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800479 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700480 }
481
Colin Cross7ad621c2015-01-07 16:22:45 -0800482 select {
483 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700484 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800485 case dep := <-depsCh:
486 deps = append(deps, dep)
487 case modules := <-modulesCh:
488 newErrs := c.addModules(modules)
489 errs = append(errs, newErrs...)
490 case blueprint := <-blueprintsCh:
491 if tooManyErrors {
492 continue
493 }
494 if blueprintsSet[blueprint.string] {
495 continue
496 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497
Colin Cross7ad621c2015-01-07 16:22:45 -0800498 blueprintsSet[blueprint.string] = true
499 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
500 case <-doneCh:
501 count--
502 if count == 0 {
503 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700504 }
505 }
506 }
507
Colin Cross7ad621c2015-01-07 16:22:45 -0800508 return
509}
510
511// parseBlueprintFile parses a single Blueprints file, returning any errors through
512// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
513// blueprintsCh, and any dependencies on Blueprints files or directories through
514// depsCh.
515func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
516 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
517 depsCh chan<- string) {
518
519 dir := filepath.Dir(filename)
520
521 file, err := os.Open(filename)
522 if err != nil {
523 errsCh <- []error{err}
524 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700525 }
526
Colin Cross7ad621c2015-01-07 16:22:45 -0800527 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
528 if len(errs) > 0 {
529 errsCh <- errs
530 }
531
532 err = file.Close()
533 if err != nil {
534 errsCh <- []error{err}
535 }
536
537 modulesCh <- modules
538
539 for _, subdir := range subdirs {
540 subdir = filepath.Join(dir, subdir)
541
542 dirPart, filePart := filepath.Split(subdir)
543 dirPart = filepath.Clean(dirPart)
544
545 if filePart == "*" {
546 foundSubdirs, err := listSubdirs(dirPart)
547 if err != nil {
548 errsCh <- []error{err}
549 return
550 }
551
552 for _, foundSubdir := range foundSubdirs {
553 subBlueprints := filepath.Join(dirPart, foundSubdir,
554 "Blueprints")
555
556 _, err := os.Stat(subBlueprints)
557 if os.IsNotExist(err) {
558 // There is no Blueprints file in this subdirectory. We
559 // need to add the directory to the list of dependencies
560 // so that if someone adds a Blueprints file in the
561 // future we'll pick it up.
562 depsCh <- filepath.Dir(subBlueprints)
563 } else {
564 depsCh <- subBlueprints
565 blueprintsCh <- stringAndScope{
566 subBlueprints,
567 subScope,
568 }
569 }
570 }
571
572 // We now depend on the directory itself because if any new
573 // subdirectories get added or removed we need to rebuild the
574 // Ninja manifest.
575 depsCh <- dirPart
576 } else {
577 subBlueprints := filepath.Join(subdir, "Blueprints")
578 depsCh <- subBlueprints
579 blueprintsCh <- stringAndScope{
580 subBlueprints,
581 subScope,
582 }
583
584 }
585 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700586}
587
588func listSubdirs(dir string) ([]string, error) {
589 d, err := os.Open(dir)
590 if err != nil {
591 return nil, err
592 }
593 defer d.Close()
594
595 infos, err := d.Readdir(-1)
596 if err != nil {
597 return nil, err
598 }
599
600 var subdirs []string
601 for _, info := range infos {
Jamie Gennis0c35b2d2014-09-25 13:15:10 -0700602 isDotFile := strings.HasPrefix(info.Name(), ".")
603 if info.IsDir() && !isDotFile {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700604 subdirs = append(subdirs, info.Name())
605 }
606 }
607
608 return subdirs, nil
609}
610
Colin Crossc0dbc552015-01-02 15:19:28 -0800611func (c *Context) processSubdirs(
612 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700613
Colin Crossc0dbc552015-01-02 15:19:28 -0800614 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700615 switch assignment.Value.Type {
616 case parser.List:
617 subdirs = make([]string, 0, len(assignment.Value.ListValue))
618
619 for _, value := range assignment.Value.ListValue {
620 if value.Type != parser.String {
621 // The parser should not produce this.
622 panic("non-string value found in list")
623 }
624
625 dirPart, filePart := filepath.Split(value.StringValue)
626 if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
627 strings.ContainsRune(dirPart, '*') {
628
629 errs = append(errs, &Error{
630 Err: fmt.Errorf("subdirs may only wildcard whole " +
631 "directories"),
632 Pos: value.Pos,
633 })
634
635 continue
636 }
637
638 subdirs = append(subdirs, value.StringValue)
639 }
640
641 if len(errs) > 0 {
642 subdirs = nil
643 }
644
645 return
646
647 case parser.Bool, parser.String:
648 errs = []error{
649 &Error{
650 Err: fmt.Errorf("subdirs must be a list of strings"),
651 Pos: assignment.Pos,
652 },
653 }
654
655 return
656
657 default:
658 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
659 }
660 }
661
Colin Crossc0dbc552015-01-02 15:19:28 -0800662 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700663}
664
Colin Crossc9028482014-12-18 16:28:54 -0800665func (c *Context) createVariants(origModule *moduleInfo, mutatorName string,
Colin Cross174ae052015-03-03 17:37:03 -0800666 variantNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800667
668 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800669
Colin Cross174ae052015-03-03 17:37:03 -0800670 var errs []error
671
Colin Crossc9028482014-12-18 16:28:54 -0800672 for i, variantName := range variantNames {
Colin Crossed342d92015-03-11 00:57:25 -0700673 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800674 factory, ok := c.moduleFactories[typeName]
675 if !ok {
676 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
677 }
678
679 var newLogicModule Module
680 var newProperties []interface{}
681
682 if i == 0 {
683 // Reuse the existing module for the first new variant
684 newLogicModule = origModule.logicModule
685 newProperties = origModule.moduleProperties
686 } else {
687 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700688 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800689 }
690 newLogicModule, newProperties = factory()
691
692 newProperties = append(props, newProperties...)
693
694 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700695 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800696 }
697
698 for i := range newProperties {
699 dst := reflect.ValueOf(newProperties[i]).Elem()
700 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
701
702 proptools.CopyProperties(dst, src)
703 }
704 }
705
Colin Crosse7daa222015-03-11 14:35:41 -0700706 newVariants := origModule.variants.clone()
707 newVariants[mutatorName] = variantName
Colin Crossc9028482014-12-18 16:28:54 -0800708
Colin Crossed342d92015-03-11 00:57:25 -0700709 m := *origModule
710 newModule := &m
711 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
712 newModule.logicModule = newLogicModule
Colin Crosse7daa222015-03-11 14:35:41 -0700713 newModule.variants = newVariants
Colin Crossed342d92015-03-11 00:57:25 -0700714 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800715
Colin Crosse7daa222015-03-11 14:35:41 -0700716 if newModule.variantName == "" {
717 newModule.variantName = variantName
718 } else {
719 newModule.variantName += "_" + variantName
720 }
721
Colin Crossc9028482014-12-18 16:28:54 -0800722 newModules = append(newModules, newModule)
723 c.moduleInfo[newModule.logicModule] = newModule
724
Colin Crosse7daa222015-03-11 14:35:41 -0700725 newErrs := c.convertDepsToVariant(newModule, mutatorName, variantName)
Colin Cross174ae052015-03-03 17:37:03 -0800726 if len(newErrs) > 0 {
727 errs = append(errs, newErrs...)
728 }
Colin Crossc9028482014-12-18 16:28:54 -0800729 }
730
731 // Mark original variant as invalid. Modules that depend on this module will still
732 // depend on origModule, but we'll fix it when the mutator is called on them.
733 origModule.logicModule = nil
734 origModule.splitModules = newModules
735
Colin Cross174ae052015-03-03 17:37:03 -0800736 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800737}
738
Colin Crosse7daa222015-03-11 14:35:41 -0700739func (c *Context) convertDepsToVariant(module *moduleInfo,
740 mutatorName, variantName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800741
Colin Crossc9028482014-12-18 16:28:54 -0800742 for i, dep := range module.directDeps {
743 if dep.logicModule == nil {
744 var newDep *moduleInfo
745 for _, m := range dep.splitModules {
Colin Crosse7daa222015-03-11 14:35:41 -0700746 if m.variants[mutatorName] == variantName {
Colin Crossc9028482014-12-18 16:28:54 -0800747 newDep = m
748 break
749 }
750 }
751 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800752 errs = append(errs, &Error{
753 Err: fmt.Errorf("failed to find variant %q for module %q needed by %q",
Colin Crosse7daa222015-03-11 14:35:41 -0700754 variantName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700755 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800756 })
757 continue
Colin Crossc9028482014-12-18 16:28:54 -0800758 }
759 module.directDeps[i] = newDep
760 }
761 }
Colin Cross174ae052015-03-03 17:37:03 -0800762
763 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800764}
765
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700766func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800767 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700768
Colin Crossd1facc12015-01-08 14:56:03 -0800769 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700770 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700771 if !ok {
772 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800773 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700774 }
775
Colin Cross7ad621c2015-01-07 16:22:45 -0800776 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700777 &Error{
778 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800779 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700780 },
781 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700782 }
783
Colin Crossbbfa51a2014-12-17 16:12:41 -0800784 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700785
786 module := &moduleInfo{
787 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700788 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700789 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700790 }
791
Jamie Gennis87622922014-09-30 11:38:25 -0700792 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700793 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700794 }
795 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700796 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700797
Jamie Gennis87622922014-09-30 11:38:25 -0700798 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700799 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800800 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700801 }
802
Colin Crossed342d92015-03-11 00:57:25 -0700803 module.pos = moduleDef.Type.Pos
804 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700805 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700806 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700807 }
808
Colin Cross7ad621c2015-01-07 16:22:45 -0800809 return module, nil
810}
811
812func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
813 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700814 name := module.properties.Name
815 c.moduleInfo[module.logicModule] = module
816
817 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800818 errs = append(errs, []error{
819 &Error{
820 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700821 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800822 },
823 &Error{
824 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700825 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800826 },
827 }...)
828 continue
Colin Crossed342d92015-03-11 00:57:25 -0700829 } else {
830 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800831
Colin Crossed342d92015-03-11 00:57:25 -0700832 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
833 // already exists
834 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
835 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
836 }
837
838 c.moduleNinjaNames[ninjaName] = group
839
840 group := &moduleGroup{
841 name: module.properties.Name,
842 ninjaName: ninjaName,
843 modules: []*moduleInfo{module},
844 }
845 module.group = group
846 c.moduleGroups[name] = group
847 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800848 }
849
850 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700851}
852
Jamie Gennisd4e10182014-06-12 20:06:50 -0700853// ResolveDependencies checks that the dependencies specified by all of the
854// modules defined in the parsed Blueprints files are valid. This means that
855// the modules depended upon are defined and that no circular dependencies
856// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700857//
858// The config argument is made available to all of the DynamicDependerModule
859// objects via the Config method on the DynamicDependerModuleContext objects
860// passed to their DynamicDependencies method.
861func (c *Context) ResolveDependencies(config interface{}) []error {
862 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700863 if len(errs) > 0 {
864 return errs
865 }
866
Colin Cross691a60d2015-01-07 18:08:56 -0800867 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700868 if len(errs) > 0 {
869 return errs
870 }
871
872 c.dependenciesReady = true
873 return nil
874}
875
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700876// moduleDepNames returns the sorted list of dependency names for a given
877// module. If the module implements the DynamicDependerModule interface then
878// this set consists of the union of those module names listed in its "deps"
879// property and those returned by its DynamicDependencies method. Otherwise it
880// is simply those names listed in its "deps" property.
Colin Crossed342d92015-03-11 00:57:25 -0700881func (c *Context) moduleDepNames(module *moduleInfo,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700882 config interface{}) ([]string, []error) {
883
884 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800885 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700886
Colin Crossed342d92015-03-11 00:57:25 -0700887 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800888 if !depNamesSet[depName] {
889 depNamesSet[depName] = true
890 depNames = append(depNames, depName)
891 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700892 }
893
Colin Crossed342d92015-03-11 00:57:25 -0700894 logicModule := module.logicModule
Colin Crossbbfa51a2014-12-17 16:12:41 -0800895 dynamicDepender, ok := logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700896 if ok {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800897 ddmctx := &baseModuleContext{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700898 context: c,
899 config: config,
Colin Crossed342d92015-03-11 00:57:25 -0700900 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700901 }
902
903 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
904
905 if len(ddmctx.errs) > 0 {
906 return nil, ddmctx.errs
907 }
908
909 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800910 if !depNamesSet[depName] {
911 depNamesSet[depName] = true
912 depNames = append(depNames, depName)
913 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700914 }
915 }
916
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700917 return depNames, nil
918}
919
Colin Crossbbfa51a2014-12-17 16:12:41 -0800920// resolveDependencies populates the moduleGroup.modules[0].directDeps list for every
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700921// module. In doing so it checks for missing dependencies and self-dependant
922// modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700923func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800924 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -0700925 for _, module := range group.modules {
926 depNames, newErrs := c.moduleDepNames(module, config)
Colin Crossc9028482014-12-18 16:28:54 -0800927 if len(newErrs) > 0 {
928 errs = append(errs, newErrs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700929 continue
930 }
Colin Crossed342d92015-03-11 00:57:25 -0700931
932 module.directDeps = make([]*moduleInfo, 0, len(depNames))
933
934 for _, depName := range depNames {
935 newErrs := c.addDependency(module, depName)
936 if len(newErrs) > 0 {
937 errs = append(errs, newErrs...)
938 continue
939 }
940 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700941 }
942 }
943
944 return
945}
946
Colin Crossc9028482014-12-18 16:28:54 -0800947func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -0700948 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -0800949
Colin Crossed342d92015-03-11 00:57:25 -0700950 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -0800951 return []error{&Error{
952 Err: fmt.Errorf("%q depends on itself", depName),
953 Pos: depsPos,
954 }}
955 }
956
957 depInfo, ok := c.moduleGroups[depName]
958 if !ok {
959 return []error{&Error{
960 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -0700961 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -0800962 Pos: depsPos,
963 }}
964 }
965
966 if len(depInfo.modules) != 1 {
967 panic(fmt.Sprintf("cannot add dependency from %s to %s, it already has multiple variants",
Colin Crossed342d92015-03-11 00:57:25 -0700968 module.properties.Name, depInfo.modules[0].properties.Name))
Colin Crossc9028482014-12-18 16:28:54 -0800969 }
970
971 module.directDeps = append(module.directDeps, depInfo.modules[0])
972
973 return nil
974}
975
Colin Cross8900e9b2015-03-02 14:03:01 -0800976func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleGroup) bool) {
Colin Cross691a60d2015-01-07 18:08:56 -0800977 doneCh := make(chan *moduleGroup)
978 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -0800979 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -0800980
981 for _, group := range c.moduleGroupsSorted {
982 group.waitingCount = group.depsCount
983 }
984
985 visitOne := func(group *moduleGroup) {
986 count++
987 go func() {
Colin Cross8900e9b2015-03-02 14:03:01 -0800988 ret := visit(group)
989 if ret {
990 cancel = true
991 }
Colin Cross691a60d2015-01-07 18:08:56 -0800992 doneCh <- group
993 }()
994 }
995
996 for _, group := range c.moduleGroupsSorted {
997 if group.waitingCount == 0 {
998 visitOne(group)
999 }
1000 }
1001
Colin Cross11e3b0d2015-02-04 10:41:00 -08001002 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001003 select {
1004 case doneGroup := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001005 if !cancel {
1006 for _, parent := range doneGroup.reverseDeps {
1007 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 Crossbbfa51a2014-12-17 16:12:41 -08001025 visited := make(map[*moduleGroup]bool) // modules that were already checked
1026 checking := make(map[*moduleGroup]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001027
Colin Crossbbfa51a2014-12-17 16:12:41 -08001028 sorted := make([]*moduleGroup, 0, len(c.moduleGroups))
Colin Cross573a2fd2014-12-17 14:16:51 -08001029
Colin Crossbbfa51a2014-12-17 16:12:41 -08001030 var check func(group *moduleGroup) []*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001031
Colin Cross10b54db2015-03-11 14:40:30 -07001032 cycleError := func(cycle []*moduleGroup) {
1033 // 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 Crossed342d92015-03-11 00:57:25 -07001039 Pos: cycle[len(cycle)-1].modules[0].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001040 })
1041
1042 // Iterate backwards through the cycle list.
1043 curGroup := cycle[len(cycle)-1]
1044 for i := len(cycle) - 1; i >= 0; i-- {
1045 nextGroup := cycle[i]
1046 errs = append(errs, &Error{
1047 Err: fmt.Errorf(" %q depends on %q",
Colin Crossed342d92015-03-11 00:57:25 -07001048 curGroup.name,
1049 nextGroup.name),
1050 Pos: curGroup.modules[0].propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001051 })
1052 curGroup = nextGroup
1053 }
1054 }
1055
Colin Crossbbfa51a2014-12-17 16:12:41 -08001056 check = func(group *moduleGroup) []*moduleGroup {
1057 visited[group] = true
1058 checking[group] = true
1059 defer delete(checking, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001060
Colin Crossbbfa51a2014-12-17 16:12:41 -08001061 deps := make(map[*moduleGroup]bool)
1062 for _, module := range group.modules {
1063 for _, dep := range module.directDeps {
1064 deps[dep.group] = true
1065 }
1066 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001067
Colin Cross691a60d2015-01-07 18:08:56 -08001068 group.reverseDeps = []*moduleGroup{}
1069 group.depsCount = len(deps)
1070
Colin Crossbbfa51a2014-12-17 16:12:41 -08001071 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001072 if checking[dep] {
1073 // This is a cycle.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001074 return []*moduleGroup{dep, group}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001075 }
1076
1077 if !visited[dep] {
1078 cycle := check(dep)
1079 if cycle != nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001080 if cycle[0] == group {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001081 // We are the "start" of the cycle, so we're responsible
1082 // for generating the errors. The cycle list is in
1083 // reverse order because all the 'check' calls append
1084 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001085 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001086
1087 // We can continue processing this module's children to
1088 // find more cycles. Since all the modules that were
1089 // part of the found cycle were marked as visited we
1090 // won't run into that cycle again.
1091 } else {
1092 // We're not the "start" of the cycle, so we just append
1093 // our module to the list and return it.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001094 return append(cycle, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001095 }
1096 }
1097 }
Colin Cross691a60d2015-01-07 18:08:56 -08001098
1099 dep.reverseDeps = append(dep.reverseDeps, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001100 }
1101
Colin Crossbbfa51a2014-12-17 16:12:41 -08001102 sorted = append(sorted, group)
Colin Cross573a2fd2014-12-17 14:16:51 -08001103
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001104 return nil
1105 }
1106
Colin Crossbbfa51a2014-12-17 16:12:41 -08001107 for _, group := range c.moduleGroups {
1108 if !visited[group] {
1109 cycle := check(group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001110 if cycle != nil {
Colin Cross10b54db2015-03-11 14:40:30 -07001111 if cycle[len(cycle)-1] != group {
1112 panic("inconceivable!")
1113 }
1114 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001115 }
1116 }
1117 }
1118
Colin Crossbbfa51a2014-12-17 16:12:41 -08001119 c.moduleGroupsSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001120
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001121 return
1122}
1123
Jamie Gennisd4e10182014-06-12 20:06:50 -07001124// PrepareBuildActions generates an internal representation of all the build
1125// actions that need to be performed. This process involves invoking the
1126// GenerateBuildActions method on each of the Module objects created during the
1127// parse phase and then on each of the registered Singleton objects.
1128//
1129// If the ResolveDependencies method has not already been called it is called
1130// automatically by this method.
1131//
1132// The config argument is made available to all of the Module and Singleton
1133// objects via the Config method on the ModuleContext and SingletonContext
1134// objects passed to GenerateBuildActions. It is also passed to the functions
1135// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1136// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001137//
1138// The returned deps is a list of the ninja files dependencies that were added
1139// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1140// SingletonContext.AddNinjaFileDeps() methods.
1141func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001142 c.buildActionsReady = false
1143
1144 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001145 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001146 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001147 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001148 }
1149 }
1150
Colin Crossc9028482014-12-18 16:28:54 -08001151 errs = c.runMutators(config)
1152 if len(errs) > 0 {
1153 return nil, errs
1154 }
1155
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001156 liveGlobals := newLiveTracker(config)
1157
1158 c.initSpecialVariables()
1159
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001160 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001161 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001162 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001163 }
1164
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001165 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001166 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001167 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001168 }
1169
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001170 deps = append(depsModules, depsSingletons...)
1171
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001172 if c.buildDir != nil {
1173 liveGlobals.addNinjaStringDeps(c.buildDir)
1174 }
1175
1176 pkgNames := c.makeUniquePackageNames(liveGlobals)
1177
1178 // This will panic if it finds a problem since it's a programming error.
1179 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1180
1181 c.pkgNames = pkgNames
1182 c.globalVariables = liveGlobals.variables
1183 c.globalPools = liveGlobals.pools
1184 c.globalRules = liveGlobals.rules
1185
1186 c.buildActionsReady = true
1187
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001188 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001189}
1190
Colin Crossc9028482014-12-18 16:28:54 -08001191func (c *Context) runMutators(config interface{}) (errs []error) {
1192 for _, mutator := range c.mutatorInfo {
1193 if mutator.topDownMutator != nil {
1194 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1195 } else if mutator.bottomUpMutator != nil {
1196 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1197 } else {
1198 panic("no mutator set on " + mutator.name)
1199 }
1200 if len(errs) > 0 {
1201 return errs
1202 }
1203 }
1204
1205 return nil
1206}
1207
1208func (c *Context) runTopDownMutator(config interface{},
1209 name string, mutator TopDownMutator) (errs []error) {
1210
1211 for i := 0; i < len(c.moduleGroupsSorted); i++ {
1212 group := c.moduleGroupsSorted[len(c.moduleGroupsSorted)-1-i]
1213 for _, module := range group.modules {
1214 mctx := &mutatorContext{
1215 baseModuleContext: baseModuleContext{
1216 context: c,
1217 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001218 module: module,
Colin Crossc9028482014-12-18 16:28:54 -08001219 },
Colin Crossed342d92015-03-11 00:57:25 -07001220 name: name,
Colin Crossc9028482014-12-18 16:28:54 -08001221 }
1222
1223 mutator(mctx)
1224 if len(mctx.errs) > 0 {
1225 errs = append(errs, mctx.errs...)
1226 return errs
1227 }
1228 }
1229 }
1230
1231 return errs
1232}
1233
1234func (c *Context) runBottomUpMutator(config interface{},
1235 name string, mutator BottomUpMutator) (errs []error) {
1236
1237 dependenciesModified := false
1238
1239 for _, group := range c.moduleGroupsSorted {
1240 newModules := make([]*moduleInfo, 0, len(group.modules))
1241
1242 for _, module := range group.modules {
1243 mctx := &mutatorContext{
1244 baseModuleContext: baseModuleContext{
1245 context: c,
1246 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001247 module: module,
Colin Crossc9028482014-12-18 16:28:54 -08001248 },
Colin Crossed342d92015-03-11 00:57:25 -07001249 name: name,
Colin Crossc9028482014-12-18 16:28:54 -08001250 }
1251
1252 mutator(mctx)
1253 if len(mctx.errs) > 0 {
1254 errs = append(errs, mctx.errs...)
1255 return errs
1256 }
1257
1258 // Fix up any remaining dependencies on modules that were split into variants
1259 // by replacing them with the first variant
1260 for i, dep := range module.directDeps {
1261 if dep.logicModule == nil {
1262 module.directDeps[i] = dep.splitModules[0]
1263 }
1264 }
1265
1266 if mctx.dependenciesModified {
1267 dependenciesModified = true
1268 }
1269
1270 if module.splitModules != nil {
1271 newModules = append(newModules, module.splitModules...)
1272 } else {
1273 newModules = append(newModules, module)
1274 }
1275 }
1276
1277 group.modules = newModules
1278 }
1279
1280 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001281 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001282 if len(errs) > 0 {
1283 return errs
1284 }
1285 }
1286
1287 return errs
1288}
1289
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001290func (c *Context) initSpecialVariables() {
1291 c.buildDir = nil
1292 c.requiredNinjaMajor = 1
1293 c.requiredNinjaMinor = 1
1294 c.requiredNinjaMicro = 0
1295}
1296
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001297func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001298 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001299
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001300 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001301 var errs []error
1302
Colin Cross691a60d2015-01-07 18:08:56 -08001303 cancelCh := make(chan struct{})
1304 errsCh := make(chan []error)
1305 depsCh := make(chan []string)
1306
1307 go func() {
1308 for {
1309 select {
1310 case <-cancelCh:
1311 close(cancelCh)
1312 return
1313 case newErrs := <-errsCh:
1314 errs = append(errs, newErrs...)
1315 case newDeps := <-depsCh:
1316 deps = append(deps, newDeps...)
1317
1318 }
1319 }
1320 }()
1321
Colin Cross8900e9b2015-03-02 14:03:01 -08001322 c.parallelVisitAllBottomUp(func(group *moduleGroup) bool {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001323 for _, module := range group.modules {
Colin Cross6134a5c2015-02-10 11:26:26 -08001324 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1325 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1326 // just set it to nil.
Colin Crosse7daa222015-03-11 14:35:41 -07001327 prefix := moduleNamespacePrefix(group.ninjaName + "_" + module.variantName)
Colin Cross6134a5c2015-02-10 11:26:26 -08001328 scope := newLocalScope(nil, prefix)
1329
Colin Crossbbfa51a2014-12-17 16:12:41 -08001330 mctx := &moduleContext{
Colin Cross1455a0f2014-12-17 13:23:56 -08001331 baseModuleContext: baseModuleContext{
1332 context: c,
1333 config: config,
Colin Crossed342d92015-03-11 00:57:25 -07001334 module: module,
Colin Crossb2e7b5d2014-11-11 14:18:53 -08001335 },
Colin Crossed342d92015-03-11 00:57:25 -07001336 scope: scope,
Colin Crossbbfa51a2014-12-17 16:12:41 -08001337 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001338
Colin Crossbbfa51a2014-12-17 16:12:41 -08001339 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001340
Colin Crossbbfa51a2014-12-17 16:12:41 -08001341 if len(mctx.errs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001342 errsCh <- mctx.errs
Colin Cross8900e9b2015-03-02 14:03:01 -08001343 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001344 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001345
Colin Cross691a60d2015-01-07 18:08:56 -08001346 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001347
Colin Crossbbfa51a2014-12-17 16:12:41 -08001348 newErrs := c.processLocalBuildActions(&group.actionDefs,
1349 &mctx.actionDefs, liveGlobals)
1350 if len(newErrs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001351 errsCh <- newErrs
Colin Cross8900e9b2015-03-02 14:03:01 -08001352 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001353 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001354 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001355 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001356 })
1357
1358 cancelCh <- struct{}{}
1359 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001360
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001361 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001362}
1363
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001364func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001365 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001366
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001367 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001368 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001369
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001370 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001371 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1372 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1373 // just set it to nil.
1374 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001375
1376 sctx := &singletonContext{
1377 context: c,
1378 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001379 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001380 }
1381
1382 info.singleton.GenerateBuildActions(sctx)
1383
1384 if len(sctx.errs) > 0 {
1385 errs = append(errs, sctx.errs...)
1386 if len(errs) > maxErrors {
1387 break
1388 }
1389 continue
1390 }
1391
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001392 deps = append(deps, sctx.ninjaFileDeps...)
1393
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001394 newErrs := c.processLocalBuildActions(&info.actionDefs,
1395 &sctx.actionDefs, liveGlobals)
1396 errs = append(errs, newErrs...)
1397 if len(errs) > maxErrors {
1398 break
1399 }
1400 }
1401
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001402 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001403}
1404
1405func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1406 liveGlobals *liveTracker) []error {
1407
1408 var errs []error
1409
1410 // First we go through and add everything referenced by the module's
1411 // buildDefs to the live globals set. This will end up adding the live
1412 // locals to the set as well, but we'll take them out after.
1413 for _, def := range in.buildDefs {
1414 err := liveGlobals.AddBuildDefDeps(def)
1415 if err != nil {
1416 errs = append(errs, err)
1417 }
1418 }
1419
1420 if len(errs) > 0 {
1421 return errs
1422 }
1423
Colin Crossc9028482014-12-18 16:28:54 -08001424 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001425
1426 // We use the now-incorrect set of live "globals" to determine which local
1427 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001428 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001429 for _, v := range in.variables {
1430 _, isLive := liveGlobals.variables[v]
1431 if isLive {
1432 out.variables = append(out.variables, v)
1433 delete(liveGlobals.variables, v)
1434 }
1435 }
1436
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001437 for _, r := range in.rules {
1438 _, isLive := liveGlobals.rules[r]
1439 if isLive {
1440 out.rules = append(out.rules, r)
1441 delete(liveGlobals.rules, r)
1442 }
1443 }
1444
1445 return nil
1446}
1447
Colin Crossbbfa51a2014-12-17 16:12:41 -08001448func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1449 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001450
Colin Crossbbfa51a2014-12-17 16:12:41 -08001451 var walk func(module *moduleInfo)
1452 walk = func(module *moduleInfo) {
1453 visited[module] = true
1454 for _, moduleDep := range module.directDeps {
1455 if !visited[moduleDep] {
1456 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001457 }
1458 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459
Colin Crossbbfa51a2014-12-17 16:12:41 -08001460 if module != topModule {
1461 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001462 }
1463 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001464
1465 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001466}
1467
Colin Crossbbfa51a2014-12-17 16:12:41 -08001468func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469 visit func(Module)) {
1470
Colin Crossbbfa51a2014-12-17 16:12:41 -08001471 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001472
Colin Crossbbfa51a2014-12-17 16:12:41 -08001473 var walk func(module *moduleInfo)
1474 walk = func(module *moduleInfo) {
1475 visited[module] = true
1476 for _, moduleDep := range module.directDeps {
1477 if !visited[moduleDep] {
1478 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001479 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001480 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001481
1482 if module != topModule {
1483 if pred(module.logicModule) {
1484 visit(module.logicModule)
1485 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001486 }
1487 }
1488
Colin Crossbbfa51a2014-12-17 16:12:41 -08001489 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001490}
1491
Colin Crossc9028482014-12-18 16:28:54 -08001492func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1493 for _, dep := range module.directDeps {
1494 visit(dep.logicModule)
1495 }
1496}
1497
1498func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1499 visit func(Module)) {
1500
1501 for _, dep := range module.directDeps {
1502 if pred(dep.logicModule) {
1503 visit(dep.logicModule)
1504 }
1505 }
1506}
1507
Jamie Gennisc15544d2014-09-24 20:26:52 -07001508func (c *Context) sortedModuleNames() []string {
1509 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001510 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1511 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001512 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1513 moduleName)
1514 }
1515 sort.Strings(c.cachedSortedModuleNames)
1516 }
1517
1518 return c.cachedSortedModuleNames
1519}
1520
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001521func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001522 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001523 group := c.moduleGroups[moduleName]
1524 for _, module := range group.modules {
1525 visit(module.logicModule)
1526 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001527 }
1528}
1529
1530func (c *Context) visitAllModulesIf(pred func(Module) bool,
1531 visit func(Module)) {
1532
Jamie Gennisc15544d2014-09-24 20:26:52 -07001533 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001534 group := c.moduleGroups[moduleName]
1535 for _, module := range group.modules {
1536 if pred(module.logicModule) {
1537 visit(module.logicModule)
1538 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001539 }
1540 }
1541}
1542
1543func (c *Context) requireNinjaVersion(major, minor, micro int) {
1544 if major != 1 {
1545 panic("ninja version with major version != 1 not supported")
1546 }
1547 if c.requiredNinjaMinor < minor {
1548 c.requiredNinjaMinor = minor
1549 c.requiredNinjaMicro = micro
1550 }
1551 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1552 c.requiredNinjaMicro = micro
1553 }
1554}
1555
1556func (c *Context) setBuildDir(value *ninjaString) {
1557 if c.buildDir != nil {
1558 panic("buildDir set multiple times")
1559 }
1560 c.buildDir = value
1561}
1562
1563func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001564 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001565
Jamie Gennis2fb20952014-10-03 02:49:58 -07001566 pkgs := make(map[string]*PackageContext)
1567 pkgNames := make(map[*PackageContext]string)
1568 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001569
Jamie Gennis2fb20952014-10-03 02:49:58 -07001570 processPackage := func(pctx *PackageContext) {
1571 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001572 // This is a built-in rule and has no package.
1573 return
1574 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001575 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001576 // We've already processed this package.
1577 return
1578 }
1579
Jamie Gennis2fb20952014-10-03 02:49:58 -07001580 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001581 if present {
1582 // Short name collision. Both this package and the one that's
1583 // already there need to use their full names. We leave the short
1584 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001585 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001586 longPkgNames[otherPkg] = true
1587 } else {
1588 // No collision so far. Tentatively set the package's name to be
1589 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001590 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001591 }
1592 }
1593
1594 // We try to give all packages their short name, but when we get collisions
1595 // we need to use the full unique package name.
1596 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001597 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001598 }
1599 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001600 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001601 }
1602 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001603 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001604 }
1605
1606 // Add the packages that had collisions using their full unique names. This
1607 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001608 for pctx := range longPkgNames {
1609 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001610 }
1611
1612 return pkgNames
1613}
1614
1615func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001616 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001617
1618 visited := make(map[Variable]bool) // variables that were already checked
1619 checking := make(map[Variable]bool) // variables actively being checked
1620
1621 var check func(v Variable) []Variable
1622
1623 check = func(v Variable) []Variable {
1624 visited[v] = true
1625 checking[v] = true
1626 defer delete(checking, v)
1627
1628 value := variables[v]
1629 for _, dep := range value.variables {
1630 if checking[dep] {
1631 // This is a cycle.
1632 return []Variable{dep, v}
1633 }
1634
1635 if !visited[dep] {
1636 cycle := check(dep)
1637 if cycle != nil {
1638 if cycle[0] == v {
1639 // We are the "start" of the cycle, so we're responsible
1640 // for generating the errors. The cycle list is in
1641 // reverse order because all the 'check' calls append
1642 // their own module to the list.
1643 msgs := []string{"detected variable reference cycle:"}
1644
1645 // Iterate backwards through the cycle list.
1646 curName := v.fullName(pkgNames)
1647 curValue := value.Value(pkgNames)
1648 for i := len(cycle) - 1; i >= 0; i-- {
1649 next := cycle[i]
1650 nextName := next.fullName(pkgNames)
1651 nextValue := variables[next].Value(pkgNames)
1652
1653 msgs = append(msgs, fmt.Sprintf(
1654 " %q depends on %q", curName, nextName))
1655 msgs = append(msgs, fmt.Sprintf(
1656 " [%s = %s]", curName, curValue))
1657
1658 curName = nextName
1659 curValue = nextValue
1660 }
1661
1662 // Variable reference cycles are a programming error,
1663 // not the fault of the Blueprint file authors.
1664 panic(strings.Join(msgs, "\n"))
1665 } else {
1666 // We're not the "start" of the cycle, so we just append
1667 // our module to the list and return it.
1668 return append(cycle, v)
1669 }
1670 }
1671 }
1672 }
1673
1674 return nil
1675 }
1676
1677 for v := range variables {
1678 if !visited[v] {
1679 cycle := check(v)
1680 if cycle != nil {
1681 panic("inconceivable!")
1682 }
1683 }
1684 }
1685}
1686
Jamie Gennisaf435562014-10-27 22:34:56 -07001687// AllTargets returns a map all the build target names to the rule used to build
1688// them. This is the same information that is output by running 'ninja -t
1689// targets all'. If this is called before PrepareBuildActions successfully
1690// completes then ErrbuildActionsNotReady is returned.
1691func (c *Context) AllTargets() (map[string]string, error) {
1692 if !c.buildActionsReady {
1693 return nil, ErrBuildActionsNotReady
1694 }
1695
1696 targets := map[string]string{}
1697
1698 // Collect all the module build targets.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001699 for _, info := range c.moduleGroups {
Jamie Gennisaf435562014-10-27 22:34:56 -07001700 for _, buildDef := range info.actionDefs.buildDefs {
1701 ruleName := buildDef.Rule.fullName(c.pkgNames)
1702 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001703 outputValue, err := output.Eval(c.globalVariables)
1704 if err != nil {
1705 return nil, err
1706 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001707 targets[outputValue] = ruleName
1708 }
1709 }
1710 }
1711
1712 // Collect all the singleton build targets.
1713 for _, info := range c.singletonInfo {
1714 for _, buildDef := range info.actionDefs.buildDefs {
1715 ruleName := buildDef.Rule.fullName(c.pkgNames)
1716 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001717 outputValue, err := output.Eval(c.globalVariables)
1718 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001719 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001720 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001721 targets[outputValue] = ruleName
1722 }
1723 }
1724 }
1725
1726 return targets, nil
1727}
1728
Jamie Gennisd4e10182014-06-12 20:06:50 -07001729// WriteBuildFile writes the Ninja manifeset text for the generated build
1730// actions to w. If this is called before PrepareBuildActions successfully
1731// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001732func (c *Context) WriteBuildFile(w io.Writer) error {
1733 if !c.buildActionsReady {
1734 return ErrBuildActionsNotReady
1735 }
1736
1737 nw := newNinjaWriter(w)
1738
1739 err := c.writeBuildFileHeader(nw)
1740 if err != nil {
1741 return err
1742 }
1743
1744 err = c.writeNinjaRequiredVersion(nw)
1745 if err != nil {
1746 return err
1747 }
1748
1749 // TODO: Group the globals by package.
1750
1751 err = c.writeGlobalVariables(nw)
1752 if err != nil {
1753 return err
1754 }
1755
1756 err = c.writeGlobalPools(nw)
1757 if err != nil {
1758 return err
1759 }
1760
1761 err = c.writeBuildDir(nw)
1762 if err != nil {
1763 return err
1764 }
1765
1766 err = c.writeGlobalRules(nw)
1767 if err != nil {
1768 return err
1769 }
1770
1771 err = c.writeAllModuleActions(nw)
1772 if err != nil {
1773 return err
1774 }
1775
1776 err = c.writeAllSingletonActions(nw)
1777 if err != nil {
1778 return err
1779 }
1780
1781 return nil
1782}
1783
Jamie Gennisc15544d2014-09-24 20:26:52 -07001784type pkgAssociation struct {
1785 PkgName string
1786 PkgPath string
1787}
1788
1789type pkgAssociationSorter struct {
1790 pkgs []pkgAssociation
1791}
1792
1793func (s *pkgAssociationSorter) Len() int {
1794 return len(s.pkgs)
1795}
1796
1797func (s *pkgAssociationSorter) Less(i, j int) bool {
1798 iName := s.pkgs[i].PkgName
1799 jName := s.pkgs[j].PkgName
1800 return iName < jName
1801}
1802
1803func (s *pkgAssociationSorter) Swap(i, j int) {
1804 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1805}
1806
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001807func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1808 headerTemplate := template.New("fileHeader")
1809 _, err := headerTemplate.Parse(fileHeaderTemplate)
1810 if err != nil {
1811 // This is a programming error.
1812 panic(err)
1813 }
1814
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001815 var pkgs []pkgAssociation
1816 maxNameLen := 0
1817 for pkg, name := range c.pkgNames {
1818 pkgs = append(pkgs, pkgAssociation{
1819 PkgName: name,
1820 PkgPath: pkg.pkgPath,
1821 })
1822 if len(name) > maxNameLen {
1823 maxNameLen = len(name)
1824 }
1825 }
1826
1827 for i := range pkgs {
1828 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1829 }
1830
Jamie Gennisc15544d2014-09-24 20:26:52 -07001831 sort.Sort(&pkgAssociationSorter{pkgs})
1832
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001833 params := map[string]interface{}{
1834 "Pkgs": pkgs,
1835 }
1836
1837 buf := bytes.NewBuffer(nil)
1838 err = headerTemplate.Execute(buf, params)
1839 if err != nil {
1840 return err
1841 }
1842
1843 return nw.Comment(buf.String())
1844}
1845
1846func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1847 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1848 c.requiredNinjaMicro)
1849
1850 err := nw.Assign("ninja_required_version", value)
1851 if err != nil {
1852 return err
1853 }
1854
1855 return nw.BlankLine()
1856}
1857
1858func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1859 if c.buildDir != nil {
1860 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1861 if err != nil {
1862 return err
1863 }
1864
1865 err = nw.BlankLine()
1866 if err != nil {
1867 return err
1868 }
1869 }
1870 return nil
1871}
1872
Jamie Gennisc15544d2014-09-24 20:26:52 -07001873type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001874 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001875}
1876
Jamie Gennisc15544d2014-09-24 20:26:52 -07001877type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001878 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001879 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001880}
1881
Jamie Gennisc15544d2014-09-24 20:26:52 -07001882func (s *globalEntitySorter) Len() int {
1883 return len(s.entities)
1884}
1885
1886func (s *globalEntitySorter) Less(i, j int) bool {
1887 iName := s.entities[i].fullName(s.pkgNames)
1888 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001889 return iName < jName
1890}
1891
Jamie Gennisc15544d2014-09-24 20:26:52 -07001892func (s *globalEntitySorter) Swap(i, j int) {
1893 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001894}
1895
1896func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1897 visited := make(map[Variable]bool)
1898
1899 var walk func(v Variable) error
1900 walk = func(v Variable) error {
1901 visited[v] = true
1902
1903 // First visit variables on which this variable depends.
1904 value := c.globalVariables[v]
1905 for _, dep := range value.variables {
1906 if !visited[dep] {
1907 err := walk(dep)
1908 if err != nil {
1909 return err
1910 }
1911 }
1912 }
1913
1914 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1915 if err != nil {
1916 return err
1917 }
1918
1919 err = nw.BlankLine()
1920 if err != nil {
1921 return err
1922 }
1923
1924 return nil
1925 }
1926
Jamie Gennisc15544d2014-09-24 20:26:52 -07001927 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1928 for variable := range c.globalVariables {
1929 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930 }
1931
Jamie Gennisc15544d2014-09-24 20:26:52 -07001932 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001933
Jamie Gennisc15544d2014-09-24 20:26:52 -07001934 for _, entity := range globalVariables {
1935 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001936 if !visited[v] {
1937 err := walk(v)
1938 if err != nil {
1939 return nil
1940 }
1941 }
1942 }
1943
1944 return nil
1945}
1946
1947func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001948 globalPools := make([]globalEntity, 0, len(c.globalPools))
1949 for pool := range c.globalPools {
1950 globalPools = append(globalPools, pool)
1951 }
1952
1953 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1954
1955 for _, entity := range globalPools {
1956 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001957 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001958 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001959 err := def.WriteTo(nw, name)
1960 if err != nil {
1961 return err
1962 }
1963
1964 err = nw.BlankLine()
1965 if err != nil {
1966 return err
1967 }
1968 }
1969
1970 return nil
1971}
1972
1973func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001974 globalRules := make([]globalEntity, 0, len(c.globalRules))
1975 for rule := range c.globalRules {
1976 globalRules = append(globalRules, rule)
1977 }
1978
1979 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
1980
1981 for _, entity := range globalRules {
1982 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001983 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001984 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001985 err := def.WriteTo(nw, name, c.pkgNames)
1986 if err != nil {
1987 return err
1988 }
1989
1990 err = nw.BlankLine()
1991 if err != nil {
1992 return err
1993 }
1994 }
1995
1996 return nil
1997}
1998
Colin Crossbbfa51a2014-12-17 16:12:41 -08001999type moduleGroupSorter []*moduleGroup
Jamie Gennis86179fe2014-06-11 16:27:16 -07002000
Colin Crossbbfa51a2014-12-17 16:12:41 -08002001func (s moduleGroupSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002002 return len(s)
2003}
2004
Colin Crossbbfa51a2014-12-17 16:12:41 -08002005func (s moduleGroupSorter) Less(i, j int) bool {
Colin Crossed342d92015-03-11 00:57:25 -07002006 iName := s[i].name
2007 jName := s[j].name
Jamie Gennis86179fe2014-06-11 16:27:16 -07002008 return iName < jName
2009}
2010
Colin Crossbbfa51a2014-12-17 16:12:41 -08002011func (s moduleGroupSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002012 s[i], s[j] = s[j], s[i]
2013}
2014
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002015func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2016 headerTemplate := template.New("moduleHeader")
2017 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2018 if err != nil {
2019 // This is a programming error.
2020 panic(err)
2021 }
2022
Colin Crossbbfa51a2014-12-17 16:12:41 -08002023 infos := make([]*moduleGroup, 0, len(c.moduleGroups))
2024 for _, info := range c.moduleGroups {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002025 infos = append(infos, info)
2026 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002027 sort.Sort(moduleGroupSorter(infos))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002028
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002029 buf := bytes.NewBuffer(nil)
2030
Jamie Gennis86179fe2014-06-11 16:27:16 -07002031 for _, info := range infos {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002032 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002033
2034 // In order to make the bootstrap build manifest independent of the
2035 // build dir we need to output the Blueprints file locations in the
2036 // comments as paths relative to the source directory.
Colin Crossed342d92015-03-11 00:57:25 -07002037 relPos := info.modules[0].pos
2038 relPos.Filename = info.modules[0].relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002039
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002040 // Get the name and location of the factory function for the module.
Colin Crossed342d92015-03-11 00:57:25 -07002041 factory := c.moduleFactories[info.modules[0].typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002042 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2043 factoryName := factoryFunc.Name()
2044
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002045 infoMap := map[string]interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07002046 "properties": info.modules[0].properties,
2047 "typeName": info.modules[0].typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002048 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002049 "pos": relPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002050 }
2051 err = headerTemplate.Execute(buf, infoMap)
2052 if err != nil {
2053 return err
2054 }
2055
2056 err = nw.Comment(buf.String())
2057 if err != nil {
2058 return err
2059 }
2060
2061 err = nw.BlankLine()
2062 if err != nil {
2063 return err
2064 }
2065
2066 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2067 if err != nil {
2068 return err
2069 }
2070
2071 err = nw.BlankLine()
2072 if err != nil {
2073 return err
2074 }
2075 }
2076
2077 return nil
2078}
2079
2080func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2081 headerTemplate := template.New("singletonHeader")
2082 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2083 if err != nil {
2084 // This is a programming error.
2085 panic(err)
2086 }
2087
2088 buf := bytes.NewBuffer(nil)
2089
Jamie Gennis86179fe2014-06-11 16:27:16 -07002090 singletonNames := make([]string, 0, len(c.singletonInfo))
2091 for name := range c.singletonInfo {
2092 singletonNames = append(singletonNames, name)
2093 }
2094 sort.Strings(singletonNames)
2095
2096 for _, name := range singletonNames {
2097 info := c.singletonInfo[name]
2098
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002099 // Get the name of the factory function for the module.
2100 factory := info.factory
2101 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2102 factoryName := factoryFunc.Name()
2103
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002104 buf.Reset()
2105 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002106 "name": name,
2107 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002108 }
2109 err = headerTemplate.Execute(buf, infoMap)
2110 if err != nil {
2111 return err
2112 }
2113
2114 err = nw.Comment(buf.String())
2115 if err != nil {
2116 return err
2117 }
2118
2119 err = nw.BlankLine()
2120 if err != nil {
2121 return err
2122 }
2123
2124 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2125 if err != nil {
2126 return err
2127 }
2128
2129 err = nw.BlankLine()
2130 if err != nil {
2131 return err
2132 }
2133 }
2134
2135 return nil
2136}
2137
2138func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2139 defs *localBuildActions) error {
2140
2141 // Write the local variable assignments.
2142 for _, v := range defs.variables {
2143 // A localVariable doesn't need the package names or config to
2144 // determine its name or value.
2145 name := v.fullName(nil)
2146 value, err := v.value(nil)
2147 if err != nil {
2148 panic(err)
2149 }
2150 err = nw.Assign(name, value.Value(c.pkgNames))
2151 if err != nil {
2152 return err
2153 }
2154 }
2155
2156 if len(defs.variables) > 0 {
2157 err := nw.BlankLine()
2158 if err != nil {
2159 return err
2160 }
2161 }
2162
2163 // Write the local rules.
2164 for _, r := range defs.rules {
2165 // A localRule doesn't need the package names or config to determine
2166 // its name or definition.
2167 name := r.fullName(nil)
2168 def, err := r.def(nil)
2169 if err != nil {
2170 panic(err)
2171 }
2172
2173 err = def.WriteTo(nw, name, c.pkgNames)
2174 if err != nil {
2175 return err
2176 }
2177
2178 err = nw.BlankLine()
2179 if err != nil {
2180 return err
2181 }
2182 }
2183
2184 // Write the build definitions.
2185 for _, buildDef := range defs.buildDefs {
2186 err := buildDef.WriteTo(nw, c.pkgNames)
2187 if err != nil {
2188 return err
2189 }
2190
2191 if len(buildDef.Args) > 0 {
2192 err = nw.BlankLine()
2193 if err != nil {
2194 return err
2195 }
2196 }
2197 }
2198
2199 return nil
2200}
2201
2202var fileHeaderTemplate = `******************************************************************************
2203*** This file is generated and should not be edited ***
2204******************************************************************************
2205{{if .Pkgs}}
2206This file contains variables, rules, and pools with name prefixes indicating
2207they were generated by the following Go packages:
2208{{range .Pkgs}}
2209 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2210
2211`
2212
2213var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2214Module: {{.properties.Name}}
2215Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002216Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002217Defined: {{.pos}}
2218`
2219
2220var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2221Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002222Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002223`