blob: f96306b9e3df02952286423a6d00085bf409283a [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"
Jeff Gastonc3e28442017-08-09 15:13:12 -070022 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070023 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070024 "path/filepath"
25 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070026 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070027 "sort"
28 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070029 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070030 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070031 "text/scanner"
32 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070033
34 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080035 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070036 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070037)
38
39var ErrBuildActionsNotReady = errors.New("build actions are not ready")
40
41const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080042const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070043
Jamie Gennisd4e10182014-06-12 20:06:50 -070044// A Context contains all the state needed to parse a set of Blueprints files
45// and generate a Ninja file. The process of generating a Ninja file proceeds
46// through a series of four phases. Each phase corresponds with a some methods
47// on the Context object
48//
49// Phase Methods
50// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070051// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070052//
53// 2. Parse ParseBlueprintsFiles, Parse
54//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070055// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070056//
57// 4. Write WriteBuildFile
58//
59// The registration phase prepares the context to process Blueprints files
60// containing various types of modules. The parse phase reads in one or more
61// Blueprints files and validates their contents against the module types that
62// have been registered. The generate phase then analyzes the parsed Blueprints
63// contents to create an internal representation for the build actions that must
64// be performed. This phase also performs validation of the module dependencies
65// and property values defined in the parsed Blueprints files. Finally, the
66// write phase generates the Ninja manifest text based on the generated build
67// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070068type Context struct {
69 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070070 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080071 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070072 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070073 moduleInfo map[Module]*moduleInfo
74 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080075 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070076 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070077 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070078 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070079 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070080
Colin Cross3702ac72016-08-11 11:09:00 -070081 depsModified uint32 // positive if a mutator modified the dependencies
82
Jamie Gennis1bc967e2014-05-27 16:34:41 -070083 dependenciesReady bool // set to true on a successful ResolveDependencies
84 buildActionsReady bool // set to true on a successful PrepareBuildActions
85
86 // set by SetIgnoreUnknownModuleTypes
87 ignoreUnknownModuleTypes bool
88
Colin Cross036a1df2015-12-17 15:49:30 -080089 // set by SetAllowMissingDependencies
90 allowMissingDependencies bool
91
Jamie Gennis1bc967e2014-05-27 16:34:41 -070092 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080093 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080094 liveGlobals *liveTracker
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095 globalVariables map[Variable]*ninjaString
96 globalPools map[Pool]*poolDef
97 globalRules map[Rule]*ruleDef
98
99 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -0800100 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101 requiredNinjaMajor int // For the ninja_required_version variable
102 requiredNinjaMinor int // For the ninja_required_version variable
103 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700104
Jeff Gastond70bf752017-11-10 15:12:08 -0800105 // set lazily by sortedModuleGroups
106 cachedSortedModuleGroups []*moduleGroup
Colin Crossd7b0f602016-06-02 15:30:20 -0700107
Colin Cross127d2ea2016-11-01 11:10:51 -0700108 globs map[string]GlobPath
109 globLock sync.Mutex
110
Jeff Gastonc3e28442017-08-09 15:13:12 -0700111 fs pathtools.FileSystem
112 moduleListFile string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700113}
114
Jamie Gennisd4e10182014-06-12 20:06:50 -0700115// An Error describes a problem that was encountered that is related to a
116// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700117type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700118 Err error // the error that occurred
119 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700120}
121
Colin Cross2c628442016-10-07 17:13:10 -0700122// A ModuleError describes a problem that was encountered that is related to a
123// particular module in a Blueprints file
124type ModuleError struct {
125 BlueprintError
126 module *moduleInfo
127}
128
129// A PropertyError describes a problem that was encountered that is related to a
130// particular property in a Blueprints file
131type PropertyError struct {
132 ModuleError
133 property string
134}
135
136func (e *BlueprintError) Error() string {
137 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
138}
139
140func (e *ModuleError) Error() string {
141 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
142}
143
144func (e *PropertyError) Error() string {
145 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
146}
147
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700148type localBuildActions struct {
149 variables []*localVariable
150 rules []*localRule
151 buildDefs []*buildDef
152}
153
Colin Crossbbfa51a2014-12-17 16:12:41 -0800154type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700155 name string
156 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700157
Colin Crossbbfa51a2014-12-17 16:12:41 -0800158 modules []*moduleInfo
Jeff Gastond70bf752017-11-10 15:12:08 -0800159
160 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700161}
162
Colin Crossbbfa51a2014-12-17 16:12:41 -0800163type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700164 // set during Parse
165 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700166 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700167 relBlueprintsFile string
168 pos scanner.Position
169 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700170
Colin Crossf5e34b92015-03-13 16:02:36 -0700171 variantName string
172 variant variationMap
173 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700174
Colin Crossd2f4ac12017-07-28 14:31:03 -0700175 logicModule Module
176 group *moduleGroup
177 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800178
179 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700180 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800181 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800182
Colin Cross7addea32015-03-11 15:43:52 -0700183 // set during updateDependencies
184 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700185 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700186
187 // used by parallelVisitAllBottomUp
188 waitingCount int
189
Colin Crossc9028482014-12-18 16:28:54 -0800190 // set during each runMutator
191 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700192
193 // set during PrepareBuildActions
194 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800195}
196
Colin Cross2c1f3d12016-04-11 15:47:28 -0700197type depInfo struct {
198 module *moduleInfo
199 tag DependencyTag
200}
201
Colin Cross0b7e83e2016-05-17 14:58:05 -0700202func (module *moduleInfo) Name() string {
203 return module.group.name
204}
205
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800206func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700207 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800208 if module.variantName != "" {
209 s += fmt.Sprintf(" variant %q", module.variantName)
210 }
211 return s
212}
213
Jeff Gastond70bf752017-11-10 15:12:08 -0800214func (module *moduleInfo) namespace() Namespace {
215 return module.group.namespace
216}
217
Colin Crossf5e34b92015-03-13 16:02:36 -0700218// A Variation is a way that a variant of a module differs from other variants of the same module.
219// For example, two variants of the same module might have Variation{"arch","arm"} and
220// Variation{"arch","arm64"}
221type Variation struct {
222 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700223 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700224 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
225 // "shared" or "static" for link.
226 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700227}
228
Colin Crossf5e34b92015-03-13 16:02:36 -0700229// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
230type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700231
Colin Crossf5e34b92015-03-13 16:02:36 -0700232func (vm variationMap) clone() variationMap {
233 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700234 for k, v := range vm {
235 newVm[k] = v
236 }
237
238 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800239}
240
Colin Cross89486232015-05-08 11:14:54 -0700241// Compare this variationMap to another one. Returns true if the every entry in this map
242// is either the same in the other map or doesn't exist in the other map.
243func (vm variationMap) subset(other variationMap) bool {
244 for k, v1 := range vm {
245 if v2, ok := other[k]; ok && v1 != v2 {
246 return false
247 }
248 }
249 return true
250}
251
Colin Crossf5e34b92015-03-13 16:02:36 -0700252func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700253 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800254}
255
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700256type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700257 // set during RegisterSingletonType
258 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700259 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700260 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700261
262 // set during PrepareBuildActions
263 actionDefs localBuildActions
264}
265
Colin Crossc9028482014-12-18 16:28:54 -0800266type mutatorInfo struct {
267 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800268 topDownMutator TopDownMutator
269 bottomUpMutator BottomUpMutator
270 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700271 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800272}
273
Colin Crossaf4fd212017-07-28 14:32:36 -0700274func newContext() *Context {
275 return &Context{
Colin Cross5f03f112017-11-07 13:29:54 -0800276 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800277 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800278 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross5f03f112017-11-07 13:29:54 -0800279 globs: make(map[string]GlobPath),
280 fs: pathtools.OsFs,
281 ninjaBuildDir: nil,
282 requiredNinjaMajor: 1,
283 requiredNinjaMinor: 7,
284 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700285 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700286}
287
288// NewContext creates a new Context object. The created context initially has
289// no module or singleton factories registered, so the RegisterModuleFactory and
290// RegisterSingletonFactory methods must be called before it can do anything
291// useful.
292func NewContext() *Context {
293 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700294
295 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
296
297 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700298}
299
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700300// A ModuleFactory function creates a new Module object. See the
301// Context.RegisterModuleType method for details about how a registered
302// ModuleFactory is used by a Context.
303type ModuleFactory func() (m Module, propertyStructs []interface{})
304
Jamie Gennisd4e10182014-06-12 20:06:50 -0700305// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700306// Blueprints file) with a Module factory function. When the given module type
307// name is encountered in a Blueprints file during parsing, the Module factory
308// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800309// generation for the module. If a Mutator splits a module into multiple variants,
310// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700311//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700312// The module type names given here must be unique for the context. The factory
313// function should be a named function so that its package and name can be
314// included in the generated Ninja file for debugging purposes.
315//
316// The factory function returns two values. The first is the newly created
317// Module object. The second is a slice of pointers to that Module object's
318// properties structs. Each properties struct is examined when parsing a module
319// definition of this type in a Blueprints file. Exported fields of the
320// properties structs are automatically set to the property values specified in
321// the Blueprints file. The properties struct field names determine the name of
322// the Blueprints file properties that are used - the Blueprints property name
323// matches that of the properties struct field name with the first letter
324// converted to lower-case.
325//
326// The fields of the properties struct must be either []string, a string, or
327// bool. The Context will panic if a Module gets instantiated with a properties
328// struct containing a field that is not one these supported types.
329//
330// Any properties that appear in the Blueprints files that are not built-in
331// module properties (such as "name" and "deps") and do not have a corresponding
332// field in the returned module properties struct result in an error during the
333// Context's parse phase.
334//
335// As an example, the follow code:
336//
337// type myModule struct {
338// properties struct {
339// Foo string
340// Bar []string
341// }
342// }
343//
344// func NewMyModule() (blueprint.Module, []interface{}) {
345// module := new(myModule)
346// properties := &module.properties
347// return module, []interface{}{properties}
348// }
349//
350// func main() {
351// ctx := blueprint.NewContext()
352// ctx.RegisterModuleType("my_module", NewMyModule)
353// // ...
354// }
355//
356// would support parsing a module defined in a Blueprints file as follows:
357//
358// my_module {
359// name: "myName",
360// foo: "my foo string",
361// bar: ["my", "bar", "strings"],
362// }
363//
Colin Cross7ad621c2015-01-07 16:22:45 -0800364// The factory function may be called from multiple goroutines. Any accesses
365// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700366func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
367 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700368 panic(errors.New("module type name is already registered"))
369 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700370 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700371}
372
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700373// A SingletonFactory function creates a new Singleton object. See the
374// Context.RegisterSingletonType method for details about how a registered
375// SingletonFactory is used by a Context.
376type SingletonFactory func() Singleton
377
378// RegisterSingletonType registers a singleton type that will be invoked to
379// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700380// and invoked exactly once as part of the generate phase. Each registered
381// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700382//
383// The singleton type names given here must be unique for the context. The
384// factory function should be a named function so that its package and name can
385// be included in the generated Ninja file for debugging purposes.
386func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700387 for _, s := range c.singletonInfo {
388 if s.name == name {
389 panic(errors.New("singleton name is already registered"))
390 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700391 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700392
Yuchen Wub9103ef2015-08-25 17:58:17 -0700393 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700394 factory: factory,
395 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700396 name: name,
397 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398}
399
Colin Cross5f03f112017-11-07 13:29:54 -0800400// RegisterPreSingletonType registers a presingleton type that will be invoked to
401// generate build actions before any Blueprint files have been read. Each registered
402// presingleton type is instantiated and invoked exactly once at the beginning of the
403// parse phase. Each registered presingleton is invoked in registration order.
404//
405// The presingleton type names given here must be unique for the context. The
406// factory function should be a named function so that its package and name can
407// be included in the generated Ninja file for debugging purposes.
408func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
409 for _, s := range c.preSingletonInfo {
410 if s.name == name {
411 panic(errors.New("presingleton name is already registered"))
412 }
413 }
414
415 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
416 factory: factory,
417 singleton: factory(),
418 name: name,
419 })
420}
421
Jeff Gastond70bf752017-11-10 15:12:08 -0800422func (c *Context) SetNameInterface(i NameInterface) {
423 c.nameInterface = i
424}
425
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700426func singletonPkgPath(singleton Singleton) string {
427 typ := reflect.TypeOf(singleton)
428 for typ.Kind() == reflect.Ptr {
429 typ = typ.Elem()
430 }
431 return typ.PkgPath()
432}
433
434func singletonTypeName(singleton Singleton) string {
435 typ := reflect.TypeOf(singleton)
436 for typ.Kind() == reflect.Ptr {
437 typ = typ.Elem()
438 }
439 return typ.PkgPath() + "." + typ.Name()
440}
441
Colin Cross3702ac72016-08-11 11:09:00 -0700442// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
443// top-down between Modules. Each registered mutator is invoked in registration order (mixing
444// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
445// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800446//
Colin Cross65569e42015-03-10 20:08:19 -0700447// The mutator type names given here must be unique to all top down mutators in
448// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700449//
450// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
451// parallel while maintaining ordering.
452func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800453 for _, m := range c.mutatorInfo {
454 if m.name == name && m.topDownMutator != nil {
455 panic(fmt.Errorf("mutator name %s is already registered", name))
456 }
457 }
458
Colin Cross3702ac72016-08-11 11:09:00 -0700459 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800460 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800461 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700462 }
463
464 c.mutatorInfo = append(c.mutatorInfo, info)
465
466 return info
Colin Crossc9028482014-12-18 16:28:54 -0800467}
468
Colin Cross3702ac72016-08-11 11:09:00 -0700469// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
470// Each registered mutator is invoked in registration order (mixing TopDownMutators and
471// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
472// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800473//
Colin Cross65569e42015-03-10 20:08:19 -0700474// The mutator type names given here must be unique to all bottom up or early
475// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700476//
Colin Cross3702ac72016-08-11 11:09:00 -0700477// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
478// parallel while maintaining ordering.
479func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700480 for _, m := range c.variantMutatorNames {
481 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800482 panic(fmt.Errorf("mutator name %s is already registered", name))
483 }
484 }
485
Colin Cross49c279a2016-08-05 22:30:44 -0700486 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800487 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800488 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700489 }
490 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700491
492 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700493
494 return info
495}
496
Colin Cross3702ac72016-08-11 11:09:00 -0700497type MutatorHandle interface {
498 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
499 // method on the mutator context is thread-safe, but the mutator must handle synchronization
500 // for any modifications to global state or any modules outside the one it was invoked on.
501 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700502}
503
Colin Cross3702ac72016-08-11 11:09:00 -0700504func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700505 mutator.parallel = true
506 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700507}
508
509// RegisterEarlyMutator registers a mutator that will be invoked to split
510// Modules into multiple variant Modules before any dependencies have been
511// created. Each registered mutator is invoked in registration order once
512// per Module (including each variant from previous early mutators). Module
513// order is unpredictable.
514//
515// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700516// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700517//
518// The mutator type names given here must be unique to all bottom up or early
519// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700520//
521// Deprecated, use a BottomUpMutator instead. The only difference between
522// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
523// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700524func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
525 for _, m := range c.variantMutatorNames {
526 if m == name {
527 panic(fmt.Errorf("mutator name %s is already registered", name))
528 }
529 }
530
Colin Crossf8b50422016-08-10 12:56:40 -0700531 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
532 bottomUpMutator: func(mctx BottomUpMutatorContext) {
533 mutator(mctx)
534 },
535 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700536 })
537
538 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800539}
540
Jamie Gennisd4e10182014-06-12 20:06:50 -0700541// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
542// where it encounters an unknown module type while parsing Blueprints files. By
543// default, the context will report unknown module types as an error. If this
544// method is called with ignoreUnknownModuleTypes set to true then the context
545// will silently ignore unknown module types.
546//
547// This method should generally not be used. It exists to facilitate the
548// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700549func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
550 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
551}
552
Colin Cross036a1df2015-12-17 15:49:30 -0800553// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
554// unresolved dependencies. If the module's GenerateBuildActions calls
555// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
556// for missing dependencies.
557func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
558 c.allowMissingDependencies = allowMissingDependencies
559}
560
Jeff Gastonc3e28442017-08-09 15:13:12 -0700561func (c *Context) SetModuleListFile(listFile string) {
562 c.moduleListFile = listFile
563}
564
565func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
566 reader, err := c.fs.Open(c.moduleListFile)
567 if err != nil {
568 return nil, err
569 }
570 bytes, err := ioutil.ReadAll(reader)
571 if err != nil {
572 return nil, err
573 }
574 text := string(bytes)
575
576 text = strings.Trim(text, "\n")
577 lines := strings.Split(text, "\n")
578 for i := range lines {
579 lines[i] = filepath.Join(baseDir, lines[i])
580 }
581
582 return lines, nil
583}
584
Jeff Gaston656870f2017-11-29 18:37:31 -0800585// a fileParseContext tells the status of parsing a particular file
586type fileParseContext struct {
587 // name of file
588 fileName string
589
590 // scope to use when resolving variables
591 Scope *parser.Scope
592
593 // pointer to the one in the parent directory
594 parent *fileParseContext
595
596 // is closed once FileHandler has completed for this file
597 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700598}
599
Jeff Gastonc3e28442017-08-09 15:13:12 -0700600func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
601 baseDir := filepath.Dir(rootFile)
602 pathsToParse, err := c.ListModulePaths(baseDir)
603 if err != nil {
604 return nil, []error{err}
605 }
606 return c.ParseFileList(baseDir, pathsToParse)
607}
608
Jamie Gennisd4e10182014-06-12 20:06:50 -0700609// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
610// at rootFile. When it encounters a Blueprints file with a set of subdirs
611// listed it recursively parses any Blueprints files found in those
612// subdirectories.
613//
614// If no errors are encountered while parsing the files, the list of paths on
615// which the future output will depend is returned. This list will include both
616// Blueprints file paths as well as directory paths for cases where wildcard
617// subdirs are found.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700618func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700619 errs []error) {
620
Jeff Gastonc3e28442017-08-09 15:13:12 -0700621 if len(filePaths) < 1 {
622 return nil, []error{fmt.Errorf("no paths provided to parse")}
623 }
624
Colin Cross7ad621c2015-01-07 16:22:45 -0800625 c.dependenciesReady = false
626
Colin Cross23d7aa12015-06-30 16:05:22 -0700627 moduleCh := make(chan *moduleInfo)
628 errsCh := make(chan []error)
629 doneCh := make(chan struct{})
630 var numErrs uint32
631 var numGoroutines int32
632
633 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700634 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700635 if atomic.LoadUint32(&numErrs) > maxErrors {
636 return
637 }
638
Jeff Gaston656870f2017-11-29 18:37:31 -0800639 for _, def := range file.Defs {
640 var module *moduleInfo
641 var errs []error
642 switch def := def.(type) {
643 case *parser.Module:
644 module, errs = c.processModuleDef(def, file.Name)
645 case *parser.Assignment:
646 // Already handled via Scope object
647 default:
648 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700649 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800650
651 if len(errs) > 0 {
652 atomic.AddUint32(&numErrs, uint32(len(errs)))
653 errsCh <- errs
654 } else if module != nil {
655 moduleCh <- module
656 }
657 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700658 }
659
660 atomic.AddInt32(&numGoroutines, 1)
661 go func() {
662 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700663 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700664 if len(errs) > 0 {
665 errsCh <- errs
666 }
667 doneCh <- struct{}{}
668 }()
669
670loop:
671 for {
672 select {
673 case newErrs := <-errsCh:
674 errs = append(errs, newErrs...)
675 case module := <-moduleCh:
676 newErrs := c.addModule(module)
677 if len(newErrs) > 0 {
678 errs = append(errs, newErrs...)
679 }
680 case <-doneCh:
681 n := atomic.AddInt32(&numGoroutines, -1)
682 if n == 0 {
683 break loop
684 }
685 }
686 }
687
688 return deps, errs
689}
690
691type FileHandler func(*parser.File)
692
Jeff Gastonc3e28442017-08-09 15:13:12 -0700693// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
694// calling the given file handler on each
695//
696// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
697// it recursively parses any Blueprints files found in those subdirectories.
698//
699// If any of the file paths is an ancestor directory of any other of file path, the ancestor
700// will be parsed and visited first.
701//
702// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700703//
704// If no errors are encountered while parsing the files, the list of paths on
705// which the future output will depend is returned. This list will include both
706// Blueprints file paths as well as directory paths for cases where wildcard
707// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800708//
709// visitor will be called asynchronously, and will only be called once visitor for each
710// ancestor directory has completed.
711//
712// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700713func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
714 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700715
Jeff Gastonc3e28442017-08-09 15:13:12 -0700716 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
717 descendantsMap, err := findBlueprintDescendants(filePaths)
718 if err != nil {
719 panic(err.Error())
720 return nil, []error{err}
721 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800722 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700723
Jeff Gaston5800d042017-12-05 14:57:58 -0800724 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800725 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800726 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800727 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700728
Jeff Gaston5800d042017-12-05 14:57:58 -0800729 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800730 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700731
Colin Cross7ad621c2015-01-07 16:22:45 -0800732 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700733 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800734 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700735 tooManyErrors := false
736
737 // Limit concurrent calls to parseBlueprintFiles to 200
738 // Darwin has a default limit of 256 open files
739 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800740
Jeff Gaston656870f2017-11-29 18:37:31 -0800741 // count the number of pending calls to visitor()
742 visitorWaitGroup := sync.WaitGroup{}
743
744 startParseBlueprintsFile := func(blueprint fileParseContext) {
745 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700746 return
747 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800748 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700749 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800750 deps = append(deps, blueprint.fileName)
751 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800752 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800753 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
754 &blueprint)
755 if len(errs) > 0 {
756 errsCh <- errs
757 }
758 for _, blueprint := range blueprints {
759 blueprintsCh <- blueprint
760 }
761 for _, dep := range deps {
762 depsCh <- dep
763 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800764 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700765
Jeff Gaston656870f2017-11-29 18:37:31 -0800766 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
767 // wait for visitor() of parent to complete
768 <-blueprint.parent.doneVisiting
769 }
770
Jeff Gastona7e408a2017-12-05 15:11:55 -0800771 if len(errs) == 0 {
772 // process this file
773 visitor(file)
774 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800775 if blueprint.doneVisiting != nil {
776 close(blueprint.doneVisiting)
777 }
778 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800779 }()
780 }
781
Jeff Gaston656870f2017-11-29 18:37:31 -0800782 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700783 if activeCount >= maxActiveCount {
784 pending = append(pending, blueprint)
785 } else {
786 startParseBlueprintsFile(blueprint)
787 }
788 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800789
Jeff Gaston656870f2017-11-29 18:37:31 -0800790 startParseDescendants := func(blueprint fileParseContext) {
791 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700792 if hasDescendants {
793 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800794 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700795 }
796 }
797 }
Colin Cross4a02a302017-05-16 10:33:58 -0700798
Jeff Gastonc3e28442017-08-09 15:13:12 -0700799 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800800 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800801
802loop:
803 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700804 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800805 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700806 }
807
Colin Cross7ad621c2015-01-07 16:22:45 -0800808 select {
809 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700810 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800811 case dep := <-depsCh:
812 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800813 case blueprint := <-blueprintsCh:
814 if tooManyErrors {
815 continue
816 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700817 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800818 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700819 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700820 if !tooManyErrors {
821 startParseDescendants(blueprint)
822 }
823 if activeCount < maxActiveCount && len(pending) > 0 {
824 // start to process the next one from the queue
825 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700826 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700827 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700828 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700829 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800830 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700831 }
832 }
833 }
834
Jeff Gastonc3e28442017-08-09 15:13:12 -0700835 sort.Strings(deps)
836
Jeff Gaston656870f2017-11-29 18:37:31 -0800837 // wait for every visitor() to complete
838 visitorWaitGroup.Wait()
839
Colin Cross7ad621c2015-01-07 16:22:45 -0800840 return
841}
842
Colin Crossd7b0f602016-06-02 15:30:20 -0700843// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
844// filenames to contents stored as a byte slice.
845func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800846 // look for a module list file
847 _, ok := files[MockModuleListFile]
848 if !ok {
849 // no module list file specified; find every file named Blueprints
850 pathsToParse := []string{}
851 for candidate := range files {
852 if filepath.Base(candidate) == "Blueprints" {
853 pathsToParse = append(pathsToParse, candidate)
854 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700855 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800856 if len(pathsToParse) < 1 {
857 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
858 }
859 // put the list of Blueprints files into a list file
860 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700861 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800862 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700863
864 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800865 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700866}
867
Jeff Gaston8fd95782017-12-05 15:03:51 -0800868// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -0800869func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -0800870 parent *fileParseContext) (file *parser.File,
871 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800872
Colin Crossd7b0f602016-06-02 15:30:20 -0700873 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800874 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700875 // couldn't open the file; see if we can provide a clearer error than "could not open file"
876 stats, statErr := c.fs.Lstat(filename)
877 if statErr == nil {
878 isSymlink := stats.Mode()&os.ModeSymlink != 0
879 if isSymlink {
880 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
881 target, readlinkErr := os.Readlink(filename)
882 if readlinkErr == nil {
883 _, targetStatsErr := c.fs.Lstat(target)
884 if targetStatsErr != nil {
885 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
886 }
887 }
888 } else {
889 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
890 }
891 }
Jeff Gaston8fd95782017-12-05 15:03:51 -0800892 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700893 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800894
Jeff Gaston8fd95782017-12-05 15:03:51 -0800895 func() {
896 defer func() {
897 err = f.Close()
898 if err != nil {
899 errs = append(errs, err)
900 }
901 }()
902 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -0700903 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700904
Colin Cross7ad621c2015-01-07 16:22:45 -0800905 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800906 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -0800907 }
908
Colin Cross1fef5362015-04-20 16:50:54 -0700909 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800910 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -0700911 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800912
Jeff Gaston8fd95782017-12-05 15:03:51 -0800913 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -0700914}
915
Jeff Gastona12f22f2017-08-08 14:45:56 -0700916// parseOne parses a single Blueprints file from the given reader, creating Module
917// objects for each of the module definitions encountered. If the Blueprints
918// file contains an assignment to the "subdirs" variable, then the
919// subdirectories listed are searched for Blueprints files returned in the
920// subBlueprints return value. If the Blueprints file contains an assignment
921// to the "build" variable, then the file listed are returned in the
922// subBlueprints return value.
923//
924// rootDir specifies the path to the root directory of the source tree, while
925// filename specifies the path to the Blueprints file. These paths are used for
926// error reporting and for determining the module's directory.
927func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -0800928 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -0700929
930 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
931 if err != nil {
932 return nil, nil, []error{err}
933 }
934
Jeff Gastona12f22f2017-08-08 14:45:56 -0700935 scope.Remove("subdirs")
936 scope.Remove("optional_subdirs")
937 scope.Remove("build")
938 file, errs = parser.ParseAndEval(filename, reader, scope)
939 if len(errs) > 0 {
940 for i, err := range errs {
941 if parseErr, ok := err.(*parser.ParseError); ok {
942 err = &BlueprintError{
943 Err: parseErr.Err,
944 Pos: parseErr.Pos,
945 }
946 errs[i] = err
947 }
948 }
949
950 // If there were any parse errors don't bother trying to interpret the
951 // result.
952 return nil, nil, errs
953 }
954 file.Name = relBlueprintsFile
955
Jeff Gastona12f22f2017-08-08 14:45:56 -0700956 build, buildPos, err := getLocalStringListFromScope(scope, "build")
957 if err != nil {
958 errs = append(errs, err)
959 }
Jeff Gastonf23e3662017-11-30 17:31:43 -0800960 for _, buildEntry := range build {
961 if strings.Contains(buildEntry, "/") {
962 errs = append(errs, &BlueprintError{
963 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
964 Pos: buildPos,
965 })
966 }
967 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700968
969 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
970 if err != nil {
971 errs = append(errs, err)
972 }
973
974 if subBlueprintsName == "" {
975 subBlueprintsName = "Blueprints"
976 }
977
978 var blueprints []string
979
980 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
981 blueprints = append(blueprints, newBlueprints...)
982 errs = append(errs, newErrs...)
983
Jeff Gaston656870f2017-11-29 18:37:31 -0800984 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -0700985 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -0800986 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -0700987 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700988 return file, subBlueprintsAndScope, errs
989}
990
Colin Cross7f507402015-12-16 13:03:41 -0800991func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -0700992 buildPos scanner.Position) ([]string, []error) {
993
994 var blueprints []string
995 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -0800996
997 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -0700998 pattern := filepath.Join(dir, file)
999 var matches []string
1000 var err error
1001
Colin Cross08e49542016-11-14 15:23:33 -08001002 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001003
Colin Cross7f507402015-12-16 13:03:41 -08001004 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001005 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001006 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001007 Pos: buildPos,
1008 })
1009 continue
1010 }
1011
1012 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001013 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001014 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001015 Pos: buildPos,
1016 })
1017 }
1018
Colin Cross7f507402015-12-16 13:03:41 -08001019 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001020 if strings.HasSuffix(foundBlueprints, "/") {
1021 errs = append(errs, &BlueprintError{
1022 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1023 Pos: buildPos,
1024 })
1025 }
Colin Cross7f507402015-12-16 13:03:41 -08001026 blueprints = append(blueprints, foundBlueprints)
1027 }
1028 }
1029
Colin Cross127d2ea2016-11-01 11:10:51 -07001030 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001031}
1032
1033func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001034 subBlueprintsName string, optional bool) ([]string, []error) {
1035
1036 var blueprints []string
1037 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001038
1039 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001040 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1041 var matches []string
1042 var err error
1043
Colin Cross08e49542016-11-14 15:23:33 -08001044 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001045
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001046 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001047 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001048 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001049 Pos: subdirsPos,
1050 })
1051 continue
1052 }
1053
Colin Cross7f507402015-12-16 13:03:41 -08001054 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001055 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001056 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001057 Pos: subdirsPos,
1058 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001059 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001060
Colin Cross127d2ea2016-11-01 11:10:51 -07001061 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001062 if strings.HasSuffix(subBlueprints, "/") {
1063 errs = append(errs, &BlueprintError{
1064 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1065 Pos: subdirsPos,
1066 })
1067 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001068 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001069 }
1070 }
Colin Cross1fef5362015-04-20 16:50:54 -07001071
Colin Cross127d2ea2016-11-01 11:10:51 -07001072 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001073}
1074
Colin Cross6d8780f2015-07-10 17:51:55 -07001075func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1076 if assignment, local := scope.Get(v); assignment == nil || !local {
1077 return nil, scanner.Position{}, nil
1078 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001079 switch value := assignment.Value.Eval().(type) {
1080 case *parser.List:
1081 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001082
Colin Crosse32cc802016-06-07 12:28:16 -07001083 for _, listValue := range value.Values {
1084 s, ok := listValue.(*parser.String)
1085 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001086 // The parser should not produce this.
1087 panic("non-string value found in list")
1088 }
1089
Colin Crosse32cc802016-06-07 12:28:16 -07001090 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001091 }
1092
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001093 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001094 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001095 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001096 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001097 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001098 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001099 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001100 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001101 }
1102 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001103}
1104
Colin Cross29394222015-04-27 13:18:21 -07001105func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001106 if assignment, _ := scope.Get(v); assignment == nil {
1107 return "", scanner.Position{}, nil
1108 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001109 switch value := assignment.Value.Eval().(type) {
1110 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001111 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001112 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001113 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001114 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001115 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001116 }
1117 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001118 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001119 }
1120 }
Colin Cross29394222015-04-27 13:18:21 -07001121}
1122
Colin Cross910242b2016-04-11 15:41:52 -07001123// Clones a build logic module by calling the factory method for its module type, and then cloning
1124// property values. Any values stored in the module object that are not stored in properties
1125// structs will be lost.
1126func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001127 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001128
Colin Crossd2f4ac12017-07-28 14:31:03 -07001129 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001130 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001131 }
1132
1133 for i := range newProperties {
1134 dst := reflect.ValueOf(newProperties[i]).Elem()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001135 src := reflect.ValueOf(origModule.properties[i]).Elem()
Colin Cross910242b2016-04-11 15:41:52 -07001136
1137 proptools.CopyProperties(dst, src)
1138 }
1139
1140 return newLogicModule, newProperties
1141}
1142
Colin Crossf5e34b92015-03-13 16:02:36 -07001143func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
1144 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001145
Colin Crossf4d18a62015-03-18 17:43:15 -07001146 if len(variationNames) == 0 {
1147 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001148 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001149 }
1150
Colin Crossc9028482014-12-18 16:28:54 -08001151 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001152
Colin Cross174ae052015-03-03 17:37:03 -08001153 var errs []error
1154
Colin Crossf5e34b92015-03-13 16:02:36 -07001155 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001156 var newLogicModule Module
1157 var newProperties []interface{}
1158
1159 if i == 0 {
1160 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001161 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1162 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001163 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001164 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001165 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001166 }
1167
Colin Crossf5e34b92015-03-13 16:02:36 -07001168 newVariant := origModule.variant.clone()
1169 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001170
Colin Crossed342d92015-03-11 00:57:25 -07001171 m := *origModule
1172 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001173 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001174 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001175 newModule.variant = newVariant
1176 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001177 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001178
Colin Crossbadc8812016-08-11 17:01:46 -07001179 if variationName != "" {
1180 if newModule.variantName == "" {
1181 newModule.variantName = variationName
1182 } else {
1183 newModule.variantName += "_" + variationName
1184 }
Colin Crosse7daa222015-03-11 14:35:41 -07001185 }
1186
Colin Crossc9028482014-12-18 16:28:54 -08001187 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001188
Colin Crossf5e34b92015-03-13 16:02:36 -07001189 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001190 if len(newErrs) > 0 {
1191 errs = append(errs, newErrs...)
1192 }
Colin Crossc9028482014-12-18 16:28:54 -08001193 }
1194
1195 // Mark original variant as invalid. Modules that depend on this module will still
1196 // depend on origModule, but we'll fix it when the mutator is called on them.
1197 origModule.logicModule = nil
1198 origModule.splitModules = newModules
1199
Colin Cross3702ac72016-08-11 11:09:00 -07001200 atomic.AddUint32(&c.depsModified, 1)
1201
Colin Cross174ae052015-03-03 17:37:03 -08001202 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001203}
1204
Colin Crossf5e34b92015-03-13 16:02:36 -07001205func (c *Context) convertDepsToVariation(module *moduleInfo,
1206 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001207
Colin Crossc9028482014-12-18 16:28:54 -08001208 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001209 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001210 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001211 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001212 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001213 newDep = m
1214 break
1215 }
1216 }
1217 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001218 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001219 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001220 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001221 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001222 })
1223 continue
Colin Crossc9028482014-12-18 16:28:54 -08001224 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001225 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001226 }
1227 }
Colin Cross174ae052015-03-03 17:37:03 -08001228
1229 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001230}
1231
Colin Crossf5e34b92015-03-13 16:02:36 -07001232func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001233 names := make([]string, 0, len(variant))
1234 for _, m := range c.variantMutatorNames {
1235 if v, ok := variant[m]; ok {
1236 names = append(names, m+":"+v)
1237 }
1238 }
1239
1240 return strings.Join(names, ", ")
1241}
1242
Colin Crossaf4fd212017-07-28 14:32:36 -07001243func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
1244 logicModule, properties := factory()
1245
1246 module := &moduleInfo{
1247 logicModule: logicModule,
1248 factory: factory,
1249 }
1250
1251 module.properties = properties
1252
1253 return module
1254}
1255
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001256func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001257 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001258
Colin Crossc32c4792016-06-09 15:52:30 -07001259 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001260 if !ok {
1261 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001262 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001263 }
1264
Colin Cross7ad621c2015-01-07 16:22:45 -08001265 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001266 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001267 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1268 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001269 },
1270 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001271 }
1272
Colin Crossaf4fd212017-07-28 14:32:36 -07001273 module := c.newModule(factory)
1274 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001275
Colin Crossaf4fd212017-07-28 14:32:36 -07001276 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001277
Colin Crossaf4fd212017-07-28 14:32:36 -07001278 propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001279 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001280 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001281 }
1282
Colin Crossc32c4792016-06-09 15:52:30 -07001283 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001284 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001285 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001286 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001287 }
1288
Colin Cross7ad621c2015-01-07 16:22:45 -08001289 return module, nil
1290}
1291
Colin Cross23d7aa12015-06-30 16:05:22 -07001292func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001293 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001294 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001295
Colin Cross0b7e83e2016-05-17 14:58:05 -07001296 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001297 name: name,
1298 modules: []*moduleInfo{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001299 }
1300 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001301 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001302 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001303 ModuleGroup{moduleGroup: group},
1304 module.logicModule)
1305 if len(errs) > 0 {
1306 for i := range errs {
1307 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1308 }
1309 return errs
1310 }
1311 group.namespace = namespace
1312
Colin Cross0b7e83e2016-05-17 14:58:05 -07001313 c.moduleGroups = append(c.moduleGroups, group)
1314
Colin Cross23d7aa12015-06-30 16:05:22 -07001315 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001316}
1317
Jamie Gennisd4e10182014-06-12 20:06:50 -07001318// ResolveDependencies checks that the dependencies specified by all of the
1319// modules defined in the parsed Blueprints files are valid. This means that
1320// the modules depended upon are defined and that no circular dependencies
1321// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001322func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross5f03f112017-11-07 13:29:54 -08001323 c.liveGlobals = newLiveTracker(config)
1324
1325 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1326 if len(errs) > 0 {
1327 return nil, errs
1328 }
1329
Colin Cross874a3462017-07-31 17:26:06 -07001330 errs = c.updateDependencies()
Colin Crossf8b50422016-08-10 12:56:40 -07001331 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001332 return nil, errs
Colin Crossf8b50422016-08-10 12:56:40 -07001333 }
1334
Colin Cross5f03f112017-11-07 13:29:54 -08001335 mutatorDeps, errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001336 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001337 return nil, errs
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001338 }
Colin Cross5f03f112017-11-07 13:29:54 -08001339 deps = append(deps, mutatorDeps...)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001340
Colin Cross910242b2016-04-11 15:41:52 -07001341 c.cloneModules()
1342
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001343 c.dependenciesReady = true
Colin Cross874a3462017-07-31 17:26:06 -07001344 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001345}
1346
Colin Cross763b6f12015-10-29 15:32:56 -07001347// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001348// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001349// module names returned by its DynamicDependencies method and those added by calling
1350// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001351func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001352 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001353 func() {
1354 defer func() {
1355 if r := recover(); r != nil {
1356 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1357 }
1358 }()
1359 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001360
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001361 if ctx.Failed() {
1362 return
1363 }
Colin Cross763b6f12015-10-29 15:32:56 -07001364
Colin Cross2c1f3d12016-04-11 15:47:28 -07001365 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001366 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001367 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001368}
1369
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001370// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1371// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001372func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1373 if len(possible) == 1 {
1374 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001375 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001376 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001377 if m.variant.equal(module.dependencyVariant) {
1378 return m
1379 }
1380 }
1381 }
1382
1383 return nil
1384}
1385
Colin Cross2c1f3d12016-04-11 15:47:28 -07001386func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001387 if _, ok := tag.(BaseDependencyTag); ok {
1388 panic("BaseDependencyTag is not allowed to be used directly!")
1389 }
1390
Colin Cross0b7e83e2016-05-17 14:58:05 -07001391 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001392 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001393 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001394 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001395 }}
1396 }
1397
Jeff Gastond70bf752017-11-10 15:12:08 -08001398 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001399 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001400 return c.discoveredMissingDependencies(module, depName)
Colin Crossc9028482014-12-18 16:28:54 -08001401 }
1402
Colin Cross0b7e83e2016-05-17 14:58:05 -07001403 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001404 for _, dep := range module.directDeps {
1405 if m == dep.module {
1406 // TODO(ccross): what if adding a dependency with a different tag?
1407 return nil
1408 }
Colin Cross65569e42015-03-10 20:08:19 -07001409 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001410 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001411 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001412 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001413 }
Colin Crossc9028482014-12-18 16:28:54 -08001414
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001415 variants := make([]string, len(possibleDeps))
1416 for i, mod := range possibleDeps {
1417 variants[i] = c.prettyPrintVariant(mod.variant)
1418 }
1419 sort.Strings(variants)
1420
Colin Cross2c628442016-10-07 17:13:10 -07001421 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001422 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001423 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001424 c.prettyPrintVariant(module.dependencyVariant),
1425 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001426 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001427 }}
1428}
1429
Colin Cross8d8a7af2015-11-03 16:41:29 -08001430func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001431 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001432 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001433 Err: fmt.Errorf("%q depends on itself", destName),
1434 Pos: module.pos,
1435 }}
1436 }
1437
Jeff Gastond70bf752017-11-10 15:12:08 -08001438 possibleDeps := c.modulesFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001439 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001440 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001441 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001442 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001443 Pos: module.pos,
1444 }}
1445 }
1446
Colin Cross0b7e83e2016-05-17 14:58:05 -07001447 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001448 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001449 }
1450
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001451 variants := make([]string, len(possibleDeps))
1452 for i, mod := range possibleDeps {
1453 variants[i] = c.prettyPrintVariant(mod.variant)
1454 }
1455 sort.Strings(variants)
1456
Colin Cross2c628442016-10-07 17:13:10 -07001457 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001458 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001459 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001460 c.prettyPrintVariant(module.dependencyVariant),
1461 strings.Join(variants, "\n ")),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001462 Pos: module.pos,
1463 }}
1464}
1465
Colin Crossf5e34b92015-03-13 16:02:36 -07001466func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001467 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001468 if _, ok := tag.(BaseDependencyTag); ok {
1469 panic("BaseDependencyTag is not allowed to be used directly!")
1470 }
Colin Cross65569e42015-03-10 20:08:19 -07001471
Jeff Gastond70bf752017-11-10 15:12:08 -08001472 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001473 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001474 return c.discoveredMissingDependencies(module, depName)
Colin Cross65569e42015-03-10 20:08:19 -07001475 }
1476
1477 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1478 // compare the strings because the result won't be in mutator registration order.
1479 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001480 var newVariant variationMap
1481 if !far {
1482 newVariant = module.dependencyVariant.clone()
1483 } else {
1484 newVariant = make(variationMap)
1485 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001486 for _, v := range variations {
1487 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001488 }
1489
Colin Cross0b7e83e2016-05-17 14:58:05 -07001490 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001491 var found bool
1492 if far {
1493 found = m.variant.subset(newVariant)
1494 } else {
1495 found = m.variant.equal(newVariant)
1496 }
1497 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001498 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001499 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001500 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001501 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001502 }}
1503 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001504 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001505 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001506 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001507 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001508 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001509 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001510 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001511 }}
1512 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001513 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001514 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001515 return nil
1516 }
1517 }
1518
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001519 variants := make([]string, len(possibleDeps))
1520 for i, mod := range possibleDeps {
1521 variants[i] = c.prettyPrintVariant(mod.variant)
1522 }
1523 sort.Strings(variants)
1524
Colin Cross2c628442016-10-07 17:13:10 -07001525 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001526 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001527 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001528 c.prettyPrintVariant(newVariant),
1529 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001530 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001531 }}
Colin Crossc9028482014-12-18 16:28:54 -08001532}
1533
Colin Crossf1875462016-04-11 17:33:13 -07001534func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1535 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001536 if _, ok := tag.(BaseDependencyTag); ok {
1537 panic("BaseDependencyTag is not allowed to be used directly!")
1538 }
Colin Crossf1875462016-04-11 17:33:13 -07001539
1540 var fromInfo, toInfo *moduleInfo
1541 for _, m := range origModule.splitModules {
1542 if m.logicModule == from {
1543 fromInfo = m
1544 }
1545 if m.logicModule == to {
1546 toInfo = m
1547 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001548 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001549 }
1550 }
1551 }
1552
1553 if fromInfo == nil || toInfo == nil {
1554 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001555 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001556 }
1557
1558 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001559 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001560}
1561
Jeff Gastonc3e28442017-08-09 15:13:12 -07001562// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1563// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1564// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1565func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1566 // make mapping from dir path to file path
1567 filesByDir := make(map[string]string, len(paths))
1568 for _, path := range paths {
1569 dir := filepath.Dir(path)
1570 _, alreadyFound := filesByDir[dir]
1571 if alreadyFound {
1572 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1573 }
1574 filesByDir[dir] = path
1575 }
1576
Jeff Gaston656870f2017-11-29 18:37:31 -08001577 findAncestor := func(childFile string) (ancestor string) {
1578 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001579 for {
1580 ancestorDir := filepath.Dir(prevAncestorDir)
1581 if ancestorDir == prevAncestorDir {
1582 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001583 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001584 }
1585
1586 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1587 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001588 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001589 }
1590 prevAncestorDir = ancestorDir
1591 }
1592 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001593 // generate the descendants map
1594 descendants = make(map[string][]string, len(filesByDir))
1595 for _, childFile := range filesByDir {
1596 ancestorFile := findAncestor(childFile)
1597 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1598 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001599 return descendants, nil
1600}
1601
Colin Cross3702ac72016-08-11 11:09:00 -07001602type visitOrderer interface {
1603 // returns the number of modules that this module needs to wait for
1604 waitCount(module *moduleInfo) int
1605 // returns the list of modules that are waiting for this module
1606 propagate(module *moduleInfo) []*moduleInfo
1607 // visit modules in order
1608 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1609}
1610
Colin Cross7e723372018-03-28 11:50:12 -07001611type unorderedVisitorImpl struct{}
1612
1613func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1614 return 0
1615}
1616
1617func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1618 return nil
1619}
1620
1621func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1622 for _, module := range modules {
1623 if visit(module) {
1624 return
1625 }
1626 }
1627}
1628
Colin Cross3702ac72016-08-11 11:09:00 -07001629type bottomUpVisitorImpl struct{}
1630
1631func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1632 return len(module.forwardDeps)
1633}
1634
1635func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1636 return module.reverseDeps
1637}
1638
1639func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1640 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001641 if visit(module) {
1642 return
1643 }
1644 }
1645}
1646
Colin Cross3702ac72016-08-11 11:09:00 -07001647type topDownVisitorImpl struct{}
1648
1649func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1650 return len(module.reverseDeps)
1651}
1652
1653func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1654 return module.forwardDeps
1655}
1656
1657func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1658 for i := 0; i < len(modules); i++ {
1659 module := modules[len(modules)-1-i]
1660 if visit(module) {
1661 return
1662 }
1663 }
1664}
1665
1666var (
1667 bottomUpVisitor bottomUpVisitorImpl
1668 topDownVisitor topDownVisitorImpl
1669)
1670
Colin Cross49c279a2016-08-05 22:30:44 -07001671// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1672// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001673func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001674 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001675 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001676 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001677 cancel := false
Colin Cross7e723372018-03-28 11:50:12 -07001678 var backlog []*moduleInfo
1679 const limit = 1000
Colin Cross691a60d2015-01-07 18:08:56 -08001680
Colin Cross7addea32015-03-11 15:43:52 -07001681 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001682 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001683 }
1684
Colin Cross7addea32015-03-11 15:43:52 -07001685 visitOne := func(module *moduleInfo) {
Colin Cross7e723372018-03-28 11:50:12 -07001686 if count < limit {
1687 count++
1688 go func() {
1689 ret := visit(module)
1690 if ret {
1691 cancelCh <- true
1692 }
1693 doneCh <- module
1694 }()
1695 } else {
1696 backlog = append(backlog, module)
1697 }
Colin Cross691a60d2015-01-07 18:08:56 -08001698 }
1699
Colin Cross7addea32015-03-11 15:43:52 -07001700 for _, module := range c.modulesSorted {
1701 if module.waitingCount == 0 {
1702 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001703 }
1704 }
1705
Colin Cross7e723372018-03-28 11:50:12 -07001706 for count > 0 || len(backlog) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001707 select {
Colin Cross7e723372018-03-28 11:50:12 -07001708 case <-cancelCh:
1709 cancel = true
1710 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07001711 case doneModule := <-doneCh:
Colin Cross7e723372018-03-28 11:50:12 -07001712 count--
Colin Cross8900e9b2015-03-02 14:03:01 -08001713 if !cancel {
Colin Cross7e723372018-03-28 11:50:12 -07001714 for count < limit && len(backlog) > 0 {
1715 toVisit := backlog[0]
1716 backlog = backlog[1:]
1717 visitOne(toVisit)
1718 }
Colin Cross3702ac72016-08-11 11:09:00 -07001719 for _, module := range order.propagate(doneModule) {
1720 module.waitingCount--
1721 if module.waitingCount == 0 {
1722 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001723 }
Colin Cross691a60d2015-01-07 18:08:56 -08001724 }
1725 }
Colin Cross691a60d2015-01-07 18:08:56 -08001726 }
1727 }
1728}
1729
1730// updateDependencies recursively walks the module dependency graph and updates
1731// additional fields based on the dependencies. It builds a sorted list of modules
1732// such that dependencies of a module always appear first, and populates reverse
1733// dependency links and counts of total dependencies. It also reports errors when
1734// it encounters dependency cycles. This should called after resolveDependencies,
1735// as well as after any mutator pass has called addDependency
1736func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001737 visited := make(map[*moduleInfo]bool) // modules that were already checked
1738 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001739
Colin Cross7addea32015-03-11 15:43:52 -07001740 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001741
Colin Cross7addea32015-03-11 15:43:52 -07001742 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001743
Colin Cross7addea32015-03-11 15:43:52 -07001744 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001745 // We are the "start" of the cycle, so we're responsible
1746 // for generating the errors. The cycle list is in
1747 // reverse order because all the 'check' calls append
1748 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001749 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001750 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001751 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001752 })
1753
1754 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001755 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001756 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001757 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001758 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001759 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001760 curModule.Name(),
1761 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001762 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001763 })
Colin Cross7addea32015-03-11 15:43:52 -07001764 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001765 }
1766 }
1767
Colin Cross7addea32015-03-11 15:43:52 -07001768 check = func(module *moduleInfo) []*moduleInfo {
1769 visited[module] = true
1770 checking[module] = true
1771 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001772
Colin Cross7addea32015-03-11 15:43:52 -07001773 deps := make(map[*moduleInfo]bool)
1774
1775 // Add an implicit dependency ordering on all earlier modules in the same module group
1776 for _, dep := range module.group.modules {
1777 if dep == module {
1778 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001779 }
Colin Cross7addea32015-03-11 15:43:52 -07001780 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001781 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001782
Colin Cross7addea32015-03-11 15:43:52 -07001783 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001784 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001785 }
1786
1787 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001788 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001789
Colin Crossbbfa51a2014-12-17 16:12:41 -08001790 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001791 if checking[dep] {
1792 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001793 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001794 }
1795
1796 if !visited[dep] {
1797 cycle := check(dep)
1798 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001799 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001800 // We are the "start" of the cycle, so we're responsible
1801 // for generating the errors. The cycle list is in
1802 // reverse order because all the 'check' calls append
1803 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001804 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001805
1806 // We can continue processing this module's children to
1807 // find more cycles. Since all the modules that were
1808 // part of the found cycle were marked as visited we
1809 // won't run into that cycle again.
1810 } else {
1811 // We're not the "start" of the cycle, so we just append
1812 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001813 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001814 }
1815 }
1816 }
Colin Cross691a60d2015-01-07 18:08:56 -08001817
Colin Cross3702ac72016-08-11 11:09:00 -07001818 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001819 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001820 }
1821
Colin Cross7addea32015-03-11 15:43:52 -07001822 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001823
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001824 return nil
1825 }
1826
Colin Cross7addea32015-03-11 15:43:52 -07001827 for _, module := range c.moduleInfo {
1828 if !visited[module] {
1829 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001830 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001831 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001832 panic("inconceivable!")
1833 }
1834 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001835 }
1836 }
1837 }
1838
Colin Cross7addea32015-03-11 15:43:52 -07001839 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001840
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001841 return
1842}
1843
Jamie Gennisd4e10182014-06-12 20:06:50 -07001844// PrepareBuildActions generates an internal representation of all the build
1845// actions that need to be performed. This process involves invoking the
1846// GenerateBuildActions method on each of the Module objects created during the
1847// parse phase and then on each of the registered Singleton objects.
1848//
1849// If the ResolveDependencies method has not already been called it is called
1850// automatically by this method.
1851//
1852// The config argument is made available to all of the Module and Singleton
1853// objects via the Config method on the ModuleContext and SingletonContext
1854// objects passed to GenerateBuildActions. It is also passed to the functions
1855// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1856// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001857//
1858// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001859// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1860// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1861// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001862func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001863 c.buildActionsReady = false
1864
1865 if !c.dependenciesReady {
Colin Cross874a3462017-07-31 17:26:06 -07001866 extraDeps, errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001867 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001868 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001869 }
Colin Cross874a3462017-07-31 17:26:06 -07001870 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001871 }
1872
Colin Cross5f03f112017-11-07 13:29:54 -08001873 depsModules, errs := c.generateModuleBuildActions(config, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001874 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001875 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001876 }
1877
Colin Cross5f03f112017-11-07 13:29:54 -08001878 depsSingletons, errs := c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001879 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001880 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001881 }
1882
Colin Cross874a3462017-07-31 17:26:06 -07001883 deps = append(deps, depsModules...)
1884 deps = append(deps, depsSingletons...)
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001885
Colin Crossa2599452015-11-18 16:01:01 -08001886 if c.ninjaBuildDir != nil {
Colin Cross5f03f112017-11-07 13:29:54 -08001887 c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001888 }
1889
Colin Cross5f03f112017-11-07 13:29:54 -08001890 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
Dan Willemsena481ae22015-12-18 15:18:03 -08001891
1892 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001893
1894 // This will panic if it finds a problem since it's a programming error.
Colin Cross5f03f112017-11-07 13:29:54 -08001895 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001896
1897 c.pkgNames = pkgNames
Colin Cross5f03f112017-11-07 13:29:54 -08001898 c.globalVariables = c.liveGlobals.variables
1899 c.globalPools = c.liveGlobals.pools
1900 c.globalRules = c.liveGlobals.rules
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001901
1902 c.buildActionsReady = true
1903
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001904 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001905}
1906
Colin Cross874a3462017-07-31 17:26:06 -07001907func (c *Context) runMutators(config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001908 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001909
Colin Crossf8b50422016-08-10 12:56:40 -07001910 mutators = append(mutators, c.earlyMutatorInfo...)
1911 mutators = append(mutators, c.mutatorInfo...)
1912
1913 for _, mutator := range mutators {
Colin Cross874a3462017-07-31 17:26:06 -07001914 var newDeps []string
Colin Crossc9028482014-12-18 16:28:54 -08001915 if mutator.topDownMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001916 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001917 } else if mutator.bottomUpMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001918 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001919 } else {
1920 panic("no mutator set on " + mutator.name)
1921 }
1922 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001923 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08001924 }
Colin Cross874a3462017-07-31 17:26:06 -07001925 deps = append(deps, newDeps...)
Colin Crossc9028482014-12-18 16:28:54 -08001926 }
1927
Colin Cross874a3462017-07-31 17:26:06 -07001928 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08001929}
1930
Colin Cross3702ac72016-08-11 11:09:00 -07001931type mutatorDirection interface {
1932 run(mutator *mutatorInfo, ctx *mutatorContext)
1933 orderer() visitOrderer
1934 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001935}
1936
Colin Cross3702ac72016-08-11 11:09:00 -07001937type bottomUpMutatorImpl struct{}
1938
1939func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1940 mutator.bottomUpMutator(ctx)
1941}
1942
1943func (bottomUpMutatorImpl) orderer() visitOrderer {
1944 return bottomUpVisitor
1945}
1946
1947func (bottomUpMutatorImpl) String() string {
1948 return "bottom up mutator"
1949}
1950
1951type topDownMutatorImpl struct{}
1952
1953func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1954 mutator.topDownMutator(ctx)
1955}
1956
1957func (topDownMutatorImpl) orderer() visitOrderer {
1958 return topDownVisitor
1959}
1960
1961func (topDownMutatorImpl) String() string {
1962 return "top down mutator"
1963}
1964
1965var (
1966 topDownMutator topDownMutatorImpl
1967 bottomUpMutator bottomUpMutatorImpl
1968)
1969
Colin Cross49c279a2016-08-05 22:30:44 -07001970type reverseDep struct {
1971 module *moduleInfo
1972 dep depInfo
1973}
1974
Colin Cross3702ac72016-08-11 11:09:00 -07001975func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07001976 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001977
1978 newModuleInfo := make(map[Module]*moduleInfo)
1979 for k, v := range c.moduleInfo {
1980 newModuleInfo[k] = v
1981 }
Colin Crossc9028482014-12-18 16:28:54 -08001982
Colin Cross0ce142c2016-12-09 10:29:05 -08001983 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07001984 reverse []reverseDep
1985 rename []rename
1986 replace []replace
1987 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07001988 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08001989 }
1990
Colin Cross2c1f3d12016-04-11 15:47:28 -07001991 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08001992 var rename []rename
1993 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07001994 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08001995
Colin Cross49c279a2016-08-05 22:30:44 -07001996 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08001997 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07001998 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07001999 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002000
Colin Cross3702ac72016-08-11 11:09:00 -07002001 c.depsModified = 0
2002
Colin Cross49c279a2016-08-05 22:30:44 -07002003 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002004 if module.splitModules != nil {
2005 panic("split module found in sorted module list")
2006 }
2007
Colin Cross7addea32015-03-11 15:43:52 -07002008 mctx := &mutatorContext{
2009 baseModuleContext: baseModuleContext{
2010 context: c,
2011 config: config,
2012 module: module,
2013 },
Colin Cross49c279a2016-08-05 22:30:44 -07002014 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07002015 }
Colin Crossc9028482014-12-18 16:28:54 -08002016
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002017 func() {
2018 defer func() {
2019 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002020 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002021 if err, ok := r.(panicError); ok {
2022 err.addIn(in)
2023 mctx.error(err)
2024 } else {
2025 mctx.error(newPanicErrorf(r, in))
2026 }
2027 }
2028 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002029 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002030 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002031
Colin Cross7addea32015-03-11 15:43:52 -07002032 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002033 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002034 return true
Colin Cross7addea32015-03-11 15:43:52 -07002035 }
Colin Crossc9028482014-12-18 16:28:54 -08002036
Colin Cross5fe225f2017-07-28 15:22:46 -07002037 if len(mctx.newVariations) > 0 {
2038 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002039 }
2040
Colin Crossaf4fd212017-07-28 14:32:36 -07002041 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08002042 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002043 reverse: mctx.reverseDeps,
2044 replace: mctx.replace,
2045 rename: mctx.rename,
2046 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002047 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002048 }
Colin Cross49c279a2016-08-05 22:30:44 -07002049 }
2050
2051 return false
2052 }
2053
2054 // Process errs and reverseDeps in a single goroutine
2055 go func() {
2056 for {
2057 select {
2058 case newErrs := <-errsCh:
2059 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002060 case globalStateChange := <-globalStateCh:
2061 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002062 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2063 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002064 replace = append(replace, globalStateChange.replace...)
2065 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002066 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002067 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002068 case newVariations := <-newVariationsCh:
2069 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002070 newModuleInfo[m.logicModule] = m
2071 }
2072 case <-done:
2073 return
Colin Crossc9028482014-12-18 16:28:54 -08002074 }
2075 }
Colin Cross49c279a2016-08-05 22:30:44 -07002076 }()
Colin Crossc9028482014-12-18 16:28:54 -08002077
Colin Cross49c279a2016-08-05 22:30:44 -07002078 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002079 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002080 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002081 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002082 }
2083
2084 done <- true
2085
2086 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002087 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002088 }
2089
2090 c.moduleInfo = newModuleInfo
2091
2092 for _, group := range c.moduleGroups {
2093 for i := 0; i < len(group.modules); i++ {
2094 module := group.modules[i]
2095
2096 // Update module group to contain newly split variants
2097 if module.splitModules != nil {
2098 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2099 }
2100
2101 // Fix up any remaining dependencies on modules that were split into variants
2102 // by replacing them with the first variant
2103 for j, dep := range module.directDeps {
2104 if dep.module.logicModule == nil {
2105 module.directDeps[j].module = dep.module.splitModules[0]
2106 }
2107 }
Colin Cross7addea32015-03-11 15:43:52 -07002108 }
Colin Crossc9028482014-12-18 16:28:54 -08002109 }
2110
Colin Cross8d8a7af2015-11-03 16:41:29 -08002111 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002112 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002113 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002114 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002115 }
2116
Colin Crossaf4fd212017-07-28 14:32:36 -07002117 for _, module := range newModules {
2118 errs = c.addModule(module)
2119 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002120 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002121 }
2122 atomic.AddUint32(&c.depsModified, 1)
2123 }
2124
Colin Cross0ce142c2016-12-09 10:29:05 -08002125 errs = c.handleRenames(rename)
2126 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002127 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002128 }
2129
2130 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002131 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002132 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002133 }
2134
Colin Cross3702ac72016-08-11 11:09:00 -07002135 if c.depsModified > 0 {
2136 errs = c.updateDependencies()
2137 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002138 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002139 }
Colin Crossc9028482014-12-18 16:28:54 -08002140 }
2141
Colin Cross874a3462017-07-31 17:26:06 -07002142 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002143}
2144
Colin Cross910242b2016-04-11 15:41:52 -07002145// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2146// a mutator sets a non-property member variable on a module, which works until a later mutator
2147// creates variants of that module.
2148func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002149 type update struct {
2150 orig Module
2151 clone *moduleInfo
2152 }
Colin Cross7e723372018-03-28 11:50:12 -07002153 ch := make(chan update)
2154 doneCh := make(chan bool)
2155 go func() {
2156 c.parallelVisit(unorderedVisitorImpl{}, func(m *moduleInfo) bool {
Colin Crossc93490c2016-08-09 14:21:02 -07002157 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002158 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002159 ch <- update{origLogicModule, m}
Colin Cross7e723372018-03-28 11:50:12 -07002160 return false
2161 })
2162 doneCh <- true
2163 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002164
Colin Cross7e723372018-03-28 11:50:12 -07002165 done := false
2166 for !done {
2167 select {
2168 case <-doneCh:
2169 done = true
2170 case update := <-ch:
2171 delete(c.moduleInfo, update.orig)
2172 c.moduleInfo[update.clone.logicModule] = update.clone
2173 }
Colin Cross910242b2016-04-11 15:41:52 -07002174 }
2175}
2176
Colin Cross49c279a2016-08-05 22:30:44 -07002177// Removes modules[i] from the list and inserts newModules... where it was located, returning
2178// the new slice and the index of the last inserted element
2179func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002180 spliceSize := len(newModules)
2181 newLen := len(modules) + spliceSize - 1
2182 var dest []*moduleInfo
2183 if cap(modules) >= len(modules)-1+len(newModules) {
2184 // We can fit the splice in the existing capacity, do everything in place
2185 dest = modules[:newLen]
2186 } else {
2187 dest = make([]*moduleInfo, newLen)
2188 copy(dest, modules[:i])
2189 }
2190
2191 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002192 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002193
2194 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002195 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002196
Colin Cross49c279a2016-08-05 22:30:44 -07002197 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002198}
2199
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002200func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002201 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002202
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002203 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002204 var errs []error
2205
Colin Cross691a60d2015-01-07 18:08:56 -08002206 cancelCh := make(chan struct{})
2207 errsCh := make(chan []error)
2208 depsCh := make(chan []string)
2209
2210 go func() {
2211 for {
2212 select {
2213 case <-cancelCh:
2214 close(cancelCh)
2215 return
2216 case newErrs := <-errsCh:
2217 errs = append(errs, newErrs...)
2218 case newDeps := <-depsCh:
2219 deps = append(deps, newDeps...)
2220
2221 }
2222 }
2223 }()
2224
Colin Cross3702ac72016-08-11 11:09:00 -07002225 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08002226
2227 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2228 sanitizedName := toNinjaName(uniqueName)
2229
2230 prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variantName)
2231
Colin Cross7addea32015-03-11 15:43:52 -07002232 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2233 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2234 // just set it to nil.
Colin Cross7addea32015-03-11 15:43:52 -07002235 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002236
Colin Cross7addea32015-03-11 15:43:52 -07002237 mctx := &moduleContext{
2238 baseModuleContext: baseModuleContext{
2239 context: c,
2240 config: config,
2241 module: module,
2242 },
Colin Cross036a1df2015-12-17 15:49:30 -08002243 scope: scope,
2244 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002245 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002246
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002247 func() {
2248 defer func() {
2249 if r := recover(); r != nil {
2250 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2251 if err, ok := r.(panicError); ok {
2252 err.addIn(in)
2253 mctx.error(err)
2254 } else {
2255 mctx.error(newPanicErrorf(r, in))
2256 }
2257 }
2258 }()
2259 mctx.module.logicModule.GenerateBuildActions(mctx)
2260 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002261
Colin Cross7addea32015-03-11 15:43:52 -07002262 if len(mctx.errs) > 0 {
2263 errsCh <- mctx.errs
2264 return true
2265 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002266
Colin Cross036a1df2015-12-17 15:49:30 -08002267 if module.missingDeps != nil && !mctx.handledMissingDeps {
2268 var errs []error
2269 for _, depName := range module.missingDeps {
Jeff Gastond70bf752017-11-10 15:12:08 -08002270 errs = append(errs, c.missingDependencyError(module, depName))
Colin Cross036a1df2015-12-17 15:49:30 -08002271 }
2272 errsCh <- errs
2273 return true
2274 }
2275
Colin Cross7addea32015-03-11 15:43:52 -07002276 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002277
Colin Crossab6d7902015-03-11 16:17:52 -07002278 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002279 &mctx.actionDefs, liveGlobals)
2280 if len(newErrs) > 0 {
2281 errsCh <- newErrs
2282 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002283 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002284 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002285 })
2286
2287 cancelCh <- struct{}{}
2288 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002289
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002290 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002291}
2292
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002293func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002294 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002295
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002296 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002297 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002298
Colin Cross5f03f112017-11-07 13:29:54 -08002299 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002300 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2301 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2302 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002303 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002304
2305 sctx := &singletonContext{
2306 context: c,
2307 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002308 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002309 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002310 }
2311
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002312 func() {
2313 defer func() {
2314 if r := recover(); r != nil {
2315 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2316 if err, ok := r.(panicError); ok {
2317 err.addIn(in)
2318 sctx.error(err)
2319 } else {
2320 sctx.error(newPanicErrorf(r, in))
2321 }
2322 }
2323 }()
2324 info.singleton.GenerateBuildActions(sctx)
2325 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002326
2327 if len(sctx.errs) > 0 {
2328 errs = append(errs, sctx.errs...)
2329 if len(errs) > maxErrors {
2330 break
2331 }
2332 continue
2333 }
2334
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002335 deps = append(deps, sctx.ninjaFileDeps...)
2336
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002337 newErrs := c.processLocalBuildActions(&info.actionDefs,
2338 &sctx.actionDefs, liveGlobals)
2339 errs = append(errs, newErrs...)
2340 if len(errs) > maxErrors {
2341 break
2342 }
2343 }
2344
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002345 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002346}
2347
2348func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2349 liveGlobals *liveTracker) []error {
2350
2351 var errs []error
2352
2353 // First we go through and add everything referenced by the module's
2354 // buildDefs to the live globals set. This will end up adding the live
2355 // locals to the set as well, but we'll take them out after.
2356 for _, def := range in.buildDefs {
2357 err := liveGlobals.AddBuildDefDeps(def)
2358 if err != nil {
2359 errs = append(errs, err)
2360 }
2361 }
2362
2363 if len(errs) > 0 {
2364 return errs
2365 }
2366
Colin Crossc9028482014-12-18 16:28:54 -08002367 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002368
2369 // We use the now-incorrect set of live "globals" to determine which local
2370 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002371 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002372 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002373 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002374 if isLive {
2375 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002376 }
2377 }
2378
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002379 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002380 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002381 if isLive {
2382 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002383 }
2384 }
2385
2386 return nil
2387}
2388
Yuchen Wu222e2452015-10-06 14:03:27 -07002389func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002390 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002391
2392 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002393 var visiting *moduleInfo
2394
2395 defer func() {
2396 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002397 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2398 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002399 }
2400 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002401
2402 var walk func(module *moduleInfo)
2403 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002404 for _, dep := range module.directDeps {
2405 if !visited[dep.module] {
2406 visited[dep.module] = true
2407 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002408 recurse := true
2409 if visitDown != nil {
2410 recurse = visitDown(dep, module)
2411 }
2412 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002413 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002414 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002415 if visitUp != nil {
2416 visitUp(dep, module)
2417 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002418 }
2419 }
2420 }
2421
2422 walk(topModule)
2423}
2424
Colin Cross9cfd1982016-10-11 09:58:53 -07002425type replace struct {
2426 from, to *moduleInfo
2427}
2428
Colin Crossc4e5b812016-10-12 10:45:05 -07002429type rename struct {
2430 group *moduleGroup
2431 name string
2432}
2433
Colin Cross0ce142c2016-12-09 10:29:05 -08002434func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Jeff Gastond70bf752017-11-10 15:12:08 -08002435 targets := c.modulesFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07002436
2437 if targets == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002438 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002439 }
2440
Colin Cross9cfd1982016-10-11 09:58:53 -07002441 for _, m := range targets {
2442 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002443 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002444 }
2445 }
2446
Colin Cross0ce142c2016-12-09 10:29:05 -08002447 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002448}
2449
Colin Cross0ce142c2016-12-09 10:29:05 -08002450func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002451 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002452 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002453 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08002454 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07002455 continue
2456 }
2457
Jeff Gastond70bf752017-11-10 15:12:08 -08002458 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07002459 }
2460
Colin Cross0ce142c2016-12-09 10:29:05 -08002461 return errs
2462}
2463
2464func (c *Context) handleReplacements(replacements []replace) []error {
2465 var errs []error
2466 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002467 for _, m := range replace.from.reverseDeps {
2468 for i, d := range m.directDeps {
2469 if d.module == replace.from {
2470 m.directDeps[i].module = replace.to
2471 }
2472 }
2473 }
2474
2475 atomic.AddUint32(&c.depsModified, 1)
2476 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002477
Colin Crossc4e5b812016-10-12 10:45:05 -07002478 return errs
2479}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002480
Jeff Gastond70bf752017-11-10 15:12:08 -08002481func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
2482 if c.allowMissingDependencies {
2483 module.missingDeps = append(module.missingDeps, depName)
2484 return nil
2485 }
2486 return []error{c.missingDependencyError(module, depName)}
2487}
2488
2489func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
2490 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
2491
2492 return &BlueprintError{
2493 Err: err,
2494 Pos: module.pos,
2495 }
2496}
2497
2498func (c *Context) modulesFromName(name string, namespace Namespace) []*moduleInfo {
2499 group, exists := c.nameInterface.ModuleFromName(name, namespace)
2500 if exists {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002501 return group.modules
2502 }
2503 return nil
2504}
2505
Jeff Gastond70bf752017-11-10 15:12:08 -08002506func (c *Context) sortedModuleGroups() []*moduleGroup {
2507 if c.cachedSortedModuleGroups == nil {
2508 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
2509 result := make([]*moduleGroup, 0, len(wrappers))
2510 for _, group := range wrappers {
2511 result = append(result, group.moduleGroup)
2512 }
2513 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07002514 }
Jeff Gastond70bf752017-11-10 15:12:08 -08002515
2516 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Jamie Gennisc15544d2014-09-24 20:26:52 -07002517 }
2518
Jeff Gastond70bf752017-11-10 15:12:08 -08002519 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07002520}
2521
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002522func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002523 var module *moduleInfo
2524
2525 defer func() {
2526 if r := recover(); r != nil {
2527 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2528 funcName(visit), module))
2529 }
2530 }()
2531
Jeff Gastond70bf752017-11-10 15:12:08 -08002532 for _, moduleGroup := range c.sortedModuleGroups() {
2533 for _, module = range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002534 visit(module.logicModule)
2535 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002536 }
2537}
2538
2539func (c *Context) visitAllModulesIf(pred func(Module) bool,
2540 visit func(Module)) {
2541
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002542 var module *moduleInfo
2543
2544 defer func() {
2545 if r := recover(); r != nil {
2546 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2547 funcName(pred), funcName(visit), module))
2548 }
2549 }()
2550
Jeff Gastond70bf752017-11-10 15:12:08 -08002551 for _, moduleGroup := range c.sortedModuleGroups() {
2552 for _, module := range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002553 if pred(module.logicModule) {
2554 visit(module.logicModule)
2555 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002556 }
2557 }
2558}
2559
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002560func (c *Context) visitAllModuleVariants(module *moduleInfo,
2561 visit func(Module)) {
2562
2563 var variant *moduleInfo
2564
2565 defer func() {
2566 if r := recover(); r != nil {
2567 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2568 module, funcName(visit), variant))
2569 }
2570 }()
2571
2572 for _, variant = range module.group.modules {
2573 visit(variant.logicModule)
2574 }
2575}
2576
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002577func (c *Context) requireNinjaVersion(major, minor, micro int) {
2578 if major != 1 {
2579 panic("ninja version with major version != 1 not supported")
2580 }
2581 if c.requiredNinjaMinor < minor {
2582 c.requiredNinjaMinor = minor
2583 c.requiredNinjaMicro = micro
2584 }
2585 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2586 c.requiredNinjaMicro = micro
2587 }
2588}
2589
Colin Crossa2599452015-11-18 16:01:01 -08002590func (c *Context) setNinjaBuildDir(value *ninjaString) {
2591 if c.ninjaBuildDir == nil {
2592 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002593 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002594}
2595
2596func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002597 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002598
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002599 pkgs := make(map[string]*packageContext)
2600 pkgNames := make(map[*packageContext]string)
2601 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002602
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002603 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002604 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002605 // This is a built-in rule and has no package.
2606 return
2607 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002608 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002609 // We've already processed this package.
2610 return
2611 }
2612
Jamie Gennis2fb20952014-10-03 02:49:58 -07002613 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002614 if present {
2615 // Short name collision. Both this package and the one that's
2616 // already there need to use their full names. We leave the short
2617 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002618 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002619 longPkgNames[otherPkg] = true
2620 } else {
2621 // No collision so far. Tentatively set the package's name to be
2622 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002623 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002624 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002625 }
2626 }
2627
2628 // We try to give all packages their short name, but when we get collisions
2629 // we need to use the full unique package name.
2630 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002631 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002632 }
2633 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002634 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002635 }
2636 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002637 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002638 }
2639
2640 // Add the packages that had collisions using their full unique names. This
2641 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002642 for pctx := range longPkgNames {
2643 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002644 }
2645
Dan Willemsena481ae22015-12-18 15:18:03 -08002646 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2647 deps := []string{}
2648 for _, pkg := range pkgs {
2649 deps = append(deps, pkg.ninjaFileDeps...)
2650 }
2651
2652 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002653}
2654
2655func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002656 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002657
2658 visited := make(map[Variable]bool) // variables that were already checked
2659 checking := make(map[Variable]bool) // variables actively being checked
2660
2661 var check func(v Variable) []Variable
2662
2663 check = func(v Variable) []Variable {
2664 visited[v] = true
2665 checking[v] = true
2666 defer delete(checking, v)
2667
2668 value := variables[v]
2669 for _, dep := range value.variables {
2670 if checking[dep] {
2671 // This is a cycle.
2672 return []Variable{dep, v}
2673 }
2674
2675 if !visited[dep] {
2676 cycle := check(dep)
2677 if cycle != nil {
2678 if cycle[0] == v {
2679 // We are the "start" of the cycle, so we're responsible
2680 // for generating the errors. The cycle list is in
2681 // reverse order because all the 'check' calls append
2682 // their own module to the list.
2683 msgs := []string{"detected variable reference cycle:"}
2684
2685 // Iterate backwards through the cycle list.
2686 curName := v.fullName(pkgNames)
2687 curValue := value.Value(pkgNames)
2688 for i := len(cycle) - 1; i >= 0; i-- {
2689 next := cycle[i]
2690 nextName := next.fullName(pkgNames)
2691 nextValue := variables[next].Value(pkgNames)
2692
2693 msgs = append(msgs, fmt.Sprintf(
2694 " %q depends on %q", curName, nextName))
2695 msgs = append(msgs, fmt.Sprintf(
2696 " [%s = %s]", curName, curValue))
2697
2698 curName = nextName
2699 curValue = nextValue
2700 }
2701
2702 // Variable reference cycles are a programming error,
2703 // not the fault of the Blueprint file authors.
2704 panic(strings.Join(msgs, "\n"))
2705 } else {
2706 // We're not the "start" of the cycle, so we just append
2707 // our module to the list and return it.
2708 return append(cycle, v)
2709 }
2710 }
2711 }
2712 }
2713
2714 return nil
2715 }
2716
2717 for v := range variables {
2718 if !visited[v] {
2719 cycle := check(v)
2720 if cycle != nil {
2721 panic("inconceivable!")
2722 }
2723 }
2724 }
2725}
2726
Jamie Gennisaf435562014-10-27 22:34:56 -07002727// AllTargets returns a map all the build target names to the rule used to build
2728// them. This is the same information that is output by running 'ninja -t
2729// targets all'. If this is called before PrepareBuildActions successfully
2730// completes then ErrbuildActionsNotReady is returned.
2731func (c *Context) AllTargets() (map[string]string, error) {
2732 if !c.buildActionsReady {
2733 return nil, ErrBuildActionsNotReady
2734 }
2735
2736 targets := map[string]string{}
2737
2738 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002739 for _, module := range c.moduleInfo {
2740 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002741 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002742 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002743 outputValue, err := output.Eval(c.globalVariables)
2744 if err != nil {
2745 return nil, err
2746 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002747 targets[outputValue] = ruleName
2748 }
2749 }
2750 }
2751
2752 // Collect all the singleton build targets.
2753 for _, info := range c.singletonInfo {
2754 for _, buildDef := range info.actionDefs.buildDefs {
2755 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002756 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002757 outputValue, err := output.Eval(c.globalVariables)
2758 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002759 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002760 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002761 targets[outputValue] = ruleName
2762 }
2763 }
2764 }
2765
2766 return targets, nil
2767}
2768
Colin Crossa2599452015-11-18 16:01:01 -08002769func (c *Context) NinjaBuildDir() (string, error) {
2770 if c.ninjaBuildDir != nil {
2771 return c.ninjaBuildDir.Eval(c.globalVariables)
2772 } else {
2773 return "", nil
2774 }
2775}
2776
Colin Cross4572edd2015-05-13 14:36:24 -07002777// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2778// property structs returned by the factory for that module type.
2779func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2780 ret := make(map[string][]interface{})
2781 for moduleType, factory := range c.moduleFactories {
2782 _, ret[moduleType] = factory()
2783 }
2784
2785 return ret
2786}
2787
2788func (c *Context) ModuleName(logicModule Module) string {
2789 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002790 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002791}
2792
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002793func (c *Context) ModulePath(logicModule Module) string {
Colin Cross4572edd2015-05-13 14:36:24 -07002794 module := c.moduleInfo[logicModule]
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002795 return module.relBlueprintsFile
2796}
2797
2798func (c *Context) ModuleDir(logicModule Module) string {
2799 return filepath.Dir(c.ModulePath(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07002800}
2801
Colin Cross8c602f72015-12-17 18:02:11 -08002802func (c *Context) ModuleSubDir(logicModule Module) string {
2803 module := c.moduleInfo[logicModule]
2804 return module.variantName
2805}
2806
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002807func (c *Context) ModuleType(logicModule Module) string {
2808 module := c.moduleInfo[logicModule]
2809 return module.typeName
2810}
2811
Colin Cross4572edd2015-05-13 14:36:24 -07002812func (c *Context) BlueprintFile(logicModule Module) string {
2813 module := c.moduleInfo[logicModule]
2814 return module.relBlueprintsFile
2815}
2816
2817func (c *Context) ModuleErrorf(logicModule Module, format string,
2818 args ...interface{}) error {
2819
2820 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002821 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002822 Err: fmt.Errorf(format, args...),
2823 Pos: module.pos,
2824 }
2825}
2826
2827func (c *Context) VisitAllModules(visit func(Module)) {
2828 c.visitAllModules(visit)
2829}
2830
2831func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2832 visit func(Module)) {
2833
2834 c.visitAllModulesIf(pred, visit)
2835}
2836
Colin Cross080c1332017-03-17 13:09:05 -07002837func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
2838 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07002839
Colin Cross080c1332017-03-17 13:09:05 -07002840 var visiting *moduleInfo
2841
2842 defer func() {
2843 if r := recover(); r != nil {
2844 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
2845 topModule, funcName(visit), visiting))
2846 }
2847 }()
2848
2849 for _, dep := range topModule.directDeps {
2850 visiting = dep.module
2851 visit(dep.module.logicModule)
2852 }
2853}
2854
2855func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
2856 topModule := c.moduleInfo[module]
2857
2858 var visiting *moduleInfo
2859
2860 defer func() {
2861 if r := recover(); r != nil {
2862 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
2863 topModule, funcName(pred), funcName(visit), visiting))
2864 }
2865 }()
2866
2867 for _, dep := range topModule.directDeps {
2868 visiting = dep.module
2869 if pred(dep.module.logicModule) {
2870 visit(dep.module.logicModule)
2871 }
2872 }
2873}
2874
2875func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002876 topModule := c.moduleInfo[module]
2877
2878 var visiting *moduleInfo
2879
2880 defer func() {
2881 if r := recover(); r != nil {
2882 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2883 topModule, funcName(visit), visiting))
2884 }
2885 }()
2886
2887 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2888 visiting = dep.module
2889 visit(dep.module.logicModule)
2890 })
Colin Cross4572edd2015-05-13 14:36:24 -07002891}
2892
Colin Cross080c1332017-03-17 13:09:05 -07002893func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002894 topModule := c.moduleInfo[module]
2895
2896 var visiting *moduleInfo
2897
2898 defer func() {
2899 if r := recover(); r != nil {
2900 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2901 topModule, funcName(pred), funcName(visit), visiting))
2902 }
2903 }()
2904
2905 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2906 if pred(dep.module.logicModule) {
2907 visiting = dep.module
2908 visit(dep.module.logicModule)
2909 }
2910 })
Colin Cross4572edd2015-05-13 14:36:24 -07002911}
2912
Colin Cross24ad5872015-11-17 16:22:29 -08002913func (c *Context) PrimaryModule(module Module) Module {
2914 return c.moduleInfo[module].group.modules[0].logicModule
2915}
2916
2917func (c *Context) FinalModule(module Module) Module {
2918 modules := c.moduleInfo[module].group.modules
2919 return modules[len(modules)-1].logicModule
2920}
2921
2922func (c *Context) VisitAllModuleVariants(module Module,
2923 visit func(Module)) {
2924
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002925 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002926}
2927
Jamie Gennisd4e10182014-06-12 20:06:50 -07002928// WriteBuildFile writes the Ninja manifeset text for the generated build
2929// actions to w. If this is called before PrepareBuildActions successfully
2930// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002931func (c *Context) WriteBuildFile(w io.Writer) error {
2932 if !c.buildActionsReady {
2933 return ErrBuildActionsNotReady
2934 }
2935
2936 nw := newNinjaWriter(w)
2937
2938 err := c.writeBuildFileHeader(nw)
2939 if err != nil {
2940 return err
2941 }
2942
2943 err = c.writeNinjaRequiredVersion(nw)
2944 if err != nil {
2945 return err
2946 }
2947
2948 // TODO: Group the globals by package.
2949
2950 err = c.writeGlobalVariables(nw)
2951 if err != nil {
2952 return err
2953 }
2954
2955 err = c.writeGlobalPools(nw)
2956 if err != nil {
2957 return err
2958 }
2959
2960 err = c.writeBuildDir(nw)
2961 if err != nil {
2962 return err
2963 }
2964
2965 err = c.writeGlobalRules(nw)
2966 if err != nil {
2967 return err
2968 }
2969
2970 err = c.writeAllModuleActions(nw)
2971 if err != nil {
2972 return err
2973 }
2974
2975 err = c.writeAllSingletonActions(nw)
2976 if err != nil {
2977 return err
2978 }
2979
2980 return nil
2981}
2982
Jamie Gennisc15544d2014-09-24 20:26:52 -07002983type pkgAssociation struct {
2984 PkgName string
2985 PkgPath string
2986}
2987
2988type pkgAssociationSorter struct {
2989 pkgs []pkgAssociation
2990}
2991
2992func (s *pkgAssociationSorter) Len() int {
2993 return len(s.pkgs)
2994}
2995
2996func (s *pkgAssociationSorter) Less(i, j int) bool {
2997 iName := s.pkgs[i].PkgName
2998 jName := s.pkgs[j].PkgName
2999 return iName < jName
3000}
3001
3002func (s *pkgAssociationSorter) Swap(i, j int) {
3003 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3004}
3005
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003006func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3007 headerTemplate := template.New("fileHeader")
3008 _, err := headerTemplate.Parse(fileHeaderTemplate)
3009 if err != nil {
3010 // This is a programming error.
3011 panic(err)
3012 }
3013
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003014 var pkgs []pkgAssociation
3015 maxNameLen := 0
3016 for pkg, name := range c.pkgNames {
3017 pkgs = append(pkgs, pkgAssociation{
3018 PkgName: name,
3019 PkgPath: pkg.pkgPath,
3020 })
3021 if len(name) > maxNameLen {
3022 maxNameLen = len(name)
3023 }
3024 }
3025
3026 for i := range pkgs {
3027 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3028 }
3029
Jamie Gennisc15544d2014-09-24 20:26:52 -07003030 sort.Sort(&pkgAssociationSorter{pkgs})
3031
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003032 params := map[string]interface{}{
3033 "Pkgs": pkgs,
3034 }
3035
3036 buf := bytes.NewBuffer(nil)
3037 err = headerTemplate.Execute(buf, params)
3038 if err != nil {
3039 return err
3040 }
3041
3042 return nw.Comment(buf.String())
3043}
3044
3045func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3046 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3047 c.requiredNinjaMicro)
3048
3049 err := nw.Assign("ninja_required_version", value)
3050 if err != nil {
3051 return err
3052 }
3053
3054 return nw.BlankLine()
3055}
3056
3057func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08003058 if c.ninjaBuildDir != nil {
3059 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003060 if err != nil {
3061 return err
3062 }
3063
3064 err = nw.BlankLine()
3065 if err != nil {
3066 return err
3067 }
3068 }
3069 return nil
3070}
3071
Jamie Gennisc15544d2014-09-24 20:26:52 -07003072type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003073 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003074}
3075
Jamie Gennisc15544d2014-09-24 20:26:52 -07003076type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003077 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003078 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003079}
3080
Jamie Gennisc15544d2014-09-24 20:26:52 -07003081func (s *globalEntitySorter) Len() int {
3082 return len(s.entities)
3083}
3084
3085func (s *globalEntitySorter) Less(i, j int) bool {
3086 iName := s.entities[i].fullName(s.pkgNames)
3087 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003088 return iName < jName
3089}
3090
Jamie Gennisc15544d2014-09-24 20:26:52 -07003091func (s *globalEntitySorter) Swap(i, j int) {
3092 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003093}
3094
3095func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3096 visited := make(map[Variable]bool)
3097
3098 var walk func(v Variable) error
3099 walk = func(v Variable) error {
3100 visited[v] = true
3101
3102 // First visit variables on which this variable depends.
3103 value := c.globalVariables[v]
3104 for _, dep := range value.variables {
3105 if !visited[dep] {
3106 err := walk(dep)
3107 if err != nil {
3108 return err
3109 }
3110 }
3111 }
3112
3113 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3114 if err != nil {
3115 return err
3116 }
3117
3118 err = nw.BlankLine()
3119 if err != nil {
3120 return err
3121 }
3122
3123 return nil
3124 }
3125
Jamie Gennisc15544d2014-09-24 20:26:52 -07003126 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3127 for variable := range c.globalVariables {
3128 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003129 }
3130
Jamie Gennisc15544d2014-09-24 20:26:52 -07003131 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003132
Jamie Gennisc15544d2014-09-24 20:26:52 -07003133 for _, entity := range globalVariables {
3134 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003135 if !visited[v] {
3136 err := walk(v)
3137 if err != nil {
3138 return nil
3139 }
3140 }
3141 }
3142
3143 return nil
3144}
3145
3146func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003147 globalPools := make([]globalEntity, 0, len(c.globalPools))
3148 for pool := range c.globalPools {
3149 globalPools = append(globalPools, pool)
3150 }
3151
3152 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3153
3154 for _, entity := range globalPools {
3155 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003156 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003157 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003158 err := def.WriteTo(nw, name)
3159 if err != nil {
3160 return err
3161 }
3162
3163 err = nw.BlankLine()
3164 if err != nil {
3165 return err
3166 }
3167 }
3168
3169 return nil
3170}
3171
3172func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003173 globalRules := make([]globalEntity, 0, len(c.globalRules))
3174 for rule := range c.globalRules {
3175 globalRules = append(globalRules, rule)
3176 }
3177
3178 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3179
3180 for _, entity := range globalRules {
3181 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003182 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003183 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003184 err := def.WriteTo(nw, name, c.pkgNames)
3185 if err != nil {
3186 return err
3187 }
3188
3189 err = nw.BlankLine()
3190 if err != nil {
3191 return err
3192 }
3193 }
3194
3195 return nil
3196}
3197
Colin Cross2c1f3d12016-04-11 15:47:28 -07003198type depSorter []depInfo
3199
3200func (s depSorter) Len() int {
3201 return len(s)
3202}
3203
3204func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003205 iName := s[i].module.Name()
3206 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003207 if iName == jName {
3208 iName = s[i].module.variantName
3209 jName = s[j].module.variantName
3210 }
3211 return iName < jName
3212}
3213
3214func (s depSorter) Swap(i, j int) {
3215 s[i], s[j] = s[j], s[i]
3216}
3217
Jeff Gaston0e907592017-12-01 17:10:52 -08003218type moduleSorter struct {
3219 modules []*moduleInfo
3220 nameInterface NameInterface
3221}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003222
Colin Crossab6d7902015-03-11 16:17:52 -07003223func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003224 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003225}
3226
Colin Crossab6d7902015-03-11 16:17:52 -07003227func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003228 iMod := s.modules[i]
3229 jMod := s.modules[j]
3230 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3231 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003232 if iName == jName {
Jeff Gaston0e907592017-12-01 17:10:52 -08003233 iName = s.modules[i].variantName
3234 jName = s.modules[j].variantName
3235 }
3236
3237 if iName == jName {
3238 panic(fmt.Sprintf("duplicate module name: %s: %#v and %#v\n", iName, iMod, jMod))
Colin Crossab6d7902015-03-11 16:17:52 -07003239 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003240 return iName < jName
3241}
3242
Colin Crossab6d7902015-03-11 16:17:52 -07003243func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003244 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003245}
3246
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003247func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3248 headerTemplate := template.New("moduleHeader")
3249 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3250 if err != nil {
3251 // This is a programming error.
3252 panic(err)
3253 }
3254
Colin Crossab6d7902015-03-11 16:17:52 -07003255 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3256 for _, module := range c.moduleInfo {
3257 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003258 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003259 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003260
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003261 buf := bytes.NewBuffer(nil)
3262
Colin Crossab6d7902015-03-11 16:17:52 -07003263 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003264 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3265 continue
3266 }
3267
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003268 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003269
3270 // In order to make the bootstrap build manifest independent of the
3271 // build dir we need to output the Blueprints file locations in the
3272 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003273 relPos := module.pos
3274 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003275
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003276 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003277 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003278 factoryName := factoryFunc.Name()
3279
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003280 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003281 "name": module.Name(),
3282 "typeName": module.typeName,
3283 "goFactory": factoryName,
3284 "pos": relPos,
3285 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003286 }
3287 err = headerTemplate.Execute(buf, infoMap)
3288 if err != nil {
3289 return err
3290 }
3291
3292 err = nw.Comment(buf.String())
3293 if err != nil {
3294 return err
3295 }
3296
3297 err = nw.BlankLine()
3298 if err != nil {
3299 return err
3300 }
3301
Colin Crossab6d7902015-03-11 16:17:52 -07003302 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003303 if err != nil {
3304 return err
3305 }
3306
3307 err = nw.BlankLine()
3308 if err != nil {
3309 return err
3310 }
3311 }
3312
3313 return nil
3314}
3315
3316func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3317 headerTemplate := template.New("singletonHeader")
3318 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3319 if err != nil {
3320 // This is a programming error.
3321 panic(err)
3322 }
3323
3324 buf := bytes.NewBuffer(nil)
3325
Yuchen Wub9103ef2015-08-25 17:58:17 -07003326 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003327 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3328 continue
3329 }
3330
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003331 // Get the name of the factory function for the module.
3332 factory := info.factory
3333 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3334 factoryName := factoryFunc.Name()
3335
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003336 buf.Reset()
3337 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003338 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003339 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003340 }
3341 err = headerTemplate.Execute(buf, infoMap)
3342 if err != nil {
3343 return err
3344 }
3345
3346 err = nw.Comment(buf.String())
3347 if err != nil {
3348 return err
3349 }
3350
3351 err = nw.BlankLine()
3352 if err != nil {
3353 return err
3354 }
3355
3356 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3357 if err != nil {
3358 return err
3359 }
3360
3361 err = nw.BlankLine()
3362 if err != nil {
3363 return err
3364 }
3365 }
3366
3367 return nil
3368}
3369
3370func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3371 defs *localBuildActions) error {
3372
3373 // Write the local variable assignments.
3374 for _, v := range defs.variables {
3375 // A localVariable doesn't need the package names or config to
3376 // determine its name or value.
3377 name := v.fullName(nil)
3378 value, err := v.value(nil)
3379 if err != nil {
3380 panic(err)
3381 }
3382 err = nw.Assign(name, value.Value(c.pkgNames))
3383 if err != nil {
3384 return err
3385 }
3386 }
3387
3388 if len(defs.variables) > 0 {
3389 err := nw.BlankLine()
3390 if err != nil {
3391 return err
3392 }
3393 }
3394
3395 // Write the local rules.
3396 for _, r := range defs.rules {
3397 // A localRule doesn't need the package names or config to determine
3398 // its name or definition.
3399 name := r.fullName(nil)
3400 def, err := r.def(nil)
3401 if err != nil {
3402 panic(err)
3403 }
3404
3405 err = def.WriteTo(nw, name, c.pkgNames)
3406 if err != nil {
3407 return err
3408 }
3409
3410 err = nw.BlankLine()
3411 if err != nil {
3412 return err
3413 }
3414 }
3415
3416 // Write the build definitions.
3417 for _, buildDef := range defs.buildDefs {
3418 err := buildDef.WriteTo(nw, c.pkgNames)
3419 if err != nil {
3420 return err
3421 }
3422
3423 if len(buildDef.Args) > 0 {
3424 err = nw.BlankLine()
3425 if err != nil {
3426 return err
3427 }
3428 }
3429 }
3430
3431 return nil
3432}
3433
Colin Cross65569e42015-03-10 20:08:19 -07003434func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3435 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003436 if a == b {
3437 return false
3438 }
Colin Cross65569e42015-03-10 20:08:19 -07003439 for _, l := range list {
3440 if l == a {
3441 found = true
3442 } else if l == b {
3443 return found
3444 }
3445 }
3446
3447 missing := a
3448 if found {
3449 missing = b
3450 }
3451 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3452}
3453
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003454type panicError struct {
3455 panic interface{}
3456 stack []byte
3457 in string
3458}
3459
3460func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3461 buf := make([]byte, 4096)
3462 count := runtime.Stack(buf, false)
3463 return panicError{
3464 panic: panic,
3465 in: fmt.Sprintf(in, a...),
3466 stack: buf[:count],
3467 }
3468}
3469
3470func (p panicError) Error() string {
3471 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3472}
3473
3474func (p *panicError) addIn(in string) {
3475 p.in += " in " + in
3476}
3477
3478func funcName(f interface{}) string {
3479 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3480}
3481
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003482var fileHeaderTemplate = `******************************************************************************
3483*** This file is generated and should not be edited ***
3484******************************************************************************
3485{{if .Pkgs}}
3486This file contains variables, rules, and pools with name prefixes indicating
3487they were generated by the following Go packages:
3488{{range .Pkgs}}
3489 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3490
3491`
3492
3493var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003494Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003495Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003496Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003497Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003498Defined: {{.pos}}
3499`
3500
3501var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3502Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003503Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003504`