blob: b98ffbebf8a1af3cb256956b02d28c07157e3f53 [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 (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
19 "errors"
20 "fmt"
Jamie Gennis6cafc2c2015-03-20 22:39:29 -040021 "github.com/google/blueprint/parser"
Michael Beardsworth1ec44532015-03-31 20:39:02 -070022 "github.com/google/blueprint/pathtools"
Jamie Gennis6cafc2c2015-03-20 22:39:29 -040023 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070024 "io"
25 "os"
26 "path/filepath"
27 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070028 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080030 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070031 "strings"
32 "text/scanner"
33 "text/template"
34)
35
36var ErrBuildActionsNotReady = errors.New("build actions are not ready")
37
38const maxErrors = 10
39
Jamie Gennisd4e10182014-06-12 20:06:50 -070040// A Context contains all the state needed to parse a set of Blueprints files
41// and generate a Ninja file. The process of generating a Ninja file proceeds
42// through a series of four phases. Each phase corresponds with a some methods
43// on the Context object
44//
45// Phase Methods
46// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070047// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070048//
49// 2. Parse ParseBlueprintsFiles, Parse
50//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070051// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070052//
53// 4. Write WriteBuildFile
54//
55// The registration phase prepares the context to process Blueprints files
56// containing various types of modules. The parse phase reads in one or more
57// Blueprints files and validates their contents against the module types that
58// have been registered. The generate phase then analyzes the parsed Blueprints
59// contents to create an internal representation for the build actions that must
60// be performed. This phase also performs validation of the module dependencies
61// and property values defined in the parsed Blueprints files. Finally, the
62// write phase generates the Ninja manifest text based on the generated build
63// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064type Context struct {
65 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070066 moduleFactories map[string]ModuleFactory
67 moduleGroups map[string]*moduleGroup
68 moduleInfo map[Module]*moduleInfo
69 modulesSorted []*moduleInfo
70 singletonInfo map[string]*singletonInfo
71 mutatorInfo []*mutatorInfo
72 earlyMutatorInfo []*earlyMutatorInfo
73 variantMutatorNames []string
74 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070075
76 dependenciesReady bool // set to true on a successful ResolveDependencies
77 buildActionsReady bool // set to true on a successful PrepareBuildActions
78
79 // set by SetIgnoreUnknownModuleTypes
80 ignoreUnknownModuleTypes bool
81
82 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070083 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070084 globalVariables map[Variable]*ninjaString
85 globalPools map[Pool]*poolDef
86 globalRules map[Rule]*ruleDef
87
88 // set during PrepareBuildActions
89 buildDir *ninjaString // The builddir special Ninja variable
90 requiredNinjaMajor int // For the ninja_required_version variable
91 requiredNinjaMinor int // For the ninja_required_version variable
92 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070093
94 // set lazily by sortedModuleNames
95 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070096}
97
Jamie Gennisd4e10182014-06-12 20:06:50 -070098// An Error describes a problem that was encountered that is related to a
99// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700101 Err error // the error that occurred
102 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700103}
104
105type localBuildActions struct {
106 variables []*localVariable
107 rules []*localRule
108 buildDefs []*buildDef
109}
110
Colin Crossbbfa51a2014-12-17 16:12:41 -0800111type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700112 name string
113 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700114
Colin Crossbbfa51a2014-12-17 16:12:41 -0800115 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116}
117
Colin Crossbbfa51a2014-12-17 16:12:41 -0800118type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700119 // set during Parse
120 typeName string
121 relBlueprintsFile string
122 pos scanner.Position
123 propertyPos map[string]scanner.Position
124 properties struct {
125 Name string
126 Deps []string
127 }
128
Colin Crossf5e34b92015-03-13 16:02:36 -0700129 variantName string
130 variant variationMap
131 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700132
Colin Crossc9028482014-12-18 16:28:54 -0800133 logicModule Module
134 group *moduleGroup
135 moduleProperties []interface{}
136
137 // set during ResolveDependencies
138 directDeps []*moduleInfo
139
Colin Cross7addea32015-03-11 15:43:52 -0700140 // set during updateDependencies
141 reverseDeps []*moduleInfo
142 depsCount int
143
144 // used by parallelVisitAllBottomUp
145 waitingCount int
146
Colin Crossc9028482014-12-18 16:28:54 -0800147 // set during each runMutator
148 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700149
150 // set during PrepareBuildActions
151 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800152}
153
Colin Crossf5e34b92015-03-13 16:02:36 -0700154// A Variation is a way that a variant of a module differs from other variants of the same module.
155// For example, two variants of the same module might have Variation{"arch","arm"} and
156// Variation{"arch","arm64"}
157type Variation struct {
158 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700159 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700160 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
161 // "shared" or "static" for link.
162 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700163}
164
Colin Crossf5e34b92015-03-13 16:02:36 -0700165// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
166type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700167
Colin Crossf5e34b92015-03-13 16:02:36 -0700168func (vm variationMap) clone() variationMap {
169 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700170 for k, v := range vm {
171 newVm[k] = v
172 }
173
174 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800175}
176
Colin Crossf5e34b92015-03-13 16:02:36 -0700177func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700178 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800179}
180
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700181type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700182 // set during RegisterSingletonType
183 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700184 singleton Singleton
185
186 // set during PrepareBuildActions
187 actionDefs localBuildActions
188}
189
Colin Crossc9028482014-12-18 16:28:54 -0800190type mutatorInfo struct {
191 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800192 topDownMutator TopDownMutator
193 bottomUpMutator BottomUpMutator
194 name string
Colin Crossc9028482014-12-18 16:28:54 -0800195}
196
Colin Cross65569e42015-03-10 20:08:19 -0700197type earlyMutatorInfo struct {
198 // set during RegisterEarlyMutator
199 mutator EarlyMutator
200 name string
201}
202
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700203func (e *Error) Error() string {
204
205 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
206}
207
Jamie Gennisd4e10182014-06-12 20:06:50 -0700208// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700209// no module or singleton factories registered, so the RegisterModuleFactory and
210// RegisterSingletonFactory methods must be called before it can do anything
211// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700212func NewContext() *Context {
213 return &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800214 moduleFactories: make(map[string]ModuleFactory),
215 moduleGroups: make(map[string]*moduleGroup),
216 moduleInfo: make(map[Module]*moduleInfo),
217 singletonInfo: make(map[string]*singletonInfo),
218 moduleNinjaNames: make(map[string]*moduleGroup),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700219 }
220}
221
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700222// A ModuleFactory function creates a new Module object. See the
223// Context.RegisterModuleType method for details about how a registered
224// ModuleFactory is used by a Context.
225type ModuleFactory func() (m Module, propertyStructs []interface{})
226
Jamie Gennisd4e10182014-06-12 20:06:50 -0700227// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700228// Blueprints file) with a Module factory function. When the given module type
229// name is encountered in a Blueprints file during parsing, the Module factory
230// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800231// generation for the module. If a Mutator splits a module into multiple variants,
232// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700233//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700234// The module type names given here must be unique for the context. The factory
235// function should be a named function so that its package and name can be
236// included in the generated Ninja file for debugging purposes.
237//
238// The factory function returns two values. The first is the newly created
239// Module object. The second is a slice of pointers to that Module object's
240// properties structs. Each properties struct is examined when parsing a module
241// definition of this type in a Blueprints file. Exported fields of the
242// properties structs are automatically set to the property values specified in
243// the Blueprints file. The properties struct field names determine the name of
244// the Blueprints file properties that are used - the Blueprints property name
245// matches that of the properties struct field name with the first letter
246// converted to lower-case.
247//
248// The fields of the properties struct must be either []string, a string, or
249// bool. The Context will panic if a Module gets instantiated with a properties
250// struct containing a field that is not one these supported types.
251//
252// Any properties that appear in the Blueprints files that are not built-in
253// module properties (such as "name" and "deps") and do not have a corresponding
254// field in the returned module properties struct result in an error during the
255// Context's parse phase.
256//
257// As an example, the follow code:
258//
259// type myModule struct {
260// properties struct {
261// Foo string
262// Bar []string
263// }
264// }
265//
266// func NewMyModule() (blueprint.Module, []interface{}) {
267// module := new(myModule)
268// properties := &module.properties
269// return module, []interface{}{properties}
270// }
271//
272// func main() {
273// ctx := blueprint.NewContext()
274// ctx.RegisterModuleType("my_module", NewMyModule)
275// // ...
276// }
277//
278// would support parsing a module defined in a Blueprints file as follows:
279//
280// my_module {
281// name: "myName",
282// foo: "my foo string",
283// bar: ["my", "bar", "strings"],
284// }
285//
Colin Cross7ad621c2015-01-07 16:22:45 -0800286// The factory function may be called from multiple goroutines. Any accesses
287// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700288func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
289 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700290 panic(errors.New("module type name is already registered"))
291 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700292 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700293}
294
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700295// A SingletonFactory function creates a new Singleton object. See the
296// Context.RegisterSingletonType method for details about how a registered
297// SingletonFactory is used by a Context.
298type SingletonFactory func() Singleton
299
300// RegisterSingletonType registers a singleton type that will be invoked to
301// generate build actions. Each registered singleton type is instantiated and
302// and invoked exactly once as part of the generate phase.
303//
304// The singleton type names given here must be unique for the context. The
305// factory function should be a named function so that its package and name can
306// be included in the generated Ninja file for debugging purposes.
307func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700308 if _, present := c.singletonInfo[name]; present {
309 panic(errors.New("singleton name is already registered"))
310 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700311
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700312 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700313 factory: factory,
314 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700315 }
316}
317
318func singletonPkgPath(singleton Singleton) string {
319 typ := reflect.TypeOf(singleton)
320 for typ.Kind() == reflect.Ptr {
321 typ = typ.Elem()
322 }
323 return typ.PkgPath()
324}
325
326func singletonTypeName(singleton Singleton) string {
327 typ := reflect.TypeOf(singleton)
328 for typ.Kind() == reflect.Ptr {
329 typ = typ.Elem()
330 }
331 return typ.PkgPath() + "." + typ.Name()
332}
333
Colin Crossc9028482014-12-18 16:28:54 -0800334// RegisterTopDownMutator registers a mutator that will be invoked to propagate
335// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700336// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
337// once per Module, and is invoked on a module before being invoked on any of its
338// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800339//
Colin Cross65569e42015-03-10 20:08:19 -0700340// The mutator type names given here must be unique to all top down mutators in
341// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800342func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
343 for _, m := range c.mutatorInfo {
344 if m.name == name && m.topDownMutator != nil {
345 panic(fmt.Errorf("mutator name %s is already registered", name))
346 }
347 }
348
349 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
350 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800351 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800352 })
353}
354
355// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700356// Modules into variants. Each registered mutator is invoked in registration
357// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
358// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800359//
Colin Cross65569e42015-03-10 20:08:19 -0700360// The mutator type names given here must be unique to all bottom up or early
361// mutators in the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800362func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
Colin Cross65569e42015-03-10 20:08:19 -0700363 for _, m := range c.variantMutatorNames {
364 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800365 panic(fmt.Errorf("mutator name %s is already registered", name))
366 }
367 }
368
369 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
370 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800371 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800372 })
Colin Cross65569e42015-03-10 20:08:19 -0700373
374 c.variantMutatorNames = append(c.variantMutatorNames, name)
375}
376
377// RegisterEarlyMutator registers a mutator that will be invoked to split
378// Modules into multiple variant Modules before any dependencies have been
379// created. Each registered mutator is invoked in registration order once
380// per Module (including each variant from previous early mutators). Module
381// order is unpredictable.
382//
383// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700384// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700385//
386// The mutator type names given here must be unique to all bottom up or early
387// mutators in the Context.
388func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
389 for _, m := range c.variantMutatorNames {
390 if m == name {
391 panic(fmt.Errorf("mutator name %s is already registered", name))
392 }
393 }
394
395 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &earlyMutatorInfo{
396 mutator: mutator,
397 name: name,
398 })
399
400 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800401}
402
Jamie Gennisd4e10182014-06-12 20:06:50 -0700403// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
404// where it encounters an unknown module type while parsing Blueprints files. By
405// default, the context will report unknown module types as an error. If this
406// method is called with ignoreUnknownModuleTypes set to true then the context
407// will silently ignore unknown module types.
408//
409// This method should generally not be used. It exists to facilitate the
410// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700411func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
412 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
413}
414
Jamie Gennisd4e10182014-06-12 20:06:50 -0700415// Parse parses a single Blueprints file from r, creating Module objects for
416// each of the module definitions encountered. If the Blueprints file contains
417// an assignment to the "subdirs" variable, then the subdirectories listed are
418// returned in the subdirs first return value.
419//
420// rootDir specifies the path to the root directory of the source tree, while
421// filename specifies the path to the Blueprints file. These paths are used for
422// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800423func (c *Context) parse(rootDir, filename string, r io.Reader,
424 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
425 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700426
Jamie Gennisec701282014-06-12 20:06:31 -0700427 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700428 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800429 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700430 }
431
Colin Crossc0dbc552015-01-02 15:19:28 -0800432 scope = parser.NewScope(scope)
433 scope.Remove("subdirs")
Colin Cross96e56702015-03-19 17:28:06 -0700434 file, errs := parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700435 if len(errs) > 0 {
436 for i, err := range errs {
437 if parseErr, ok := err.(*parser.ParseError); ok {
438 err = &Error{
439 Err: parseErr.Err,
440 Pos: parseErr.Pos,
441 }
442 errs[i] = err
443 }
444 }
445
446 // If there were any parse errors don't bother trying to interpret the
447 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800448 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700449 }
450
Colin Crossd1facc12015-01-08 14:56:03 -0800451 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700452 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800453 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700454 switch def := def.(type) {
455 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800456 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700457
458 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800459 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700460 default:
461 panic("unknown definition type")
462 }
463
464 if len(newErrs) > 0 {
465 errs = append(errs, newErrs...)
466 if len(errs) > maxErrors {
467 break
468 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800469 } else if newModule != nil {
470 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700471 }
472 }
473
Colin Crossc0dbc552015-01-02 15:19:28 -0800474 subdirs, newErrs := c.processSubdirs(scope)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700475
Colin Crossc0dbc552015-01-02 15:19:28 -0800476 if len(newErrs) > 0 {
477 errs = append(errs, newErrs...)
478 }
479
Colin Cross7ad621c2015-01-07 16:22:45 -0800480 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800481}
482
Colin Cross7ad621c2015-01-07 16:22:45 -0800483type stringAndScope struct {
484 string
485 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700486}
487
Jamie Gennisd4e10182014-06-12 20:06:50 -0700488// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
489// at rootFile. When it encounters a Blueprints file with a set of subdirs
490// listed it recursively parses any Blueprints files found in those
491// subdirectories.
492//
493// If no errors are encountered while parsing the files, the list of paths on
494// which the future output will depend is returned. This list will include both
495// Blueprints file paths as well as directory paths for cases where wildcard
496// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
498 errs []error) {
499
Colin Cross7ad621c2015-01-07 16:22:45 -0800500 c.dependenciesReady = false
501
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700502 rootDir := filepath.Dir(rootFile)
503
Colin Cross7ad621c2015-01-07 16:22:45 -0800504 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700505
Colin Cross7ad621c2015-01-07 16:22:45 -0800506 // Channels to receive data back from parseBlueprintsFile goroutines
507 blueprintsCh := make(chan stringAndScope)
508 errsCh := make(chan []error)
509 modulesCh := make(chan []*moduleInfo)
510 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700511
Colin Cross7ad621c2015-01-07 16:22:45 -0800512 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
513 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700514
Colin Cross7ad621c2015-01-07 16:22:45 -0800515 // Number of outstanding goroutines to wait for
516 count := 0
517
518 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
519 count++
520 go func() {
521 c.parseBlueprintsFile(filename, scope, rootDir,
522 errsCh, modulesCh, blueprintsCh, depsCh)
523 doneCh <- struct{}{}
524 }()
525 }
526
527 tooManyErrors := false
528
529 startParseBlueprintsFile(rootFile, nil)
530
531loop:
532 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700533 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800534 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700535 }
536
Colin Cross7ad621c2015-01-07 16:22:45 -0800537 select {
538 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700539 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800540 case dep := <-depsCh:
541 deps = append(deps, dep)
542 case modules := <-modulesCh:
543 newErrs := c.addModules(modules)
544 errs = append(errs, newErrs...)
545 case blueprint := <-blueprintsCh:
546 if tooManyErrors {
547 continue
548 }
549 if blueprintsSet[blueprint.string] {
550 continue
551 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700552
Colin Cross7ad621c2015-01-07 16:22:45 -0800553 blueprintsSet[blueprint.string] = true
554 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
555 case <-doneCh:
556 count--
557 if count == 0 {
558 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700559 }
560 }
561 }
562
Colin Cross7ad621c2015-01-07 16:22:45 -0800563 return
564}
565
566// parseBlueprintFile parses a single Blueprints file, returning any errors through
567// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
568// blueprintsCh, and any dependencies on Blueprints files or directories through
569// depsCh.
570func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
571 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
572 depsCh chan<- string) {
573
574 dir := filepath.Dir(filename)
575
576 file, err := os.Open(filename)
577 if err != nil {
578 errsCh <- []error{err}
579 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700580 }
581
Colin Cross7ad621c2015-01-07 16:22:45 -0800582 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
583 if len(errs) > 0 {
584 errsCh <- errs
585 }
586
587 err = file.Close()
588 if err != nil {
589 errsCh <- []error{err}
590 }
591
592 modulesCh <- modules
593
594 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700595 globPattern := filepath.Join(dir, subdir)
596 matches, matchedDirs, err := pathtools.Glob(globPattern)
597 if err != nil {
598 errsCh <- []error{err}
599 return
600 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800601
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700602 // Depend on all searched directories so we pick up future changes.
603 for _, matchedDir := range matchedDirs {
604 depsCh <- matchedDir
605 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800606
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700607 for _, foundSubdir := range matches {
608 fileInfo, subdirStatErr := os.Stat(foundSubdir)
609 if subdirStatErr != nil {
610 errsCh <- []error{subdirStatErr}
611 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800612 }
613
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700614 // Skip files
615 if !fileInfo.IsDir() {
616 continue
617 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800618
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700619 subBlueprints := filepath.Join(foundSubdir, "Blueprints")
620
621 _, err := os.Stat(subBlueprints)
622 if os.IsNotExist(err) {
623 // There is no Blueprints file in this subdirectory. We
624 // need to add the directory to the list of dependencies
625 // so that if someone adds a Blueprints file in the
626 // future we'll pick it up.
627 depsCh <- filepath.Dir(subBlueprints)
628 } else {
629 depsCh <- subBlueprints
630 blueprintsCh <- stringAndScope{
631 subBlueprints,
632 subScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800633 }
634 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800635 }
636 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700637}
638
Colin Crossc0dbc552015-01-02 15:19:28 -0800639func (c *Context) processSubdirs(
640 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700641
Colin Crossc0dbc552015-01-02 15:19:28 -0800642 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700643 switch assignment.Value.Type {
644 case parser.List:
645 subdirs = make([]string, 0, len(assignment.Value.ListValue))
646
647 for _, value := range assignment.Value.ListValue {
648 if value.Type != parser.String {
649 // The parser should not produce this.
650 panic("non-string value found in list")
651 }
652
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700653 subdirs = append(subdirs, value.StringValue)
654 }
655
656 if len(errs) > 0 {
657 subdirs = nil
658 }
659
660 return
661
662 case parser.Bool, parser.String:
663 errs = []error{
664 &Error{
665 Err: fmt.Errorf("subdirs must be a list of strings"),
666 Pos: assignment.Pos,
667 },
668 }
669
670 return
671
672 default:
673 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
674 }
675 }
676
Colin Crossc0dbc552015-01-02 15:19:28 -0800677 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700678}
679
Colin Crossf5e34b92015-03-13 16:02:36 -0700680func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
681 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800682
Colin Crossf4d18a62015-03-18 17:43:15 -0700683 if len(variationNames) == 0 {
684 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400685 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700686 }
687
Colin Crossc9028482014-12-18 16:28:54 -0800688 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800689
Colin Cross174ae052015-03-03 17:37:03 -0800690 var errs []error
691
Colin Crossf5e34b92015-03-13 16:02:36 -0700692 for i, variationName := range variationNames {
Colin Crossed342d92015-03-11 00:57:25 -0700693 typeName := origModule.typeName
Colin Crossc9028482014-12-18 16:28:54 -0800694 factory, ok := c.moduleFactories[typeName]
695 if !ok {
696 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
697 }
698
699 var newLogicModule Module
700 var newProperties []interface{}
701
702 if i == 0 {
703 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700704 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
705 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossc9028482014-12-18 16:28:54 -0800706 newLogicModule = origModule.logicModule
707 newProperties = origModule.moduleProperties
708 } else {
709 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700710 &origModule.properties,
Colin Crossc9028482014-12-18 16:28:54 -0800711 }
712 newLogicModule, newProperties = factory()
713
714 newProperties = append(props, newProperties...)
715
716 if len(newProperties) != len(origModule.moduleProperties) {
Colin Crossed342d92015-03-11 00:57:25 -0700717 panic("mismatched properties array length in " + origModule.properties.Name)
Colin Crossc9028482014-12-18 16:28:54 -0800718 }
719
720 for i := range newProperties {
721 dst := reflect.ValueOf(newProperties[i]).Elem()
722 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
723
724 proptools.CopyProperties(dst, src)
725 }
726 }
727
Colin Crossf5e34b92015-03-13 16:02:36 -0700728 newVariant := origModule.variant.clone()
729 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800730
Colin Crossed342d92015-03-11 00:57:25 -0700731 m := *origModule
732 newModule := &m
733 newModule.directDeps = append([]*moduleInfo(nil), origModule.directDeps...)
734 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700735 newModule.variant = newVariant
736 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700737 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800738
Colin Crosse7daa222015-03-11 14:35:41 -0700739 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -0700740 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700741 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -0700742 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -0700743 }
744
Colin Crossc9028482014-12-18 16:28:54 -0800745 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700746
747 // Insert the new variant into the global module map. If this is the first variant then
748 // it reuses logicModule from the original module, which causes this to replace the
749 // original module in the global module map.
Colin Crossc9028482014-12-18 16:28:54 -0800750 c.moduleInfo[newModule.logicModule] = newModule
751
Colin Crossf5e34b92015-03-13 16:02:36 -0700752 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -0800753 if len(newErrs) > 0 {
754 errs = append(errs, newErrs...)
755 }
Colin Crossc9028482014-12-18 16:28:54 -0800756 }
757
758 // Mark original variant as invalid. Modules that depend on this module will still
759 // depend on origModule, but we'll fix it when the mutator is called on them.
760 origModule.logicModule = nil
761 origModule.splitModules = newModules
762
Colin Cross174ae052015-03-03 17:37:03 -0800763 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800764}
765
Colin Crossf5e34b92015-03-13 16:02:36 -0700766func (c *Context) convertDepsToVariation(module *moduleInfo,
767 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -0800768
Colin Crossc9028482014-12-18 16:28:54 -0800769 for i, dep := range module.directDeps {
770 if dep.logicModule == nil {
771 var newDep *moduleInfo
772 for _, m := range dep.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -0700773 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -0800774 newDep = m
775 break
776 }
777 }
778 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800779 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -0700780 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
781 variationName, dep.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -0700782 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -0800783 })
784 continue
Colin Crossc9028482014-12-18 16:28:54 -0800785 }
786 module.directDeps[i] = newDep
787 }
788 }
Colin Cross174ae052015-03-03 17:37:03 -0800789
790 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800791}
792
Colin Crossf5e34b92015-03-13 16:02:36 -0700793func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -0700794 names := make([]string, 0, len(variant))
795 for _, m := range c.variantMutatorNames {
796 if v, ok := variant[m]; ok {
797 names = append(names, m+":"+v)
798 }
799 }
800
801 return strings.Join(names, ", ")
802}
803
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700804func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800805 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700806
Colin Crossd1facc12015-01-08 14:56:03 -0800807 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700808 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700809 if !ok {
810 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800811 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700812 }
813
Colin Cross7ad621c2015-01-07 16:22:45 -0800814 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700815 &Error{
816 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800817 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700818 },
819 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700820 }
821
Colin Crossbbfa51a2014-12-17 16:12:41 -0800822 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -0700823
824 module := &moduleInfo{
825 logicModule: logicModule,
Jamie Gennisec701282014-06-12 20:06:31 -0700826 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700827 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700828 }
829
Jamie Gennis87622922014-09-30 11:38:25 -0700830 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -0700831 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700832 }
833 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -0700834 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700835
Jamie Gennis87622922014-09-30 11:38:25 -0700836 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700837 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800838 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700839 }
840
Colin Crossed342d92015-03-11 00:57:25 -0700841 module.pos = moduleDef.Type.Pos
842 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700843 for name, propertyDef := range propertyMap {
Colin Crossed342d92015-03-11 00:57:25 -0700844 module.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700845 }
846
Colin Cross7ad621c2015-01-07 16:22:45 -0800847 return module, nil
848}
849
850func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
851 for _, module := range modules {
Colin Crossed342d92015-03-11 00:57:25 -0700852 name := module.properties.Name
853 c.moduleInfo[module.logicModule] = module
854
855 if group, present := c.moduleGroups[name]; present {
Colin Cross7ad621c2015-01-07 16:22:45 -0800856 errs = append(errs, []error{
857 &Error{
858 Err: fmt.Errorf("module %q already defined", name),
Colin Crossed342d92015-03-11 00:57:25 -0700859 Pos: module.pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800860 },
861 &Error{
862 Err: fmt.Errorf("<-- previous definition here"),
Colin Crossed342d92015-03-11 00:57:25 -0700863 Pos: group.modules[0].pos,
Colin Cross7ad621c2015-01-07 16:22:45 -0800864 },
865 }...)
866 continue
Colin Crossed342d92015-03-11 00:57:25 -0700867 } else {
868 ninjaName := toNinjaName(module.properties.Name)
Colin Cross7ad621c2015-01-07 16:22:45 -0800869
Colin Crossed342d92015-03-11 00:57:25 -0700870 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
871 // already exists
872 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
873 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
874 }
875
876 c.moduleNinjaNames[ninjaName] = group
877
878 group := &moduleGroup{
879 name: module.properties.Name,
880 ninjaName: ninjaName,
881 modules: []*moduleInfo{module},
882 }
883 module.group = group
884 c.moduleGroups[name] = group
885 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800886 }
887
888 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700889}
890
Jamie Gennisd4e10182014-06-12 20:06:50 -0700891// ResolveDependencies checks that the dependencies specified by all of the
892// modules defined in the parsed Blueprints files are valid. This means that
893// the modules depended upon are defined and that no circular dependencies
894// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700895//
896// The config argument is made available to all of the DynamicDependerModule
897// objects via the Config method on the DynamicDependerModuleContext objects
898// passed to their DynamicDependencies method.
899func (c *Context) ResolveDependencies(config interface{}) []error {
900 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700901 if len(errs) > 0 {
902 return errs
903 }
904
Colin Cross691a60d2015-01-07 18:08:56 -0800905 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700906 if len(errs) > 0 {
907 return errs
908 }
909
910 c.dependenciesReady = true
911 return nil
912}
913
Colin Cross65569e42015-03-10 20:08:19 -0700914// moduleDeps adds dependencies to a module. If the module implements the
915// DynamicDependerModule interface then this set consists of the union of those
916// module names listed in its "deps" property, those returned by its
917// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -0700918// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700919// is simply those names listed in its "deps" property.
Colin Cross65569e42015-03-10 20:08:19 -0700920func (c *Context) moduleDeps(module *moduleInfo,
921 config interface{}) (errs []error) {
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700922
923 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800924 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700925
Colin Crossed342d92015-03-11 00:57:25 -0700926 for _, depName := range module.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800927 if !depNamesSet[depName] {
928 depNamesSet[depName] = true
929 depNames = append(depNames, depName)
930 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700931 }
932
Colin Cross65569e42015-03-10 20:08:19 -0700933 dynamicDepender, ok := module.logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700934 if ok {
Colin Cross65569e42015-03-10 20:08:19 -0700935 ddmctx := &dynamicDependerModuleContext{
936 baseModuleContext: baseModuleContext{
937 context: c,
938 config: config,
939 module: module,
940 },
941 module: module,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700942 }
943
944 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
945
946 if len(ddmctx.errs) > 0 {
Colin Cross65569e42015-03-10 20:08:19 -0700947 return ddmctx.errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700948 }
949
950 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800951 if !depNamesSet[depName] {
952 depNamesSet[depName] = true
953 depNames = append(depNames, depName)
954 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700955 }
956 }
957
Colin Cross65569e42015-03-10 20:08:19 -0700958 for _, depName := range depNames {
959 newErrs := c.addDependency(module, depName)
960 if len(newErrs) > 0 {
961 errs = append(errs, newErrs...)
962 }
963 }
964 return errs
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700965}
966
Colin Cross65569e42015-03-10 20:08:19 -0700967// resolveDependencies populates the directDeps list for every module. In doing so it checks for
968// missing dependencies and self-dependant modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700969func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800970 for _, group := range c.moduleGroups {
Colin Crossed342d92015-03-11 00:57:25 -0700971 for _, module := range group.modules {
Colin Cross65569e42015-03-10 20:08:19 -0700972 module.directDeps = make([]*moduleInfo, 0, len(module.properties.Deps))
973
974 newErrs := c.moduleDeps(module, config)
Colin Crossc9028482014-12-18 16:28:54 -0800975 if len(newErrs) > 0 {
976 errs = append(errs, newErrs...)
Colin Crossed342d92015-03-11 00:57:25 -0700977 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700978 }
979 }
980
981 return
982}
983
Colin Crossc9028482014-12-18 16:28:54 -0800984func (c *Context) addDependency(module *moduleInfo, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -0700985 depsPos := module.propertyPos["deps"]
Colin Crossc9028482014-12-18 16:28:54 -0800986
Colin Crossed342d92015-03-11 00:57:25 -0700987 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -0800988 return []error{&Error{
989 Err: fmt.Errorf("%q depends on itself", depName),
990 Pos: depsPos,
991 }}
992 }
993
994 depInfo, ok := c.moduleGroups[depName]
995 if !ok {
996 return []error{&Error{
997 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -0700998 module.properties.Name, depName),
Colin Crossc9028482014-12-18 16:28:54 -0800999 Pos: depsPos,
1000 }}
1001 }
1002
Colin Cross65569e42015-03-10 20:08:19 -07001003 for _, m := range module.directDeps {
1004 if m.group == depInfo {
1005 return nil
1006 }
Colin Crossc9028482014-12-18 16:28:54 -08001007 }
1008
Colin Cross65569e42015-03-10 20:08:19 -07001009 if len(depInfo.modules) == 1 {
1010 module.directDeps = append(module.directDeps, depInfo.modules[0])
1011 return nil
1012 } else {
1013 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001014 if m.variant.equal(module.dependencyVariant) {
Colin Cross65569e42015-03-10 20:08:19 -07001015 module.directDeps = append(module.directDeps, m)
1016 return nil
1017 }
1018 }
1019 }
Colin Crossc9028482014-12-18 16:28:54 -08001020
Colin Cross65569e42015-03-10 20:08:19 -07001021 return []error{&Error{
1022 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1023 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001024 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001025 Pos: depsPos,
1026 }}
1027}
1028
Colin Crossf5e34b92015-03-13 16:02:36 -07001029func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross65569e42015-03-10 20:08:19 -07001030 depName string) []error {
1031
1032 depsPos := module.propertyPos["deps"]
1033
1034 depInfo, ok := c.moduleGroups[depName]
1035 if !ok {
1036 return []error{&Error{
1037 Err: fmt.Errorf("%q depends on undefined module %q",
1038 module.properties.Name, depName),
1039 Pos: depsPos,
1040 }}
1041 }
1042
1043 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1044 // compare the strings because the result won't be in mutator registration order.
1045 // Create a new map instead, and then deep compare the maps.
Colin Crossf5e34b92015-03-13 16:02:36 -07001046 newVariant := module.dependencyVariant.clone()
1047 for _, v := range variations {
1048 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001049 }
1050
1051 for _, m := range depInfo.modules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001052 if newVariant.equal(m.variant) {
1053 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001054 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001055 // run GenerateBuildActions in order for the variants of a module
Colin Cross65569e42015-03-10 20:08:19 -07001056 if depInfo == module.group && beforeInModuleList(module, m, module.group.modules) {
1057 return []error{&Error{
1058 Err: fmt.Errorf("%q depends on later version of itself", depName),
1059 Pos: depsPos,
1060 }}
1061 }
1062 module.directDeps = append(module.directDeps, m)
1063 return nil
1064 }
1065 }
1066
1067 return []error{&Error{
1068 Err: fmt.Errorf("dependency %q of %q missing variant %q",
1069 depInfo.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001070 c.prettyPrintVariant(newVariant)),
Colin Cross65569e42015-03-10 20:08:19 -07001071 Pos: depsPos,
1072 }}
Colin Crossc9028482014-12-18 16:28:54 -08001073}
1074
Colin Cross7addea32015-03-11 15:43:52 -07001075func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1076 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001077 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001078 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001079
Colin Cross7addea32015-03-11 15:43:52 -07001080 for _, module := range c.modulesSorted {
1081 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001082 }
1083
Colin Cross7addea32015-03-11 15:43:52 -07001084 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001085 count++
1086 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001087 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001088 if ret {
1089 cancel = true
1090 }
Colin Cross7addea32015-03-11 15:43:52 -07001091 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001092 }()
1093 }
1094
Colin Cross7addea32015-03-11 15:43:52 -07001095 for _, module := range c.modulesSorted {
1096 if module.waitingCount == 0 {
1097 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001098 }
1099 }
1100
Colin Cross11e3b0d2015-02-04 10:41:00 -08001101 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001102 select {
Colin Cross7addea32015-03-11 15:43:52 -07001103 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001104 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001105 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001106 parent.waitingCount--
1107 if parent.waitingCount == 0 {
1108 visitOne(parent)
1109 }
Colin Cross691a60d2015-01-07 18:08:56 -08001110 }
1111 }
1112 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001113 }
1114 }
1115}
1116
1117// updateDependencies recursively walks the module dependency graph and updates
1118// additional fields based on the dependencies. It builds a sorted list of modules
1119// such that dependencies of a module always appear first, and populates reverse
1120// dependency links and counts of total dependencies. It also reports errors when
1121// it encounters dependency cycles. This should called after resolveDependencies,
1122// as well as after any mutator pass has called addDependency
1123func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001124 visited := make(map[*moduleInfo]bool) // modules that were already checked
1125 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001126
Colin Cross7addea32015-03-11 15:43:52 -07001127 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001128
Colin Cross7addea32015-03-11 15:43:52 -07001129 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001130
Colin Cross7addea32015-03-11 15:43:52 -07001131 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001132 // We are the "start" of the cycle, so we're responsible
1133 // for generating the errors. The cycle list is in
1134 // reverse order because all the 'check' calls append
1135 // their own module to the list.
1136 errs = append(errs, &Error{
1137 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001138 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001139 })
1140
1141 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001142 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001143 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001144 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001145 errs = append(errs, &Error{
1146 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001147 curModule.properties.Name,
1148 nextModule.properties.Name),
1149 Pos: curModule.propertyPos["deps"],
Colin Cross10b54db2015-03-11 14:40:30 -07001150 })
Colin Cross7addea32015-03-11 15:43:52 -07001151 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001152 }
1153 }
1154
Colin Cross7addea32015-03-11 15:43:52 -07001155 check = func(module *moduleInfo) []*moduleInfo {
1156 visited[module] = true
1157 checking[module] = true
1158 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001159
Colin Cross7addea32015-03-11 15:43:52 -07001160 deps := make(map[*moduleInfo]bool)
1161
1162 // Add an implicit dependency ordering on all earlier modules in the same module group
1163 for _, dep := range module.group.modules {
1164 if dep == module {
1165 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001166 }
Colin Cross7addea32015-03-11 15:43:52 -07001167 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001168 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001169
Colin Cross7addea32015-03-11 15:43:52 -07001170 for _, dep := range module.directDeps {
1171 deps[dep] = true
1172 }
1173
1174 module.reverseDeps = []*moduleInfo{}
1175 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001176
Colin Crossbbfa51a2014-12-17 16:12:41 -08001177 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001178 if checking[dep] {
1179 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001180 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001181 }
1182
1183 if !visited[dep] {
1184 cycle := check(dep)
1185 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001186 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001187 // We are the "start" of the cycle, so we're responsible
1188 // for generating the errors. The cycle list is in
1189 // reverse order because all the 'check' calls append
1190 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001191 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001192
1193 // We can continue processing this module's children to
1194 // find more cycles. Since all the modules that were
1195 // part of the found cycle were marked as visited we
1196 // won't run into that cycle again.
1197 } else {
1198 // We're not the "start" of the cycle, so we just append
1199 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001200 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001201 }
1202 }
1203 }
Colin Cross691a60d2015-01-07 18:08:56 -08001204
Colin Cross7addea32015-03-11 15:43:52 -07001205 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001206 }
1207
Colin Cross7addea32015-03-11 15:43:52 -07001208 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001209
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001210 return nil
1211 }
1212
Colin Cross7addea32015-03-11 15:43:52 -07001213 for _, module := range c.moduleInfo {
1214 if !visited[module] {
1215 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001216 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001217 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001218 panic("inconceivable!")
1219 }
1220 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001221 }
1222 }
1223 }
1224
Colin Cross7addea32015-03-11 15:43:52 -07001225 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001226
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001227 return
1228}
1229
Jamie Gennisd4e10182014-06-12 20:06:50 -07001230// PrepareBuildActions generates an internal representation of all the build
1231// actions that need to be performed. This process involves invoking the
1232// GenerateBuildActions method on each of the Module objects created during the
1233// parse phase and then on each of the registered Singleton objects.
1234//
1235// If the ResolveDependencies method has not already been called it is called
1236// automatically by this method.
1237//
1238// The config argument is made available to all of the Module and Singleton
1239// objects via the Config method on the ModuleContext and SingletonContext
1240// objects passed to GenerateBuildActions. It is also passed to the functions
1241// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1242// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001243//
1244// The returned deps is a list of the ninja files dependencies that were added
1245// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1246// SingletonContext.AddNinjaFileDeps() methods.
1247func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001248 c.buildActionsReady = false
1249
Colin Cross65569e42015-03-10 20:08:19 -07001250 errs = c.runEarlyMutators(config)
1251 if len(errs) > 0 {
1252 return nil, errs
1253 }
1254
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001255 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001256 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001257 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001258 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001259 }
1260 }
1261
Colin Crossc9028482014-12-18 16:28:54 -08001262 errs = c.runMutators(config)
1263 if len(errs) > 0 {
1264 return nil, errs
1265 }
1266
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001267 liveGlobals := newLiveTracker(config)
1268
1269 c.initSpecialVariables()
1270
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001271 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001272 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001273 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001274 }
1275
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001276 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001277 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001278 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001279 }
1280
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001281 deps = append(depsModules, depsSingletons...)
1282
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001283 if c.buildDir != nil {
1284 liveGlobals.addNinjaStringDeps(c.buildDir)
1285 }
1286
1287 pkgNames := c.makeUniquePackageNames(liveGlobals)
1288
1289 // This will panic if it finds a problem since it's a programming error.
1290 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1291
1292 c.pkgNames = pkgNames
1293 c.globalVariables = liveGlobals.variables
1294 c.globalPools = liveGlobals.pools
1295 c.globalRules = liveGlobals.rules
1296
1297 c.buildActionsReady = true
1298
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001299 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001300}
1301
Colin Cross65569e42015-03-10 20:08:19 -07001302func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
1303 for _, mutator := range c.earlyMutatorInfo {
1304 for _, group := range c.moduleGroups {
1305 newModules := make([]*moduleInfo, 0, len(group.modules))
1306
1307 for _, module := range group.modules {
1308 mctx := &mutatorContext{
1309 baseModuleContext: baseModuleContext{
1310 context: c,
1311 config: config,
1312 module: module,
1313 },
1314 name: mutator.name,
1315 }
1316 mutator.mutator(mctx)
1317 if len(mctx.errs) > 0 {
1318 errs = append(errs, mctx.errs...)
1319 return errs
1320 }
1321
1322 if module.splitModules != nil {
1323 newModules = append(newModules, module.splitModules...)
1324 } else {
1325 newModules = append(newModules, module)
1326 }
1327 }
1328
1329 group.modules = newModules
1330 }
1331 }
1332
1333 return nil
1334}
1335
Colin Crossc9028482014-12-18 16:28:54 -08001336func (c *Context) runMutators(config interface{}) (errs []error) {
1337 for _, mutator := range c.mutatorInfo {
1338 if mutator.topDownMutator != nil {
1339 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1340 } else if mutator.bottomUpMutator != nil {
1341 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1342 } else {
1343 panic("no mutator set on " + mutator.name)
1344 }
1345 if len(errs) > 0 {
1346 return errs
1347 }
1348 }
1349
1350 return nil
1351}
1352
1353func (c *Context) runTopDownMutator(config interface{},
1354 name string, mutator TopDownMutator) (errs []error) {
1355
Colin Cross7addea32015-03-11 15:43:52 -07001356 for i := 0; i < len(c.modulesSorted); i++ {
1357 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1358 mctx := &mutatorContext{
1359 baseModuleContext: baseModuleContext{
1360 context: c,
1361 config: config,
1362 module: module,
1363 },
1364 name: name,
1365 }
Colin Crossc9028482014-12-18 16:28:54 -08001366
Colin Cross7addea32015-03-11 15:43:52 -07001367 mutator(mctx)
1368 if len(mctx.errs) > 0 {
1369 errs = append(errs, mctx.errs...)
1370 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001371 }
1372 }
1373
1374 return errs
1375}
1376
1377func (c *Context) runBottomUpMutator(config interface{},
1378 name string, mutator BottomUpMutator) (errs []error) {
1379
1380 dependenciesModified := false
1381
Colin Cross7addea32015-03-11 15:43:52 -07001382 for _, module := range c.modulesSorted {
1383 newModules := make([]*moduleInfo, 0, 1)
Colin Crossc9028482014-12-18 16:28:54 -08001384
Colin Cross7addea32015-03-11 15:43:52 -07001385 mctx := &mutatorContext{
1386 baseModuleContext: baseModuleContext{
1387 context: c,
1388 config: config,
1389 module: module,
1390 },
1391 name: name,
1392 }
Colin Crossc9028482014-12-18 16:28:54 -08001393
Colin Cross7addea32015-03-11 15:43:52 -07001394 mutator(mctx)
1395 if len(mctx.errs) > 0 {
1396 errs = append(errs, mctx.errs...)
1397 return errs
1398 }
Colin Crossc9028482014-12-18 16:28:54 -08001399
Colin Cross7addea32015-03-11 15:43:52 -07001400 // Fix up any remaining dependencies on modules that were split into variants
1401 // by replacing them with the first variant
1402 for i, dep := range module.directDeps {
1403 if dep.logicModule == nil {
1404 module.directDeps[i] = dep.splitModules[0]
Colin Crossc9028482014-12-18 16:28:54 -08001405 }
1406 }
1407
Colin Cross7addea32015-03-11 15:43:52 -07001408 if mctx.dependenciesModified {
1409 dependenciesModified = true
1410 }
1411
1412 if module.splitModules != nil {
1413 newModules = append(newModules, module.splitModules...)
1414 } else {
1415 newModules = append(newModules, module)
1416 }
1417
1418 module.group.modules = spliceModules(module.group.modules, module, newModules)
Colin Crossc9028482014-12-18 16:28:54 -08001419 }
1420
1421 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001422 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001423 if len(errs) > 0 {
1424 return errs
1425 }
1426 }
1427
1428 return errs
1429}
1430
Colin Cross7addea32015-03-11 15:43:52 -07001431func spliceModules(modules []*moduleInfo, origModule *moduleInfo,
1432 newModules []*moduleInfo) []*moduleInfo {
1433 for i, m := range modules {
1434 if m == origModule {
1435 return spliceModulesAtIndex(modules, i, newModules)
1436 }
1437 }
1438
1439 panic("failed to find original module to splice")
1440}
1441
1442func spliceModulesAtIndex(modules []*moduleInfo, i int, newModules []*moduleInfo) []*moduleInfo {
1443 spliceSize := len(newModules)
1444 newLen := len(modules) + spliceSize - 1
1445 var dest []*moduleInfo
1446 if cap(modules) >= len(modules)-1+len(newModules) {
1447 // We can fit the splice in the existing capacity, do everything in place
1448 dest = modules[:newLen]
1449 } else {
1450 dest = make([]*moduleInfo, newLen)
1451 copy(dest, modules[:i])
1452 }
1453
1454 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001455 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001456
1457 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001458 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001459
Colin Cross72bd1932015-03-16 00:13:59 -07001460 return dest
Colin Cross7addea32015-03-11 15:43:52 -07001461}
1462
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001463func (c *Context) initSpecialVariables() {
1464 c.buildDir = nil
1465 c.requiredNinjaMajor = 1
1466 c.requiredNinjaMinor = 1
1467 c.requiredNinjaMicro = 0
1468}
1469
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001470func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001471 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001472
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001473 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001474 var errs []error
1475
Colin Cross691a60d2015-01-07 18:08:56 -08001476 cancelCh := make(chan struct{})
1477 errsCh := make(chan []error)
1478 depsCh := make(chan []string)
1479
1480 go func() {
1481 for {
1482 select {
1483 case <-cancelCh:
1484 close(cancelCh)
1485 return
1486 case newErrs := <-errsCh:
1487 errs = append(errs, newErrs...)
1488 case newDeps := <-depsCh:
1489 deps = append(deps, newDeps...)
1490
1491 }
1492 }
1493 }()
1494
Colin Cross7addea32015-03-11 15:43:52 -07001495 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1496 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1497 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1498 // just set it to nil.
1499 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1500 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001501
Colin Cross7addea32015-03-11 15:43:52 -07001502 mctx := &moduleContext{
1503 baseModuleContext: baseModuleContext{
1504 context: c,
1505 config: config,
1506 module: module,
1507 },
1508 scope: scope,
1509 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001510
Colin Cross7addea32015-03-11 15:43:52 -07001511 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001512
Colin Cross7addea32015-03-11 15:43:52 -07001513 if len(mctx.errs) > 0 {
1514 errsCh <- mctx.errs
1515 return true
1516 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001517
Colin Cross7addea32015-03-11 15:43:52 -07001518 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001519
Colin Crossab6d7902015-03-11 16:17:52 -07001520 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001521 &mctx.actionDefs, liveGlobals)
1522 if len(newErrs) > 0 {
1523 errsCh <- newErrs
1524 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001525 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001526 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001527 })
1528
1529 cancelCh <- struct{}{}
1530 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001531
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001532 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001533}
1534
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001535func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001536 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001537
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001538 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001539 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001540
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001541 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001542 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1543 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1544 // just set it to nil.
1545 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001546
1547 sctx := &singletonContext{
1548 context: c,
1549 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001550 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001551 }
1552
1553 info.singleton.GenerateBuildActions(sctx)
1554
1555 if len(sctx.errs) > 0 {
1556 errs = append(errs, sctx.errs...)
1557 if len(errs) > maxErrors {
1558 break
1559 }
1560 continue
1561 }
1562
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001563 deps = append(deps, sctx.ninjaFileDeps...)
1564
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001565 newErrs := c.processLocalBuildActions(&info.actionDefs,
1566 &sctx.actionDefs, liveGlobals)
1567 errs = append(errs, newErrs...)
1568 if len(errs) > maxErrors {
1569 break
1570 }
1571 }
1572
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001573 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001574}
1575
1576func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1577 liveGlobals *liveTracker) []error {
1578
1579 var errs []error
1580
1581 // First we go through and add everything referenced by the module's
1582 // buildDefs to the live globals set. This will end up adding the live
1583 // locals to the set as well, but we'll take them out after.
1584 for _, def := range in.buildDefs {
1585 err := liveGlobals.AddBuildDefDeps(def)
1586 if err != nil {
1587 errs = append(errs, err)
1588 }
1589 }
1590
1591 if len(errs) > 0 {
1592 return errs
1593 }
1594
Colin Crossc9028482014-12-18 16:28:54 -08001595 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001596
1597 // We use the now-incorrect set of live "globals" to determine which local
1598 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001599 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001600 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07001601 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001602 if isLive {
1603 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001604 }
1605 }
1606
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001607 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07001608 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001609 if isLive {
1610 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001611 }
1612 }
1613
1614 return nil
1615}
1616
Colin Crossbbfa51a2014-12-17 16:12:41 -08001617func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1618 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001619
Colin Crossbbfa51a2014-12-17 16:12:41 -08001620 var walk func(module *moduleInfo)
1621 walk = func(module *moduleInfo) {
1622 visited[module] = true
1623 for _, moduleDep := range module.directDeps {
1624 if !visited[moduleDep] {
1625 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001626 }
1627 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001628
Colin Crossbbfa51a2014-12-17 16:12:41 -08001629 if module != topModule {
1630 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001631 }
1632 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001633
1634 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001635}
1636
Colin Crossbbfa51a2014-12-17 16:12:41 -08001637func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001638 visit func(Module)) {
1639
Colin Crossbbfa51a2014-12-17 16:12:41 -08001640 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001641
Colin Crossbbfa51a2014-12-17 16:12:41 -08001642 var walk func(module *moduleInfo)
1643 walk = func(module *moduleInfo) {
1644 visited[module] = true
1645 for _, moduleDep := range module.directDeps {
1646 if !visited[moduleDep] {
1647 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001648 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001649 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001650
1651 if module != topModule {
1652 if pred(module.logicModule) {
1653 visit(module.logicModule)
1654 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001655 }
1656 }
1657
Colin Crossbbfa51a2014-12-17 16:12:41 -08001658 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001659}
1660
Colin Crossc9028482014-12-18 16:28:54 -08001661func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1662 for _, dep := range module.directDeps {
1663 visit(dep.logicModule)
1664 }
1665}
1666
1667func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1668 visit func(Module)) {
1669
1670 for _, dep := range module.directDeps {
1671 if pred(dep.logicModule) {
1672 visit(dep.logicModule)
1673 }
1674 }
1675}
1676
Jamie Gennisc15544d2014-09-24 20:26:52 -07001677func (c *Context) sortedModuleNames() []string {
1678 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001679 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1680 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001681 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1682 moduleName)
1683 }
1684 sort.Strings(c.cachedSortedModuleNames)
1685 }
1686
1687 return c.cachedSortedModuleNames
1688}
1689
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001690func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001691 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001692 group := c.moduleGroups[moduleName]
1693 for _, module := range group.modules {
1694 visit(module.logicModule)
1695 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001696 }
1697}
1698
1699func (c *Context) visitAllModulesIf(pred func(Module) bool,
1700 visit func(Module)) {
1701
Jamie Gennisc15544d2014-09-24 20:26:52 -07001702 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001703 group := c.moduleGroups[moduleName]
1704 for _, module := range group.modules {
1705 if pred(module.logicModule) {
1706 visit(module.logicModule)
1707 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001708 }
1709 }
1710}
1711
1712func (c *Context) requireNinjaVersion(major, minor, micro int) {
1713 if major != 1 {
1714 panic("ninja version with major version != 1 not supported")
1715 }
1716 if c.requiredNinjaMinor < minor {
1717 c.requiredNinjaMinor = minor
1718 c.requiredNinjaMicro = micro
1719 }
1720 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1721 c.requiredNinjaMicro = micro
1722 }
1723}
1724
1725func (c *Context) setBuildDir(value *ninjaString) {
1726 if c.buildDir != nil {
1727 panic("buildDir set multiple times")
1728 }
1729 c.buildDir = value
1730}
1731
1732func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001733 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001734
Jamie Gennis2fb20952014-10-03 02:49:58 -07001735 pkgs := make(map[string]*PackageContext)
1736 pkgNames := make(map[*PackageContext]string)
1737 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001738
Jamie Gennis2fb20952014-10-03 02:49:58 -07001739 processPackage := func(pctx *PackageContext) {
1740 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001741 // This is a built-in rule and has no package.
1742 return
1743 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001744 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001745 // We've already processed this package.
1746 return
1747 }
1748
Jamie Gennis2fb20952014-10-03 02:49:58 -07001749 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001750 if present {
1751 // Short name collision. Both this package and the one that's
1752 // already there need to use their full names. We leave the short
1753 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001754 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001755 longPkgNames[otherPkg] = true
1756 } else {
1757 // No collision so far. Tentatively set the package's name to be
1758 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001759 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001760 }
1761 }
1762
1763 // We try to give all packages their short name, but when we get collisions
1764 // we need to use the full unique package name.
1765 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001766 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001767 }
1768 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001769 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001770 }
1771 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001772 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001773 }
1774
1775 // Add the packages that had collisions using their full unique names. This
1776 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001777 for pctx := range longPkgNames {
1778 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001779 }
1780
1781 return pkgNames
1782}
1783
1784func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001785 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001786
1787 visited := make(map[Variable]bool) // variables that were already checked
1788 checking := make(map[Variable]bool) // variables actively being checked
1789
1790 var check func(v Variable) []Variable
1791
1792 check = func(v Variable) []Variable {
1793 visited[v] = true
1794 checking[v] = true
1795 defer delete(checking, v)
1796
1797 value := variables[v]
1798 for _, dep := range value.variables {
1799 if checking[dep] {
1800 // This is a cycle.
1801 return []Variable{dep, v}
1802 }
1803
1804 if !visited[dep] {
1805 cycle := check(dep)
1806 if cycle != nil {
1807 if cycle[0] == v {
1808 // We are the "start" of the cycle, so we're responsible
1809 // for generating the errors. The cycle list is in
1810 // reverse order because all the 'check' calls append
1811 // their own module to the list.
1812 msgs := []string{"detected variable reference cycle:"}
1813
1814 // Iterate backwards through the cycle list.
1815 curName := v.fullName(pkgNames)
1816 curValue := value.Value(pkgNames)
1817 for i := len(cycle) - 1; i >= 0; i-- {
1818 next := cycle[i]
1819 nextName := next.fullName(pkgNames)
1820 nextValue := variables[next].Value(pkgNames)
1821
1822 msgs = append(msgs, fmt.Sprintf(
1823 " %q depends on %q", curName, nextName))
1824 msgs = append(msgs, fmt.Sprintf(
1825 " [%s = %s]", curName, curValue))
1826
1827 curName = nextName
1828 curValue = nextValue
1829 }
1830
1831 // Variable reference cycles are a programming error,
1832 // not the fault of the Blueprint file authors.
1833 panic(strings.Join(msgs, "\n"))
1834 } else {
1835 // We're not the "start" of the cycle, so we just append
1836 // our module to the list and return it.
1837 return append(cycle, v)
1838 }
1839 }
1840 }
1841 }
1842
1843 return nil
1844 }
1845
1846 for v := range variables {
1847 if !visited[v] {
1848 cycle := check(v)
1849 if cycle != nil {
1850 panic("inconceivable!")
1851 }
1852 }
1853 }
1854}
1855
Jamie Gennisaf435562014-10-27 22:34:56 -07001856// AllTargets returns a map all the build target names to the rule used to build
1857// them. This is the same information that is output by running 'ninja -t
1858// targets all'. If this is called before PrepareBuildActions successfully
1859// completes then ErrbuildActionsNotReady is returned.
1860func (c *Context) AllTargets() (map[string]string, error) {
1861 if !c.buildActionsReady {
1862 return nil, ErrBuildActionsNotReady
1863 }
1864
1865 targets := map[string]string{}
1866
1867 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07001868 for _, module := range c.moduleInfo {
1869 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07001870 ruleName := buildDef.Rule.fullName(c.pkgNames)
1871 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001872 outputValue, err := output.Eval(c.globalVariables)
1873 if err != nil {
1874 return nil, err
1875 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001876 targets[outputValue] = ruleName
1877 }
1878 }
1879 }
1880
1881 // Collect all the singleton build targets.
1882 for _, info := range c.singletonInfo {
1883 for _, buildDef := range info.actionDefs.buildDefs {
1884 ruleName := buildDef.Rule.fullName(c.pkgNames)
1885 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001886 outputValue, err := output.Eval(c.globalVariables)
1887 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001888 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001889 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001890 targets[outputValue] = ruleName
1891 }
1892 }
1893 }
1894
1895 return targets, nil
1896}
1897
Jamie Gennisd4e10182014-06-12 20:06:50 -07001898// WriteBuildFile writes the Ninja manifeset text for the generated build
1899// actions to w. If this is called before PrepareBuildActions successfully
1900// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001901func (c *Context) WriteBuildFile(w io.Writer) error {
1902 if !c.buildActionsReady {
1903 return ErrBuildActionsNotReady
1904 }
1905
1906 nw := newNinjaWriter(w)
1907
1908 err := c.writeBuildFileHeader(nw)
1909 if err != nil {
1910 return err
1911 }
1912
1913 err = c.writeNinjaRequiredVersion(nw)
1914 if err != nil {
1915 return err
1916 }
1917
1918 // TODO: Group the globals by package.
1919
1920 err = c.writeGlobalVariables(nw)
1921 if err != nil {
1922 return err
1923 }
1924
1925 err = c.writeGlobalPools(nw)
1926 if err != nil {
1927 return err
1928 }
1929
1930 err = c.writeBuildDir(nw)
1931 if err != nil {
1932 return err
1933 }
1934
1935 err = c.writeGlobalRules(nw)
1936 if err != nil {
1937 return err
1938 }
1939
1940 err = c.writeAllModuleActions(nw)
1941 if err != nil {
1942 return err
1943 }
1944
1945 err = c.writeAllSingletonActions(nw)
1946 if err != nil {
1947 return err
1948 }
1949
1950 return nil
1951}
1952
Jamie Gennisc15544d2014-09-24 20:26:52 -07001953type pkgAssociation struct {
1954 PkgName string
1955 PkgPath string
1956}
1957
1958type pkgAssociationSorter struct {
1959 pkgs []pkgAssociation
1960}
1961
1962func (s *pkgAssociationSorter) Len() int {
1963 return len(s.pkgs)
1964}
1965
1966func (s *pkgAssociationSorter) Less(i, j int) bool {
1967 iName := s.pkgs[i].PkgName
1968 jName := s.pkgs[j].PkgName
1969 return iName < jName
1970}
1971
1972func (s *pkgAssociationSorter) Swap(i, j int) {
1973 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1974}
1975
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001976func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1977 headerTemplate := template.New("fileHeader")
1978 _, err := headerTemplate.Parse(fileHeaderTemplate)
1979 if err != nil {
1980 // This is a programming error.
1981 panic(err)
1982 }
1983
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001984 var pkgs []pkgAssociation
1985 maxNameLen := 0
1986 for pkg, name := range c.pkgNames {
1987 pkgs = append(pkgs, pkgAssociation{
1988 PkgName: name,
1989 PkgPath: pkg.pkgPath,
1990 })
1991 if len(name) > maxNameLen {
1992 maxNameLen = len(name)
1993 }
1994 }
1995
1996 for i := range pkgs {
1997 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1998 }
1999
Jamie Gennisc15544d2014-09-24 20:26:52 -07002000 sort.Sort(&pkgAssociationSorter{pkgs})
2001
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002002 params := map[string]interface{}{
2003 "Pkgs": pkgs,
2004 }
2005
2006 buf := bytes.NewBuffer(nil)
2007 err = headerTemplate.Execute(buf, params)
2008 if err != nil {
2009 return err
2010 }
2011
2012 return nw.Comment(buf.String())
2013}
2014
2015func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2016 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2017 c.requiredNinjaMicro)
2018
2019 err := nw.Assign("ninja_required_version", value)
2020 if err != nil {
2021 return err
2022 }
2023
2024 return nw.BlankLine()
2025}
2026
2027func (c *Context) writeBuildDir(nw *ninjaWriter) error {
2028 if c.buildDir != nil {
2029 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
2030 if err != nil {
2031 return err
2032 }
2033
2034 err = nw.BlankLine()
2035 if err != nil {
2036 return err
2037 }
2038 }
2039 return nil
2040}
2041
Jamie Gennisc15544d2014-09-24 20:26:52 -07002042type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002043 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002044}
2045
Jamie Gennisc15544d2014-09-24 20:26:52 -07002046type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002047 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002048 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002049}
2050
Jamie Gennisc15544d2014-09-24 20:26:52 -07002051func (s *globalEntitySorter) Len() int {
2052 return len(s.entities)
2053}
2054
2055func (s *globalEntitySorter) Less(i, j int) bool {
2056 iName := s.entities[i].fullName(s.pkgNames)
2057 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002058 return iName < jName
2059}
2060
Jamie Gennisc15544d2014-09-24 20:26:52 -07002061func (s *globalEntitySorter) Swap(i, j int) {
2062 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002063}
2064
2065func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2066 visited := make(map[Variable]bool)
2067
2068 var walk func(v Variable) error
2069 walk = func(v Variable) error {
2070 visited[v] = true
2071
2072 // First visit variables on which this variable depends.
2073 value := c.globalVariables[v]
2074 for _, dep := range value.variables {
2075 if !visited[dep] {
2076 err := walk(dep)
2077 if err != nil {
2078 return err
2079 }
2080 }
2081 }
2082
2083 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2084 if err != nil {
2085 return err
2086 }
2087
2088 err = nw.BlankLine()
2089 if err != nil {
2090 return err
2091 }
2092
2093 return nil
2094 }
2095
Jamie Gennisc15544d2014-09-24 20:26:52 -07002096 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2097 for variable := range c.globalVariables {
2098 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002099 }
2100
Jamie Gennisc15544d2014-09-24 20:26:52 -07002101 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002102
Jamie Gennisc15544d2014-09-24 20:26:52 -07002103 for _, entity := range globalVariables {
2104 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002105 if !visited[v] {
2106 err := walk(v)
2107 if err != nil {
2108 return nil
2109 }
2110 }
2111 }
2112
2113 return nil
2114}
2115
2116func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002117 globalPools := make([]globalEntity, 0, len(c.globalPools))
2118 for pool := range c.globalPools {
2119 globalPools = append(globalPools, pool)
2120 }
2121
2122 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2123
2124 for _, entity := range globalPools {
2125 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002126 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002127 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002128 err := def.WriteTo(nw, name)
2129 if err != nil {
2130 return err
2131 }
2132
2133 err = nw.BlankLine()
2134 if err != nil {
2135 return err
2136 }
2137 }
2138
2139 return nil
2140}
2141
2142func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002143 globalRules := make([]globalEntity, 0, len(c.globalRules))
2144 for rule := range c.globalRules {
2145 globalRules = append(globalRules, rule)
2146 }
2147
2148 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2149
2150 for _, entity := range globalRules {
2151 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002152 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002153 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002154 err := def.WriteTo(nw, name, c.pkgNames)
2155 if err != nil {
2156 return err
2157 }
2158
2159 err = nw.BlankLine()
2160 if err != nil {
2161 return err
2162 }
2163 }
2164
2165 return nil
2166}
2167
Colin Crossab6d7902015-03-11 16:17:52 -07002168type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002169
Colin Crossab6d7902015-03-11 16:17:52 -07002170func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002171 return len(s)
2172}
2173
Colin Crossab6d7902015-03-11 16:17:52 -07002174func (s moduleSorter) Less(i, j int) bool {
2175 iName := s[i].properties.Name
2176 jName := s[j].properties.Name
2177 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002178 iName = s[i].variantName
2179 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002180 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002181 return iName < jName
2182}
2183
Colin Crossab6d7902015-03-11 16:17:52 -07002184func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002185 s[i], s[j] = s[j], s[i]
2186}
2187
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002188func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2189 headerTemplate := template.New("moduleHeader")
2190 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2191 if err != nil {
2192 // This is a programming error.
2193 panic(err)
2194 }
2195
Colin Crossab6d7902015-03-11 16:17:52 -07002196 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2197 for _, module := range c.moduleInfo {
2198 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002199 }
Colin Crossab6d7902015-03-11 16:17:52 -07002200 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002201
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002202 buf := bytes.NewBuffer(nil)
2203
Colin Crossab6d7902015-03-11 16:17:52 -07002204 for _, module := range modules {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002205 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002206
2207 // In order to make the bootstrap build manifest independent of the
2208 // build dir we need to output the Blueprints file locations in the
2209 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002210 relPos := module.pos
2211 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002212
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002213 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002214 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002215 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2216 factoryName := factoryFunc.Name()
2217
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002219 "properties": module.properties,
2220 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002221 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002222 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002223 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002224 }
2225 err = headerTemplate.Execute(buf, infoMap)
2226 if err != nil {
2227 return err
2228 }
2229
2230 err = nw.Comment(buf.String())
2231 if err != nil {
2232 return err
2233 }
2234
2235 err = nw.BlankLine()
2236 if err != nil {
2237 return err
2238 }
2239
Colin Crossab6d7902015-03-11 16:17:52 -07002240 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002241 if err != nil {
2242 return err
2243 }
2244
2245 err = nw.BlankLine()
2246 if err != nil {
2247 return err
2248 }
2249 }
2250
2251 return nil
2252}
2253
2254func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2255 headerTemplate := template.New("singletonHeader")
2256 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2257 if err != nil {
2258 // This is a programming error.
2259 panic(err)
2260 }
2261
2262 buf := bytes.NewBuffer(nil)
2263
Jamie Gennis86179fe2014-06-11 16:27:16 -07002264 singletonNames := make([]string, 0, len(c.singletonInfo))
2265 for name := range c.singletonInfo {
2266 singletonNames = append(singletonNames, name)
2267 }
2268 sort.Strings(singletonNames)
2269
2270 for _, name := range singletonNames {
2271 info := c.singletonInfo[name]
2272
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002273 // Get the name of the factory function for the module.
2274 factory := info.factory
2275 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2276 factoryName := factoryFunc.Name()
2277
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002278 buf.Reset()
2279 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002280 "name": name,
2281 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002282 }
2283 err = headerTemplate.Execute(buf, infoMap)
2284 if err != nil {
2285 return err
2286 }
2287
2288 err = nw.Comment(buf.String())
2289 if err != nil {
2290 return err
2291 }
2292
2293 err = nw.BlankLine()
2294 if err != nil {
2295 return err
2296 }
2297
2298 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2299 if err != nil {
2300 return err
2301 }
2302
2303 err = nw.BlankLine()
2304 if err != nil {
2305 return err
2306 }
2307 }
2308
2309 return nil
2310}
2311
2312func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2313 defs *localBuildActions) error {
2314
2315 // Write the local variable assignments.
2316 for _, v := range defs.variables {
2317 // A localVariable doesn't need the package names or config to
2318 // determine its name or value.
2319 name := v.fullName(nil)
2320 value, err := v.value(nil)
2321 if err != nil {
2322 panic(err)
2323 }
2324 err = nw.Assign(name, value.Value(c.pkgNames))
2325 if err != nil {
2326 return err
2327 }
2328 }
2329
2330 if len(defs.variables) > 0 {
2331 err := nw.BlankLine()
2332 if err != nil {
2333 return err
2334 }
2335 }
2336
2337 // Write the local rules.
2338 for _, r := range defs.rules {
2339 // A localRule doesn't need the package names or config to determine
2340 // its name or definition.
2341 name := r.fullName(nil)
2342 def, err := r.def(nil)
2343 if err != nil {
2344 panic(err)
2345 }
2346
2347 err = def.WriteTo(nw, name, c.pkgNames)
2348 if err != nil {
2349 return err
2350 }
2351
2352 err = nw.BlankLine()
2353 if err != nil {
2354 return err
2355 }
2356 }
2357
2358 // Write the build definitions.
2359 for _, buildDef := range defs.buildDefs {
2360 err := buildDef.WriteTo(nw, c.pkgNames)
2361 if err != nil {
2362 return err
2363 }
2364
2365 if len(buildDef.Args) > 0 {
2366 err = nw.BlankLine()
2367 if err != nil {
2368 return err
2369 }
2370 }
2371 }
2372
2373 return nil
2374}
2375
Colin Cross65569e42015-03-10 20:08:19 -07002376func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2377 found := false
2378 for _, l := range list {
2379 if l == a {
2380 found = true
2381 } else if l == b {
2382 return found
2383 }
2384 }
2385
2386 missing := a
2387 if found {
2388 missing = b
2389 }
2390 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2391}
2392
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002393var fileHeaderTemplate = `******************************************************************************
2394*** This file is generated and should not be edited ***
2395******************************************************************************
2396{{if .Pkgs}}
2397This file contains variables, rules, and pools with name prefixes indicating
2398they were generated by the following Go packages:
2399{{range .Pkgs}}
2400 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2401
2402`
2403
2404var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2405Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07002406Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002407Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002408Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002409Defined: {{.pos}}
2410`
2411
2412var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2413Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002414Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002415`