blob: 6793ac34f5c2189d27bf6efb5770fa87aaf26294 [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 Cross127d2ea2016-11-01 11:10:51 -070028 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070029 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "text/scanner"
31 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070032
33 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080034 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070035 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070036)
37
38var ErrBuildActionsNotReady = errors.New("build actions are not ready")
39
40const maxErrors = 10
41
Jamie Gennisd4e10182014-06-12 20:06:50 -070042// A Context contains all the state needed to parse a set of Blueprints files
43// and generate a Ninja file. The process of generating a Ninja file proceeds
44// through a series of four phases. Each phase corresponds with a some methods
45// on the Context object
46//
47// Phase Methods
48// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070049// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070050//
51// 2. Parse ParseBlueprintsFiles, Parse
52//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 4. Write WriteBuildFile
56//
57// The registration phase prepares the context to process Blueprints files
58// containing various types of modules. The parse phase reads in one or more
59// Blueprints files and validates their contents against the module types that
60// have been registered. The generate phase then analyzes the parsed Blueprints
61// contents to create an internal representation for the build actions that must
62// be performed. This phase also performs validation of the module dependencies
63// and property values defined in the parsed Blueprints files. Finally, the
64// write phase generates the Ninja manifest text based on the generated build
65// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066type Context struct {
67 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070068 moduleFactories map[string]ModuleFactory
Colin Cross0b7e83e2016-05-17 14:58:05 -070069 moduleNames map[string]*moduleGroup
70 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070071 moduleInfo map[Module]*moduleInfo
72 modulesSorted []*moduleInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070073 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070074 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070075 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070076 variantMutatorNames []string
77 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070078
Colin Cross3702ac72016-08-11 11:09:00 -070079 depsModified uint32 // positive if a mutator modified the dependencies
80
Jamie Gennis1bc967e2014-05-27 16:34:41 -070081 dependenciesReady bool // set to true on a successful ResolveDependencies
82 buildActionsReady bool // set to true on a successful PrepareBuildActions
83
84 // set by SetIgnoreUnknownModuleTypes
85 ignoreUnknownModuleTypes bool
86
Colin Cross036a1df2015-12-17 15:49:30 -080087 // set by SetAllowMissingDependencies
88 allowMissingDependencies bool
89
Jamie Gennis1bc967e2014-05-27 16:34:41 -070090 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080091 pkgNames map[*packageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070092 globalVariables map[Variable]*ninjaString
93 globalPools map[Pool]*poolDef
94 globalRules map[Rule]*ruleDef
95
96 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -080097 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -070098 requiredNinjaMajor int // For the ninja_required_version variable
99 requiredNinjaMinor int // For the ninja_required_version variable
100 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700101
102 // set lazily by sortedModuleNames
103 cachedSortedModuleNames []string
Colin Crossd7b0f602016-06-02 15:30:20 -0700104
Colin Cross127d2ea2016-11-01 11:10:51 -0700105 globs map[string]GlobPath
106 globLock sync.Mutex
107
Colin Crossb519a7e2017-02-01 13:21:35 -0800108 fs pathtools.FileSystem
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109}
110
Jamie Gennisd4e10182014-06-12 20:06:50 -0700111// An Error describes a problem that was encountered that is related to a
112// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700113type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700114 Err error // the error that occurred
115 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116}
117
Colin Cross2c628442016-10-07 17:13:10 -0700118// A ModuleError describes a problem that was encountered that is related to a
119// particular module in a Blueprints file
120type ModuleError struct {
121 BlueprintError
122 module *moduleInfo
123}
124
125// A PropertyError describes a problem that was encountered that is related to a
126// particular property in a Blueprints file
127type PropertyError struct {
128 ModuleError
129 property string
130}
131
132func (e *BlueprintError) Error() string {
133 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
134}
135
136func (e *ModuleError) Error() string {
137 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
138}
139
140func (e *PropertyError) Error() string {
141 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
142}
143
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700144type localBuildActions struct {
145 variables []*localVariable
146 rules []*localRule
147 buildDefs []*buildDef
148}
149
Colin Crossbbfa51a2014-12-17 16:12:41 -0800150type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700151 name string
152 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700153
Colin Crossbbfa51a2014-12-17 16:12:41 -0800154 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700155}
156
Colin Crossbbfa51a2014-12-17 16:12:41 -0800157type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700158 // set during Parse
159 typeName string
160 relBlueprintsFile string
161 pos scanner.Position
162 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700163
Colin Crossf5e34b92015-03-13 16:02:36 -0700164 variantName string
165 variant variationMap
166 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700167
Colin Crossc9028482014-12-18 16:28:54 -0800168 logicModule Module
169 group *moduleGroup
170 moduleProperties []interface{}
171
172 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700173 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800174 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800175
Colin Cross7addea32015-03-11 15:43:52 -0700176 // set during updateDependencies
177 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700178 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700179
180 // used by parallelVisitAllBottomUp
181 waitingCount int
182
Colin Crossc9028482014-12-18 16:28:54 -0800183 // set during each runMutator
184 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700185
186 // set during PrepareBuildActions
187 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800188}
189
Colin Cross2c1f3d12016-04-11 15:47:28 -0700190type depInfo struct {
191 module *moduleInfo
192 tag DependencyTag
193}
194
Colin Cross0b7e83e2016-05-17 14:58:05 -0700195func (module *moduleInfo) Name() string {
196 return module.group.name
197}
198
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800199func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700200 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800201 if module.variantName != "" {
202 s += fmt.Sprintf(" variant %q", module.variantName)
203 }
204 return s
205}
206
Colin Crossf5e34b92015-03-13 16:02:36 -0700207// A Variation is a way that a variant of a module differs from other variants of the same module.
208// For example, two variants of the same module might have Variation{"arch","arm"} and
209// Variation{"arch","arm64"}
210type Variation struct {
211 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700212 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700213 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
214 // "shared" or "static" for link.
215 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700216}
217
Colin Crossf5e34b92015-03-13 16:02:36 -0700218// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
219type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700220
Colin Crossf5e34b92015-03-13 16:02:36 -0700221func (vm variationMap) clone() variationMap {
222 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700223 for k, v := range vm {
224 newVm[k] = v
225 }
226
227 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800228}
229
Colin Cross89486232015-05-08 11:14:54 -0700230// Compare this variationMap to another one. Returns true if the every entry in this map
231// is either the same in the other map or doesn't exist in the other map.
232func (vm variationMap) subset(other variationMap) bool {
233 for k, v1 := range vm {
234 if v2, ok := other[k]; ok && v1 != v2 {
235 return false
236 }
237 }
238 return true
239}
240
Colin Crossf5e34b92015-03-13 16:02:36 -0700241func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700242 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800243}
244
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700245type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700246 // set during RegisterSingletonType
247 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700248 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700249 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700250
251 // set during PrepareBuildActions
252 actionDefs localBuildActions
253}
254
Colin Crossc9028482014-12-18 16:28:54 -0800255type mutatorInfo struct {
256 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800257 topDownMutator TopDownMutator
258 bottomUpMutator BottomUpMutator
259 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700260 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800261}
262
Jamie Gennisd4e10182014-06-12 20:06:50 -0700263// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700264// no module or singleton factories registered, so the RegisterModuleFactory and
265// RegisterSingletonFactory methods must be called before it can do anything
266// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700267func NewContext() *Context {
Colin Cross763b6f12015-10-29 15:32:56 -0700268 ctx := &Context{
Colin Cross6134a5c2015-02-10 11:26:26 -0800269 moduleFactories: make(map[string]ModuleFactory),
Colin Cross0b7e83e2016-05-17 14:58:05 -0700270 moduleNames: make(map[string]*moduleGroup),
Colin Cross6134a5c2015-02-10 11:26:26 -0800271 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross6134a5c2015-02-10 11:26:26 -0800272 moduleNinjaNames: make(map[string]*moduleGroup),
Colin Cross127d2ea2016-11-01 11:10:51 -0700273 globs: make(map[string]GlobPath),
Colin Crossb519a7e2017-02-01 13:21:35 -0800274 fs: pathtools.OsFs,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700275 }
Colin Cross763b6f12015-10-29 15:32:56 -0700276
277 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
278
279 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700280}
281
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700282// A ModuleFactory function creates a new Module object. See the
283// Context.RegisterModuleType method for details about how a registered
284// ModuleFactory is used by a Context.
285type ModuleFactory func() (m Module, propertyStructs []interface{})
286
Jamie Gennisd4e10182014-06-12 20:06:50 -0700287// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700288// Blueprints file) with a Module factory function. When the given module type
289// name is encountered in a Blueprints file during parsing, the Module factory
290// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800291// generation for the module. If a Mutator splits a module into multiple variants,
292// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700293//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700294// The module type names given here must be unique for the context. The factory
295// function should be a named function so that its package and name can be
296// included in the generated Ninja file for debugging purposes.
297//
298// The factory function returns two values. The first is the newly created
299// Module object. The second is a slice of pointers to that Module object's
300// properties structs. Each properties struct is examined when parsing a module
301// definition of this type in a Blueprints file. Exported fields of the
302// properties structs are automatically set to the property values specified in
303// the Blueprints file. The properties struct field names determine the name of
304// the Blueprints file properties that are used - the Blueprints property name
305// matches that of the properties struct field name with the first letter
306// converted to lower-case.
307//
308// The fields of the properties struct must be either []string, a string, or
309// bool. The Context will panic if a Module gets instantiated with a properties
310// struct containing a field that is not one these supported types.
311//
312// Any properties that appear in the Blueprints files that are not built-in
313// module properties (such as "name" and "deps") and do not have a corresponding
314// field in the returned module properties struct result in an error during the
315// Context's parse phase.
316//
317// As an example, the follow code:
318//
319// type myModule struct {
320// properties struct {
321// Foo string
322// Bar []string
323// }
324// }
325//
326// func NewMyModule() (blueprint.Module, []interface{}) {
327// module := new(myModule)
328// properties := &module.properties
329// return module, []interface{}{properties}
330// }
331//
332// func main() {
333// ctx := blueprint.NewContext()
334// ctx.RegisterModuleType("my_module", NewMyModule)
335// // ...
336// }
337//
338// would support parsing a module defined in a Blueprints file as follows:
339//
340// my_module {
341// name: "myName",
342// foo: "my foo string",
343// bar: ["my", "bar", "strings"],
344// }
345//
Colin Cross7ad621c2015-01-07 16:22:45 -0800346// The factory function may be called from multiple goroutines. Any accesses
347// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700348func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
349 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700350 panic(errors.New("module type name is already registered"))
351 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700352 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700353}
354
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700355// A SingletonFactory function creates a new Singleton object. See the
356// Context.RegisterSingletonType method for details about how a registered
357// SingletonFactory is used by a Context.
358type SingletonFactory func() Singleton
359
360// RegisterSingletonType registers a singleton type that will be invoked to
361// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700362// and invoked exactly once as part of the generate phase. Each registered
363// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700364//
365// The singleton type names given here must be unique for the context. The
366// factory function should be a named function so that its package and name can
367// be included in the generated Ninja file for debugging purposes.
368func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700369 for _, s := range c.singletonInfo {
370 if s.name == name {
371 panic(errors.New("singleton name is already registered"))
372 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700373 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700374
Yuchen Wub9103ef2015-08-25 17:58:17 -0700375 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700376 factory: factory,
377 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700378 name: name,
379 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700380}
381
382func singletonPkgPath(singleton Singleton) string {
383 typ := reflect.TypeOf(singleton)
384 for typ.Kind() == reflect.Ptr {
385 typ = typ.Elem()
386 }
387 return typ.PkgPath()
388}
389
390func singletonTypeName(singleton Singleton) string {
391 typ := reflect.TypeOf(singleton)
392 for typ.Kind() == reflect.Ptr {
393 typ = typ.Elem()
394 }
395 return typ.PkgPath() + "." + typ.Name()
396}
397
Colin Cross3702ac72016-08-11 11:09:00 -0700398// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
399// top-down between Modules. Each registered mutator is invoked in registration order (mixing
400// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
401// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800402//
Colin Cross65569e42015-03-10 20:08:19 -0700403// The mutator type names given here must be unique to all top down mutators in
404// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700405//
406// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
407// parallel while maintaining ordering.
408func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800409 for _, m := range c.mutatorInfo {
410 if m.name == name && m.topDownMutator != nil {
411 panic(fmt.Errorf("mutator name %s is already registered", name))
412 }
413 }
414
Colin Cross3702ac72016-08-11 11:09:00 -0700415 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800416 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800417 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700418 }
419
420 c.mutatorInfo = append(c.mutatorInfo, info)
421
422 return info
Colin Crossc9028482014-12-18 16:28:54 -0800423}
424
Colin Cross3702ac72016-08-11 11:09:00 -0700425// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
426// Each registered mutator is invoked in registration order (mixing TopDownMutators and
427// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
428// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800429//
Colin Cross65569e42015-03-10 20:08:19 -0700430// The mutator type names given here must be unique to all bottom up or early
431// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700432//
Colin Cross3702ac72016-08-11 11:09:00 -0700433// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
434// parallel while maintaining ordering.
435func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700436 for _, m := range c.variantMutatorNames {
437 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800438 panic(fmt.Errorf("mutator name %s is already registered", name))
439 }
440 }
441
Colin Cross49c279a2016-08-05 22:30:44 -0700442 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800443 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800444 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700445 }
446 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700447
448 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700449
450 return info
451}
452
Colin Cross3702ac72016-08-11 11:09:00 -0700453type MutatorHandle interface {
454 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
455 // method on the mutator context is thread-safe, but the mutator must handle synchronization
456 // for any modifications to global state or any modules outside the one it was invoked on.
457 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700458}
459
Colin Cross3702ac72016-08-11 11:09:00 -0700460func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700461 mutator.parallel = true
462 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700463}
464
465// RegisterEarlyMutator registers a mutator that will be invoked to split
466// Modules into multiple variant Modules before any dependencies have been
467// created. Each registered mutator is invoked in registration order once
468// per Module (including each variant from previous early mutators). Module
469// order is unpredictable.
470//
471// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700472// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700473//
474// The mutator type names given here must be unique to all bottom up or early
475// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700476//
477// Deprecated, use a BottomUpMutator instead. The only difference between
478// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
479// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700480func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
481 for _, m := range c.variantMutatorNames {
482 if m == name {
483 panic(fmt.Errorf("mutator name %s is already registered", name))
484 }
485 }
486
Colin Crossf8b50422016-08-10 12:56:40 -0700487 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
488 bottomUpMutator: func(mctx BottomUpMutatorContext) {
489 mutator(mctx)
490 },
491 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700492 })
493
494 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800495}
496
Jamie Gennisd4e10182014-06-12 20:06:50 -0700497// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
498// where it encounters an unknown module type while parsing Blueprints files. By
499// default, the context will report unknown module types as an error. If this
500// method is called with ignoreUnknownModuleTypes set to true then the context
501// will silently ignore unknown module types.
502//
503// This method should generally not be used. It exists to facilitate the
504// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700505func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
506 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
507}
508
Colin Cross036a1df2015-12-17 15:49:30 -0800509// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
510// unresolved dependencies. If the module's GenerateBuildActions calls
511// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
512// for missing dependencies.
513func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
514 c.allowMissingDependencies = allowMissingDependencies
515}
516
Jamie Gennisd4e10182014-06-12 20:06:50 -0700517// Parse parses a single Blueprints file from r, creating Module objects for
518// each of the module definitions encountered. If the Blueprints file contains
519// an assignment to the "subdirs" variable, then the subdirectories listed are
Colin Cross1fef5362015-04-20 16:50:54 -0700520// searched for Blueprints files returned in the subBlueprints return value.
521// If the Blueprints file contains an assignment to the "build" variable, then
522// the file listed are returned in the subBlueprints return value.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700523//
524// rootDir specifies the path to the root directory of the source tree, while
525// filename specifies the path to the Blueprints file. These paths are used for
526// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800527func (c *Context) parse(rootDir, filename string, r io.Reader,
Colin Cross127d2ea2016-11-01 11:10:51 -0700528 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700529
Jamie Gennisec701282014-06-12 20:06:31 -0700530 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700531 if err != nil {
Colin Cross127d2ea2016-11-01 11:10:51 -0700532 return nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700533 }
534
Colin Crossc0dbc552015-01-02 15:19:28 -0800535 scope = parser.NewScope(scope)
536 scope.Remove("subdirs")
Colin Cross7f507402015-12-16 13:03:41 -0800537 scope.Remove("optional_subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700538 scope.Remove("build")
Colin Cross23d7aa12015-06-30 16:05:22 -0700539 file, errs = parser.ParseAndEval(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700540 if len(errs) > 0 {
541 for i, err := range errs {
542 if parseErr, ok := err.(*parser.ParseError); ok {
Colin Cross2c628442016-10-07 17:13:10 -0700543 err = &BlueprintError{
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700544 Err: parseErr.Err,
545 Pos: parseErr.Pos,
546 }
547 errs[i] = err
548 }
549 }
550
551 // If there were any parse errors don't bother trying to interpret the
552 // result.
Colin Cross127d2ea2016-11-01 11:10:51 -0700553 return nil, nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700554 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700555 file.Name = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700556
Colin Cross6d8780f2015-07-10 17:51:55 -0700557 subdirs, subdirsPos, err := getLocalStringListFromScope(scope, "subdirs")
Colin Cross1fef5362015-04-20 16:50:54 -0700558 if err != nil {
559 errs = append(errs, err)
560 }
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700561
Colin Cross7f507402015-12-16 13:03:41 -0800562 optionalSubdirs, optionalSubdirsPos, err := getLocalStringListFromScope(scope, "optional_subdirs")
563 if err != nil {
564 errs = append(errs, err)
565 }
566
Colin Cross6d8780f2015-07-10 17:51:55 -0700567 build, buildPos, err := getLocalStringListFromScope(scope, "build")
Colin Cross1fef5362015-04-20 16:50:54 -0700568 if err != nil {
569 errs = append(errs, err)
570 }
571
Colin Cross29394222015-04-27 13:18:21 -0700572 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
Colin Cross127d2ea2016-11-01 11:10:51 -0700573 if err != nil {
574 errs = append(errs, err)
575 }
576
577 if subBlueprintsName == "" {
578 subBlueprintsName = "Blueprints"
579 }
Colin Cross29394222015-04-27 13:18:21 -0700580
Colin Cross7f507402015-12-16 13:03:41 -0800581 var blueprints []string
582
Colin Cross127d2ea2016-11-01 11:10:51 -0700583 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
Colin Cross7f507402015-12-16 13:03:41 -0800584 blueprints = append(blueprints, newBlueprints...)
Colin Cross7f507402015-12-16 13:03:41 -0800585 errs = append(errs, newErrs...)
586
Colin Cross127d2ea2016-11-01 11:10:51 -0700587 newBlueprints, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), subdirs, subdirsPos,
Colin Cross7f507402015-12-16 13:03:41 -0800588 subBlueprintsName, false)
589 blueprints = append(blueprints, newBlueprints...)
Colin Cross7f507402015-12-16 13:03:41 -0800590 errs = append(errs, newErrs...)
591
Colin Cross127d2ea2016-11-01 11:10:51 -0700592 newBlueprints, newErrs = c.findSubdirBlueprints(filepath.Dir(filename), optionalSubdirs,
Colin Cross7f507402015-12-16 13:03:41 -0800593 optionalSubdirsPos, subBlueprintsName, true)
594 blueprints = append(blueprints, newBlueprints...)
Colin Cross7f507402015-12-16 13:03:41 -0800595 errs = append(errs, newErrs...)
Colin Crossc0dbc552015-01-02 15:19:28 -0800596
Colin Cross1fef5362015-04-20 16:50:54 -0700597 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
598 for i, b := range blueprints {
599 subBlueprintsAndScope[i] = stringAndScope{b, scope}
600 }
601
Colin Cross127d2ea2016-11-01 11:10:51 -0700602 return file, subBlueprintsAndScope, errs
Colin Crossc0dbc552015-01-02 15:19:28 -0800603}
604
Colin Cross7ad621c2015-01-07 16:22:45 -0800605type stringAndScope struct {
606 string
607 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700608}
609
Jamie Gennisd4e10182014-06-12 20:06:50 -0700610// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
611// at rootFile. When it encounters a Blueprints file with a set of subdirs
612// listed it recursively parses any Blueprints files found in those
613// subdirectories.
614//
615// If no errors are encountered while parsing the files, the list of paths on
616// which the future output will depend is returned. This list will include both
617// Blueprints file paths as well as directory paths for cases where wildcard
618// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700619func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
620 errs []error) {
621
Colin Cross7ad621c2015-01-07 16:22:45 -0800622 c.dependenciesReady = false
623
Colin Cross23d7aa12015-06-30 16:05:22 -0700624 moduleCh := make(chan *moduleInfo)
625 errsCh := make(chan []error)
626 doneCh := make(chan struct{})
627 var numErrs uint32
628 var numGoroutines int32
629
630 // handler must be reentrant
631 handler := func(file *parser.File) {
632 if atomic.LoadUint32(&numErrs) > maxErrors {
633 return
634 }
635
636 atomic.AddInt32(&numGoroutines, 1)
637 go func() {
638 for _, def := range file.Defs {
639 var module *moduleInfo
640 var errs []error
641 switch def := def.(type) {
642 case *parser.Module:
643 module, errs = c.processModuleDef(def, file.Name)
644 case *parser.Assignment:
645 // Already handled via Scope object
646 default:
647 panic("unknown definition type")
648 }
649
650 if len(errs) > 0 {
651 atomic.AddUint32(&numErrs, uint32(len(errs)))
652 errsCh <- errs
653 } else if module != nil {
654 moduleCh <- module
655 }
656 }
657 doneCh <- struct{}{}
658 }()
659 }
660
661 atomic.AddInt32(&numGoroutines, 1)
662 go func() {
663 var errs []error
664 deps, errs = c.WalkBlueprintsFiles(rootFile, handler)
665 if len(errs) > 0 {
666 errsCh <- errs
667 }
668 doneCh <- struct{}{}
669 }()
670
671loop:
672 for {
673 select {
674 case newErrs := <-errsCh:
675 errs = append(errs, newErrs...)
676 case module := <-moduleCh:
677 newErrs := c.addModule(module)
678 if len(newErrs) > 0 {
679 errs = append(errs, newErrs...)
680 }
681 case <-doneCh:
682 n := atomic.AddInt32(&numGoroutines, -1)
683 if n == 0 {
684 break loop
685 }
686 }
687 }
688
689 return deps, errs
690}
691
692type FileHandler func(*parser.File)
693
694// Walk a set of Blueprints files starting with the file at rootFile, calling handler on each.
695// When it encounters a Blueprints file with a set of subdirs listed it recursively parses any
696// Blueprints files found in those subdirectories. handler will be called from a goroutine, so
697// it must be reentrant.
698//
699// If no errors are encountered while parsing the files, the list of paths on
700// which the future output will depend is returned. This list will include both
701// Blueprints file paths as well as directory paths for cases where wildcard
702// subdirs are found.
703func (c *Context) WalkBlueprintsFiles(rootFile string, handler FileHandler) (deps []string,
704 errs []error) {
705
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700706 rootDir := filepath.Dir(rootFile)
707
Colin Cross7ad621c2015-01-07 16:22:45 -0800708 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700709
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 // Channels to receive data back from parseBlueprintsFile goroutines
711 blueprintsCh := make(chan stringAndScope)
712 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700713 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800714 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700715
Colin Cross7ad621c2015-01-07 16:22:45 -0800716 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
717 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700718
Colin Cross7ad621c2015-01-07 16:22:45 -0800719 // Number of outstanding goroutines to wait for
720 count := 0
721
722 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
723 count++
724 go func() {
725 c.parseBlueprintsFile(filename, scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700726 errsCh, fileCh, blueprintsCh, depsCh)
Colin Cross7ad621c2015-01-07 16:22:45 -0800727 doneCh <- struct{}{}
728 }()
729 }
730
731 tooManyErrors := false
732
733 startParseBlueprintsFile(rootFile, nil)
734
735loop:
736 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700737 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800738 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700739 }
740
Colin Cross7ad621c2015-01-07 16:22:45 -0800741 select {
742 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700743 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800744 case dep := <-depsCh:
745 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700746 case file := <-fileCh:
747 handler(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800748 case blueprint := <-blueprintsCh:
749 if tooManyErrors {
750 continue
751 }
752 if blueprintsSet[blueprint.string] {
753 continue
754 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700755
Colin Cross7ad621c2015-01-07 16:22:45 -0800756 blueprintsSet[blueprint.string] = true
757 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
758 case <-doneCh:
759 count--
760 if count == 0 {
761 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700762 }
763 }
764 }
765
Colin Cross7ad621c2015-01-07 16:22:45 -0800766 return
767}
768
Colin Crossd7b0f602016-06-02 15:30:20 -0700769// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
770// filenames to contents stored as a byte slice.
771func (c *Context) MockFileSystem(files map[string][]byte) {
Colin Crossb519a7e2017-02-01 13:21:35 -0800772 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700773}
774
Colin Cross7ad621c2015-01-07 16:22:45 -0800775// parseBlueprintFile parses a single Blueprints file, returning any errors through
776// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
777// blueprintsCh, and any dependencies on Blueprints files or directories through
778// depsCh.
779func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700780 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800781 depsCh chan<- string) {
782
Colin Crossd7b0f602016-06-02 15:30:20 -0700783 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800784 if err != nil {
785 errsCh <- []error{err}
786 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700787 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700788 defer func() {
789 err = f.Close()
790 if err != nil {
791 errsCh <- []error{err}
792 }
793 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700794
Colin Cross127d2ea2016-11-01 11:10:51 -0700795 file, subBlueprints, errs := c.parse(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800796 if len(errs) > 0 {
797 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700798 } else {
799 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800800 }
801
Colin Cross1fef5362015-04-20 16:50:54 -0700802 for _, b := range subBlueprints {
803 blueprintsCh <- b
Colin Cross127d2ea2016-11-01 11:10:51 -0700804 depsCh <- b.string
Colin Cross1fef5362015-04-20 16:50:54 -0700805 }
Colin Cross1fef5362015-04-20 16:50:54 -0700806}
807
Colin Cross7f507402015-12-16 13:03:41 -0800808func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -0700809 buildPos scanner.Position) ([]string, []error) {
810
811 var blueprints []string
812 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -0800813
814 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -0700815 pattern := filepath.Join(dir, file)
816 var matches []string
817 var err error
818
Colin Cross08e49542016-11-14 15:23:33 -0800819 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -0700820
Colin Cross7f507402015-12-16 13:03:41 -0800821 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700822 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700823 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -0800824 Pos: buildPos,
825 })
826 continue
827 }
828
829 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -0700830 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700831 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -0800832 Pos: buildPos,
833 })
834 }
835
Colin Cross7f507402015-12-16 13:03:41 -0800836 for _, foundBlueprints := range matches {
Colin Cross7f507402015-12-16 13:03:41 -0800837 blueprints = append(blueprints, foundBlueprints)
838 }
839 }
840
Colin Cross127d2ea2016-11-01 11:10:51 -0700841 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -0800842}
843
844func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -0700845 subBlueprintsName string, optional bool) ([]string, []error) {
846
847 var blueprints []string
848 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800849
850 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -0700851 pattern := filepath.Join(dir, subdir, subBlueprintsName)
852 var matches []string
853 var err error
854
Colin Cross08e49542016-11-14 15:23:33 -0800855 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -0700856
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700857 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700858 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700859 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -0700860 Pos: subdirsPos,
861 })
862 continue
863 }
864
Colin Cross7f507402015-12-16 13:03:41 -0800865 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -0700866 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700867 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -0700868 Pos: subdirsPos,
869 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700870 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800871
Colin Cross127d2ea2016-11-01 11:10:51 -0700872 for _, subBlueprints := range matches {
873 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -0800874 }
875 }
Colin Cross1fef5362015-04-20 16:50:54 -0700876
Colin Cross127d2ea2016-11-01 11:10:51 -0700877 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700878}
879
Colin Cross6d8780f2015-07-10 17:51:55 -0700880func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
881 if assignment, local := scope.Get(v); assignment == nil || !local {
882 return nil, scanner.Position{}, nil
883 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700884 switch value := assignment.Value.Eval().(type) {
885 case *parser.List:
886 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700887
Colin Crosse32cc802016-06-07 12:28:16 -0700888 for _, listValue := range value.Values {
889 s, ok := listValue.(*parser.String)
890 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700891 // The parser should not produce this.
892 panic("non-string value found in list")
893 }
894
Colin Crosse32cc802016-06-07 12:28:16 -0700895 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700896 }
897
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700898 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700899 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -0700900 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -0700901 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700902 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700903 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700904 default:
905 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
906 }
907 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700908}
909
Colin Cross29394222015-04-27 13:18:21 -0700910func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -0700911 if assignment, _ := scope.Get(v); assignment == nil {
912 return "", scanner.Position{}, nil
913 } else {
Colin Crosse32cc802016-06-07 12:28:16 -0700914 switch value := assignment.Value.Eval().(type) {
915 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700916 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -0700917 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -0700918 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -0700919 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -0700920 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -0700921 }
922 default:
923 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
924 }
925 }
Colin Cross29394222015-04-27 13:18:21 -0700926}
927
Colin Cross910242b2016-04-11 15:41:52 -0700928// Clones a build logic module by calling the factory method for its module type, and then cloning
929// property values. Any values stored in the module object that are not stored in properties
930// structs will be lost.
931func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
932 typeName := origModule.typeName
933 factory, ok := c.moduleFactories[typeName]
934 if !ok {
935 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
936 }
937
Colin Cross910242b2016-04-11 15:41:52 -0700938 newLogicModule, newProperties := factory()
939
Colin Cross910242b2016-04-11 15:41:52 -0700940 if len(newProperties) != len(origModule.moduleProperties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700941 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -0700942 }
943
944 for i := range newProperties {
945 dst := reflect.ValueOf(newProperties[i]).Elem()
946 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
947
948 proptools.CopyProperties(dst, src)
949 }
950
951 return newLogicModule, newProperties
952}
953
Colin Crossf5e34b92015-03-13 16:02:36 -0700954func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
955 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800956
Colin Crossf4d18a62015-03-18 17:43:15 -0700957 if len(variationNames) == 0 {
958 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -0700959 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -0700960 }
961
Colin Crossc9028482014-12-18 16:28:54 -0800962 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -0800963
Colin Cross174ae052015-03-03 17:37:03 -0800964 var errs []error
965
Colin Crossf5e34b92015-03-13 16:02:36 -0700966 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -0800967 var newLogicModule Module
968 var newProperties []interface{}
969
970 if i == 0 {
971 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -0700972 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
973 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Cross910242b2016-04-11 15:41:52 -0700974 newLogicModule, newProperties = origModule.logicModule, origModule.moduleProperties
Colin Crossc9028482014-12-18 16:28:54 -0800975 } else {
Colin Cross910242b2016-04-11 15:41:52 -0700976 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -0800977 }
978
Colin Crossf5e34b92015-03-13 16:02:36 -0700979 newVariant := origModule.variant.clone()
980 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -0800981
Colin Crossed342d92015-03-11 00:57:25 -0700982 m := *origModule
983 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -0700984 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -0700985 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -0700986 newModule.variant = newVariant
987 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossed342d92015-03-11 00:57:25 -0700988 newModule.moduleProperties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -0800989
Colin Crossbadc8812016-08-11 17:01:46 -0700990 if variationName != "" {
991 if newModule.variantName == "" {
992 newModule.variantName = variationName
993 } else {
994 newModule.variantName += "_" + variationName
995 }
Colin Crosse7daa222015-03-11 14:35:41 -0700996 }
997
Colin Crossc9028482014-12-18 16:28:54 -0800998 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -0700999
Colin Crossf5e34b92015-03-13 16:02:36 -07001000 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001001 if len(newErrs) > 0 {
1002 errs = append(errs, newErrs...)
1003 }
Colin Crossc9028482014-12-18 16:28:54 -08001004 }
1005
1006 // Mark original variant as invalid. Modules that depend on this module will still
1007 // depend on origModule, but we'll fix it when the mutator is called on them.
1008 origModule.logicModule = nil
1009 origModule.splitModules = newModules
1010
Colin Cross3702ac72016-08-11 11:09:00 -07001011 atomic.AddUint32(&c.depsModified, 1)
1012
Colin Cross174ae052015-03-03 17:37:03 -08001013 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001014}
1015
Colin Crossf5e34b92015-03-13 16:02:36 -07001016func (c *Context) convertDepsToVariation(module *moduleInfo,
1017 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001018
Colin Crossc9028482014-12-18 16:28:54 -08001019 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001020 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001021 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001022 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001023 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001024 newDep = m
1025 break
1026 }
1027 }
1028 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001029 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001030 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001031 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001032 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001033 })
1034 continue
Colin Crossc9028482014-12-18 16:28:54 -08001035 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001036 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001037 }
1038 }
Colin Cross174ae052015-03-03 17:37:03 -08001039
1040 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001041}
1042
Colin Crossf5e34b92015-03-13 16:02:36 -07001043func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001044 names := make([]string, 0, len(variant))
1045 for _, m := range c.variantMutatorNames {
1046 if v, ok := variant[m]; ok {
1047 names = append(names, m+":"+v)
1048 }
1049 }
1050
1051 return strings.Join(names, ", ")
1052}
1053
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001054func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001055 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001056
Colin Crossc32c4792016-06-09 15:52:30 -07001057 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001058 if !ok {
1059 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001060 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001061 }
1062
Colin Cross7ad621c2015-01-07 16:22:45 -08001063 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001064 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001065 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1066 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001067 },
1068 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001069 }
1070
Colin Crossbbfa51a2014-12-17 16:12:41 -08001071 logicModule, properties := factory()
Colin Crossed342d92015-03-11 00:57:25 -07001072
1073 module := &moduleInfo{
1074 logicModule: logicModule,
Colin Crossc32c4792016-06-09 15:52:30 -07001075 typeName: moduleDef.Type,
Jamie Gennisec701282014-06-12 20:06:31 -07001076 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001077 }
1078
Colin Crossed342d92015-03-11 00:57:25 -07001079 module.moduleProperties = properties
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001080
Jamie Gennis87622922014-09-30 11:38:25 -07001081 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001082 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001083 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001084 }
1085
Colin Crossc32c4792016-06-09 15:52:30 -07001086 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001087 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001088 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001089 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001090 }
1091
Colin Cross7ad621c2015-01-07 16:22:45 -08001092 return module, nil
1093}
1094
Colin Cross23d7aa12015-06-30 16:05:22 -07001095func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001096 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001097 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001098
Colin Cross0b7e83e2016-05-17 14:58:05 -07001099 if group, present := c.moduleNames[name]; present {
Colin Cross23d7aa12015-06-30 16:05:22 -07001100 return []error{
Colin Cross2c628442016-10-07 17:13:10 -07001101 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001102 Err: fmt.Errorf("module %q already defined", name),
1103 Pos: module.pos,
1104 },
Colin Cross2c628442016-10-07 17:13:10 -07001105 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001106 Err: fmt.Errorf("<-- previous definition here"),
1107 Pos: group.modules[0].pos,
1108 },
Colin Crossed342d92015-03-11 00:57:25 -07001109 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001110 }
1111
Colin Cross0b7e83e2016-05-17 14:58:05 -07001112 ninjaName := toNinjaName(name)
1113
1114 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1115 // already exists
1116 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1117 ninjaName = toNinjaName(name) + strconv.Itoa(i)
1118 }
1119
1120 group := &moduleGroup{
1121 name: name,
1122 ninjaName: ninjaName,
1123 modules: []*moduleInfo{module},
1124 }
1125 module.group = group
1126 c.moduleNames[name] = group
1127 c.moduleNinjaNames[ninjaName] = group
1128 c.moduleGroups = append(c.moduleGroups, group)
1129
Colin Cross23d7aa12015-06-30 16:05:22 -07001130 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001131}
1132
Jamie Gennisd4e10182014-06-12 20:06:50 -07001133// ResolveDependencies checks that the dependencies specified by all of the
1134// modules defined in the parsed Blueprints files are valid. This means that
1135// the modules depended upon are defined and that no circular dependencies
1136// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001137func (c *Context) ResolveDependencies(config interface{}) []error {
Colin Crossf8b50422016-08-10 12:56:40 -07001138 errs := c.updateDependencies()
1139 if len(errs) > 0 {
1140 return errs
1141 }
1142
1143 errs = c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001144 if len(errs) > 0 {
1145 return errs
1146 }
1147
Colin Cross910242b2016-04-11 15:41:52 -07001148 c.cloneModules()
1149
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001150 c.dependenciesReady = true
1151 return nil
1152}
1153
Colin Cross763b6f12015-10-29 15:32:56 -07001154// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001155// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001156// module names returned by its DynamicDependencies method and those added by calling
1157// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001158func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001159 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001160 func() {
1161 defer func() {
1162 if r := recover(); r != nil {
1163 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1164 }
1165 }()
1166 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001167
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001168 if ctx.Failed() {
1169 return
1170 }
Colin Cross763b6f12015-10-29 15:32:56 -07001171
Colin Cross2c1f3d12016-04-11 15:47:28 -07001172 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001173 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001174 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001175}
1176
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001177// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1178// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001179func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1180 if len(possible) == 1 {
1181 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001182 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001183 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001184 if m.variant.equal(module.dependencyVariant) {
1185 return m
1186 }
1187 }
1188 }
1189
1190 return nil
1191}
1192
Colin Cross2c1f3d12016-04-11 15:47:28 -07001193func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001194 if _, ok := tag.(BaseDependencyTag); ok {
1195 panic("BaseDependencyTag is not allowed to be used directly!")
1196 }
1197
Colin Cross0b7e83e2016-05-17 14:58:05 -07001198 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001199 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001200 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001201 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001202 }}
1203 }
1204
Colin Cross0b7e83e2016-05-17 14:58:05 -07001205 possibleDeps := c.modulesFromName(depName)
1206 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001207 if c.allowMissingDependencies {
1208 module.missingDeps = append(module.missingDeps, depName)
1209 return nil
1210 }
Colin Cross2c628442016-10-07 17:13:10 -07001211 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001212 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001213 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001214 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001215 }}
1216 }
1217
Colin Cross0b7e83e2016-05-17 14:58:05 -07001218 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001219 for _, dep := range module.directDeps {
1220 if m == dep.module {
1221 // TODO(ccross): what if adding a dependency with a different tag?
1222 return nil
1223 }
Colin Cross65569e42015-03-10 20:08:19 -07001224 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001225 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001226 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001227 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001228 }
Colin Crossc9028482014-12-18 16:28:54 -08001229
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001230 variants := make([]string, len(possibleDeps))
1231 for i, mod := range possibleDeps {
1232 variants[i] = c.prettyPrintVariant(mod.variant)
1233 }
1234 sort.Strings(variants)
1235
Colin Cross2c628442016-10-07 17:13:10 -07001236 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001237 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001238 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001239 c.prettyPrintVariant(module.dependencyVariant),
1240 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001241 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001242 }}
1243}
1244
Colin Cross8d8a7af2015-11-03 16:41:29 -08001245func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001246 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001247 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001248 Err: fmt.Errorf("%q depends on itself", destName),
1249 Pos: module.pos,
1250 }}
1251 }
1252
Colin Cross0b7e83e2016-05-17 14:58:05 -07001253 possibleDeps := c.modulesFromName(destName)
1254 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001255 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001256 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001257 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001258 Pos: module.pos,
1259 }}
1260 }
1261
Colin Cross0b7e83e2016-05-17 14:58:05 -07001262 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001263 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001264 }
1265
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001266 variants := make([]string, len(possibleDeps))
1267 for i, mod := range possibleDeps {
1268 variants[i] = c.prettyPrintVariant(mod.variant)
1269 }
1270 sort.Strings(variants)
1271
Colin Cross2c628442016-10-07 17:13:10 -07001272 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001273 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001274 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001275 c.prettyPrintVariant(module.dependencyVariant),
1276 strings.Join(variants, "\n ")),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001277 Pos: module.pos,
1278 }}
1279}
1280
Colin Crossf5e34b92015-03-13 16:02:36 -07001281func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001282 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001283 if _, ok := tag.(BaseDependencyTag); ok {
1284 panic("BaseDependencyTag is not allowed to be used directly!")
1285 }
Colin Cross65569e42015-03-10 20:08:19 -07001286
Colin Cross0b7e83e2016-05-17 14:58:05 -07001287 possibleDeps := c.modulesFromName(depName)
1288 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001289 if c.allowMissingDependencies {
1290 module.missingDeps = append(module.missingDeps, depName)
1291 return nil
1292 }
Colin Cross2c628442016-10-07 17:13:10 -07001293 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001294 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001295 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001296 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001297 }}
1298 }
1299
1300 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1301 // compare the strings because the result won't be in mutator registration order.
1302 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001303 var newVariant variationMap
1304 if !far {
1305 newVariant = module.dependencyVariant.clone()
1306 } else {
1307 newVariant = make(variationMap)
1308 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001309 for _, v := range variations {
1310 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001311 }
1312
Colin Cross0b7e83e2016-05-17 14:58:05 -07001313 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001314 var found bool
1315 if far {
1316 found = m.variant.subset(newVariant)
1317 } else {
1318 found = m.variant.equal(newVariant)
1319 }
1320 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001321 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001322 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001323 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001324 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001325 }}
1326 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001327 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001328 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001329 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001330 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001331 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001332 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001333 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001334 }}
1335 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001336 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001337 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001338 return nil
1339 }
1340 }
1341
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001342 variants := make([]string, len(possibleDeps))
1343 for i, mod := range possibleDeps {
1344 variants[i] = c.prettyPrintVariant(mod.variant)
1345 }
1346 sort.Strings(variants)
1347
Colin Cross2c628442016-10-07 17:13:10 -07001348 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001349 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001350 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001351 c.prettyPrintVariant(newVariant),
1352 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001353 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001354 }}
Colin Crossc9028482014-12-18 16:28:54 -08001355}
1356
Colin Crossf1875462016-04-11 17:33:13 -07001357func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1358 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001359 if _, ok := tag.(BaseDependencyTag); ok {
1360 panic("BaseDependencyTag is not allowed to be used directly!")
1361 }
Colin Crossf1875462016-04-11 17:33:13 -07001362
1363 var fromInfo, toInfo *moduleInfo
1364 for _, m := range origModule.splitModules {
1365 if m.logicModule == from {
1366 fromInfo = m
1367 }
1368 if m.logicModule == to {
1369 toInfo = m
1370 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001371 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001372 }
1373 }
1374 }
1375
1376 if fromInfo == nil || toInfo == nil {
1377 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001378 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001379 }
1380
1381 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001382 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001383}
1384
Colin Cross3702ac72016-08-11 11:09:00 -07001385type visitOrderer interface {
1386 // returns the number of modules that this module needs to wait for
1387 waitCount(module *moduleInfo) int
1388 // returns the list of modules that are waiting for this module
1389 propagate(module *moduleInfo) []*moduleInfo
1390 // visit modules in order
1391 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1392}
1393
1394type bottomUpVisitorImpl struct{}
1395
1396func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1397 return len(module.forwardDeps)
1398}
1399
1400func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1401 return module.reverseDeps
1402}
1403
1404func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1405 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001406 if visit(module) {
1407 return
1408 }
1409 }
1410}
1411
Colin Cross3702ac72016-08-11 11:09:00 -07001412type topDownVisitorImpl struct{}
1413
1414func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1415 return len(module.reverseDeps)
1416}
1417
1418func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1419 return module.forwardDeps
1420}
1421
1422func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1423 for i := 0; i < len(modules); i++ {
1424 module := modules[len(modules)-1-i]
1425 if visit(module) {
1426 return
1427 }
1428 }
1429}
1430
1431var (
1432 bottomUpVisitor bottomUpVisitorImpl
1433 topDownVisitor topDownVisitorImpl
1434)
1435
Colin Cross49c279a2016-08-05 22:30:44 -07001436// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1437// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001438func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001439 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001440 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001441 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001442 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001443
Colin Cross7addea32015-03-11 15:43:52 -07001444 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001445 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001446 }
1447
Colin Cross7addea32015-03-11 15:43:52 -07001448 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001449 count++
1450 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001451 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001452 if ret {
Colin Cross0fff7422016-08-11 15:37:45 -07001453 cancelCh <- true
Colin Cross8900e9b2015-03-02 14:03:01 -08001454 }
Colin Cross7addea32015-03-11 15:43:52 -07001455 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001456 }()
1457 }
1458
Colin Cross7addea32015-03-11 15:43:52 -07001459 for _, module := range c.modulesSorted {
1460 if module.waitingCount == 0 {
1461 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001462 }
1463 }
1464
Colin Cross11e3b0d2015-02-04 10:41:00 -08001465 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001466 select {
Colin Cross0fff7422016-08-11 15:37:45 -07001467 case cancel = <-cancelCh:
Colin Cross7addea32015-03-11 15:43:52 -07001468 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001469 if !cancel {
Colin Cross3702ac72016-08-11 11:09:00 -07001470 for _, module := range order.propagate(doneModule) {
1471 module.waitingCount--
1472 if module.waitingCount == 0 {
1473 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001474 }
Colin Cross691a60d2015-01-07 18:08:56 -08001475 }
1476 }
1477 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001478 }
1479 }
1480}
1481
1482// updateDependencies recursively walks the module dependency graph and updates
1483// additional fields based on the dependencies. It builds a sorted list of modules
1484// such that dependencies of a module always appear first, and populates reverse
1485// dependency links and counts of total dependencies. It also reports errors when
1486// it encounters dependency cycles. This should called after resolveDependencies,
1487// as well as after any mutator pass has called addDependency
1488func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001489 visited := make(map[*moduleInfo]bool) // modules that were already checked
1490 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001491
Colin Cross7addea32015-03-11 15:43:52 -07001492 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001493
Colin Cross7addea32015-03-11 15:43:52 -07001494 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001495
Colin Cross7addea32015-03-11 15:43:52 -07001496 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001497 // We are the "start" of the cycle, so we're responsible
1498 // for generating the errors. The cycle list is in
1499 // reverse order because all the 'check' calls append
1500 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001501 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001502 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001503 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001504 })
1505
1506 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001507 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001508 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001509 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001510 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001511 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001512 curModule.Name(),
1513 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001514 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001515 })
Colin Cross7addea32015-03-11 15:43:52 -07001516 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001517 }
1518 }
1519
Colin Cross7addea32015-03-11 15:43:52 -07001520 check = func(module *moduleInfo) []*moduleInfo {
1521 visited[module] = true
1522 checking[module] = true
1523 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001524
Colin Cross7addea32015-03-11 15:43:52 -07001525 deps := make(map[*moduleInfo]bool)
1526
1527 // Add an implicit dependency ordering on all earlier modules in the same module group
1528 for _, dep := range module.group.modules {
1529 if dep == module {
1530 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001531 }
Colin Cross7addea32015-03-11 15:43:52 -07001532 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001533 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001534
Colin Cross7addea32015-03-11 15:43:52 -07001535 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001536 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001537 }
1538
1539 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001540 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001541
Colin Crossbbfa51a2014-12-17 16:12:41 -08001542 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001543 if checking[dep] {
1544 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001545 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001546 }
1547
1548 if !visited[dep] {
1549 cycle := check(dep)
1550 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001551 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001552 // We are the "start" of the cycle, so we're responsible
1553 // for generating the errors. The cycle list is in
1554 // reverse order because all the 'check' calls append
1555 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001556 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001557
1558 // We can continue processing this module's children to
1559 // find more cycles. Since all the modules that were
1560 // part of the found cycle were marked as visited we
1561 // won't run into that cycle again.
1562 } else {
1563 // We're not the "start" of the cycle, so we just append
1564 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001565 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001566 }
1567 }
1568 }
Colin Cross691a60d2015-01-07 18:08:56 -08001569
Colin Cross3702ac72016-08-11 11:09:00 -07001570 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001571 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001572 }
1573
Colin Cross7addea32015-03-11 15:43:52 -07001574 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001575
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001576 return nil
1577 }
1578
Colin Cross7addea32015-03-11 15:43:52 -07001579 for _, module := range c.moduleInfo {
1580 if !visited[module] {
1581 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001582 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001583 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001584 panic("inconceivable!")
1585 }
1586 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001587 }
1588 }
1589 }
1590
Colin Cross7addea32015-03-11 15:43:52 -07001591 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001592
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001593 return
1594}
1595
Jamie Gennisd4e10182014-06-12 20:06:50 -07001596// PrepareBuildActions generates an internal representation of all the build
1597// actions that need to be performed. This process involves invoking the
1598// GenerateBuildActions method on each of the Module objects created during the
1599// parse phase and then on each of the registered Singleton objects.
1600//
1601// If the ResolveDependencies method has not already been called it is called
1602// automatically by this method.
1603//
1604// The config argument is made available to all of the Module and Singleton
1605// objects via the Config method on the ModuleContext and SingletonContext
1606// objects passed to GenerateBuildActions. It is also passed to the functions
1607// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1608// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001609//
1610// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001611// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1612// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1613// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001614func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001615 c.buildActionsReady = false
1616
1617 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001618 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001619 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001620 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001621 }
1622 }
1623
1624 liveGlobals := newLiveTracker(config)
1625
1626 c.initSpecialVariables()
1627
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001628 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001629 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001630 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001631 }
1632
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001633 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001634 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001635 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001636 }
1637
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001638 deps = append(depsModules, depsSingletons...)
1639
Colin Crossa2599452015-11-18 16:01:01 -08001640 if c.ninjaBuildDir != nil {
1641 liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001642 }
1643
Dan Willemsena481ae22015-12-18 15:18:03 -08001644 pkgNames, depsPackages := c.makeUniquePackageNames(liveGlobals)
1645
1646 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001647
1648 // This will panic if it finds a problem since it's a programming error.
1649 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1650
1651 c.pkgNames = pkgNames
1652 c.globalVariables = liveGlobals.variables
1653 c.globalPools = liveGlobals.pools
1654 c.globalRules = liveGlobals.rules
1655
1656 c.buildActionsReady = true
1657
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001658 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001659}
1660
Colin Crossc9028482014-12-18 16:28:54 -08001661func (c *Context) runMutators(config interface{}) (errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001662 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001663
Colin Crossf8b50422016-08-10 12:56:40 -07001664 mutators = append(mutators, c.earlyMutatorInfo...)
1665 mutators = append(mutators, c.mutatorInfo...)
1666
1667 for _, mutator := range mutators {
Colin Crossc9028482014-12-18 16:28:54 -08001668 if mutator.topDownMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001669 errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001670 } else if mutator.bottomUpMutator != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001671 errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001672 } else {
1673 panic("no mutator set on " + mutator.name)
1674 }
1675 if len(errs) > 0 {
1676 return errs
1677 }
1678 }
1679
1680 return nil
1681}
1682
Colin Cross3702ac72016-08-11 11:09:00 -07001683type mutatorDirection interface {
1684 run(mutator *mutatorInfo, ctx *mutatorContext)
1685 orderer() visitOrderer
1686 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001687}
1688
Colin Cross3702ac72016-08-11 11:09:00 -07001689type bottomUpMutatorImpl struct{}
1690
1691func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1692 mutator.bottomUpMutator(ctx)
1693}
1694
1695func (bottomUpMutatorImpl) orderer() visitOrderer {
1696 return bottomUpVisitor
1697}
1698
1699func (bottomUpMutatorImpl) String() string {
1700 return "bottom up mutator"
1701}
1702
1703type topDownMutatorImpl struct{}
1704
1705func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1706 mutator.topDownMutator(ctx)
1707}
1708
1709func (topDownMutatorImpl) orderer() visitOrderer {
1710 return topDownVisitor
1711}
1712
1713func (topDownMutatorImpl) String() string {
1714 return "top down mutator"
1715}
1716
1717var (
1718 topDownMutator topDownMutatorImpl
1719 bottomUpMutator bottomUpMutatorImpl
1720)
1721
Colin Cross49c279a2016-08-05 22:30:44 -07001722type reverseDep struct {
1723 module *moduleInfo
1724 dep depInfo
1725}
1726
Colin Cross3702ac72016-08-11 11:09:00 -07001727func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
1728 direction mutatorDirection) (errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001729
1730 newModuleInfo := make(map[Module]*moduleInfo)
1731 for k, v := range c.moduleInfo {
1732 newModuleInfo[k] = v
1733 }
Colin Crossc9028482014-12-18 16:28:54 -08001734
Colin Cross0ce142c2016-12-09 10:29:05 -08001735 type globalStateChange struct {
1736 reverse []reverseDep
1737 rename []rename
1738 replace []replace
1739 }
1740
Colin Cross2c1f3d12016-04-11 15:47:28 -07001741 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08001742 var rename []rename
1743 var replace []replace
Colin Cross8d8a7af2015-11-03 16:41:29 -08001744
Colin Cross49c279a2016-08-05 22:30:44 -07001745 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08001746 globalStateCh := make(chan globalStateChange)
Colin Cross49c279a2016-08-05 22:30:44 -07001747 newModulesCh := make(chan []*moduleInfo)
1748 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001749
Colin Cross3702ac72016-08-11 11:09:00 -07001750 c.depsModified = 0
1751
Colin Cross49c279a2016-08-05 22:30:44 -07001752 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001753 if module.splitModules != nil {
1754 panic("split module found in sorted module list")
1755 }
1756
Colin Cross7addea32015-03-11 15:43:52 -07001757 mctx := &mutatorContext{
1758 baseModuleContext: baseModuleContext{
1759 context: c,
1760 config: config,
1761 module: module,
1762 },
Colin Cross49c279a2016-08-05 22:30:44 -07001763 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001764 }
Colin Crossc9028482014-12-18 16:28:54 -08001765
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001766 func() {
1767 defer func() {
1768 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001769 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001770 if err, ok := r.(panicError); ok {
1771 err.addIn(in)
1772 mctx.error(err)
1773 } else {
1774 mctx.error(newPanicErrorf(r, in))
1775 }
1776 }
1777 }()
Colin Cross3702ac72016-08-11 11:09:00 -07001778 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001779 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001780
Colin Cross7addea32015-03-11 15:43:52 -07001781 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07001782 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07001783 return true
Colin Cross7addea32015-03-11 15:43:52 -07001784 }
Colin Crossc9028482014-12-18 16:28:54 -08001785
Colin Cross49c279a2016-08-05 22:30:44 -07001786 if len(mctx.newModules) > 0 {
1787 newModulesCh <- mctx.newModules
1788 }
1789
Colin Cross0ce142c2016-12-09 10:29:05 -08001790 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 {
1791 globalStateCh <- globalStateChange{
1792 reverse: mctx.reverseDeps,
1793 replace: mctx.replace,
1794 rename: mctx.rename,
1795 }
Colin Cross49c279a2016-08-05 22:30:44 -07001796 }
1797
1798 return false
1799 }
1800
1801 // Process errs and reverseDeps in a single goroutine
1802 go func() {
1803 for {
1804 select {
1805 case newErrs := <-errsCh:
1806 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08001807 case globalStateChange := <-globalStateCh:
1808 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07001809 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
1810 }
Colin Cross0ce142c2016-12-09 10:29:05 -08001811 replace = append(replace, globalStateChange.replace...)
1812 rename = append(rename, globalStateChange.rename...)
Colin Cross49c279a2016-08-05 22:30:44 -07001813 case newModules := <-newModulesCh:
1814 for _, m := range newModules {
1815 newModuleInfo[m.logicModule] = m
1816 }
1817 case <-done:
1818 return
Colin Crossc9028482014-12-18 16:28:54 -08001819 }
1820 }
Colin Cross49c279a2016-08-05 22:30:44 -07001821 }()
Colin Crossc9028482014-12-18 16:28:54 -08001822
Colin Cross49c279a2016-08-05 22:30:44 -07001823 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07001824 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001825 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07001826 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07001827 }
1828
1829 done <- true
1830
1831 if len(errs) > 0 {
1832 return errs
1833 }
1834
1835 c.moduleInfo = newModuleInfo
1836
1837 for _, group := range c.moduleGroups {
1838 for i := 0; i < len(group.modules); i++ {
1839 module := group.modules[i]
1840
1841 // Update module group to contain newly split variants
1842 if module.splitModules != nil {
1843 group.modules, i = spliceModules(group.modules, i, module.splitModules)
1844 }
1845
1846 // Fix up any remaining dependencies on modules that were split into variants
1847 // by replacing them with the first variant
1848 for j, dep := range module.directDeps {
1849 if dep.module.logicModule == nil {
1850 module.directDeps[j].module = dep.module.splitModules[0]
1851 }
1852 }
Colin Cross7addea32015-03-11 15:43:52 -07001853 }
Colin Crossc9028482014-12-18 16:28:54 -08001854 }
1855
Colin Cross8d8a7af2015-11-03 16:41:29 -08001856 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001857 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08001858 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07001859 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08001860 }
1861
Colin Cross0ce142c2016-12-09 10:29:05 -08001862 errs = c.handleRenames(rename)
1863 if len(errs) > 0 {
1864 return errs
1865 }
1866
1867 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07001868 if len(errs) > 0 {
1869 return errs
1870 }
1871
Colin Cross3702ac72016-08-11 11:09:00 -07001872 if c.depsModified > 0 {
1873 errs = c.updateDependencies()
1874 if len(errs) > 0 {
1875 return errs
1876 }
Colin Crossc9028482014-12-18 16:28:54 -08001877 }
1878
1879 return errs
1880}
1881
Colin Cross910242b2016-04-11 15:41:52 -07001882// Replaces every build logic module with a clone of itself. Prevents introducing problems where
1883// a mutator sets a non-property member variable on a module, which works until a later mutator
1884// creates variants of that module.
1885func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07001886 type update struct {
1887 orig Module
1888 clone *moduleInfo
1889 }
1890 ch := make(chan update, 100)
1891
Colin Cross910242b2016-04-11 15:41:52 -07001892 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07001893 go func(m *moduleInfo) {
1894 origLogicModule := m.logicModule
1895 m.logicModule, m.moduleProperties = c.cloneLogicModule(m)
1896 ch <- update{origLogicModule, m}
1897 }(m)
1898 }
1899
1900 for i := 0; i < len(c.modulesSorted); i++ {
1901 update := <-ch
1902 delete(c.moduleInfo, update.orig)
1903 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07001904 }
1905}
1906
Colin Cross49c279a2016-08-05 22:30:44 -07001907// Removes modules[i] from the list and inserts newModules... where it was located, returning
1908// the new slice and the index of the last inserted element
1909func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07001910 spliceSize := len(newModules)
1911 newLen := len(modules) + spliceSize - 1
1912 var dest []*moduleInfo
1913 if cap(modules) >= len(modules)-1+len(newModules) {
1914 // We can fit the splice in the existing capacity, do everything in place
1915 dest = modules[:newLen]
1916 } else {
1917 dest = make([]*moduleInfo, newLen)
1918 copy(dest, modules[:i])
1919 }
1920
1921 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07001922 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07001923
1924 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07001925 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07001926
Colin Cross49c279a2016-08-05 22:30:44 -07001927 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07001928}
1929
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930func (c *Context) initSpecialVariables() {
Colin Crossa2599452015-11-18 16:01:01 -08001931 c.ninjaBuildDir = nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001932 c.requiredNinjaMajor = 1
Dan Willemsen5c43e072016-10-25 21:26:12 -07001933 c.requiredNinjaMinor = 7
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001934 c.requiredNinjaMicro = 0
1935}
1936
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001937func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001938 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001939
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001940 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001941 var errs []error
1942
Colin Cross691a60d2015-01-07 18:08:56 -08001943 cancelCh := make(chan struct{})
1944 errsCh := make(chan []error)
1945 depsCh := make(chan []string)
1946
1947 go func() {
1948 for {
1949 select {
1950 case <-cancelCh:
1951 close(cancelCh)
1952 return
1953 case newErrs := <-errsCh:
1954 errs = append(errs, newErrs...)
1955 case newDeps := <-depsCh:
1956 deps = append(deps, newDeps...)
1957
1958 }
1959 }
1960 }()
1961
Colin Cross3702ac72016-08-11 11:09:00 -07001962 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Colin Cross7addea32015-03-11 15:43:52 -07001963 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1964 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1965 // just set it to nil.
1966 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
1967 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08001968
Colin Cross7addea32015-03-11 15:43:52 -07001969 mctx := &moduleContext{
1970 baseModuleContext: baseModuleContext{
1971 context: c,
1972 config: config,
1973 module: module,
1974 },
Colin Cross036a1df2015-12-17 15:49:30 -08001975 scope: scope,
1976 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07001977 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001978
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001979 func() {
1980 defer func() {
1981 if r := recover(); r != nil {
1982 in := fmt.Sprintf("GenerateBuildActions for %s", module)
1983 if err, ok := r.(panicError); ok {
1984 err.addIn(in)
1985 mctx.error(err)
1986 } else {
1987 mctx.error(newPanicErrorf(r, in))
1988 }
1989 }
1990 }()
1991 mctx.module.logicModule.GenerateBuildActions(mctx)
1992 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001993
Colin Cross7addea32015-03-11 15:43:52 -07001994 if len(mctx.errs) > 0 {
1995 errsCh <- mctx.errs
1996 return true
1997 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001998
Colin Cross036a1df2015-12-17 15:49:30 -08001999 if module.missingDeps != nil && !mctx.handledMissingDeps {
2000 var errs []error
2001 for _, depName := range module.missingDeps {
Colin Cross2c628442016-10-07 17:13:10 -07002002 errs = append(errs, &BlueprintError{
Colin Cross036a1df2015-12-17 15:49:30 -08002003 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07002004 module.Name(), depName),
Colin Cross036a1df2015-12-17 15:49:30 -08002005 Pos: module.pos,
2006 })
2007 }
2008 errsCh <- errs
2009 return true
2010 }
2011
Colin Cross7addea32015-03-11 15:43:52 -07002012 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002013
Colin Crossab6d7902015-03-11 16:17:52 -07002014 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002015 &mctx.actionDefs, liveGlobals)
2016 if len(newErrs) > 0 {
2017 errsCh <- newErrs
2018 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002019 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002020 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002021 })
2022
2023 cancelCh <- struct{}{}
2024 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002025
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002026 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002027}
2028
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002029func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002030 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002031
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002032 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002033 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002034
Yuchen Wub9103ef2015-08-25 17:58:17 -07002035 for _, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002036 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2037 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2038 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002039 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002040
2041 sctx := &singletonContext{
2042 context: c,
2043 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002044 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002045 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002046 }
2047
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002048 func() {
2049 defer func() {
2050 if r := recover(); r != nil {
2051 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2052 if err, ok := r.(panicError); ok {
2053 err.addIn(in)
2054 sctx.error(err)
2055 } else {
2056 sctx.error(newPanicErrorf(r, in))
2057 }
2058 }
2059 }()
2060 info.singleton.GenerateBuildActions(sctx)
2061 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002062
2063 if len(sctx.errs) > 0 {
2064 errs = append(errs, sctx.errs...)
2065 if len(errs) > maxErrors {
2066 break
2067 }
2068 continue
2069 }
2070
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002071 deps = append(deps, sctx.ninjaFileDeps...)
2072
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002073 newErrs := c.processLocalBuildActions(&info.actionDefs,
2074 &sctx.actionDefs, liveGlobals)
2075 errs = append(errs, newErrs...)
2076 if len(errs) > maxErrors {
2077 break
2078 }
2079 }
2080
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002081 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002082}
2083
2084func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2085 liveGlobals *liveTracker) []error {
2086
2087 var errs []error
2088
2089 // First we go through and add everything referenced by the module's
2090 // buildDefs to the live globals set. This will end up adding the live
2091 // locals to the set as well, but we'll take them out after.
2092 for _, def := range in.buildDefs {
2093 err := liveGlobals.AddBuildDefDeps(def)
2094 if err != nil {
2095 errs = append(errs, err)
2096 }
2097 }
2098
2099 if len(errs) > 0 {
2100 return errs
2101 }
2102
Colin Crossc9028482014-12-18 16:28:54 -08002103 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002104
2105 // We use the now-incorrect set of live "globals" to determine which local
2106 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002107 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002108 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002109 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002110 if isLive {
2111 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002112 }
2113 }
2114
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002115 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002116 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002117 if isLive {
2118 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002119 }
2120 }
2121
2122 return nil
2123}
2124
Yuchen Wu222e2452015-10-06 14:03:27 -07002125func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002126 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002127
2128 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002129 var visiting *moduleInfo
2130
2131 defer func() {
2132 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002133 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2134 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002135 }
2136 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002137
2138 var walk func(module *moduleInfo)
2139 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002140 for _, dep := range module.directDeps {
2141 if !visited[dep.module] {
2142 visited[dep.module] = true
2143 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002144 recurse := true
2145 if visitDown != nil {
2146 recurse = visitDown(dep, module)
2147 }
2148 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002149 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002150 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002151 if visitUp != nil {
2152 visitUp(dep, module)
2153 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002154 }
2155 }
2156 }
2157
2158 walk(topModule)
2159}
2160
Colin Cross9cfd1982016-10-11 09:58:53 -07002161type replace struct {
2162 from, to *moduleInfo
2163}
2164
Colin Crossc4e5b812016-10-12 10:45:05 -07002165type rename struct {
2166 group *moduleGroup
2167 name string
2168}
2169
Colin Cross0ce142c2016-12-09 10:29:05 -08002170func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Cross9cfd1982016-10-11 09:58:53 -07002171 targets := c.modulesFromName(name)
2172
2173 if targets == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002174 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002175 }
2176
Colin Cross9cfd1982016-10-11 09:58:53 -07002177 for _, m := range targets {
2178 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002179 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002180 }
2181 }
2182
Colin Cross0ce142c2016-12-09 10:29:05 -08002183 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002184}
2185
Colin Cross0ce142c2016-12-09 10:29:05 -08002186func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002187 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002188 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002189 group, name := rename.group, rename.name
2190 if name == group.name {
2191 continue
2192 }
2193
2194 existing := c.moduleNames[name]
2195 if existing != nil {
2196 errs = append(errs,
2197 &BlueprintError{
2198 Err: fmt.Errorf("renaming module %q to %q conflicts with existing module",
2199 group.name, name),
2200 Pos: group.modules[0].pos,
2201 },
2202 &BlueprintError{
2203 Err: fmt.Errorf("<-- existing module defined here"),
2204 Pos: existing.modules[0].pos,
2205 },
2206 )
2207 continue
2208 }
2209
2210 c.moduleNames[name] = group
2211 delete(c.moduleNames, group.name)
2212 group.name = name
2213 }
2214
Colin Cross0ce142c2016-12-09 10:29:05 -08002215 return errs
2216}
2217
2218func (c *Context) handleReplacements(replacements []replace) []error {
2219 var errs []error
2220 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002221 for _, m := range replace.from.reverseDeps {
2222 for i, d := range m.directDeps {
2223 if d.module == replace.from {
2224 m.directDeps[i].module = replace.to
2225 }
2226 }
2227 }
2228
2229 atomic.AddUint32(&c.depsModified, 1)
2230 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002231
Colin Crossc4e5b812016-10-12 10:45:05 -07002232 return errs
2233}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002234
Colin Cross0b7e83e2016-05-17 14:58:05 -07002235func (c *Context) modulesFromName(name string) []*moduleInfo {
2236 if group := c.moduleNames[name]; group != nil {
2237 return group.modules
2238 }
2239 return nil
2240}
2241
Jamie Gennisc15544d2014-09-24 20:26:52 -07002242func (c *Context) sortedModuleNames() []string {
2243 if c.cachedSortedModuleNames == nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002244 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleNames))
2245 for moduleName := range c.moduleNames {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002246 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2247 moduleName)
2248 }
2249 sort.Strings(c.cachedSortedModuleNames)
2250 }
2251
2252 return c.cachedSortedModuleNames
2253}
2254
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002255func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002256 var module *moduleInfo
2257
2258 defer func() {
2259 if r := recover(); r != nil {
2260 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2261 funcName(visit), module))
2262 }
2263 }()
2264
Jamie Gennisc15544d2014-09-24 20:26:52 -07002265 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002266 modules := c.modulesFromName(moduleName)
2267 for _, module = range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002268 visit(module.logicModule)
2269 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002270 }
2271}
2272
2273func (c *Context) visitAllModulesIf(pred func(Module) bool,
2274 visit func(Module)) {
2275
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002276 var module *moduleInfo
2277
2278 defer func() {
2279 if r := recover(); r != nil {
2280 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2281 funcName(pred), funcName(visit), module))
2282 }
2283 }()
2284
Jamie Gennisc15544d2014-09-24 20:26:52 -07002285 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002286 modules := c.modulesFromName(moduleName)
2287 for _, module := range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002288 if pred(module.logicModule) {
2289 visit(module.logicModule)
2290 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002291 }
2292 }
2293}
2294
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002295func (c *Context) visitAllModuleVariants(module *moduleInfo,
2296 visit func(Module)) {
2297
2298 var variant *moduleInfo
2299
2300 defer func() {
2301 if r := recover(); r != nil {
2302 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2303 module, funcName(visit), variant))
2304 }
2305 }()
2306
2307 for _, variant = range module.group.modules {
2308 visit(variant.logicModule)
2309 }
2310}
2311
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002312func (c *Context) requireNinjaVersion(major, minor, micro int) {
2313 if major != 1 {
2314 panic("ninja version with major version != 1 not supported")
2315 }
2316 if c.requiredNinjaMinor < minor {
2317 c.requiredNinjaMinor = minor
2318 c.requiredNinjaMicro = micro
2319 }
2320 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2321 c.requiredNinjaMicro = micro
2322 }
2323}
2324
Colin Crossa2599452015-11-18 16:01:01 -08002325func (c *Context) setNinjaBuildDir(value *ninjaString) {
2326 if c.ninjaBuildDir == nil {
2327 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002328 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002329}
2330
2331func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002332 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002333
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002334 pkgs := make(map[string]*packageContext)
2335 pkgNames := make(map[*packageContext]string)
2336 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002337
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002338 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002339 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002340 // This is a built-in rule and has no package.
2341 return
2342 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002343 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002344 // We've already processed this package.
2345 return
2346 }
2347
Jamie Gennis2fb20952014-10-03 02:49:58 -07002348 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002349 if present {
2350 // Short name collision. Both this package and the one that's
2351 // already there need to use their full names. We leave the short
2352 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002353 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002354 longPkgNames[otherPkg] = true
2355 } else {
2356 // No collision so far. Tentatively set the package's name to be
2357 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002358 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002359 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002360 }
2361 }
2362
2363 // We try to give all packages their short name, but when we get collisions
2364 // we need to use the full unique package name.
2365 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002366 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002367 }
2368 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002369 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002370 }
2371 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002372 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002373 }
2374
2375 // Add the packages that had collisions using their full unique names. This
2376 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002377 for pctx := range longPkgNames {
2378 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002379 }
2380
Dan Willemsena481ae22015-12-18 15:18:03 -08002381 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2382 deps := []string{}
2383 for _, pkg := range pkgs {
2384 deps = append(deps, pkg.ninjaFileDeps...)
2385 }
2386
2387 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002388}
2389
2390func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002391 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002392
2393 visited := make(map[Variable]bool) // variables that were already checked
2394 checking := make(map[Variable]bool) // variables actively being checked
2395
2396 var check func(v Variable) []Variable
2397
2398 check = func(v Variable) []Variable {
2399 visited[v] = true
2400 checking[v] = true
2401 defer delete(checking, v)
2402
2403 value := variables[v]
2404 for _, dep := range value.variables {
2405 if checking[dep] {
2406 // This is a cycle.
2407 return []Variable{dep, v}
2408 }
2409
2410 if !visited[dep] {
2411 cycle := check(dep)
2412 if cycle != nil {
2413 if cycle[0] == v {
2414 // We are the "start" of the cycle, so we're responsible
2415 // for generating the errors. The cycle list is in
2416 // reverse order because all the 'check' calls append
2417 // their own module to the list.
2418 msgs := []string{"detected variable reference cycle:"}
2419
2420 // Iterate backwards through the cycle list.
2421 curName := v.fullName(pkgNames)
2422 curValue := value.Value(pkgNames)
2423 for i := len(cycle) - 1; i >= 0; i-- {
2424 next := cycle[i]
2425 nextName := next.fullName(pkgNames)
2426 nextValue := variables[next].Value(pkgNames)
2427
2428 msgs = append(msgs, fmt.Sprintf(
2429 " %q depends on %q", curName, nextName))
2430 msgs = append(msgs, fmt.Sprintf(
2431 " [%s = %s]", curName, curValue))
2432
2433 curName = nextName
2434 curValue = nextValue
2435 }
2436
2437 // Variable reference cycles are a programming error,
2438 // not the fault of the Blueprint file authors.
2439 panic(strings.Join(msgs, "\n"))
2440 } else {
2441 // We're not the "start" of the cycle, so we just append
2442 // our module to the list and return it.
2443 return append(cycle, v)
2444 }
2445 }
2446 }
2447 }
2448
2449 return nil
2450 }
2451
2452 for v := range variables {
2453 if !visited[v] {
2454 cycle := check(v)
2455 if cycle != nil {
2456 panic("inconceivable!")
2457 }
2458 }
2459 }
2460}
2461
Jamie Gennisaf435562014-10-27 22:34:56 -07002462// AllTargets returns a map all the build target names to the rule used to build
2463// them. This is the same information that is output by running 'ninja -t
2464// targets all'. If this is called before PrepareBuildActions successfully
2465// completes then ErrbuildActionsNotReady is returned.
2466func (c *Context) AllTargets() (map[string]string, error) {
2467 if !c.buildActionsReady {
2468 return nil, ErrBuildActionsNotReady
2469 }
2470
2471 targets := map[string]string{}
2472
2473 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002474 for _, module := range c.moduleInfo {
2475 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002476 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002477 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002478 outputValue, err := output.Eval(c.globalVariables)
2479 if err != nil {
2480 return nil, err
2481 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002482 targets[outputValue] = ruleName
2483 }
2484 }
2485 }
2486
2487 // Collect all the singleton build targets.
2488 for _, info := range c.singletonInfo {
2489 for _, buildDef := range info.actionDefs.buildDefs {
2490 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002491 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002492 outputValue, err := output.Eval(c.globalVariables)
2493 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002494 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002495 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002496 targets[outputValue] = ruleName
2497 }
2498 }
2499 }
2500
2501 return targets, nil
2502}
2503
Colin Crossa2599452015-11-18 16:01:01 -08002504func (c *Context) NinjaBuildDir() (string, error) {
2505 if c.ninjaBuildDir != nil {
2506 return c.ninjaBuildDir.Eval(c.globalVariables)
2507 } else {
2508 return "", nil
2509 }
2510}
2511
Colin Cross4572edd2015-05-13 14:36:24 -07002512// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2513// property structs returned by the factory for that module type.
2514func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2515 ret := make(map[string][]interface{})
2516 for moduleType, factory := range c.moduleFactories {
2517 _, ret[moduleType] = factory()
2518 }
2519
2520 return ret
2521}
2522
2523func (c *Context) ModuleName(logicModule Module) string {
2524 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002525 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002526}
2527
2528func (c *Context) ModuleDir(logicModule Module) string {
2529 module := c.moduleInfo[logicModule]
2530 return filepath.Dir(module.relBlueprintsFile)
2531}
2532
Colin Cross8c602f72015-12-17 18:02:11 -08002533func (c *Context) ModuleSubDir(logicModule Module) string {
2534 module := c.moduleInfo[logicModule]
2535 return module.variantName
2536}
2537
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002538func (c *Context) ModuleType(logicModule Module) string {
2539 module := c.moduleInfo[logicModule]
2540 return module.typeName
2541}
2542
Colin Cross4572edd2015-05-13 14:36:24 -07002543func (c *Context) BlueprintFile(logicModule Module) string {
2544 module := c.moduleInfo[logicModule]
2545 return module.relBlueprintsFile
2546}
2547
2548func (c *Context) ModuleErrorf(logicModule Module, format string,
2549 args ...interface{}) error {
2550
2551 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002552 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002553 Err: fmt.Errorf(format, args...),
2554 Pos: module.pos,
2555 }
2556}
2557
2558func (c *Context) VisitAllModules(visit func(Module)) {
2559 c.visitAllModules(visit)
2560}
2561
2562func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2563 visit func(Module)) {
2564
2565 c.visitAllModulesIf(pred, visit)
2566}
2567
Colin Cross080c1332017-03-17 13:09:05 -07002568func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
2569 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07002570
Colin Cross080c1332017-03-17 13:09:05 -07002571 var visiting *moduleInfo
2572
2573 defer func() {
2574 if r := recover(); r != nil {
2575 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
2576 topModule, funcName(visit), visiting))
2577 }
2578 }()
2579
2580 for _, dep := range topModule.directDeps {
2581 visiting = dep.module
2582 visit(dep.module.logicModule)
2583 }
2584}
2585
2586func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
2587 topModule := c.moduleInfo[module]
2588
2589 var visiting *moduleInfo
2590
2591 defer func() {
2592 if r := recover(); r != nil {
2593 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
2594 topModule, funcName(pred), funcName(visit), visiting))
2595 }
2596 }()
2597
2598 for _, dep := range topModule.directDeps {
2599 visiting = dep.module
2600 if pred(dep.module.logicModule) {
2601 visit(dep.module.logicModule)
2602 }
2603 }
2604}
2605
2606func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002607 topModule := c.moduleInfo[module]
2608
2609 var visiting *moduleInfo
2610
2611 defer func() {
2612 if r := recover(); r != nil {
2613 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2614 topModule, funcName(visit), visiting))
2615 }
2616 }()
2617
2618 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2619 visiting = dep.module
2620 visit(dep.module.logicModule)
2621 })
Colin Cross4572edd2015-05-13 14:36:24 -07002622}
2623
Colin Cross080c1332017-03-17 13:09:05 -07002624func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002625 topModule := c.moduleInfo[module]
2626
2627 var visiting *moduleInfo
2628
2629 defer func() {
2630 if r := recover(); r != nil {
2631 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2632 topModule, funcName(pred), funcName(visit), visiting))
2633 }
2634 }()
2635
2636 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2637 if pred(dep.module.logicModule) {
2638 visiting = dep.module
2639 visit(dep.module.logicModule)
2640 }
2641 })
Colin Cross4572edd2015-05-13 14:36:24 -07002642}
2643
Colin Cross24ad5872015-11-17 16:22:29 -08002644func (c *Context) PrimaryModule(module Module) Module {
2645 return c.moduleInfo[module].group.modules[0].logicModule
2646}
2647
2648func (c *Context) FinalModule(module Module) Module {
2649 modules := c.moduleInfo[module].group.modules
2650 return modules[len(modules)-1].logicModule
2651}
2652
2653func (c *Context) VisitAllModuleVariants(module Module,
2654 visit func(Module)) {
2655
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002656 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002657}
2658
Jamie Gennisd4e10182014-06-12 20:06:50 -07002659// WriteBuildFile writes the Ninja manifeset text for the generated build
2660// actions to w. If this is called before PrepareBuildActions successfully
2661// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002662func (c *Context) WriteBuildFile(w io.Writer) error {
2663 if !c.buildActionsReady {
2664 return ErrBuildActionsNotReady
2665 }
2666
2667 nw := newNinjaWriter(w)
2668
2669 err := c.writeBuildFileHeader(nw)
2670 if err != nil {
2671 return err
2672 }
2673
2674 err = c.writeNinjaRequiredVersion(nw)
2675 if err != nil {
2676 return err
2677 }
2678
2679 // TODO: Group the globals by package.
2680
2681 err = c.writeGlobalVariables(nw)
2682 if err != nil {
2683 return err
2684 }
2685
2686 err = c.writeGlobalPools(nw)
2687 if err != nil {
2688 return err
2689 }
2690
2691 err = c.writeBuildDir(nw)
2692 if err != nil {
2693 return err
2694 }
2695
2696 err = c.writeGlobalRules(nw)
2697 if err != nil {
2698 return err
2699 }
2700
2701 err = c.writeAllModuleActions(nw)
2702 if err != nil {
2703 return err
2704 }
2705
2706 err = c.writeAllSingletonActions(nw)
2707 if err != nil {
2708 return err
2709 }
2710
2711 return nil
2712}
2713
Jamie Gennisc15544d2014-09-24 20:26:52 -07002714type pkgAssociation struct {
2715 PkgName string
2716 PkgPath string
2717}
2718
2719type pkgAssociationSorter struct {
2720 pkgs []pkgAssociation
2721}
2722
2723func (s *pkgAssociationSorter) Len() int {
2724 return len(s.pkgs)
2725}
2726
2727func (s *pkgAssociationSorter) Less(i, j int) bool {
2728 iName := s.pkgs[i].PkgName
2729 jName := s.pkgs[j].PkgName
2730 return iName < jName
2731}
2732
2733func (s *pkgAssociationSorter) Swap(i, j int) {
2734 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2735}
2736
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002737func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2738 headerTemplate := template.New("fileHeader")
2739 _, err := headerTemplate.Parse(fileHeaderTemplate)
2740 if err != nil {
2741 // This is a programming error.
2742 panic(err)
2743 }
2744
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002745 var pkgs []pkgAssociation
2746 maxNameLen := 0
2747 for pkg, name := range c.pkgNames {
2748 pkgs = append(pkgs, pkgAssociation{
2749 PkgName: name,
2750 PkgPath: pkg.pkgPath,
2751 })
2752 if len(name) > maxNameLen {
2753 maxNameLen = len(name)
2754 }
2755 }
2756
2757 for i := range pkgs {
2758 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2759 }
2760
Jamie Gennisc15544d2014-09-24 20:26:52 -07002761 sort.Sort(&pkgAssociationSorter{pkgs})
2762
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002763 params := map[string]interface{}{
2764 "Pkgs": pkgs,
2765 }
2766
2767 buf := bytes.NewBuffer(nil)
2768 err = headerTemplate.Execute(buf, params)
2769 if err != nil {
2770 return err
2771 }
2772
2773 return nw.Comment(buf.String())
2774}
2775
2776func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2777 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2778 c.requiredNinjaMicro)
2779
2780 err := nw.Assign("ninja_required_version", value)
2781 if err != nil {
2782 return err
2783 }
2784
2785 return nw.BlankLine()
2786}
2787
2788func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002789 if c.ninjaBuildDir != nil {
2790 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002791 if err != nil {
2792 return err
2793 }
2794
2795 err = nw.BlankLine()
2796 if err != nil {
2797 return err
2798 }
2799 }
2800 return nil
2801}
2802
Jamie Gennisc15544d2014-09-24 20:26:52 -07002803type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002804 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002805}
2806
Jamie Gennisc15544d2014-09-24 20:26:52 -07002807type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002808 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07002809 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002810}
2811
Jamie Gennisc15544d2014-09-24 20:26:52 -07002812func (s *globalEntitySorter) Len() int {
2813 return len(s.entities)
2814}
2815
2816func (s *globalEntitySorter) Less(i, j int) bool {
2817 iName := s.entities[i].fullName(s.pkgNames)
2818 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002819 return iName < jName
2820}
2821
Jamie Gennisc15544d2014-09-24 20:26:52 -07002822func (s *globalEntitySorter) Swap(i, j int) {
2823 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002824}
2825
2826func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
2827 visited := make(map[Variable]bool)
2828
2829 var walk func(v Variable) error
2830 walk = func(v Variable) error {
2831 visited[v] = true
2832
2833 // First visit variables on which this variable depends.
2834 value := c.globalVariables[v]
2835 for _, dep := range value.variables {
2836 if !visited[dep] {
2837 err := walk(dep)
2838 if err != nil {
2839 return err
2840 }
2841 }
2842 }
2843
2844 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
2845 if err != nil {
2846 return err
2847 }
2848
2849 err = nw.BlankLine()
2850 if err != nil {
2851 return err
2852 }
2853
2854 return nil
2855 }
2856
Jamie Gennisc15544d2014-09-24 20:26:52 -07002857 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
2858 for variable := range c.globalVariables {
2859 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002860 }
2861
Jamie Gennisc15544d2014-09-24 20:26:52 -07002862 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002863
Jamie Gennisc15544d2014-09-24 20:26:52 -07002864 for _, entity := range globalVariables {
2865 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002866 if !visited[v] {
2867 err := walk(v)
2868 if err != nil {
2869 return nil
2870 }
2871 }
2872 }
2873
2874 return nil
2875}
2876
2877func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002878 globalPools := make([]globalEntity, 0, len(c.globalPools))
2879 for pool := range c.globalPools {
2880 globalPools = append(globalPools, pool)
2881 }
2882
2883 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
2884
2885 for _, entity := range globalPools {
2886 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002887 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002888 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002889 err := def.WriteTo(nw, name)
2890 if err != nil {
2891 return err
2892 }
2893
2894 err = nw.BlankLine()
2895 if err != nil {
2896 return err
2897 }
2898 }
2899
2900 return nil
2901}
2902
2903func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002904 globalRules := make([]globalEntity, 0, len(c.globalRules))
2905 for rule := range c.globalRules {
2906 globalRules = append(globalRules, rule)
2907 }
2908
2909 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
2910
2911 for _, entity := range globalRules {
2912 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002913 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07002914 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002915 err := def.WriteTo(nw, name, c.pkgNames)
2916 if err != nil {
2917 return err
2918 }
2919
2920 err = nw.BlankLine()
2921 if err != nil {
2922 return err
2923 }
2924 }
2925
2926 return nil
2927}
2928
Colin Cross2c1f3d12016-04-11 15:47:28 -07002929type depSorter []depInfo
2930
2931func (s depSorter) Len() int {
2932 return len(s)
2933}
2934
2935func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002936 iName := s[i].module.Name()
2937 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07002938 if iName == jName {
2939 iName = s[i].module.variantName
2940 jName = s[j].module.variantName
2941 }
2942 return iName < jName
2943}
2944
2945func (s depSorter) Swap(i, j int) {
2946 s[i], s[j] = s[j], s[i]
2947}
2948
Colin Crossab6d7902015-03-11 16:17:52 -07002949type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07002950
Colin Crossab6d7902015-03-11 16:17:52 -07002951func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002952 return len(s)
2953}
2954
Colin Crossab6d7902015-03-11 16:17:52 -07002955func (s moduleSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002956 iName := s[i].Name()
2957 jName := s[j].Name()
Colin Crossab6d7902015-03-11 16:17:52 -07002958 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07002959 iName = s[i].variantName
2960 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07002961 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07002962 return iName < jName
2963}
2964
Colin Crossab6d7902015-03-11 16:17:52 -07002965func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002966 s[i], s[j] = s[j], s[i]
2967}
2968
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002969func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
2970 headerTemplate := template.New("moduleHeader")
2971 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2972 if err != nil {
2973 // This is a programming error.
2974 panic(err)
2975 }
2976
Colin Crossab6d7902015-03-11 16:17:52 -07002977 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
2978 for _, module := range c.moduleInfo {
2979 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07002980 }
Colin Crossab6d7902015-03-11 16:17:52 -07002981 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002982
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002983 buf := bytes.NewBuffer(nil)
2984
Colin Crossab6d7902015-03-11 16:17:52 -07002985 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07002986 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
2987 continue
2988 }
2989
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002990 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002991
2992 // In order to make the bootstrap build manifest independent of the
2993 // build dir we need to output the Blueprints file locations in the
2994 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07002995 relPos := module.pos
2996 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002997
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002998 // Get the name and location of the factory function for the module.
Colin Crossab6d7902015-03-11 16:17:52 -07002999 factory := c.moduleFactories[module.typeName]
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003000 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3001 factoryName := factoryFunc.Name()
3002
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003003 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003004 "name": module.Name(),
3005 "typeName": module.typeName,
3006 "goFactory": factoryName,
3007 "pos": relPos,
3008 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003009 }
3010 err = headerTemplate.Execute(buf, infoMap)
3011 if err != nil {
3012 return err
3013 }
3014
3015 err = nw.Comment(buf.String())
3016 if err != nil {
3017 return err
3018 }
3019
3020 err = nw.BlankLine()
3021 if err != nil {
3022 return err
3023 }
3024
Colin Crossab6d7902015-03-11 16:17:52 -07003025 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003026 if err != nil {
3027 return err
3028 }
3029
3030 err = nw.BlankLine()
3031 if err != nil {
3032 return err
3033 }
3034 }
3035
3036 return nil
3037}
3038
3039func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3040 headerTemplate := template.New("singletonHeader")
3041 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3042 if err != nil {
3043 // This is a programming error.
3044 panic(err)
3045 }
3046
3047 buf := bytes.NewBuffer(nil)
3048
Yuchen Wub9103ef2015-08-25 17:58:17 -07003049 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003050 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3051 continue
3052 }
3053
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003054 // Get the name of the factory function for the module.
3055 factory := info.factory
3056 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3057 factoryName := factoryFunc.Name()
3058
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003059 buf.Reset()
3060 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003061 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003062 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003063 }
3064 err = headerTemplate.Execute(buf, infoMap)
3065 if err != nil {
3066 return err
3067 }
3068
3069 err = nw.Comment(buf.String())
3070 if err != nil {
3071 return err
3072 }
3073
3074 err = nw.BlankLine()
3075 if err != nil {
3076 return err
3077 }
3078
3079 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3080 if err != nil {
3081 return err
3082 }
3083
3084 err = nw.BlankLine()
3085 if err != nil {
3086 return err
3087 }
3088 }
3089
3090 return nil
3091}
3092
3093func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3094 defs *localBuildActions) error {
3095
3096 // Write the local variable assignments.
3097 for _, v := range defs.variables {
3098 // A localVariable doesn't need the package names or config to
3099 // determine its name or value.
3100 name := v.fullName(nil)
3101 value, err := v.value(nil)
3102 if err != nil {
3103 panic(err)
3104 }
3105 err = nw.Assign(name, value.Value(c.pkgNames))
3106 if err != nil {
3107 return err
3108 }
3109 }
3110
3111 if len(defs.variables) > 0 {
3112 err := nw.BlankLine()
3113 if err != nil {
3114 return err
3115 }
3116 }
3117
3118 // Write the local rules.
3119 for _, r := range defs.rules {
3120 // A localRule doesn't need the package names or config to determine
3121 // its name or definition.
3122 name := r.fullName(nil)
3123 def, err := r.def(nil)
3124 if err != nil {
3125 panic(err)
3126 }
3127
3128 err = def.WriteTo(nw, name, c.pkgNames)
3129 if err != nil {
3130 return err
3131 }
3132
3133 err = nw.BlankLine()
3134 if err != nil {
3135 return err
3136 }
3137 }
3138
3139 // Write the build definitions.
3140 for _, buildDef := range defs.buildDefs {
3141 err := buildDef.WriteTo(nw, c.pkgNames)
3142 if err != nil {
3143 return err
3144 }
3145
3146 if len(buildDef.Args) > 0 {
3147 err = nw.BlankLine()
3148 if err != nil {
3149 return err
3150 }
3151 }
3152 }
3153
3154 return nil
3155}
3156
Colin Cross65569e42015-03-10 20:08:19 -07003157func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3158 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003159 if a == b {
3160 return false
3161 }
Colin Cross65569e42015-03-10 20:08:19 -07003162 for _, l := range list {
3163 if l == a {
3164 found = true
3165 } else if l == b {
3166 return found
3167 }
3168 }
3169
3170 missing := a
3171 if found {
3172 missing = b
3173 }
3174 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3175}
3176
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003177type panicError struct {
3178 panic interface{}
3179 stack []byte
3180 in string
3181}
3182
3183func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3184 buf := make([]byte, 4096)
3185 count := runtime.Stack(buf, false)
3186 return panicError{
3187 panic: panic,
3188 in: fmt.Sprintf(in, a...),
3189 stack: buf[:count],
3190 }
3191}
3192
3193func (p panicError) Error() string {
3194 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3195}
3196
3197func (p *panicError) addIn(in string) {
3198 p.in += " in " + in
3199}
3200
3201func funcName(f interface{}) string {
3202 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3203}
3204
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003205var fileHeaderTemplate = `******************************************************************************
3206*** This file is generated and should not be edited ***
3207******************************************************************************
3208{{if .Pkgs}}
3209This file contains variables, rules, and pools with name prefixes indicating
3210they were generated by the following Go packages:
3211{{range .Pkgs}}
3212 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3213
3214`
3215
3216var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003217Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003218Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003219Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003220Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003221Defined: {{.pos}}
3222`
3223
3224var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3225Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003226Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003227`