blob: 60a436389e3d4f59ca21e13c5b48d5251a3f8688 [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"
21 "io"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070022 "path/filepath"
23 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070024 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080026 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070027 "strings"
Colin Cross23d7aa12015-06-30 16:05:22 -070028 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "text/scanner"
30 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070031
32 "github.com/google/blueprint/parser"
33 "github.com/google/blueprint/pathtools"
34 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070035)
36
37var ErrBuildActionsNotReady = errors.New("build actions are not ready")
38
39const maxErrors = 10
40
Jamie Gennisd4e10182014-06-12 20:06:50 -070041// A Context contains all the state needed to parse a set of Blueprints files
42// and generate a Ninja file. The process of generating a Ninja file proceeds
43// through a series of four phases. Each phase corresponds with a some methods
44// on the Context object
45//
46// Phase Methods
47// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070048// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070049//
50// 2. Parse ParseBlueprintsFiles, Parse
51//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070052// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070053//
54// 4. Write WriteBuildFile
55//
56// The registration phase prepares the context to process Blueprints files
57// containing various types of modules. The parse phase reads in one or more
58// Blueprints files and validates their contents against the module types that
59// have been registered. The generate phase then analyzes the parsed Blueprints
60// contents to create an internal representation for the build actions that must
61// be performed. This phase also performs validation of the module dependencies
62// and property values defined in the parsed Blueprints files. Finally, the
63// write phase generates the Ninja manifest text based on the generated build
64// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070065type Context struct {
66 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070067 moduleFactories map[string]ModuleFactory
68 moduleGroups map[string]*moduleGroup
69 moduleInfo map[Module]*moduleInfo
70 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070071 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070072 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070073 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070074 variantMutatorNames []string
75 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070076
77 dependenciesReady bool // set to true on a successful ResolveDependencies
78 buildActionsReady bool // set to true on a successful PrepareBuildActions
79
80 // set by SetIgnoreUnknownModuleTypes
81 ignoreUnknownModuleTypes bool
82
Colin Cross036a1df2015-12-17 15:49:30 -080083 // set by SetAllowMissingDependencies
84 allowMissingDependencies bool
85
Jamie Gennis1bc967e2014-05-27 16:34:41 -070086 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080087 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070088 globalVariables map[Variable]*ninjaString
89 globalPools map[Pool]*poolDef
90 globalRules map[Rule]*ruleDef
91
92 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080093 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070094 requiredNinjaMajor int // For the ninja_required_version variable
95 requiredNinjaMinor int // For the ninja_required_version variable
96 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070097
98 // set lazily by sortedModuleNames
99 cachedSortedModuleNames []string
Colin Crossd7b0f602016-06-02 15:30:20 -0700100
101 fs fileSystem
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102}
103
Jamie Gennisd4e10182014-06-12 20:06:50 -0700104// An Error describes a problem that was encountered that is related to a
105// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700106type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700107 Err error // the error that occurred
108 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109}
110
111type localBuildActions struct {
112 variables []*localVariable
113 rules []*localRule
114 buildDefs []*buildDef
115}
116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700118 name string
119 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700120
Colin Crossbbfa51a2014-12-17 16:12:41 -0800121 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122}
123
Colin Crossbbfa51a2014-12-17 16:12:41 -0800124type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700125 // set during Parse
126 typeName string
127 relBlueprintsFile string
128 pos scanner.Position
129 propertyPos map[string]scanner.Position
130 properties struct {
131 Name string
132 Deps []string
133 }
134
Colin Crossf5e34b92015-03-13 16:02:36 -0700135 variantName string
136 variant variationMap
137 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700138
Colin Crossc9028482014-12-18 16:28:54 -0800139 logicModule Module
140 group *moduleGroup
141 moduleProperties []interface{}
142
143 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700144 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800145 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800146
Colin Cross7addea32015-03-11 15:43:52 -0700147 // set during updateDependencies
148 reverseDeps []*moduleInfo
149 depsCount int
150
151 // used by parallelVisitAllBottomUp
152 waitingCount int
153
Colin Crossc9028482014-12-18 16:28:54 -0800154 // set during each runMutator
155 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700156
157 // set during PrepareBuildActions
158 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800159}
160
Colin Cross2c1f3d12016-04-11 15:47:28 -0700161type depInfo struct {
162 module *moduleInfo
163 tag DependencyTag
164}
165
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800166func (module *moduleInfo) String() string {
167 s := fmt.Sprintf("module %q", module.properties.Name)
168 if module.variantName != "" {
169 s += fmt.Sprintf(" variant %q", module.variantName)
170 }
171 return s
172}
173
Colin Crossf5e34b92015-03-13 16:02:36 -0700174// A Variation is a way that a variant of a module differs from other variants of the same module.
175// For example, two variants of the same module might have Variation{"arch","arm"} and
176// Variation{"arch","arm64"}
177type Variation struct {
178 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700179 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700180 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
181 // "shared" or "static" for link.
182 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700183}
184
Colin Crossf5e34b92015-03-13 16:02:36 -0700185// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
186type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700187
Colin Crossf5e34b92015-03-13 16:02:36 -0700188func (vm variationMap) clone() variationMap {
189 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700190 for k, v := range vm {
191 newVm[k] = v
192 }
193
194 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800195}
196
Colin Cross89486232015-05-08 11:14:54 -0700197// Compare this variationMap to another one. Returns true if the every entry in this map
198// is either the same in the other map or doesn't exist in the other map.
199func (vm variationMap) subset(other variationMap) bool {
200 for k, v1 := range vm {
201 if v2, ok := other[k]; ok && v1 != v2 {
202 return false
203 }
204 }
205 return true
206}
207
Colin Crossf5e34b92015-03-13 16:02:36 -0700208func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700209 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800210}
211
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700212type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700213 // set during RegisterSingletonType
214 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700215 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700216 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700217
218 // set during PrepareBuildActions
219 actionDefs localBuildActions
220}
221
Colin Crossc9028482014-12-18 16:28:54 -0800222type mutatorInfo struct {
223 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800224 topDownMutator TopDownMutator
225 bottomUpMutator BottomUpMutator
226 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700227 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800228}
229
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700230func (e *Error) Error() string {
231
232 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
233}
234
Jamie Gennisd4e10182014-06-12 20:06:50 -0700235// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700236// no module or singleton factories registered, so the RegisterModuleFactory and
237// RegisterSingletonFactory methods must be called before it can do anything
238// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700239func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700240 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800241 moduleFactories: make(map[string]ModuleFactory),
242 moduleGroups: make(map[string]*moduleGroup),
243 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800244 moduleNinjaNames: make(map[string]*moduleGroup),
Colin Crossd7b0f602016-06-02 15:30:20 -0700245 fs: fs,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700246 }
Colin Cross763b6f12015-10-29 15:32:56 -0700247
248 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
249
250 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700251}
252
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700253// A ModuleFactory function creates a new Module object. See the
254// Context.RegisterModuleType method for details about how a registered
255// ModuleFactory is used by a Context.
256type ModuleFactory func() (m Module, propertyStructs []interface{})
257
Jamie Gennisd4e10182014-06-12 20:06:50 -0700258// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700259// Blueprints file) with a Module factory function. When the given module type
260// name is encountered in a Blueprints file during parsing, the Module factory
261// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800262// generation for the module. If a Mutator splits a module into multiple variants,
263// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700264//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700265// The module type names given here must be unique for the context. The factory
266// function should be a named function so that its package and name can be
267// included in the generated Ninja file for debugging purposes.
268//
269// The factory function returns two values. The first is the newly created
270// Module object. The second is a slice of pointers to that Module object's
271// properties structs. Each properties struct is examined when parsing a module
272// definition of this type in a Blueprints file. Exported fields of the
273// properties structs are automatically set to the property values specified in
274// the Blueprints file. The properties struct field names determine the name of
275// the Blueprints file properties that are used - the Blueprints property name
276// matches that of the properties struct field name with the first letter
277// converted to lower-case.
278//
279// The fields of the properties struct must be either []string, a string, or
280// bool. The Context will panic if a Module gets instantiated with a properties
281// struct containing a field that is not one these supported types.
282//
283// Any properties that appear in the Blueprints files that are not built-in
284// module properties (such as "name" and "deps") and do not have a corresponding
285// field in the returned module properties struct result in an error during the
286// Context's parse phase.
287//
288// As an example, the follow code:
289//
290// type myModule struct {
291// properties struct {
292// Foo string
293// Bar []string
294// }
295// }
296//
297// func NewMyModule() (blueprint.Module, []interface{}) {
298// module := new(myModule)
299// properties := &module.properties
300// return module, []interface{}{properties}
301// }
302//
303// func main() {
304// ctx := blueprint.NewContext()
305// ctx.RegisterModuleType("my_module", NewMyModule)
306// // ...
307// }
308//
309// would support parsing a module defined in a Blueprints file as follows:
310//
311// my_module {
312// name: "myName",
313// foo: "my foo string",
314// bar: ["my", "bar", "strings"],
315// }
316//
Colin Cross7ad621c2015-01-07 16:22:45 -0800317// The factory function may be called from multiple goroutines. Any accesses
318// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700319func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
320 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700321 panic(errors.New("module type name is already registered"))
322 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700323 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700324}
325
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700326// A SingletonFactory function creates a new Singleton object. See the
327// Context.RegisterSingletonType method for details about how a registered
328// SingletonFactory is used by a Context.
329type SingletonFactory func() Singleton
330
331// RegisterSingletonType registers a singleton type that will be invoked to
332// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700333// and invoked exactly once as part of the generate phase. Each registered
334// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700335//
336// The singleton type names given here must be unique for the context. The
337// factory function should be a named function so that its package and name can
338// be included in the generated Ninja file for debugging purposes.
339func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700340 for _, s := range c.singletonInfo {
341 if s.name == name {
342 panic(errors.New("singleton name is already registered"))
343 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700344 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700345
Yuchen Wub9103ef2015-08-25 17:58:17 -0700346 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700347 factory: factory,
348 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700349 name: name,
350 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700351}
352
353func singletonPkgPath(singleton Singleton) string {
354 typ := reflect.TypeOf(singleton)
355 for typ.Kind() == reflect.Ptr {
356 typ = typ.Elem()
357 }
358 return typ.PkgPath()
359}
360
361func singletonTypeName(singleton Singleton) string {
362 typ := reflect.TypeOf(singleton)
363 for typ.Kind() == reflect.Ptr {
364 typ = typ.Elem()
365 }
366 return typ.PkgPath() + "." + typ.Name()
367}
368
Colin Crossc9028482014-12-18 16:28:54 -0800369// RegisterTopDownMutator registers a mutator that will be invoked to propagate
370// dependency info top-down between Modules. Each registered mutator
Colin Cross65569e42015-03-10 20:08:19 -0700371// is invoked in registration order (mixing TopDownMutators and BottomUpMutators)
372// once per Module, and is invoked on a module before being invoked on any of its
373// dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800374//
Colin Cross65569e42015-03-10 20:08:19 -0700375// The mutator type names given here must be unique to all top down mutators in
376// the Context.
Colin Crossc9028482014-12-18 16:28:54 -0800377func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
378 for _, m := range c.mutatorInfo {
379 if m.name == name && m.topDownMutator != nil {
380 panic(fmt.Errorf("mutator name %s is already registered", name))
381 }
382 }
383
384 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
385 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800386 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800387 })
388}
389
390// RegisterBottomUpMutator registers a mutator that will be invoked to split
Colin Cross65569e42015-03-10 20:08:19 -0700391// Modules into variants. Each registered mutator is invoked in registration
392// order (mixing TopDownMutators and BottomUpMutators) once per Module, and is
393// invoked on dependencies before being invoked on dependers.
Colin Crossc9028482014-12-18 16:28:54 -0800394//
Colin Cross65569e42015-03-10 20:08:19 -0700395// The mutator type names given here must be unique to all bottom up or early
396// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700397//
398// Returns a BottomUpMutatorHandle, on which Parallel can be called to set
399// the mutator to visit modules in parallel while maintaining ordering.
400func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) BottomUpMutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700401 for _, m := range c.variantMutatorNames {
402 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800403 panic(fmt.Errorf("mutator name %s is already registered", name))
404 }
405 }
406
Colin Cross49c279a2016-08-05 22:30:44 -0700407 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800408 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800409 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700410 }
411 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700412
413 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700414
415 return info
416}
417
418type BottomUpMutatorHandle interface {
419 // Set the mutator to visit modules in parallel while maintaining ordering
420 Parallel() BottomUpMutatorHandle
421}
422
423func (mutator *mutatorInfo) Parallel() BottomUpMutatorHandle {
424 mutator.parallel = true
425 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700426}
427
428// RegisterEarlyMutator registers a mutator that will be invoked to split
429// Modules into multiple variant Modules before any dependencies have been
430// created. Each registered mutator is invoked in registration order once
431// per Module (including each variant from previous early mutators). Module
432// order is unpredictable.
433//
434// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700435// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700436//
437// The mutator type names given here must be unique to all bottom up or early
438// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700439//
440// Deprecated, use a BottomUpMutator instead. The only difference between
441// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
442// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700443func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
444 for _, m := range c.variantMutatorNames {
445 if m == name {
446 panic(fmt.Errorf("mutator name %s is already registered", name))
447 }
448 }
449
Colin Crossf8b50422016-08-10 12:56:40 -0700450 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
451 bottomUpMutator: func(mctx BottomUpMutatorContext) {
452 mutator(mctx)
453 },
454 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700455 })
456
457 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800458}
459
Jamie Gennisd4e10182014-06-12 20:06:50 -0700460// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
461// where it encounters an unknown module type while parsing Blueprints files. By
462// default, the context will report unknown module types as an error. If this
463// method is called with ignoreUnknownModuleTypes set to true then the context
464// will silently ignore unknown module types.
465//
466// This method should generally not be used. It exists to facilitate the
467// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700468func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
469 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
470}
471
Colin Cross036a1df2015-12-17 15:49:30 -0800472// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
473// unresolved dependencies. If the module's GenerateBuildActions calls
474// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
475// for missing dependencies.
476func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
477 c.allowMissingDependencies = allowMissingDependencies
478}
479
Jamie Gennisd4e10182014-06-12 20:06:50 -0700480// Parse parses a single Blueprints file from r, creating Module objects for
481// each of the module definitions encountered. If the Blueprints file contains
482// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700483// searched for Blueprints files returned in the subBlueprints return value.
484// If the Blueprints file contains an assignment to the "build" variable, then
485// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700486//
487// rootDir specifies the path to the root directory of the source tree, while
488// filename specifies the path to the Blueprints file. These paths are used for
489// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800490func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross23d7aa12015-06-30 16:05:22 -0700491 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, deps []string,
Colin Cross1fef5362015-04-20 16:50:54 -0700492 errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700493
Jamie Gennisec701282014-06-12 20:06:31 -0700494 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700495 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700496 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700497 }
498
Colin Crossc0dbc552015-01-02 15:19:28 -0800499 scope = parser.NewScope(scope)
500 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800501 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700502 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700503 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700504 if len(errs) > 0 {
505 for i, err := range errs {
506 if parseErr, ok := err.(*parser.ParseError); ok {
507 err = &Error{
508 Err: parseErr.Err,
509 Pos: parseErr.Pos,
510 }
511 errs[i] = err
512 }
513 }
514
515 // If there were any parse errors don't bother trying to interpret the
516 // result.
Colin Cross1fef5362015-04-20 16:50:54 -0700517 return nil, nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700518 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700519 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700520
Colin Cross6d8780f2015-07-10 17:51:55 -0700521 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700522 if err != nil {
523 errs = append(errs, err)
524 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700525
Colin Cross7f507402015-12-16 13:03:41 -0800526 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
527 if err != nil {
528 errs = append(errs, err)
529 }
530
Colin Cross6d8780f2015-07-10 17:51:55 -0700531 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700532 if err != nil {
533 errs = append(errs, err)
534 }
535
Colin Cross29394222015-04-27 13:18:21 -0700536 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
537
Colin Cross7f507402015-12-16 13:03:41 -0800538 var blueprints []string
539
540 newBlueprints, newDeps, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
541 blueprints = append(blueprints, newBlueprints...)
542 deps = append(deps, newDeps...)
543 errs = append(errs, newErrs...)
544
545 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
546 subBlueprintsName, false)
547 blueprints = append(blueprints, newBlueprints...)
548 deps = append(deps, newDeps...)
549 errs = append(errs, newErrs...)
550
551 newBlueprints, newDeps, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
552 optionalSubdirsPos, subBlueprintsName, true)
553 blueprints = append(blueprints, newBlueprints...)
554 deps = append(deps, newDeps...)
555 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800556
Colin Cross1fef5362015-04-20 16:50:54 -0700557 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
558 for i, b := range blueprints {
559 subBlueprintsAndScope[i] = stringAndScope{b, scope}
560 }
561
Colin Cross23d7aa12015-06-30 16:05:22 -0700562 return file, subBlueprintsAndScope, deps, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800563}
564
Colin Cross7ad621c2015-01-07 16:22:45 -0800565type stringAndScope struct {
566 string
567 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700568}
569
Jamie Gennisd4e10182014-06-12 20:06:50 -0700570// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
571// at rootFile. When it encounters a Blueprints file with a set of subdirs
572// listed it recursively parses any Blueprints files found in those
573// subdirectories.
574//
575// If no errors are encountered while parsing the files, the list of paths on
576// which the future output will depend is returned. This list will include both
577// Blueprints file paths as well as directory paths for cases where wildcard
578// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700579func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
580 errs []error) {
581
Colin Cross7ad621c2015-01-07 16:22:45 -0800582 c.dependenciesReady = false
583
Colin Cross23d7aa12015-06-30 16:05:22 -0700584 moduleCh := make(chan *moduleInfo)
585 errsCh := make(chan []error)
586 doneCh := make(chan struct{})
587 var numErrs uint32
588 var numGoroutines int32
589
590 // handler must be reentrant
591 handler := func(file *parser.File) {
592 if atomic.LoadUint32(&numErrs) > maxErrors {
593 return
594 }
595
596 atomic.AddInt32(&numGoroutines, 1)
597 go func() {
598 for _, def := range file.Defs {
599 var module *moduleInfo
600 var errs []error
601 switch def := def.(type) {
602 case *parser.Module:
603 module, errs = c.processModuleDef(def, file.Name)
604 case *parser.Assignment:
605 // Already handled via Scope object
606 default:
607 panic("unknown definition type")
608 }
609
610 if len(errs) > 0 {
611 atomic.AddUint32(&numErrs, uint32(len(errs)))
612 errsCh <- errs
613 } else if module != nil {
614 moduleCh <- module
615 }
616 }
617 doneCh <- struct{}{}
618 }()
619 }
620
621 atomic.AddInt32(&numGoroutines, 1)
622 go func() {
623 var errs []error
624 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
625 if len(errs) > 0 {
626 errsCh <- errs
627 }
628 doneCh <- struct{}{}
629 }()
630
631loop:
632 for {
633 select {
634 case newErrs := <-errsCh:
635 errs = append(errs, newErrs...)
636 case module := <-moduleCh:
637 newErrs := c.addModule(module)
638 if len(newErrs) > 0 {
639 errs = append(errs, newErrs...)
640 }
641 case <-doneCh:
642 n := atomic.AddInt32(&numGoroutines, -1)
643 if n == 0 {
644 break loop
645 }
646 }
647 }
648
649 return deps, errs
650}
651
652type FileHandler func(*parser.File)
653
654// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
655// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
656// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
657// it must be reentrant.
658//
659// If no errors are encountered while parsing the files, the list of paths on
660// which the future output will depend is returned. This list will include both
661// Blueprints file paths as well as directory paths for cases where wildcard
662// subdirs are found.
663func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
664 errs []error) {
665
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700666 rootDir := filepath.Dir(rootFile)
667
Colin Cross7ad621c2015-01-07 16:22:45 -0800668 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700669
Colin Cross7ad621c2015-01-07 16:22:45 -0800670 // Channels to receive data back from parseBlueprintsFile goroutines
671 blueprintsCh := make(chan stringAndScope)
672 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700673 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800674 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700675
Colin Cross7ad621c2015-01-07 16:22:45 -0800676 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
677 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700678
Colin Cross7ad621c2015-01-07 16:22:45 -0800679 // Number of outstanding goroutines to wait for
680 count := 0
681
682 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
683 count++
684 go func() {
685 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700686 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800687 doneCh <- struct{}{}
688 }()
689 }
690
691 tooManyErrors := false
692
693 startParseBlueprintsFile(rootFile, nil)
694
695loop:
696 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700697 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800698 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700699 }
700
Colin Cross7ad621c2015-01-07 16:22:45 -0800701 select {
702 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700703 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800704 case dep := <-depsCh:
705 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700706 case file := <-fileCh:
707 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800708 case blueprint := <-blueprintsCh:
709 if tooManyErrors {
710 continue
711 }
712 if blueprintsSet[blueprint.string] {
713 continue
714 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700715
Colin Cross7ad621c2015-01-07 16:22:45 -0800716 blueprintsSet[blueprint.string] = true
717 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
718 case <-doneCh:
719 count--
720 if count == 0 {
721 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700722 }
723 }
724 }
725
Colin Cross7ad621c2015-01-07 16:22:45 -0800726 return
727}
728
Colin Crossd7b0f602016-06-02 15:30:20 -0700729// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
730// filenames to contents stored as a byte slice.
731func (c *Context) MockFileSystem(files map[string][]byte) {
732 c.fs = &mockFS{
733 files: files,
734 }
735}
736
Colin Cross7ad621c2015-01-07 16:22:45 -0800737// parseBlueprintFile parses a single Blueprints file, returning any errors through
738// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
739// blueprintsCh, and any dependencies on Blueprints files or directories through
740// depsCh.
741func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700742 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800743 depsCh chan<- string) {
744
Colin Crossd7b0f602016-06-02 15:30:20 -0700745 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800746 if err != nil {
747 errsCh <- []error{err}
748 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700749 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700750 defer func() {
751 err = f.Close()
752 if err != nil {
753 errsCh <- []error{err}
754 }
755 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700756
Colin Cross23d7aa12015-06-30 16:05:22 -0700757 file, subBlueprints, deps, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800758 if len(errs) > 0 {
759 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700760 } else {
761 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800762 }
763
Colin Cross1fef5362015-04-20 16:50:54 -0700764 for _, b := range subBlueprints {
765 blueprintsCh <- b
766 }
767
768 for _, d := range deps {
769 depsCh <- d
770 }
Colin Cross1fef5362015-04-20 16:50:54 -0700771}
772
Colin Cross7f507402015-12-16 13:03:41 -0800773func (c *Context) findBuildBlueprints(dir string, build []string,
774 buildPos scanner.Position) (blueprints, deps []string, errs []error) {
775
776 for _, file := range build {
777 globPattern := filepath.Join(dir, file)
778 matches, matchedDirs, err := pathtools.Glob(globPattern)
779 if err != nil {
780 errs = append(errs, &Error{
781 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
782 Pos: buildPos,
783 })
784 continue
785 }
786
787 if len(matches) == 0 {
788 errs = append(errs, &Error{
789 Err: fmt.Errorf("%q: not found", globPattern),
790 Pos: buildPos,
791 })
792 }
793
794 // Depend on all searched directories so we pick up future changes.
795 deps = append(deps, matchedDirs...)
796
797 for _, foundBlueprints := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700798 exists, dir, err := c.fs.Exists(foundBlueprints)
799 if err != nil {
800 errs = append(errs, err)
801 } else if !exists {
Colin Cross7f507402015-12-16 13:03:41 -0800802 errs = append(errs, &Error{
803 Err: fmt.Errorf("%q not found", foundBlueprints),
804 })
805 continue
Colin Crossd7b0f602016-06-02 15:30:20 -0700806 } else if dir {
Colin Cross7f507402015-12-16 13:03:41 -0800807 errs = append(errs, &Error{
808 Err: fmt.Errorf("%q is a directory", foundBlueprints),
809 })
810 continue
811 }
812
813 blueprints = append(blueprints, foundBlueprints)
814 }
815 }
816
817 return blueprints, deps, errs
818}
819
820func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
821 subBlueprintsName string, optional bool) (blueprints, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800822
823 for _, subdir := range subdirs {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700824 globPattern := filepath.Join(dir, subdir)
825 matches, matchedDirs, err := pathtools.Glob(globPattern)
826 if err != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700827 errs = append(errs, &Error{
828 Err: fmt.Errorf("%q: %s", globPattern, err.Error()),
829 Pos: subdirsPos,
830 })
831 continue
832 }
833
Colin Cross7f507402015-12-16 13:03:41 -0800834 if len(matches) == 0 && !optional {
Colin Cross1fef5362015-04-20 16:50:54 -0700835 errs = append(errs, &Error{
836 Err: fmt.Errorf("%q: not found", globPattern),
837 Pos: subdirsPos,
838 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700839 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800840
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700841 // Depend on all searched directories so we pick up future changes.
Colin Cross1fef5362015-04-20 16:50:54 -0700842 deps = append(deps, matchedDirs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800843
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700844 for _, foundSubdir := range matches {
Colin Crossd7b0f602016-06-02 15:30:20 -0700845 exists, dir, subdirStatErr := c.fs.Exists(foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700846 if subdirStatErr != nil {
Colin Cross1fef5362015-04-20 16:50:54 -0700847 errs = append(errs, subdirStatErr)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700848 continue
Colin Cross7ad621c2015-01-07 16:22:45 -0800849 }
850
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700851 // Skip files
Colin Crossd7b0f602016-06-02 15:30:20 -0700852 if !dir {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700853 continue
854 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800855
Colin Cross29394222015-04-27 13:18:21 -0700856 var subBlueprints string
857 if subBlueprintsName != "" {
858 subBlueprints = filepath.Join(foundSubdir, subBlueprintsName)
Colin Crossd7b0f602016-06-02 15:30:20 -0700859 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700860 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700861
Colin Crossd7b0f602016-06-02 15:30:20 -0700862 if err == nil && (!exists || subBlueprints == "") {
Colin Cross29394222015-04-27 13:18:21 -0700863 subBlueprints = filepath.Join(foundSubdir, "Blueprints")
Colin Crossd7b0f602016-06-02 15:30:20 -0700864 exists, _, err = c.fs.Exists(subBlueprints)
Colin Cross29394222015-04-27 13:18:21 -0700865 }
866
Colin Crossd7b0f602016-06-02 15:30:20 -0700867 if err != nil {
868 errs = append(errs, err)
869 continue
870 }
871
872 if !exists {
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700873 // There is no Blueprints file in this subdirectory. We
874 // need to add the directory to the list of dependencies
875 // so that if someone adds a Blueprints file in the
876 // future we'll pick it up.
Jamie Gennis7ccc2c22015-07-06 13:11:15 -0700877 deps = append(deps, foundSubdir)
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700878 } else {
Colin Cross1fef5362015-04-20 16:50:54 -0700879 deps = append(deps, subBlueprints)
880 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800881 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800882 }
883 }
Colin Cross1fef5362015-04-20 16:50:54 -0700884
Colin Cross1fef5362015-04-20 16:50:54 -0700885 return blueprints, deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700886}
887
Colin Cross6d8780f2015-07-10 17:51:55 -0700888func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
889 if assignment, local := scope.Get(v); assignment == nil || !local {
890 return nil, scanner.Position{}, nil
891 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700892 switch value := assignment.Value.Eval().(type) {
893 case *parser.List:
894 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700895
Colin Crosse32cc802016-06-07 12:28:16 -0700896 for _, listValue := range value.Values {
897 s, ok := listValue.(*parser.String)
898 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700899 // The parser should not produce this.
900 panic("non-string value found in list")
901 }
902
Colin Crosse32cc802016-06-07 12:28:16 -0700903 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700904 }
905
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700906 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700907 case *parser.Bool, *parser.String:
Colin Cross1fef5362015-04-20 16:50:54 -0700908 return nil, scanner.Position{}, &Error{
909 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700910 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700911 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700912 default:
913 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
914 }
915 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700916}
917
Colin Cross29394222015-04-27 13:18:21 -0700918func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700919 if assignment, _ := scope.Get(v); assignment == nil {
920 return "", scanner.Position{}, nil
921 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700922 switch value := assignment.Value.Eval().(type) {
923 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700924 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700925 case *parser.Bool, *parser.List:
Colin Cross29394222015-04-27 13:18:21 -0700926 return "", scanner.Position{}, &Error{
927 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700928 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -0700929 }
930 default:
931 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
932 }
933 }
Colin Cross29394222015-04-27 13:18:21 -0700934}
935
Colin Cross910242b2016-04-11 15:41:52 -0700936// Clones a build logic module by calling the factory method for its module type, and then cloning
937// property values. Any values stored in the module object that are not stored in properties
938// structs will be lost.
939func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
940 typeName := origModule.typeName
941 factory, ok := c.moduleFactories[typeName]
942 if !ok {
943 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
944 }
945
946 props := []interface{}{
947 &origModule.properties,
948 }
949 newLogicModule, newProperties := factory()
950
951 newProperties = append(props, newProperties...)
952
953 if len(newProperties) != len(origModule.moduleProperties) {
954 panic("mismatched properties array length in " + origModule.properties.Name)
955 }
956
957 for i := range newProperties {
958 dst := reflect.ValueOf(newProperties[i]).Elem()
959 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
960
961 proptools.CopyProperties(dst, src)
962 }
963
964 return newLogicModule, newProperties
965}
966
Colin Crossf5e34b92015-03-13 16:02:36 -0700967func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
968 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800969
Colin Crossf4d18a62015-03-18 17:43:15 -0700970 if len(variationNames) == 0 {
971 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Jamie Gennis6cafc2c2015-03-20 22:39:29 -0400972 mutatorName, origModule.properties.Name))
Colin Crossf4d18a62015-03-18 17:43:15 -0700973 }
974
Colin Crossc9028482014-12-18 16:28:54 -0800975 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800976
Colin Cross174ae052015-03-03 17:37:03 -0800977 var errs []error
978
Colin Crossf5e34b92015-03-13 16:02:36 -0700979 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -0800980 var newLogicModule Module
981 var newProperties []interface{}
982
983 if i == 0 {
984 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700985 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
986 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -0700987 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -0800988 } else {
Colin Cross910242b2016-04-11 15:41:52 -0700989 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -0800990 }
991
Colin Crossf5e34b92015-03-13 16:02:36 -0700992 newVariant := origModule.variant.clone()
993 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800994
Colin Crossed342d92015-03-11 00:57:25 -0700995 m := *origModule
996 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -0700997 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -0700998 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700999 newModule.variant = newVariant
1000 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -07001001 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001002
Colin Crosse7daa222015-03-11 14:35:41 -07001003 if newModule.variantName == "" {
Colin Crossf5e34b92015-03-13 16:02:36 -07001004 newModule.variantName = variationName
Colin Crosse7daa222015-03-11 14:35:41 -07001005 } else {
Colin Crossf5e34b92015-03-13 16:02:36 -07001006 newModule.variantName += "_" + variationName
Colin Crosse7daa222015-03-11 14:35:41 -07001007 }
1008
Colin Crossc9028482014-12-18 16:28:54 -08001009 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001010
Colin Crossf5e34b92015-03-13 16:02:36 -07001011 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001012 if len(newErrs) > 0 {
1013 errs = append(errs, newErrs...)
1014 }
Colin Crossc9028482014-12-18 16:28:54 -08001015 }
1016
1017 // Mark original variant as invalid. Modules that depend on this module will still
1018 // depend on origModule, but we'll fix it when the mutator is called on them.
1019 origModule.logicModule = nil
1020 origModule.splitModules = newModules
1021
Colin Cross174ae052015-03-03 17:37:03 -08001022 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001023}
1024
Colin Crossf5e34b92015-03-13 16:02:36 -07001025func (c *Context) convertDepsToVariation(module *moduleInfo,
1026 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001027
Colin Crossc9028482014-12-18 16:28:54 -08001028 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001029 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001030 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001031 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001032 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001033 newDep = m
1034 break
1035 }
1036 }
1037 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -08001038 errs = append(errs, &Error{
Colin Crossf5e34b92015-03-13 16:02:36 -07001039 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001040 variationName, dep.module.properties.Name, module.properties.Name),
Colin Crossed342d92015-03-11 00:57:25 -07001041 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001042 })
1043 continue
Colin Crossc9028482014-12-18 16:28:54 -08001044 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001045 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001046 }
1047 }
Colin Cross174ae052015-03-03 17:37:03 -08001048
1049 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001050}
1051
Colin Crossf5e34b92015-03-13 16:02:36 -07001052func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001053 names := make([]string, 0, len(variant))
1054 for _, m := range c.variantMutatorNames {
1055 if v, ok := variant[m]; ok {
1056 names = append(names, m+":"+v)
1057 }
1058 }
1059
1060 return strings.Join(names, ", ")
1061}
1062
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001063func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001064 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001065
Colin Crossc32c4792016-06-09 15:52:30 -07001066 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001067 if !ok {
1068 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001069 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001070 }
1071
Colin Cross7ad621c2015-01-07 16:22:45 -08001072 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001073 &Error{
Colin Crossc32c4792016-06-09 15:52:30 -07001074 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1075 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001076 },
1077 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001078 }
1079
Colin Crossbbfa51a2014-12-17 16:12:41 -08001080 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001081
1082 module := &moduleInfo{
1083 logicModule: logicModule,
Colin Crossc32c4792016-06-09 15:52:30 -07001084 typeName: moduleDef.Type,
Jamie Gennisec701282014-06-12 20:06:31 -07001085 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001086 }
1087
Jamie Gennis87622922014-09-30 11:38:25 -07001088 props := []interface{}{
Colin Crossed342d92015-03-11 00:57:25 -07001089 &module.properties,
Jamie Gennis87622922014-09-30 11:38:25 -07001090 }
1091 properties = append(props, properties...)
Colin Crossed342d92015-03-11 00:57:25 -07001092 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001093
Jamie Gennis87622922014-09-30 11:38:25 -07001094 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001095 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001096 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001097 }
1098
Colin Crossc32c4792016-06-09 15:52:30 -07001099 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001100 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001101 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001102 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001103 }
1104
Colin Cross7ad621c2015-01-07 16:22:45 -08001105 return module, nil
1106}
1107
Colin Cross23d7aa12015-06-30 16:05:22 -07001108func (c *Context) addModule(module *moduleInfo) []error {
1109 name := module.properties.Name
1110 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001111
Colin Cross23d7aa12015-06-30 16:05:22 -07001112 if group, present := c.moduleGroups[name]; present {
1113 return []error{
1114 &Error{
1115 Err: fmt.Errorf("module %q already defined", name),
1116 Pos: module.pos,
1117 },
1118 &Error{
1119 Err: fmt.Errorf("<-- previous definition here"),
1120 Pos: group.modules[0].pos,
1121 },
Colin Crossed342d92015-03-11 00:57:25 -07001122 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001123 } else {
1124 ninjaName := toNinjaName(module.properties.Name)
1125
1126 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1127 // already exists
1128 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1129 ninjaName = toNinjaName(module.properties.Name) + strconv.Itoa(i)
1130 }
1131
1132 group := &moduleGroup{
1133 name: module.properties.Name,
1134 ninjaName: ninjaName,
1135 modules: []*moduleInfo{module},
1136 }
1137 module.group = group
1138 c.moduleGroups[name] = group
1139 c.moduleNinjaNames[ninjaName] = group
Colin Cross7ad621c2015-01-07 16:22:45 -08001140 }
1141
Colin Cross23d7aa12015-06-30 16:05:22 -07001142 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001143}
1144
Jamie Gennisd4e10182014-06-12 20:06:50 -07001145// ResolveDependencies checks that the dependencies specified by all of the
1146// modules defined in the parsed Blueprints files are valid. This means that
1147// the modules depended upon are defined and that no circular dependencies
1148// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001149func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Crossf8b50422016-08-10 12:56:40 -07001150 errs := c.updateDependencies()
1151 if len(errs) > 0 {
1152 return errs
1153 }
1154
1155 errs = c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001156 if len(errs) > 0 {
1157 return errs
1158 }
1159
Colin Cross910242b2016-04-11 15:41:52 -07001160 c.cloneModules()
1161
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001162 c.dependenciesReady = true
1163 return nil
1164}
1165
Colin Cross763b6f12015-10-29 15:32:56 -07001166// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001167// DynamicDependerModule interface then this set consists of the union of those
1168// module names listed in its "deps" property, those returned by its
1169// DynamicDependencies method, and those added by calling AddDependencies or
Colin Crossf5e34b92015-03-13 16:02:36 -07001170// AddVariationDependencies on DynamicDependencyModuleContext. Otherwise it
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001171// is simply those names listed in its "deps" property.
Colin Cross763b6f12015-10-29 15:32:56 -07001172func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001173 ctx.AddDependency(ctx.Module(), nil, ctx.moduleInfo().properties.Deps...)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001174
Colin Cross763b6f12015-10-29 15:32:56 -07001175 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001176 func() {
1177 defer func() {
1178 if r := recover(); r != nil {
1179 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1180 }
1181 }()
1182 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001183
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001184 if ctx.Failed() {
1185 return
1186 }
Colin Cross763b6f12015-10-29 15:32:56 -07001187
Colin Cross2c1f3d12016-04-11 15:47:28 -07001188 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001189 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001190 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001191}
1192
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001193// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1194// and returns the matching module, or nil if one is not found.
1195func (c *Context) findMatchingVariant(module *moduleInfo, group *moduleGroup) *moduleInfo {
1196 if len(group.modules) == 1 {
1197 return group.modules[0]
1198 } else {
1199 for _, m := range group.modules {
1200 if m.variant.equal(module.dependencyVariant) {
1201 return m
1202 }
1203 }
1204 }
1205
1206 return nil
1207}
1208
Colin Cross2c1f3d12016-04-11 15:47:28 -07001209func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Colin Crossed342d92015-03-11 00:57:25 -07001210 if depName == module.properties.Name {
Colin Crossc9028482014-12-18 16:28:54 -08001211 return []error{&Error{
1212 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001213 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001214 }}
1215 }
1216
Colin Cross2c1f3d12016-04-11 15:47:28 -07001217 depGroup, ok := c.moduleGroups[depName]
Colin Crossc9028482014-12-18 16:28:54 -08001218 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001219 if c.allowMissingDependencies {
1220 module.missingDeps = append(module.missingDeps, depName)
1221 return nil
1222 }
Colin Crossc9028482014-12-18 16:28:54 -08001223 return []error{&Error{
1224 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Crossed342d92015-03-11 00:57:25 -07001225 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001226 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001227 }}
1228 }
1229
Colin Cross2c1f3d12016-04-11 15:47:28 -07001230 if m := c.findMatchingVariant(module, depGroup); m != nil {
1231 for _, dep := range module.directDeps {
1232 if m == dep.module {
1233 // TODO(ccross): what if adding a dependency with a different tag?
1234 return nil
1235 }
Colin Cross65569e42015-03-10 20:08:19 -07001236 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001237 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001238 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001239 }
Colin Crossc9028482014-12-18 16:28:54 -08001240
Colin Cross65569e42015-03-10 20:08:19 -07001241 return []error{&Error{
1242 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001243 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001244 c.prettyPrintVariant(module.dependencyVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001245 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001246 }}
1247}
1248
Colin Cross8d8a7af2015-11-03 16:41:29 -08001249func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001250 if destName == module.properties.Name {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001251 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001252 Err: fmt.Errorf("%q depends on itself", destName),
1253 Pos: module.pos,
1254 }}
1255 }
1256
1257 destInfo, ok := c.moduleGroups[destName]
1258 if !ok {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001259 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001260 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
1261 module.properties.Name, destName),
1262 Pos: module.pos,
1263 }}
1264 }
1265
1266 if m := c.findMatchingVariant(module, destInfo); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001267 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001268 }
1269
Colin Cross8d8a7af2015-11-03 16:41:29 -08001270 return nil, []error{&Error{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001271 Err: fmt.Errorf("reverse dependency %q of %q missing variant %q",
1272 destName, module.properties.Name,
1273 c.prettyPrintVariant(module.dependencyVariant)),
1274 Pos: module.pos,
1275 }}
1276}
1277
Colin Crossf5e34b92015-03-13 16:02:36 -07001278func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001279 tag DependencyTag, depName string, far bool) []error {
Colin Cross65569e42015-03-10 20:08:19 -07001280
Colin Cross2c1f3d12016-04-11 15:47:28 -07001281 depGroup, ok := c.moduleGroups[depName]
Colin Cross65569e42015-03-10 20:08:19 -07001282 if !ok {
Colin Cross036a1df2015-12-17 15:49:30 -08001283 if c.allowMissingDependencies {
1284 module.missingDeps = append(module.missingDeps, depName)
1285 return nil
1286 }
Colin Cross65569e42015-03-10 20:08:19 -07001287 return []error{&Error{
1288 Err: fmt.Errorf("%q depends on undefined module %q",
1289 module.properties.Name, depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001290 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001291 }}
1292 }
1293
1294 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1295 // compare the strings because the result won't be in mutator registration order.
1296 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001297 var newVariant variationMap
1298 if !far {
1299 newVariant = module.dependencyVariant.clone()
1300 } else {
1301 newVariant = make(variationMap)
1302 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001303 for _, v := range variations {
1304 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001305 }
1306
Colin Cross2c1f3d12016-04-11 15:47:28 -07001307 for _, m := range depGroup.modules {
Colin Cross89486232015-05-08 11:14:54 -07001308 var found bool
1309 if far {
1310 found = m.variant.subset(newVariant)
1311 } else {
1312 found = m.variant.equal(newVariant)
1313 }
1314 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001315 if module == m {
1316 return []error{&Error{
1317 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001318 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001319 }}
1320 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001321 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001322 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001323 // run GenerateBuildActions in order for the variants of a module
Colin Cross2c1f3d12016-04-11 15:47:28 -07001324 if depGroup == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross65569e42015-03-10 20:08:19 -07001325 return []error{&Error{
1326 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001327 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001328 }}
1329 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001330 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross65569e42015-03-10 20:08:19 -07001331 return nil
1332 }
1333 }
1334
1335 return []error{&Error{
1336 Err: fmt.Errorf("dependency %q of %q missing variant %q",
Colin Cross2c1f3d12016-04-11 15:47:28 -07001337 depGroup.modules[0].properties.Name, module.properties.Name,
Colin Crossf5e34b92015-03-13 16:02:36 -07001338 c.prettyPrintVariant(newVariant)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001339 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001340 }}
Colin Crossc9028482014-12-18 16:28:54 -08001341}
1342
Colin Crossf1875462016-04-11 17:33:13 -07001343func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1344 from, to Module) {
1345
1346 var fromInfo, toInfo *moduleInfo
1347 for _, m := range origModule.splitModules {
1348 if m.logicModule == from {
1349 fromInfo = m
1350 }
1351 if m.logicModule == to {
1352 toInfo = m
1353 if fromInfo != nil {
1354 panic(fmt.Errorf("%q depends on later version of itself", origModule.properties.Name))
1355 }
1356 }
1357 }
1358
1359 if fromInfo == nil || toInfo == nil {
1360 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
1361 origModule.properties.Name))
1362 }
1363
1364 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
1365}
1366
Colin Cross49c279a2016-08-05 22:30:44 -07001367func (c *Context) visitAllBottomUp(visit func(group *moduleInfo) bool) {
1368 for _, module := range c.modulesSorted {
1369 if visit(module) {
1370 return
1371 }
1372 }
1373}
1374
1375// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1376// of its dependencies has finished.
Colin Cross7addea32015-03-11 15:43:52 -07001377func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleInfo) bool) {
1378 doneCh := make(chan *moduleInfo)
Colin Cross691a60d2015-01-07 18:08:56 -08001379 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001380 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001381
Colin Cross7addea32015-03-11 15:43:52 -07001382 for _, module := range c.modulesSorted {
1383 module.waitingCount = module.depsCount
Colin Cross691a60d2015-01-07 18:08:56 -08001384 }
1385
Colin Cross7addea32015-03-11 15:43:52 -07001386 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001387 count++
1388 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001389 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001390 if ret {
1391 cancel = true
1392 }
Colin Cross7addea32015-03-11 15:43:52 -07001393 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001394 }()
1395 }
1396
Colin Cross7addea32015-03-11 15:43:52 -07001397 for _, module := range c.modulesSorted {
1398 if module.waitingCount == 0 {
1399 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001400 }
1401 }
1402
Colin Cross11e3b0d2015-02-04 10:41:00 -08001403 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001404 select {
Colin Cross7addea32015-03-11 15:43:52 -07001405 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001406 if !cancel {
Colin Cross7addea32015-03-11 15:43:52 -07001407 for _, parent := range doneModule.reverseDeps {
Colin Cross8900e9b2015-03-02 14:03:01 -08001408 parent.waitingCount--
1409 if parent.waitingCount == 0 {
1410 visitOne(parent)
1411 }
Colin Cross691a60d2015-01-07 18:08:56 -08001412 }
1413 }
1414 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001415 }
1416 }
1417}
1418
1419// updateDependencies recursively walks the module dependency graph and updates
1420// additional fields based on the dependencies. It builds a sorted list of modules
1421// such that dependencies of a module always appear first, and populates reverse
1422// dependency links and counts of total dependencies. It also reports errors when
1423// it encounters dependency cycles. This should called after resolveDependencies,
1424// as well as after any mutator pass has called addDependency
1425func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001426 visited := make(map[*moduleInfo]bool) // modules that were already checked
1427 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001428
Colin Cross7addea32015-03-11 15:43:52 -07001429 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001430
Colin Cross7addea32015-03-11 15:43:52 -07001431 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001432
Colin Cross7addea32015-03-11 15:43:52 -07001433 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001434 // We are the "start" of the cycle, so we're responsible
1435 // for generating the errors. The cycle list is in
1436 // reverse order because all the 'check' calls append
1437 // their own module to the list.
1438 errs = append(errs, &Error{
1439 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001440 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001441 })
1442
1443 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001444 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001445 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001446 nextModule := cycle[i]
Colin Cross10b54db2015-03-11 14:40:30 -07001447 errs = append(errs, &Error{
1448 Err: fmt.Errorf(" %q depends on %q",
Colin Cross7addea32015-03-11 15:43:52 -07001449 curModule.properties.Name,
1450 nextModule.properties.Name),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001451 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001452 })
Colin Cross7addea32015-03-11 15:43:52 -07001453 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001454 }
1455 }
1456
Colin Cross7addea32015-03-11 15:43:52 -07001457 check = func(module *moduleInfo) []*moduleInfo {
1458 visited[module] = true
1459 checking[module] = true
1460 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001461
Colin Cross7addea32015-03-11 15:43:52 -07001462 deps := make(map[*moduleInfo]bool)
1463
1464 // Add an implicit dependency ordering on all earlier modules in the same module group
1465 for _, dep := range module.group.modules {
1466 if dep == module {
1467 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001468 }
Colin Cross7addea32015-03-11 15:43:52 -07001469 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001470 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001471
Colin Cross7addea32015-03-11 15:43:52 -07001472 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001473 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001474 }
1475
1476 module.reverseDeps = []*moduleInfo{}
1477 module.depsCount = len(deps)
Colin Cross691a60d2015-01-07 18:08:56 -08001478
Colin Crossbbfa51a2014-12-17 16:12:41 -08001479 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001480 if checking[dep] {
1481 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001482 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001483 }
1484
1485 if !visited[dep] {
1486 cycle := check(dep)
1487 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001488 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001489 // We are the "start" of the cycle, so we're responsible
1490 // for generating the errors. The cycle list is in
1491 // reverse order because all the 'check' calls append
1492 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001493 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001494
1495 // We can continue processing this module's children to
1496 // find more cycles. Since all the modules that were
1497 // part of the found cycle were marked as visited we
1498 // won't run into that cycle again.
1499 } else {
1500 // We're not the "start" of the cycle, so we just append
1501 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001502 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001503 }
1504 }
1505 }
Colin Cross691a60d2015-01-07 18:08:56 -08001506
Colin Cross7addea32015-03-11 15:43:52 -07001507 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001508 }
1509
Colin Cross7addea32015-03-11 15:43:52 -07001510 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001511
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001512 return nil
1513 }
1514
Colin Cross7addea32015-03-11 15:43:52 -07001515 for _, module := range c.moduleInfo {
1516 if !visited[module] {
1517 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001518 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001519 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001520 panic("inconceivable!")
1521 }
1522 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001523 }
1524 }
1525 }
1526
Colin Cross7addea32015-03-11 15:43:52 -07001527 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001528
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001529 return
1530}
1531
Jamie Gennisd4e10182014-06-12 20:06:50 -07001532// PrepareBuildActions generates an internal representation of all the build
1533// actions that need to be performed. This process involves invoking the
1534// GenerateBuildActions method on each of the Module objects created during the
1535// parse phase and then on each of the registered Singleton objects.
1536//
1537// If the ResolveDependencies method has not already been called it is called
1538// automatically by this method.
1539//
1540// The config argument is made available to all of the Module and Singleton
1541// objects via the Config method on the ModuleContext and SingletonContext
1542// objects passed to GenerateBuildActions. It is also passed to the functions
1543// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1544// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001545//
1546// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001547// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1548// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1549// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001550func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001551 c.buildActionsReady = false
1552
1553 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001554 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001555 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001556 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001557 }
1558 }
1559
1560 liveGlobals := newLiveTracker(config)
1561
1562 c.initSpecialVariables()
1563
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001564 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001565 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001566 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001567 }
1568
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001569 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001570 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001571 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001572 }
1573
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001574 deps = append(depsModules, depsSingletons...)
1575
Colin Crossa2599452015-11-18 16:01:01 -08001576 if c.ninjaBuildDir != nil {
1577 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001578 }
1579
Dan Willemsena481ae22015-12-18 15:18:03 -08001580 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1581
1582 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001583
1584 // This will panic if it finds a problem since it's a programming error.
1585 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1586
1587 c.pkgNames = pkgNames
1588 c.globalVariables = liveGlobals.variables
1589 c.globalPools = liveGlobals.pools
1590 c.globalRules = liveGlobals.rules
1591
1592 c.buildActionsReady = true
1593
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001594 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001595}
1596
Colin Crossc9028482014-12-18 16:28:54 -08001597func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001598 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001599
Colin Crossf8b50422016-08-10 12:56:40 -07001600 mutators = append(mutators, c.earlyMutatorInfo...)
1601 mutators = append(mutators, c.mutatorInfo...)
1602
1603 for _, mutator := range mutators {
Colin Crossc9028482014-12-18 16:28:54 -08001604 if mutator.topDownMutator != nil {
Colin Cross49c279a2016-08-05 22:30:44 -07001605 errs = c.runTopDownMutator(config, mutator)
Colin Crossc9028482014-12-18 16:28:54 -08001606 } else if mutator.bottomUpMutator != nil {
Colin Cross49c279a2016-08-05 22:30:44 -07001607 errs = c.runBottomUpMutator(config, mutator)
Colin Crossc9028482014-12-18 16:28:54 -08001608 } else {
1609 panic("no mutator set on " + mutator.name)
1610 }
1611 if len(errs) > 0 {
1612 return errs
1613 }
1614 }
1615
1616 return nil
1617}
1618
Colin Cross49c279a2016-08-05 22:30:44 -07001619func (c *Context) runTopDownMutator(config interface{}, mutator *mutatorInfo) (errs []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001620
Colin Cross7addea32015-03-11 15:43:52 -07001621 for i := 0; i < len(c.modulesSorted); i++ {
1622 module := c.modulesSorted[len(c.modulesSorted)-1-i]
1623 mctx := &mutatorContext{
1624 baseModuleContext: baseModuleContext{
1625 context: c,
1626 config: config,
1627 module: module,
1628 },
Colin Cross49c279a2016-08-05 22:30:44 -07001629 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001630 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001631 func() {
1632 defer func() {
1633 if r := recover(); r != nil {
Colin Cross49c279a2016-08-05 22:30:44 -07001634 in := fmt.Sprintf("top down mutator %q for %s", mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001635 if err, ok := r.(panicError); ok {
1636 err.addIn(in)
1637 mctx.error(err)
1638 } else {
1639 mctx.error(newPanicErrorf(r, in))
1640 }
1641 }
1642 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001643 mutator.topDownMutator(mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001644 }()
Colin Crossc9028482014-12-18 16:28:54 -08001645
Colin Cross7addea32015-03-11 15:43:52 -07001646 if len(mctx.errs) > 0 {
1647 errs = append(errs, mctx.errs...)
1648 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001649 }
1650 }
1651
1652 return errs
1653}
1654
Colin Cross49c279a2016-08-05 22:30:44 -07001655type reverseDep struct {
1656 module *moduleInfo
1657 dep depInfo
1658}
1659
Colin Crossc9028482014-12-18 16:28:54 -08001660func (c *Context) runBottomUpMutator(config interface{},
Colin Cross49c279a2016-08-05 22:30:44 -07001661 mutator *mutatorInfo) (errs []error) {
1662
1663 newModuleInfo := make(map[Module]*moduleInfo)
1664 for k, v := range c.moduleInfo {
1665 newModuleInfo[k] = v
1666 }
Colin Crossc9028482014-12-18 16:28:54 -08001667
Colin Cross2c1f3d12016-04-11 15:47:28 -07001668 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross8d8a7af2015-11-03 16:41:29 -08001669
Colin Cross49c279a2016-08-05 22:30:44 -07001670 errsCh := make(chan []error)
1671 reverseDepsCh := make(chan []reverseDep)
1672 newModulesCh := make(chan []*moduleInfo)
1673 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001674
Colin Cross49c279a2016-08-05 22:30:44 -07001675 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001676 if module.splitModules != nil {
1677 panic("split module found in sorted module list")
1678 }
1679
Colin Cross7addea32015-03-11 15:43:52 -07001680 mctx := &mutatorContext{
1681 baseModuleContext: baseModuleContext{
1682 context: c,
1683 config: config,
1684 module: module,
1685 },
Colin Cross49c279a2016-08-05 22:30:44 -07001686 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001687 }
Colin Crossc9028482014-12-18 16:28:54 -08001688
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001689 func() {
1690 defer func() {
1691 if r := recover(); r != nil {
Colin Cross49c279a2016-08-05 22:30:44 -07001692 in := fmt.Sprintf("bottom up mutator %q for %s", mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001693 if err, ok := r.(panicError); ok {
1694 err.addIn(in)
1695 mctx.error(err)
1696 } else {
1697 mctx.error(newPanicErrorf(r, in))
1698 }
1699 }
1700 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001701 mutator.bottomUpMutator(mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001702 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001703
Colin Cross7addea32015-03-11 15:43:52 -07001704 if len(mctx.errs) > 0 {
Colin Cross49c279a2016-08-05 22:30:44 -07001705 errsCh <- errs
1706 return true
Colin Cross7addea32015-03-11 15:43:52 -07001707 }
Colin Crossc9028482014-12-18 16:28:54 -08001708
Colin Cross49c279a2016-08-05 22:30:44 -07001709 if len(mctx.newModules) > 0 {
1710 newModulesCh <- mctx.newModules
1711 }
1712
1713 if len(mctx.reverseDeps) > 0 {
1714 reverseDepsCh <- mctx.reverseDeps
1715 }
1716
1717 return false
1718 }
1719
1720 // Process errs and reverseDeps in a single goroutine
1721 go func() {
1722 for {
1723 select {
1724 case newErrs := <-errsCh:
1725 errs = append(errs, newErrs...)
1726 case newReverseDeps := <-reverseDepsCh:
1727 for _, r := range newReverseDeps {
1728 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
1729 }
1730 case newModules := <-newModulesCh:
1731 for _, m := range newModules {
1732 newModuleInfo[m.logicModule] = m
1733 }
1734 case <-done:
1735 return
Colin Crossc9028482014-12-18 16:28:54 -08001736 }
1737 }
Colin Cross49c279a2016-08-05 22:30:44 -07001738 }()
Colin Crossc9028482014-12-18 16:28:54 -08001739
Colin Cross49c279a2016-08-05 22:30:44 -07001740 if mutator.parallel {
1741 c.parallelVisitAllBottomUp(visit)
1742 } else {
1743 c.visitAllBottomUp(visit)
1744 }
1745
1746 done <- true
1747
1748 if len(errs) > 0 {
1749 return errs
1750 }
1751
1752 c.moduleInfo = newModuleInfo
1753
1754 for _, group := range c.moduleGroups {
1755 for i := 0; i < len(group.modules); i++ {
1756 module := group.modules[i]
1757
1758 // Update module group to contain newly split variants
1759 if module.splitModules != nil {
1760 group.modules, i = spliceModules(group.modules, i, module.splitModules)
1761 }
1762
1763 // Fix up any remaining dependencies on modules that were split into variants
1764 // by replacing them with the first variant
1765 for j, dep := range module.directDeps {
1766 if dep.module.logicModule == nil {
1767 module.directDeps[j].module = dep.module.splitModules[0]
1768 }
1769 }
Colin Cross7addea32015-03-11 15:43:52 -07001770 }
Colin Crossc9028482014-12-18 16:28:54 -08001771 }
1772
Colin Cross8d8a7af2015-11-03 16:41:29 -08001773 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001774 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001775 module.directDeps = append(module.directDeps, deps...)
1776 }
1777
Colin Cross49c279a2016-08-05 22:30:44 -07001778 // TODO(ccross): update can be elided if no dependencies were modified
Jamie Gennisc7988252015-04-14 23:28:10 -04001779 errs = c.updateDependencies()
1780 if len(errs) > 0 {
1781 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001782 }
1783
1784 return errs
1785}
1786
Colin Cross910242b2016-04-11 15:41:52 -07001787// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1788// a mutator sets a non-property member variable on a module, which works until a later mutator
1789// creates variants of that module.
1790func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07001791 type update struct {
1792 orig Module
1793 clone *moduleInfo
1794 }
1795 ch := make(chan update, 100)
1796
Colin Cross910242b2016-04-11 15:41:52 -07001797 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07001798 go func(m *moduleInfo) {
1799 origLogicModule := m.logicModule
1800 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1801 ch <- update{origLogicModule, m}
1802 }(m)
1803 }
1804
1805 for i := 0; i < len(c.modulesSorted); i++ {
1806 update := <-ch
1807 delete(c.moduleInfo, update.orig)
1808 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07001809 }
1810}
1811
Colin Cross49c279a2016-08-05 22:30:44 -07001812// Removes modules[i] from the list and inserts newModules... where it was located, returning
1813// the new slice and the index of the last inserted element
1814func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07001815 spliceSize := len(newModules)
1816 newLen := len(modules) + spliceSize - 1
1817 var dest []*moduleInfo
1818 if cap(modules) >= len(modules)-1+len(newModules) {
1819 // We can fit the splice in the existing capacity, do everything in place
1820 dest = modules[:newLen]
1821 } else {
1822 dest = make([]*moduleInfo, newLen)
1823 copy(dest, modules[:i])
1824 }
1825
1826 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001827 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001828
1829 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001830 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001831
Colin Cross49c279a2016-08-05 22:30:44 -07001832 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07001833}
1834
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001835func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001836 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001837 c.requiredNinjaMajor = 1
Dan Willemsen21b6f372015-07-22 12:58:01 -07001838 c.requiredNinjaMinor = 6
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001839 c.requiredNinjaMicro = 0
1840}
1841
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001842func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001843 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001845 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001846 var errs []error
1847
Colin Cross691a60d2015-01-07 18:08:56 -08001848 cancelCh := make(chan struct{})
1849 errsCh := make(chan []error)
1850 depsCh := make(chan []string)
1851
1852 go func() {
1853 for {
1854 select {
1855 case <-cancelCh:
1856 close(cancelCh)
1857 return
1858 case newErrs := <-errsCh:
1859 errs = append(errs, newErrs...)
1860 case newDeps := <-depsCh:
1861 deps = append(deps, newDeps...)
1862
1863 }
1864 }
1865 }()
1866
Colin Cross7addea32015-03-11 15:43:52 -07001867 c.parallelVisitAllBottomUp(func(module *moduleInfo) bool {
1868 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1869 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1870 // just set it to nil.
1871 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1872 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001873
Colin Cross7addea32015-03-11 15:43:52 -07001874 mctx := &moduleContext{
1875 baseModuleContext: baseModuleContext{
1876 context: c,
1877 config: config,
1878 module: module,
1879 },
Colin Cross036a1df2015-12-17 15:49:30 -08001880 scope: scope,
1881 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001882 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001883
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001884 func() {
1885 defer func() {
1886 if r := recover(); r != nil {
1887 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1888 if err, ok := r.(panicError); ok {
1889 err.addIn(in)
1890 mctx.error(err)
1891 } else {
1892 mctx.error(newPanicErrorf(r, in))
1893 }
1894 }
1895 }()
1896 mctx.module.logicModule.GenerateBuildActions(mctx)
1897 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001898
Colin Cross7addea32015-03-11 15:43:52 -07001899 if len(mctx.errs) > 0 {
1900 errsCh <- mctx.errs
1901 return true
1902 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001903
Colin Cross036a1df2015-12-17 15:49:30 -08001904 if module.missingDeps != nil && !mctx.handledMissingDeps {
1905 var errs []error
1906 for _, depName := range module.missingDeps {
1907 errs = append(errs, &Error{
1908 Err: fmt.Errorf("%q depends on undefined module %q",
1909 module.properties.Name, depName),
1910 Pos: module.pos,
1911 })
1912 }
1913 errsCh <- errs
1914 return true
1915 }
1916
Colin Cross7addea32015-03-11 15:43:52 -07001917 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001918
Colin Crossab6d7902015-03-11 16:17:52 -07001919 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07001920 &mctx.actionDefs, liveGlobals)
1921 if len(newErrs) > 0 {
1922 errsCh <- newErrs
1923 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001924 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001925 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001926 })
1927
1928 cancelCh <- struct{}{}
1929 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001931 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001932}
1933
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001934func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001935 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001936
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001937 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001938 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001939
Yuchen Wub9103ef2015-08-25 17:58:17 -07001940 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001941 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1942 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1943 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07001944 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001945
1946 sctx := &singletonContext{
1947 context: c,
1948 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001949 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08001950 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001951 }
1952
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001953 func() {
1954 defer func() {
1955 if r := recover(); r != nil {
1956 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
1957 if err, ok := r.(panicError); ok {
1958 err.addIn(in)
1959 sctx.error(err)
1960 } else {
1961 sctx.error(newPanicErrorf(r, in))
1962 }
1963 }
1964 }()
1965 info.singleton.GenerateBuildActions(sctx)
1966 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001967
1968 if len(sctx.errs) > 0 {
1969 errs = append(errs, sctx.errs...)
1970 if len(errs) > maxErrors {
1971 break
1972 }
1973 continue
1974 }
1975
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001976 deps = append(deps, sctx.ninjaFileDeps...)
1977
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001978 newErrs := c.processLocalBuildActions(&info.actionDefs,
1979 &sctx.actionDefs, liveGlobals)
1980 errs = append(errs, newErrs...)
1981 if len(errs) > maxErrors {
1982 break
1983 }
1984 }
1985
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001986 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001987}
1988
1989func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1990 liveGlobals *liveTracker) []error {
1991
1992 var errs []error
1993
1994 // First we go through and add everything referenced by the module's
1995 // buildDefs to the live globals set. This will end up adding the live
1996 // locals to the set as well, but we'll take them out after.
1997 for _, def := range in.buildDefs {
1998 err := liveGlobals.AddBuildDefDeps(def)
1999 if err != nil {
2000 errs = append(errs, err)
2001 }
2002 }
2003
2004 if len(errs) > 0 {
2005 return errs
2006 }
2007
Colin Crossc9028482014-12-18 16:28:54 -08002008 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002009
2010 // We use the now-incorrect set of live "globals" to determine which local
2011 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002012 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002013 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002014 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002015 if isLive {
2016 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002017 }
2018 }
2019
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002020 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002021 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002022 if isLive {
2023 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002024 }
2025 }
2026
2027 return nil
2028}
2029
Yuchen Wu222e2452015-10-06 14:03:27 -07002030func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002031 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002032
2033 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002034 var visiting *moduleInfo
2035
2036 defer func() {
2037 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002038 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2039 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002040 }
2041 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002042
2043 var walk func(module *moduleInfo)
2044 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002045 for _, dep := range module.directDeps {
2046 if !visited[dep.module] {
2047 visited[dep.module] = true
2048 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002049 recurse := true
2050 if visitDown != nil {
2051 recurse = visitDown(dep, module)
2052 }
2053 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002054 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002055 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002056 if visitUp != nil {
2057 visitUp(dep, module)
2058 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002059 }
2060 }
2061 }
2062
2063 walk(topModule)
2064}
2065
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002066type innerPanicError error
2067
Jamie Gennisc15544d2014-09-24 20:26:52 -07002068func (c *Context) sortedModuleNames() []string {
2069 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002070 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
2071 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002072 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2073 moduleName)
2074 }
2075 sort.Strings(c.cachedSortedModuleNames)
2076 }
2077
2078 return c.cachedSortedModuleNames
2079}
2080
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002081func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002082 var module *moduleInfo
2083
2084 defer func() {
2085 if r := recover(); r != nil {
2086 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2087 funcName(visit), module))
2088 }
2089 }()
2090
Jamie Gennisc15544d2014-09-24 20:26:52 -07002091 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002092 group := c.moduleGroups[moduleName]
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002093 for _, module = range group.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002094 visit(module.logicModule)
2095 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002096 }
2097}
2098
2099func (c *Context) visitAllModulesIf(pred func(Module) bool,
2100 visit func(Module)) {
2101
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002102 var module *moduleInfo
2103
2104 defer func() {
2105 if r := recover(); r != nil {
2106 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2107 funcName(pred), funcName(visit), module))
2108 }
2109 }()
2110
Jamie Gennisc15544d2014-09-24 20:26:52 -07002111 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002112 group := c.moduleGroups[moduleName]
2113 for _, module := range group.modules {
2114 if pred(module.logicModule) {
2115 visit(module.logicModule)
2116 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002117 }
2118 }
2119}
2120
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002121func (c *Context) visitAllModuleVariants(module *moduleInfo,
2122 visit func(Module)) {
2123
2124 var variant *moduleInfo
2125
2126 defer func() {
2127 if r := recover(); r != nil {
2128 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2129 module, funcName(visit), variant))
2130 }
2131 }()
2132
2133 for _, variant = range module.group.modules {
2134 visit(variant.logicModule)
2135 }
2136}
2137
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002138func (c *Context) requireNinjaVersion(major, minor, micro int) {
2139 if major != 1 {
2140 panic("ninja version with major version != 1 not supported")
2141 }
2142 if c.requiredNinjaMinor < minor {
2143 c.requiredNinjaMinor = minor
2144 c.requiredNinjaMicro = micro
2145 }
2146 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2147 c.requiredNinjaMicro = micro
2148 }
2149}
2150
Colin Crossa2599452015-11-18 16:01:01 -08002151func (c *Context) setNinjaBuildDir(value *ninjaString) {
2152 if c.ninjaBuildDir == nil {
2153 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002154 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002155}
2156
2157func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002158 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002159
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002160 pkgs := make(map[string]*packageContext)
2161 pkgNames := make(map[*packageContext]string)
2162 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002163
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002164 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002165 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002166 // This is a built-in rule and has no package.
2167 return
2168 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002169 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002170 // We've already processed this package.
2171 return
2172 }
2173
Jamie Gennis2fb20952014-10-03 02:49:58 -07002174 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002175 if present {
2176 // Short name collision. Both this package and the one that's
2177 // already there need to use their full names. We leave the short
2178 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002179 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002180 longPkgNames[otherPkg] = true
2181 } else {
2182 // No collision so far. Tentatively set the package's name to be
2183 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002184 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002185 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002186 }
2187 }
2188
2189 // We try to give all packages their short name, but when we get collisions
2190 // we need to use the full unique package name.
2191 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002192 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002193 }
2194 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002195 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002196 }
2197 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002198 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002199 }
2200
2201 // Add the packages that had collisions using their full unique names. This
2202 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002203 for pctx := range longPkgNames {
2204 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002205 }
2206
Dan Willemsena481ae22015-12-18 15:18:03 -08002207 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2208 deps := []string{}
2209 for _, pkg := range pkgs {
2210 deps = append(deps, pkg.ninjaFileDeps...)
2211 }
2212
2213 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002214}
2215
2216func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002217 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218
2219 visited := make(map[Variable]bool) // variables that were already checked
2220 checking := make(map[Variable]bool) // variables actively being checked
2221
2222 var check func(v Variable) []Variable
2223
2224 check = func(v Variable) []Variable {
2225 visited[v] = true
2226 checking[v] = true
2227 defer delete(checking, v)
2228
2229 value := variables[v]
2230 for _, dep := range value.variables {
2231 if checking[dep] {
2232 // This is a cycle.
2233 return []Variable{dep, v}
2234 }
2235
2236 if !visited[dep] {
2237 cycle := check(dep)
2238 if cycle != nil {
2239 if cycle[0] == v {
2240 // We are the "start" of the cycle, so we're responsible
2241 // for generating the errors. The cycle list is in
2242 // reverse order because all the 'check' calls append
2243 // their own module to the list.
2244 msgs := []string{"detected variable reference cycle:"}
2245
2246 // Iterate backwards through the cycle list.
2247 curName := v.fullName(pkgNames)
2248 curValue := value.Value(pkgNames)
2249 for i := len(cycle) - 1; i >= 0; i-- {
2250 next := cycle[i]
2251 nextName := next.fullName(pkgNames)
2252 nextValue := variables[next].Value(pkgNames)
2253
2254 msgs = append(msgs, fmt.Sprintf(
2255 " %q depends on %q", curName, nextName))
2256 msgs = append(msgs, fmt.Sprintf(
2257 " [%s = %s]", curName, curValue))
2258
2259 curName = nextName
2260 curValue = nextValue
2261 }
2262
2263 // Variable reference cycles are a programming error,
2264 // not the fault of the Blueprint file authors.
2265 panic(strings.Join(msgs, "\n"))
2266 } else {
2267 // We're not the "start" of the cycle, so we just append
2268 // our module to the list and return it.
2269 return append(cycle, v)
2270 }
2271 }
2272 }
2273 }
2274
2275 return nil
2276 }
2277
2278 for v := range variables {
2279 if !visited[v] {
2280 cycle := check(v)
2281 if cycle != nil {
2282 panic("inconceivable!")
2283 }
2284 }
2285 }
2286}
2287
Jamie Gennisaf435562014-10-27 22:34:56 -07002288// AllTargets returns a map all the build target names to the rule used to build
2289// them. This is the same information that is output by running 'ninja -t
2290// targets all'. If this is called before PrepareBuildActions successfully
2291// completes then ErrbuildActionsNotReady is returned.
2292func (c *Context) AllTargets() (map[string]string, error) {
2293 if !c.buildActionsReady {
2294 return nil, ErrBuildActionsNotReady
2295 }
2296
2297 targets := map[string]string{}
2298
2299 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002300 for _, module := range c.moduleInfo {
2301 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002302 ruleName := buildDef.Rule.fullName(c.pkgNames)
2303 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002304 outputValue, err := output.Eval(c.globalVariables)
2305 if err != nil {
2306 return nil, err
2307 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002308 targets[outputValue] = ruleName
2309 }
2310 }
2311 }
2312
2313 // Collect all the singleton build targets.
2314 for _, info := range c.singletonInfo {
2315 for _, buildDef := range info.actionDefs.buildDefs {
2316 ruleName := buildDef.Rule.fullName(c.pkgNames)
2317 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08002318 outputValue, err := output.Eval(c.globalVariables)
2319 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002320 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002321 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002322 targets[outputValue] = ruleName
2323 }
2324 }
2325 }
2326
2327 return targets, nil
2328}
2329
Colin Crossa2599452015-11-18 16:01:01 -08002330func (c *Context) NinjaBuildDir() (string, error) {
2331 if c.ninjaBuildDir != nil {
2332 return c.ninjaBuildDir.Eval(c.globalVariables)
2333 } else {
2334 return "", nil
2335 }
2336}
2337
Colin Cross4572edd2015-05-13 14:36:24 -07002338// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2339// property structs returned by the factory for that module type.
2340func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2341 ret := make(map[string][]interface{})
2342 for moduleType, factory := range c.moduleFactories {
2343 _, ret[moduleType] = factory()
2344 }
2345
2346 return ret
2347}
2348
2349func (c *Context) ModuleName(logicModule Module) string {
2350 module := c.moduleInfo[logicModule]
2351 return module.properties.Name
2352}
2353
2354func (c *Context) ModuleDir(logicModule Module) string {
2355 module := c.moduleInfo[logicModule]
2356 return filepath.Dir(module.relBlueprintsFile)
2357}
2358
Colin Cross8c602f72015-12-17 18:02:11 -08002359func (c *Context) ModuleSubDir(logicModule Module) string {
2360 module := c.moduleInfo[logicModule]
2361 return module.variantName
2362}
2363
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002364func (c *Context) ModuleType(logicModule Module) string {
2365 module := c.moduleInfo[logicModule]
2366 return module.typeName
2367}
2368
Colin Cross4572edd2015-05-13 14:36:24 -07002369func (c *Context) BlueprintFile(logicModule Module) string {
2370 module := c.moduleInfo[logicModule]
2371 return module.relBlueprintsFile
2372}
2373
2374func (c *Context) ModuleErrorf(logicModule Module, format string,
2375 args ...interface{}) error {
2376
2377 module := c.moduleInfo[logicModule]
2378 return &Error{
2379 Err: fmt.Errorf(format, args...),
2380 Pos: module.pos,
2381 }
2382}
2383
2384func (c *Context) VisitAllModules(visit func(Module)) {
2385 c.visitAllModules(visit)
2386}
2387
2388func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2389 visit func(Module)) {
2390
2391 c.visitAllModulesIf(pred, visit)
2392}
2393
2394func (c *Context) VisitDepsDepthFirst(module Module,
2395 visit func(Module)) {
2396
Colin Crossbafd5f52016-08-06 22:52:01 -07002397 topModule := c.moduleInfo[module]
2398
2399 var visiting *moduleInfo
2400
2401 defer func() {
2402 if r := recover(); r != nil {
2403 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2404 topModule, funcName(visit), visiting))
2405 }
2406 }()
2407
2408 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2409 visiting = dep.module
2410 visit(dep.module.logicModule)
2411 })
Colin Cross4572edd2015-05-13 14:36:24 -07002412}
2413
2414func (c *Context) VisitDepsDepthFirstIf(module Module,
2415 pred func(Module) bool, visit func(Module)) {
2416
Colin Crossbafd5f52016-08-06 22:52:01 -07002417 topModule := c.moduleInfo[module]
2418
2419 var visiting *moduleInfo
2420
2421 defer func() {
2422 if r := recover(); r != nil {
2423 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2424 topModule, funcName(pred), funcName(visit), visiting))
2425 }
2426 }()
2427
2428 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2429 if pred(dep.module.logicModule) {
2430 visiting = dep.module
2431 visit(dep.module.logicModule)
2432 }
2433 })
Colin Cross4572edd2015-05-13 14:36:24 -07002434}
2435
Colin Cross24ad5872015-11-17 16:22:29 -08002436func (c *Context) PrimaryModule(module Module) Module {
2437 return c.moduleInfo[module].group.modules[0].logicModule
2438}
2439
2440func (c *Context) FinalModule(module Module) Module {
2441 modules := c.moduleInfo[module].group.modules
2442 return modules[len(modules)-1].logicModule
2443}
2444
2445func (c *Context) VisitAllModuleVariants(module Module,
2446 visit func(Module)) {
2447
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002448 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002449}
2450
Jamie Gennisd4e10182014-06-12 20:06:50 -07002451// WriteBuildFile writes the Ninja manifeset text for the generated build
2452// actions to w. If this is called before PrepareBuildActions successfully
2453// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002454func (c *Context) WriteBuildFile(w io.Writer) error {
2455 if !c.buildActionsReady {
2456 return ErrBuildActionsNotReady
2457 }
2458
2459 nw := newNinjaWriter(w)
2460
2461 err := c.writeBuildFileHeader(nw)
2462 if err != nil {
2463 return err
2464 }
2465
2466 err = c.writeNinjaRequiredVersion(nw)
2467 if err != nil {
2468 return err
2469 }
2470
2471 // TODO: Group the globals by package.
2472
2473 err = c.writeGlobalVariables(nw)
2474 if err != nil {
2475 return err
2476 }
2477
2478 err = c.writeGlobalPools(nw)
2479 if err != nil {
2480 return err
2481 }
2482
2483 err = c.writeBuildDir(nw)
2484 if err != nil {
2485 return err
2486 }
2487
2488 err = c.writeGlobalRules(nw)
2489 if err != nil {
2490 return err
2491 }
2492
2493 err = c.writeAllModuleActions(nw)
2494 if err != nil {
2495 return err
2496 }
2497
2498 err = c.writeAllSingletonActions(nw)
2499 if err != nil {
2500 return err
2501 }
2502
2503 return nil
2504}
2505
Jamie Gennisc15544d2014-09-24 20:26:52 -07002506type pkgAssociation struct {
2507 PkgName string
2508 PkgPath string
2509}
2510
2511type pkgAssociationSorter struct {
2512 pkgs []pkgAssociation
2513}
2514
2515func (s *pkgAssociationSorter) Len() int {
2516 return len(s.pkgs)
2517}
2518
2519func (s *pkgAssociationSorter) Less(i, j int) bool {
2520 iName := s.pkgs[i].PkgName
2521 jName := s.pkgs[j].PkgName
2522 return iName < jName
2523}
2524
2525func (s *pkgAssociationSorter) Swap(i, j int) {
2526 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2527}
2528
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002529func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2530 headerTemplate := template.New("fileHeader")
2531 _, err := headerTemplate.Parse(fileHeaderTemplate)
2532 if err != nil {
2533 // This is a programming error.
2534 panic(err)
2535 }
2536
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002537 var pkgs []pkgAssociation
2538 maxNameLen := 0
2539 for pkg, name := range c.pkgNames {
2540 pkgs = append(pkgs, pkgAssociation{
2541 PkgName: name,
2542 PkgPath: pkg.pkgPath,
2543 })
2544 if len(name) > maxNameLen {
2545 maxNameLen = len(name)
2546 }
2547 }
2548
2549 for i := range pkgs {
2550 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2551 }
2552
Jamie Gennisc15544d2014-09-24 20:26:52 -07002553 sort.Sort(&pkgAssociationSorter{pkgs})
2554
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002555 params := map[string]interface{}{
2556 "Pkgs": pkgs,
2557 }
2558
2559 buf := bytes.NewBuffer(nil)
2560 err = headerTemplate.Execute(buf, params)
2561 if err != nil {
2562 return err
2563 }
2564
2565 return nw.Comment(buf.String())
2566}
2567
2568func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2569 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2570 c.requiredNinjaMicro)
2571
2572 err := nw.Assign("ninja_required_version", value)
2573 if err != nil {
2574 return err
2575 }
2576
2577 return nw.BlankLine()
2578}
2579
2580func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002581 if c.ninjaBuildDir != nil {
2582 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002583 if err != nil {
2584 return err
2585 }
2586
2587 err = nw.BlankLine()
2588 if err != nil {
2589 return err
2590 }
2591 }
2592 return nil
2593}
2594
Jamie Gennisc15544d2014-09-24 20:26:52 -07002595type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002596 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002597}
2598
Jamie Gennisc15544d2014-09-24 20:26:52 -07002599type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002600 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002601 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002602}
2603
Jamie Gennisc15544d2014-09-24 20:26:52 -07002604func (s *globalEntitySorter) Len() int {
2605 return len(s.entities)
2606}
2607
2608func (s *globalEntitySorter) Less(i, j int) bool {
2609 iName := s.entities[i].fullName(s.pkgNames)
2610 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002611 return iName < jName
2612}
2613
Jamie Gennisc15544d2014-09-24 20:26:52 -07002614func (s *globalEntitySorter) Swap(i, j int) {
2615 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002616}
2617
2618func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2619 visited := make(map[Variable]bool)
2620
2621 var walk func(v Variable) error
2622 walk = func(v Variable) error {
2623 visited[v] = true
2624
2625 // First visit variables on which this variable depends.
2626 value := c.globalVariables[v]
2627 for _, dep := range value.variables {
2628 if !visited[dep] {
2629 err := walk(dep)
2630 if err != nil {
2631 return err
2632 }
2633 }
2634 }
2635
2636 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2637 if err != nil {
2638 return err
2639 }
2640
2641 err = nw.BlankLine()
2642 if err != nil {
2643 return err
2644 }
2645
2646 return nil
2647 }
2648
Jamie Gennisc15544d2014-09-24 20:26:52 -07002649 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2650 for variable := range c.globalVariables {
2651 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002652 }
2653
Jamie Gennisc15544d2014-09-24 20:26:52 -07002654 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002655
Jamie Gennisc15544d2014-09-24 20:26:52 -07002656 for _, entity := range globalVariables {
2657 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002658 if !visited[v] {
2659 err := walk(v)
2660 if err != nil {
2661 return nil
2662 }
2663 }
2664 }
2665
2666 return nil
2667}
2668
2669func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002670 globalPools := make([]globalEntity, 0, len(c.globalPools))
2671 for pool := range c.globalPools {
2672 globalPools = append(globalPools, pool)
2673 }
2674
2675 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2676
2677 for _, entity := range globalPools {
2678 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002679 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002680 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002681 err := def.WriteTo(nw, name)
2682 if err != nil {
2683 return err
2684 }
2685
2686 err = nw.BlankLine()
2687 if err != nil {
2688 return err
2689 }
2690 }
2691
2692 return nil
2693}
2694
2695func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002696 globalRules := make([]globalEntity, 0, len(c.globalRules))
2697 for rule := range c.globalRules {
2698 globalRules = append(globalRules, rule)
2699 }
2700
2701 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2702
2703 for _, entity := range globalRules {
2704 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002705 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002706 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002707 err := def.WriteTo(nw, name, c.pkgNames)
2708 if err != nil {
2709 return err
2710 }
2711
2712 err = nw.BlankLine()
2713 if err != nil {
2714 return err
2715 }
2716 }
2717
2718 return nil
2719}
2720
Colin Cross2c1f3d12016-04-11 15:47:28 -07002721type depSorter []depInfo
2722
2723func (s depSorter) Len() int {
2724 return len(s)
2725}
2726
2727func (s depSorter) Less(i, j int) bool {
2728 iName := s[i].module.properties.Name
2729 jName := s[j].module.properties.Name
2730 if iName == jName {
2731 iName = s[i].module.variantName
2732 jName = s[j].module.variantName
2733 }
2734 return iName < jName
2735}
2736
2737func (s depSorter) Swap(i, j int) {
2738 s[i], s[j] = s[j], s[i]
2739}
2740
Colin Crossab6d7902015-03-11 16:17:52 -07002741type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002742
Colin Crossab6d7902015-03-11 16:17:52 -07002743func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002744 return len(s)
2745}
2746
Colin Crossab6d7902015-03-11 16:17:52 -07002747func (s moduleSorter) Less(i, j int) bool {
2748 iName := s[i].properties.Name
2749 jName := s[j].properties.Name
2750 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002751 iName = s[i].variantName
2752 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002753 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002754 return iName < jName
2755}
2756
Colin Crossab6d7902015-03-11 16:17:52 -07002757func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002758 s[i], s[j] = s[j], s[i]
2759}
2760
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002761func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2762 headerTemplate := template.New("moduleHeader")
2763 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2764 if err != nil {
2765 // This is a programming error.
2766 panic(err)
2767 }
2768
Colin Crossab6d7902015-03-11 16:17:52 -07002769 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2770 for _, module := range c.moduleInfo {
2771 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002772 }
Colin Crossab6d7902015-03-11 16:17:52 -07002773 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002774
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002775 buf := bytes.NewBuffer(nil)
2776
Colin Crossab6d7902015-03-11 16:17:52 -07002777 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002778 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2779 continue
2780 }
2781
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002782 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002783
2784 // In order to make the bootstrap build manifest independent of the
2785 // build dir we need to output the Blueprints file locations in the
2786 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002787 relPos := module.pos
2788 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002789
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002790 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002791 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002792 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2793 factoryName := factoryFunc.Name()
2794
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002795 infoMap := map[string]interface{}{
Colin Crossab6d7902015-03-11 16:17:52 -07002796 "properties": module.properties,
2797 "typeName": module.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002798 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002799 "pos": relPos,
Colin Cross65569e42015-03-10 20:08:19 -07002800 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002801 }
2802 err = headerTemplate.Execute(buf, infoMap)
2803 if err != nil {
2804 return err
2805 }
2806
2807 err = nw.Comment(buf.String())
2808 if err != nil {
2809 return err
2810 }
2811
2812 err = nw.BlankLine()
2813 if err != nil {
2814 return err
2815 }
2816
Colin Crossab6d7902015-03-11 16:17:52 -07002817 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002818 if err != nil {
2819 return err
2820 }
2821
2822 err = nw.BlankLine()
2823 if err != nil {
2824 return err
2825 }
2826 }
2827
2828 return nil
2829}
2830
2831func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2832 headerTemplate := template.New("singletonHeader")
2833 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2834 if err != nil {
2835 // This is a programming error.
2836 panic(err)
2837 }
2838
2839 buf := bytes.NewBuffer(nil)
2840
Yuchen Wub9103ef2015-08-25 17:58:17 -07002841 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002842 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
2843 continue
2844 }
2845
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002846 // Get the name of the factory function for the module.
2847 factory := info.factory
2848 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2849 factoryName := factoryFunc.Name()
2850
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002851 buf.Reset()
2852 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07002853 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002854 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002855 }
2856 err = headerTemplate.Execute(buf, infoMap)
2857 if err != nil {
2858 return err
2859 }
2860
2861 err = nw.Comment(buf.String())
2862 if err != nil {
2863 return err
2864 }
2865
2866 err = nw.BlankLine()
2867 if err != nil {
2868 return err
2869 }
2870
2871 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2872 if err != nil {
2873 return err
2874 }
2875
2876 err = nw.BlankLine()
2877 if err != nil {
2878 return err
2879 }
2880 }
2881
2882 return nil
2883}
2884
2885func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2886 defs *localBuildActions) error {
2887
2888 // Write the local variable assignments.
2889 for _, v := range defs.variables {
2890 // A localVariable doesn't need the package names or config to
2891 // determine its name or value.
2892 name := v.fullName(nil)
2893 value, err := v.value(nil)
2894 if err != nil {
2895 panic(err)
2896 }
2897 err = nw.Assign(name, value.Value(c.pkgNames))
2898 if err != nil {
2899 return err
2900 }
2901 }
2902
2903 if len(defs.variables) > 0 {
2904 err := nw.BlankLine()
2905 if err != nil {
2906 return err
2907 }
2908 }
2909
2910 // Write the local rules.
2911 for _, r := range defs.rules {
2912 // A localRule doesn't need the package names or config to determine
2913 // its name or definition.
2914 name := r.fullName(nil)
2915 def, err := r.def(nil)
2916 if err != nil {
2917 panic(err)
2918 }
2919
2920 err = def.WriteTo(nw, name, c.pkgNames)
2921 if err != nil {
2922 return err
2923 }
2924
2925 err = nw.BlankLine()
2926 if err != nil {
2927 return err
2928 }
2929 }
2930
2931 // Write the build definitions.
2932 for _, buildDef := range defs.buildDefs {
2933 err := buildDef.WriteTo(nw, c.pkgNames)
2934 if err != nil {
2935 return err
2936 }
2937
2938 if len(buildDef.Args) > 0 {
2939 err = nw.BlankLine()
2940 if err != nil {
2941 return err
2942 }
2943 }
2944 }
2945
2946 return nil
2947}
2948
Colin Cross65569e42015-03-10 20:08:19 -07002949func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
2950 found := false
Colin Cross045a5972015-11-03 16:58:48 -08002951 if a == b {
2952 return false
2953 }
Colin Cross65569e42015-03-10 20:08:19 -07002954 for _, l := range list {
2955 if l == a {
2956 found = true
2957 } else if l == b {
2958 return found
2959 }
2960 }
2961
2962 missing := a
2963 if found {
2964 missing = b
2965 }
2966 panic(fmt.Errorf("element %v not found in list %v", missing, list))
2967}
2968
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002969type panicError struct {
2970 panic interface{}
2971 stack []byte
2972 in string
2973}
2974
2975func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
2976 buf := make([]byte, 4096)
2977 count := runtime.Stack(buf, false)
2978 return panicError{
2979 panic: panic,
2980 in: fmt.Sprintf(in, a...),
2981 stack: buf[:count],
2982 }
2983}
2984
2985func (p panicError) Error() string {
2986 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
2987}
2988
2989func (p *panicError) addIn(in string) {
2990 p.in += " in " + in
2991}
2992
2993func funcName(f interface{}) string {
2994 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
2995}
2996
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002997var fileHeaderTemplate = `******************************************************************************
2998*** This file is generated and should not be edited ***
2999******************************************************************************
3000{{if .Pkgs}}
3001This file contains variables, rules, and pools with name prefixes indicating
3002they were generated by the following Go packages:
3003{{range .Pkgs}}
3004 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3005
3006`
3007
3008var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3009Module: {{.properties.Name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003010Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003011Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003012Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003013Defined: {{.pos}}
3014`
3015
3016var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3017Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003018Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003019`