blob: 0e4f586bf4e679675d60b68e213d532f9ad78fa3 [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"
Colin Cross3a8c0252019-01-23 13:21:48 -080019 "context"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "errors"
21 "fmt"
22 "io"
Jeff Gastonc3e28442017-08-09 15:13:12 -070023 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070024 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Colin Cross3a8c0252019-01-23 13:21:48 -080028 "runtime/pprof"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "sort"
30 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070031 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070032 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070033 "text/scanner"
34 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070035
36 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080037 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070038 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070039)
40
41var ErrBuildActionsNotReady = errors.New("build actions are not ready")
42
43const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080044const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070045
Jamie Gennisd4e10182014-06-12 20:06:50 -070046// A Context contains all the state needed to parse a set of Blueprints files
47// and generate a Ninja file. The process of generating a Ninja file proceeds
48// through a series of four phases. Each phase corresponds with a some methods
49// on the Context object
50//
51// Phase Methods
52// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 2. Parse ParseBlueprintsFiles, Parse
56//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070057// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070058//
59// 4. Write WriteBuildFile
60//
61// The registration phase prepares the context to process Blueprints files
62// containing various types of modules. The parse phase reads in one or more
63// Blueprints files and validates their contents against the module types that
64// have been registered. The generate phase then analyzes the parsed Blueprints
65// contents to create an internal representation for the build actions that must
66// be performed. This phase also performs validation of the module dependencies
67// and property values defined in the parsed Blueprints files. Finally, the
68// write phase generates the Ninja manifest text based on the generated build
69// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070070type Context struct {
Colin Cross3a8c0252019-01-23 13:21:48 -080071 context.Context
72
Jamie Gennis1bc967e2014-05-27 16:34:41 -070073 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070074 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080075 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070076 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070077 moduleInfo map[Module]*moduleInfo
78 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080079 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070080 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070081 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070082 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070083 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070084
Colin Cross3702ac72016-08-11 11:09:00 -070085 depsModified uint32 // positive if a mutator modified the dependencies
86
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 dependenciesReady bool // set to true on a successful ResolveDependencies
88 buildActionsReady bool // set to true on a successful PrepareBuildActions
89
90 // set by SetIgnoreUnknownModuleTypes
91 ignoreUnknownModuleTypes bool
92
Colin Cross036a1df2015-12-17 15:49:30 -080093 // set by SetAllowMissingDependencies
94 allowMissingDependencies bool
95
Jamie Gennis1bc967e2014-05-27 16:34:41 -070096 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080097 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080098 liveGlobals *liveTracker
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099 globalVariables map[Variable]*ninjaString
100 globalPools map[Pool]*poolDef
101 globalRules map[Rule]*ruleDef
102
103 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -0800104 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105 requiredNinjaMajor int // For the ninja_required_version variable
106 requiredNinjaMinor int // For the ninja_required_version variable
107 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700108
Dan Willemsenab223a52018-07-05 21:56:59 -0700109 subninjas []string
110
Jeff Gastond70bf752017-11-10 15:12:08 -0800111 // set lazily by sortedModuleGroups
112 cachedSortedModuleGroups []*moduleGroup
Colin Crossd7b0f602016-06-02 15:30:20 -0700113
Colin Cross127d2ea2016-11-01 11:10:51 -0700114 globs map[string]GlobPath
115 globLock sync.Mutex
116
Jeff Gastonc3e28442017-08-09 15:13:12 -0700117 fs pathtools.FileSystem
118 moduleListFile string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119}
120
Jamie Gennisd4e10182014-06-12 20:06:50 -0700121// An Error describes a problem that was encountered that is related to a
122// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700123type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700124 Err error // the error that occurred
125 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700126}
127
Colin Cross2c628442016-10-07 17:13:10 -0700128// A ModuleError describes a problem that was encountered that is related to a
129// particular module in a Blueprints file
130type ModuleError struct {
131 BlueprintError
132 module *moduleInfo
133}
134
135// A PropertyError describes a problem that was encountered that is related to a
136// particular property in a Blueprints file
137type PropertyError struct {
138 ModuleError
139 property string
140}
141
142func (e *BlueprintError) Error() string {
143 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
144}
145
146func (e *ModuleError) Error() string {
147 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
148}
149
150func (e *PropertyError) Error() string {
151 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
152}
153
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700154type localBuildActions struct {
155 variables []*localVariable
156 rules []*localRule
157 buildDefs []*buildDef
158}
159
Colin Crossf7beb892019-11-13 20:11:14 -0800160type moduleAlias struct {
161 variantName string
162 variant variationMap
163 dependencyVariant variationMap
164 target *moduleInfo
165}
166
Colin Crossbbfa51a2014-12-17 16:12:41 -0800167type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700168 name string
169 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700170
Colin Crossbbfa51a2014-12-17 16:12:41 -0800171 modules []*moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800172 aliases []*moduleAlias
Jeff Gastond70bf752017-11-10 15:12:08 -0800173
174 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700175}
176
Colin Crossbbfa51a2014-12-17 16:12:41 -0800177type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700178 // set during Parse
179 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700180 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700181 relBlueprintsFile string
182 pos scanner.Position
183 propertyPos map[string]scanner.Position
Colin Cross322cc012019-05-20 13:55:14 -0700184 createdBy *moduleInfo
Colin Crossed342d92015-03-11 00:57:25 -0700185
Colin Crossf5e34b92015-03-13 16:02:36 -0700186 variantName string
187 variant variationMap
188 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700189
Colin Crossd2f4ac12017-07-28 14:31:03 -0700190 logicModule Module
191 group *moduleGroup
192 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800193
194 // set during ResolveDependencies
Colin Cross99bdb2a2019-03-29 16:35:02 -0700195 missingDeps []string
196 newDirectDeps []depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800197
Colin Cross7addea32015-03-11 15:43:52 -0700198 // set during updateDependencies
199 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700200 forwardDeps []*moduleInfo
Colin Cross99bdb2a2019-03-29 16:35:02 -0700201 directDeps []depInfo
Colin Cross7addea32015-03-11 15:43:52 -0700202
203 // used by parallelVisitAllBottomUp
204 waitingCount int
205
Colin Crossc9028482014-12-18 16:28:54 -0800206 // set during each runMutator
207 splitModules []*moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800208 aliasTarget *moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700209
210 // set during PrepareBuildActions
211 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800212}
213
Colin Cross2c1f3d12016-04-11 15:47:28 -0700214type depInfo struct {
215 module *moduleInfo
216 tag DependencyTag
217}
218
Colin Cross0b7e83e2016-05-17 14:58:05 -0700219func (module *moduleInfo) Name() string {
220 return module.group.name
221}
222
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800223func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700224 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800225 if module.variantName != "" {
226 s += fmt.Sprintf(" variant %q", module.variantName)
227 }
Colin Cross322cc012019-05-20 13:55:14 -0700228 if module.createdBy != nil {
229 s += fmt.Sprintf(" (created by %s)", module.createdBy)
230 }
231
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800232 return s
233}
234
Jeff Gastond70bf752017-11-10 15:12:08 -0800235func (module *moduleInfo) namespace() Namespace {
236 return module.group.namespace
237}
238
Colin Crossf5e34b92015-03-13 16:02:36 -0700239// A Variation is a way that a variant of a module differs from other variants of the same module.
240// For example, two variants of the same module might have Variation{"arch","arm"} and
241// Variation{"arch","arm64"}
242type Variation struct {
243 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700244 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700245 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
246 // "shared" or "static" for link.
247 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700248}
249
Colin Crossf5e34b92015-03-13 16:02:36 -0700250// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
251type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700252
Colin Crossf5e34b92015-03-13 16:02:36 -0700253func (vm variationMap) clone() variationMap {
Colin Cross9403b5a2019-11-13 20:11:04 -0800254 if vm == nil {
255 return nil
256 }
Colin Crossf5e34b92015-03-13 16:02:36 -0700257 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700258 for k, v := range vm {
259 newVm[k] = v
260 }
261
262 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800263}
264
Colin Cross89486232015-05-08 11:14:54 -0700265// Compare this variationMap to another one. Returns true if the every entry in this map
266// is either the same in the other map or doesn't exist in the other map.
267func (vm variationMap) subset(other variationMap) bool {
268 for k, v1 := range vm {
269 if v2, ok := other[k]; ok && v1 != v2 {
270 return false
271 }
272 }
273 return true
274}
275
Colin Crossf5e34b92015-03-13 16:02:36 -0700276func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700277 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800278}
279
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700280type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700281 // set during RegisterSingletonType
282 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700283 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700284 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700285
286 // set during PrepareBuildActions
287 actionDefs localBuildActions
288}
289
Colin Crossc9028482014-12-18 16:28:54 -0800290type mutatorInfo struct {
291 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800292 topDownMutator TopDownMutator
293 bottomUpMutator BottomUpMutator
294 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700295 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800296}
297
Colin Crossaf4fd212017-07-28 14:32:36 -0700298func newContext() *Context {
299 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800300 Context: context.Background(),
Colin Cross5f03f112017-11-07 13:29:54 -0800301 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800302 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800303 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross5f03f112017-11-07 13:29:54 -0800304 globs: make(map[string]GlobPath),
305 fs: pathtools.OsFs,
306 ninjaBuildDir: nil,
307 requiredNinjaMajor: 1,
308 requiredNinjaMinor: 7,
309 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700310 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700311}
312
313// NewContext creates a new Context object. The created context initially has
314// no module or singleton factories registered, so the RegisterModuleFactory and
315// RegisterSingletonFactory methods must be called before it can do anything
316// useful.
317func NewContext() *Context {
318 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700319
320 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
321
322 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700323}
324
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700325// A ModuleFactory function creates a new Module object. See the
326// Context.RegisterModuleType method for details about how a registered
327// ModuleFactory is used by a Context.
328type ModuleFactory func() (m Module, propertyStructs []interface{})
329
Jamie Gennisd4e10182014-06-12 20:06:50 -0700330// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700331// Blueprints file) with a Module factory function. When the given module type
332// name is encountered in a Blueprints file during parsing, the Module factory
333// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800334// generation for the module. If a Mutator splits a module into multiple variants,
335// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700336//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700337// The module type names given here must be unique for the context. The factory
338// function should be a named function so that its package and name can be
339// included in the generated Ninja file for debugging purposes.
340//
341// The factory function returns two values. The first is the newly created
342// Module object. The second is a slice of pointers to that Module object's
343// properties structs. Each properties struct is examined when parsing a module
344// definition of this type in a Blueprints file. Exported fields of the
345// properties structs are automatically set to the property values specified in
346// the Blueprints file. The properties struct field names determine the name of
347// the Blueprints file properties that are used - the Blueprints property name
348// matches that of the properties struct field name with the first letter
349// converted to lower-case.
350//
351// The fields of the properties struct must be either []string, a string, or
352// bool. The Context will panic if a Module gets instantiated with a properties
353// struct containing a field that is not one these supported types.
354//
355// Any properties that appear in the Blueprints files that are not built-in
356// module properties (such as "name" and "deps") and do not have a corresponding
357// field in the returned module properties struct result in an error during the
358// Context's parse phase.
359//
360// As an example, the follow code:
361//
362// type myModule struct {
363// properties struct {
364// Foo string
365// Bar []string
366// }
367// }
368//
369// func NewMyModule() (blueprint.Module, []interface{}) {
370// module := new(myModule)
371// properties := &module.properties
372// return module, []interface{}{properties}
373// }
374//
375// func main() {
376// ctx := blueprint.NewContext()
377// ctx.RegisterModuleType("my_module", NewMyModule)
378// // ...
379// }
380//
381// would support parsing a module defined in a Blueprints file as follows:
382//
383// my_module {
384// name: "myName",
385// foo: "my foo string",
386// bar: ["my", "bar", "strings"],
387// }
388//
Colin Cross7ad621c2015-01-07 16:22:45 -0800389// The factory function may be called from multiple goroutines. Any accesses
390// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700391func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
392 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700393 panic(errors.New("module type name is already registered"))
394 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700395 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700396}
397
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700398// A SingletonFactory function creates a new Singleton object. See the
399// Context.RegisterSingletonType method for details about how a registered
400// SingletonFactory is used by a Context.
401type SingletonFactory func() Singleton
402
403// RegisterSingletonType registers a singleton type that will be invoked to
404// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700405// and invoked exactly once as part of the generate phase. Each registered
406// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700407//
408// The singleton type names given here must be unique for the context. The
409// factory function should be a named function so that its package and name can
410// be included in the generated Ninja file for debugging purposes.
411func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700412 for _, s := range c.singletonInfo {
413 if s.name == name {
414 panic(errors.New("singleton name is already registered"))
415 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700416 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700417
Yuchen Wub9103ef2015-08-25 17:58:17 -0700418 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700419 factory: factory,
420 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700421 name: name,
422 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700423}
424
Colin Cross5f03f112017-11-07 13:29:54 -0800425// RegisterPreSingletonType registers a presingleton type that will be invoked to
426// generate build actions before any Blueprint files have been read. Each registered
427// presingleton type is instantiated and invoked exactly once at the beginning of the
428// parse phase. Each registered presingleton is invoked in registration order.
429//
430// The presingleton type names given here must be unique for the context. The
431// factory function should be a named function so that its package and name can
432// be included in the generated Ninja file for debugging purposes.
433func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
434 for _, s := range c.preSingletonInfo {
435 if s.name == name {
436 panic(errors.New("presingleton name is already registered"))
437 }
438 }
439
440 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
441 factory: factory,
442 singleton: factory(),
443 name: name,
444 })
445}
446
Jeff Gastond70bf752017-11-10 15:12:08 -0800447func (c *Context) SetNameInterface(i NameInterface) {
448 c.nameInterface = i
449}
450
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700451func singletonPkgPath(singleton Singleton) string {
452 typ := reflect.TypeOf(singleton)
453 for typ.Kind() == reflect.Ptr {
454 typ = typ.Elem()
455 }
456 return typ.PkgPath()
457}
458
459func singletonTypeName(singleton Singleton) string {
460 typ := reflect.TypeOf(singleton)
461 for typ.Kind() == reflect.Ptr {
462 typ = typ.Elem()
463 }
464 return typ.PkgPath() + "." + typ.Name()
465}
466
Colin Cross3702ac72016-08-11 11:09:00 -0700467// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
468// top-down between Modules. Each registered mutator is invoked in registration order (mixing
469// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
470// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800471//
Colin Cross65569e42015-03-10 20:08:19 -0700472// The mutator type names given here must be unique to all top down mutators in
473// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700474//
475// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
476// parallel while maintaining ordering.
477func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800478 for _, m := range c.mutatorInfo {
479 if m.name == name && m.topDownMutator != nil {
480 panic(fmt.Errorf("mutator name %s is already registered", name))
481 }
482 }
483
Colin Cross3702ac72016-08-11 11:09:00 -0700484 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800485 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800486 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700487 }
488
489 c.mutatorInfo = append(c.mutatorInfo, info)
490
491 return info
Colin Crossc9028482014-12-18 16:28:54 -0800492}
493
Colin Cross3702ac72016-08-11 11:09:00 -0700494// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
495// Each registered mutator is invoked in registration order (mixing TopDownMutators and
496// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
497// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800498//
Colin Cross65569e42015-03-10 20:08:19 -0700499// The mutator type names given here must be unique to all bottom up or early
500// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700501//
Colin Cross3702ac72016-08-11 11:09:00 -0700502// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
503// parallel while maintaining ordering.
504func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700505 for _, m := range c.variantMutatorNames {
506 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800507 panic(fmt.Errorf("mutator name %s is already registered", name))
508 }
509 }
510
Colin Cross49c279a2016-08-05 22:30:44 -0700511 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800512 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800513 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700514 }
515 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700516
517 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700518
519 return info
520}
521
Colin Cross3702ac72016-08-11 11:09:00 -0700522type MutatorHandle interface {
523 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
524 // method on the mutator context is thread-safe, but the mutator must handle synchronization
525 // for any modifications to global state or any modules outside the one it was invoked on.
526 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700527}
528
Colin Cross3702ac72016-08-11 11:09:00 -0700529func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700530 mutator.parallel = true
531 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700532}
533
534// RegisterEarlyMutator registers a mutator that will be invoked to split
535// Modules into multiple variant Modules before any dependencies have been
536// created. Each registered mutator is invoked in registration order once
537// per Module (including each variant from previous early mutators). Module
538// order is unpredictable.
539//
540// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700541// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700542//
543// The mutator type names given here must be unique to all bottom up or early
544// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700545//
546// Deprecated, use a BottomUpMutator instead. The only difference between
547// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
548// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700549func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
550 for _, m := range c.variantMutatorNames {
551 if m == name {
552 panic(fmt.Errorf("mutator name %s is already registered", name))
553 }
554 }
555
Colin Crossf8b50422016-08-10 12:56:40 -0700556 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
557 bottomUpMutator: func(mctx BottomUpMutatorContext) {
558 mutator(mctx)
559 },
560 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700561 })
562
563 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800564}
565
Jamie Gennisd4e10182014-06-12 20:06:50 -0700566// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
567// where it encounters an unknown module type while parsing Blueprints files. By
568// default, the context will report unknown module types as an error. If this
569// method is called with ignoreUnknownModuleTypes set to true then the context
570// will silently ignore unknown module types.
571//
572// This method should generally not be used. It exists to facilitate the
573// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700574func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
575 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
576}
577
Colin Cross036a1df2015-12-17 15:49:30 -0800578// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
579// unresolved dependencies. If the module's GenerateBuildActions calls
580// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
581// for missing dependencies.
582func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
583 c.allowMissingDependencies = allowMissingDependencies
584}
585
Jeff Gastonc3e28442017-08-09 15:13:12 -0700586func (c *Context) SetModuleListFile(listFile string) {
587 c.moduleListFile = listFile
588}
589
590func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
591 reader, err := c.fs.Open(c.moduleListFile)
592 if err != nil {
593 return nil, err
594 }
595 bytes, err := ioutil.ReadAll(reader)
596 if err != nil {
597 return nil, err
598 }
599 text := string(bytes)
600
601 text = strings.Trim(text, "\n")
602 lines := strings.Split(text, "\n")
603 for i := range lines {
604 lines[i] = filepath.Join(baseDir, lines[i])
605 }
606
607 return lines, nil
608}
609
Jeff Gaston656870f2017-11-29 18:37:31 -0800610// a fileParseContext tells the status of parsing a particular file
611type fileParseContext struct {
612 // name of file
613 fileName string
614
615 // scope to use when resolving variables
616 Scope *parser.Scope
617
618 // pointer to the one in the parent directory
619 parent *fileParseContext
620
621 // is closed once FileHandler has completed for this file
622 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700623}
624
Jamie Gennisd4e10182014-06-12 20:06:50 -0700625// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
626// at rootFile. When it encounters a Blueprints file with a set of subdirs
627// listed it recursively parses any Blueprints files found in those
628// subdirectories.
629//
630// If no errors are encountered while parsing the files, the list of paths on
631// which the future output will depend is returned. This list will include both
632// Blueprints file paths as well as directory paths for cases where wildcard
633// subdirs are found.
Colin Crossda70fd02019-12-30 18:40:09 -0800634func (c *Context) ParseBlueprintsFiles(rootFile string,
635 config interface{}) (deps []string, errs []error) {
636
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800637 baseDir := filepath.Dir(rootFile)
638 pathsToParse, err := c.ListModulePaths(baseDir)
639 if err != nil {
640 return nil, []error{err}
641 }
Colin Crossda70fd02019-12-30 18:40:09 -0800642 return c.ParseFileList(baseDir, pathsToParse, config)
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800643}
644
Colin Crossda70fd02019-12-30 18:40:09 -0800645func (c *Context) ParseFileList(rootDir string, filePaths []string,
646 config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700647
Jeff Gastonc3e28442017-08-09 15:13:12 -0700648 if len(filePaths) < 1 {
649 return nil, []error{fmt.Errorf("no paths provided to parse")}
650 }
651
Colin Cross7ad621c2015-01-07 16:22:45 -0800652 c.dependenciesReady = false
653
Colin Crossda70fd02019-12-30 18:40:09 -0800654 type newModuleInfo struct {
655 *moduleInfo
656 added chan<- struct{}
657 }
658
659 moduleCh := make(chan newModuleInfo)
Colin Cross23d7aa12015-06-30 16:05:22 -0700660 errsCh := make(chan []error)
661 doneCh := make(chan struct{})
662 var numErrs uint32
663 var numGoroutines int32
664
665 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700666 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700667 if atomic.LoadUint32(&numErrs) > maxErrors {
668 return
669 }
670
Colin Crossda70fd02019-12-30 18:40:09 -0800671 addedCh := make(chan struct{})
672
673 var addModule func(module *moduleInfo) []error
674 addModule = func(module *moduleInfo) (errs []error) {
675 moduleCh <- newModuleInfo{module, addedCh}
676 <-addedCh
677 var newModules []*moduleInfo
678 newModules, errs = runAndRemoveLoadHooks(c, config, module)
679 if len(errs) > 0 {
680 return errs
681 }
682 for _, n := range newModules {
683 errs = addModule(n)
684 if len(errs) > 0 {
685 return errs
686 }
687 }
688 return nil
689 }
690
Jeff Gaston656870f2017-11-29 18:37:31 -0800691 for _, def := range file.Defs {
Jeff Gaston656870f2017-11-29 18:37:31 -0800692 switch def := def.(type) {
693 case *parser.Module:
Colin Crossda70fd02019-12-30 18:40:09 -0800694 module, errs := c.processModuleDef(def, file.Name)
695 if len(errs) == 0 && module != nil {
696 errs = addModule(module)
697 }
698
699 if len(errs) > 0 {
700 atomic.AddUint32(&numErrs, uint32(len(errs)))
701 errsCh <- errs
702 }
703
Jeff Gaston656870f2017-11-29 18:37:31 -0800704 case *parser.Assignment:
705 // Already handled via Scope object
706 default:
707 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700708 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800709
Jeff Gaston656870f2017-11-29 18:37:31 -0800710 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700711 }
712
713 atomic.AddInt32(&numGoroutines, 1)
714 go func() {
715 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700716 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700717 if len(errs) > 0 {
718 errsCh <- errs
719 }
720 doneCh <- struct{}{}
721 }()
722
723loop:
724 for {
725 select {
726 case newErrs := <-errsCh:
727 errs = append(errs, newErrs...)
728 case module := <-moduleCh:
Colin Crossda70fd02019-12-30 18:40:09 -0800729 newErrs := c.addModule(module.moduleInfo)
730 if module.added != nil {
731 module.added <- struct{}{}
732 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700733 if len(newErrs) > 0 {
734 errs = append(errs, newErrs...)
735 }
736 case <-doneCh:
737 n := atomic.AddInt32(&numGoroutines, -1)
738 if n == 0 {
739 break loop
740 }
741 }
742 }
743
744 return deps, errs
745}
746
747type FileHandler func(*parser.File)
748
Jeff Gastonc3e28442017-08-09 15:13:12 -0700749// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
750// calling the given file handler on each
751//
752// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
753// it recursively parses any Blueprints files found in those subdirectories.
754//
755// If any of the file paths is an ancestor directory of any other of file path, the ancestor
756// will be parsed and visited first.
757//
758// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700759//
760// If no errors are encountered while parsing the files, the list of paths on
761// which the future output will depend is returned. This list will include both
762// Blueprints file paths as well as directory paths for cases where wildcard
763// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800764//
765// visitor will be called asynchronously, and will only be called once visitor for each
766// ancestor directory has completed.
767//
768// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700769func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
770 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700771
Jeff Gastonc3e28442017-08-09 15:13:12 -0700772 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
773 descendantsMap, err := findBlueprintDescendants(filePaths)
774 if err != nil {
775 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700776 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800777 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700778
Jeff Gaston5800d042017-12-05 14:57:58 -0800779 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800780 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800781 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800782 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700783
Jeff Gaston5800d042017-12-05 14:57:58 -0800784 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800785 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700786
Colin Cross7ad621c2015-01-07 16:22:45 -0800787 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700788 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800789 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700790 tooManyErrors := false
791
792 // Limit concurrent calls to parseBlueprintFiles to 200
793 // Darwin has a default limit of 256 open files
794 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800795
Jeff Gaston656870f2017-11-29 18:37:31 -0800796 // count the number of pending calls to visitor()
797 visitorWaitGroup := sync.WaitGroup{}
798
799 startParseBlueprintsFile := func(blueprint fileParseContext) {
800 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700801 return
802 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800803 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700804 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800805 deps = append(deps, blueprint.fileName)
806 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800807 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800808 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
809 &blueprint)
810 if len(errs) > 0 {
811 errsCh <- errs
812 }
813 for _, blueprint := range blueprints {
814 blueprintsCh <- blueprint
815 }
816 for _, dep := range deps {
817 depsCh <- dep
818 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800819 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700820
Jeff Gaston656870f2017-11-29 18:37:31 -0800821 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
822 // wait for visitor() of parent to complete
823 <-blueprint.parent.doneVisiting
824 }
825
Jeff Gastona7e408a2017-12-05 15:11:55 -0800826 if len(errs) == 0 {
827 // process this file
828 visitor(file)
829 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800830 if blueprint.doneVisiting != nil {
831 close(blueprint.doneVisiting)
832 }
833 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800834 }()
835 }
836
Jeff Gaston656870f2017-11-29 18:37:31 -0800837 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700838 if activeCount >= maxActiveCount {
839 pending = append(pending, blueprint)
840 } else {
841 startParseBlueprintsFile(blueprint)
842 }
843 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800844
Jeff Gaston656870f2017-11-29 18:37:31 -0800845 startParseDescendants := func(blueprint fileParseContext) {
846 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700847 if hasDescendants {
848 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800849 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700850 }
851 }
852 }
Colin Cross4a02a302017-05-16 10:33:58 -0700853
Jeff Gastonc3e28442017-08-09 15:13:12 -0700854 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800855 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800856
857loop:
858 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700859 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800860 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700861 }
862
Colin Cross7ad621c2015-01-07 16:22:45 -0800863 select {
864 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700865 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800866 case dep := <-depsCh:
867 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800868 case blueprint := <-blueprintsCh:
869 if tooManyErrors {
870 continue
871 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700872 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800873 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700874 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700875 if !tooManyErrors {
876 startParseDescendants(blueprint)
877 }
878 if activeCount < maxActiveCount && len(pending) > 0 {
879 // start to process the next one from the queue
880 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700881 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700882 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700883 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700884 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800885 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700886 }
887 }
888 }
889
Jeff Gastonc3e28442017-08-09 15:13:12 -0700890 sort.Strings(deps)
891
Jeff Gaston656870f2017-11-29 18:37:31 -0800892 // wait for every visitor() to complete
893 visitorWaitGroup.Wait()
894
Colin Cross7ad621c2015-01-07 16:22:45 -0800895 return
896}
897
Colin Crossd7b0f602016-06-02 15:30:20 -0700898// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
899// filenames to contents stored as a byte slice.
900func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800901 // look for a module list file
902 _, ok := files[MockModuleListFile]
903 if !ok {
904 // no module list file specified; find every file named Blueprints
905 pathsToParse := []string{}
906 for candidate := range files {
907 if filepath.Base(candidate) == "Blueprints" {
908 pathsToParse = append(pathsToParse, candidate)
909 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700910 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800911 if len(pathsToParse) < 1 {
912 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
913 }
914 // put the list of Blueprints files into a list file
915 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700916 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800917 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700918
919 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800920 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700921}
922
Colin Cross8cde4252019-12-17 13:11:21 -0800923func (c *Context) SetFs(fs pathtools.FileSystem) {
924 c.fs = fs
925}
926
Jeff Gaston8fd95782017-12-05 15:03:51 -0800927// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -0800928func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -0800929 parent *fileParseContext) (file *parser.File,
930 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800931
Colin Crossd7b0f602016-06-02 15:30:20 -0700932 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800933 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700934 // couldn't open the file; see if we can provide a clearer error than "could not open file"
935 stats, statErr := c.fs.Lstat(filename)
936 if statErr == nil {
937 isSymlink := stats.Mode()&os.ModeSymlink != 0
938 if isSymlink {
939 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
940 target, readlinkErr := os.Readlink(filename)
941 if readlinkErr == nil {
942 _, targetStatsErr := c.fs.Lstat(target)
943 if targetStatsErr != nil {
944 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
945 }
946 }
947 } else {
948 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
949 }
950 }
Jeff Gaston8fd95782017-12-05 15:03:51 -0800951 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700952 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800953
Jeff Gaston8fd95782017-12-05 15:03:51 -0800954 func() {
955 defer func() {
956 err = f.Close()
957 if err != nil {
958 errs = append(errs, err)
959 }
960 }()
961 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -0700962 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700963
Colin Cross7ad621c2015-01-07 16:22:45 -0800964 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800965 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -0800966 }
967
Colin Cross1fef5362015-04-20 16:50:54 -0700968 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800969 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -0700970 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800971
Jeff Gaston8fd95782017-12-05 15:03:51 -0800972 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -0700973}
974
Jeff Gastona12f22f2017-08-08 14:45:56 -0700975// parseOne parses a single Blueprints file from the given reader, creating Module
976// objects for each of the module definitions encountered. If the Blueprints
977// file contains an assignment to the "subdirs" variable, then the
978// subdirectories listed are searched for Blueprints files returned in the
979// subBlueprints return value. If the Blueprints file contains an assignment
980// to the "build" variable, then the file listed are returned in the
981// subBlueprints return value.
982//
983// rootDir specifies the path to the root directory of the source tree, while
984// filename specifies the path to the Blueprints file. These paths are used for
985// error reporting and for determining the module's directory.
986func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -0800987 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -0700988
989 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
990 if err != nil {
991 return nil, nil, []error{err}
992 }
993
Jeff Gastona12f22f2017-08-08 14:45:56 -0700994 scope.Remove("subdirs")
995 scope.Remove("optional_subdirs")
996 scope.Remove("build")
997 file, errs = parser.ParseAndEval(filename, reader, scope)
998 if len(errs) > 0 {
999 for i, err := range errs {
1000 if parseErr, ok := err.(*parser.ParseError); ok {
1001 err = &BlueprintError{
1002 Err: parseErr.Err,
1003 Pos: parseErr.Pos,
1004 }
1005 errs[i] = err
1006 }
1007 }
1008
1009 // If there were any parse errors don't bother trying to interpret the
1010 // result.
1011 return nil, nil, errs
1012 }
1013 file.Name = relBlueprintsFile
1014
Jeff Gastona12f22f2017-08-08 14:45:56 -07001015 build, buildPos, err := getLocalStringListFromScope(scope, "build")
1016 if err != nil {
1017 errs = append(errs, err)
1018 }
Jeff Gastonf23e3662017-11-30 17:31:43 -08001019 for _, buildEntry := range build {
1020 if strings.Contains(buildEntry, "/") {
1021 errs = append(errs, &BlueprintError{
1022 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1023 Pos: buildPos,
1024 })
1025 }
1026 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001027
1028 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
1029 if err != nil {
1030 errs = append(errs, err)
1031 }
1032
1033 if subBlueprintsName == "" {
1034 subBlueprintsName = "Blueprints"
1035 }
1036
1037 var blueprints []string
1038
1039 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1040 blueprints = append(blueprints, newBlueprints...)
1041 errs = append(errs, newErrs...)
1042
Jeff Gaston656870f2017-11-29 18:37:31 -08001043 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -07001044 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -08001045 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -07001046 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001047 return file, subBlueprintsAndScope, errs
1048}
1049
Colin Cross7f507402015-12-16 13:03:41 -08001050func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -07001051 buildPos scanner.Position) ([]string, []error) {
1052
1053 var blueprints []string
1054 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001055
1056 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001057 pattern := filepath.Join(dir, file)
1058 var matches []string
1059 var err error
1060
Colin Cross08e49542016-11-14 15:23:33 -08001061 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001062
Colin Cross7f507402015-12-16 13:03:41 -08001063 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001064 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001065 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001066 Pos: buildPos,
1067 })
1068 continue
1069 }
1070
1071 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001072 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001073 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001074 Pos: buildPos,
1075 })
1076 }
1077
Colin Cross7f507402015-12-16 13:03:41 -08001078 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001079 if strings.HasSuffix(foundBlueprints, "/") {
1080 errs = append(errs, &BlueprintError{
1081 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1082 Pos: buildPos,
1083 })
1084 }
Colin Cross7f507402015-12-16 13:03:41 -08001085 blueprints = append(blueprints, foundBlueprints)
1086 }
1087 }
1088
Colin Cross127d2ea2016-11-01 11:10:51 -07001089 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001090}
1091
1092func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001093 subBlueprintsName string, optional bool) ([]string, []error) {
1094
1095 var blueprints []string
1096 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001097
1098 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001099 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1100 var matches []string
1101 var err error
1102
Colin Cross08e49542016-11-14 15:23:33 -08001103 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001104
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001105 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001106 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001107 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001108 Pos: subdirsPos,
1109 })
1110 continue
1111 }
1112
Colin Cross7f507402015-12-16 13:03:41 -08001113 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001114 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001115 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001116 Pos: subdirsPos,
1117 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001118 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001119
Colin Cross127d2ea2016-11-01 11:10:51 -07001120 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001121 if strings.HasSuffix(subBlueprints, "/") {
1122 errs = append(errs, &BlueprintError{
1123 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1124 Pos: subdirsPos,
1125 })
1126 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001127 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001128 }
1129 }
Colin Cross1fef5362015-04-20 16:50:54 -07001130
Colin Cross127d2ea2016-11-01 11:10:51 -07001131 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001132}
1133
Colin Cross6d8780f2015-07-10 17:51:55 -07001134func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1135 if assignment, local := scope.Get(v); assignment == nil || !local {
1136 return nil, scanner.Position{}, nil
1137 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001138 switch value := assignment.Value.Eval().(type) {
1139 case *parser.List:
1140 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001141
Colin Crosse32cc802016-06-07 12:28:16 -07001142 for _, listValue := range value.Values {
1143 s, ok := listValue.(*parser.String)
1144 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001145 // The parser should not produce this.
1146 panic("non-string value found in list")
1147 }
1148
Colin Crosse32cc802016-06-07 12:28:16 -07001149 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001150 }
1151
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001152 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001153 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001154 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001155 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001156 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001157 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001158 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001159 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001160 }
1161 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001162}
1163
Colin Cross29394222015-04-27 13:18:21 -07001164func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001165 if assignment, _ := scope.Get(v); assignment == nil {
1166 return "", scanner.Position{}, nil
1167 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001168 switch value := assignment.Value.Eval().(type) {
1169 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001170 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001171 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001172 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001173 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001174 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001175 }
1176 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001177 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001178 }
1179 }
Colin Cross29394222015-04-27 13:18:21 -07001180}
1181
Colin Cross910242b2016-04-11 15:41:52 -07001182// Clones a build logic module by calling the factory method for its module type, and then cloning
1183// property values. Any values stored in the module object that are not stored in properties
1184// structs will be lost.
1185func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001186 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001187
Colin Crossd2f4ac12017-07-28 14:31:03 -07001188 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001189 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001190 }
1191
1192 for i := range newProperties {
1193 dst := reflect.ValueOf(newProperties[i]).Elem()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001194 src := reflect.ValueOf(origModule.properties[i]).Elem()
Colin Cross910242b2016-04-11 15:41:52 -07001195
1196 proptools.CopyProperties(dst, src)
1197 }
1198
1199 return newLogicModule, newProperties
1200}
1201
Colin Crossf5e34b92015-03-13 16:02:36 -07001202func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001203 defaultVariationName *string, variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001204
Colin Crossf4d18a62015-03-18 17:43:15 -07001205 if len(variationNames) == 0 {
1206 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001207 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001208 }
1209
Colin Crossc9028482014-12-18 16:28:54 -08001210 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001211
Colin Cross174ae052015-03-03 17:37:03 -08001212 var errs []error
1213
Colin Crossf5e34b92015-03-13 16:02:36 -07001214 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001215 var newLogicModule Module
1216 var newProperties []interface{}
1217
1218 if i == 0 {
1219 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001220 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1221 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001222 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001223 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001224 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001225 }
1226
Colin Crossf5e34b92015-03-13 16:02:36 -07001227 newVariant := origModule.variant.clone()
Colin Cross9403b5a2019-11-13 20:11:04 -08001228 if newVariant == nil {
1229 newVariant = make(variationMap)
1230 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001231 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001232
Colin Crossed342d92015-03-11 00:57:25 -07001233 m := *origModule
1234 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001235 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001236 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001237 newModule.variant = newVariant
1238 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001239 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001240
Colin Crossbadc8812016-08-11 17:01:46 -07001241 if variationName != "" {
1242 if newModule.variantName == "" {
1243 newModule.variantName = variationName
1244 } else {
1245 newModule.variantName += "_" + variationName
1246 }
Colin Crosse7daa222015-03-11 14:35:41 -07001247 }
1248
Colin Crossc9028482014-12-18 16:28:54 -08001249 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001250
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001251 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName)
Colin Cross174ae052015-03-03 17:37:03 -08001252 if len(newErrs) > 0 {
1253 errs = append(errs, newErrs...)
1254 }
Colin Crossc9028482014-12-18 16:28:54 -08001255 }
1256
1257 // Mark original variant as invalid. Modules that depend on this module will still
1258 // depend on origModule, but we'll fix it when the mutator is called on them.
1259 origModule.logicModule = nil
1260 origModule.splitModules = newModules
1261
Colin Cross3702ac72016-08-11 11:09:00 -07001262 atomic.AddUint32(&c.depsModified, 1)
1263
Colin Cross174ae052015-03-03 17:37:03 -08001264 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001265}
1266
Colin Crossf5e34b92015-03-13 16:02:36 -07001267func (c *Context) convertDepsToVariation(module *moduleInfo,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001268 mutatorName, variationName string, defaultVariationName *string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001269
Colin Crossc9028482014-12-18 16:28:54 -08001270 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001271 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001272 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001273 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001274 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001275 newDep = m
1276 break
1277 }
1278 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001279 if newDep == nil && defaultVariationName != nil {
1280 // give it a second chance; match with defaultVariationName
1281 for _, m := range dep.module.splitModules {
1282 if m.variant[mutatorName] == *defaultVariationName {
1283 newDep = m
1284 break
1285 }
1286 }
1287 }
Colin Crossc9028482014-12-18 16:28:54 -08001288 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001289 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001290 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001291 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001292 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001293 })
1294 continue
Colin Crossc9028482014-12-18 16:28:54 -08001295 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001296 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001297 }
1298 }
Colin Cross174ae052015-03-03 17:37:03 -08001299
1300 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001301}
1302
Colin Crossf5e34b92015-03-13 16:02:36 -07001303func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001304 names := make([]string, 0, len(variant))
1305 for _, m := range c.variantMutatorNames {
1306 if v, ok := variant[m]; ok {
1307 names = append(names, m+":"+v)
1308 }
1309 }
1310
1311 return strings.Join(names, ", ")
1312}
1313
Colin Crossd03b59d2019-11-13 20:10:12 -08001314func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1315 var variants []string
1316 for _, mod := range group.modules {
1317 variants = append(variants, c.prettyPrintVariant(mod.variant))
1318 }
Colin Crossf7beb892019-11-13 20:11:14 -08001319 for _, mod := range group.aliases {
1320 variants = append(variants, c.prettyPrintVariant(mod.variant)+
1321 "(alias to "+c.prettyPrintVariant(mod.target.variant)+")")
1322 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001323 sort.Strings(variants)
1324 return strings.Join(variants, "\n ")
1325}
1326
Colin Crossaf4fd212017-07-28 14:32:36 -07001327func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
1328 logicModule, properties := factory()
1329
1330 module := &moduleInfo{
1331 logicModule: logicModule,
1332 factory: factory,
1333 }
1334
1335 module.properties = properties
1336
1337 return module
1338}
1339
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001340func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001341 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001342
Colin Crossc32c4792016-06-09 15:52:30 -07001343 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001344 if !ok {
1345 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001346 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001347 }
1348
Colin Cross7ad621c2015-01-07 16:22:45 -08001349 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001350 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001351 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1352 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001353 },
1354 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001355 }
1356
Colin Crossaf4fd212017-07-28 14:32:36 -07001357 module := c.newModule(factory)
1358 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001359
Colin Crossaf4fd212017-07-28 14:32:36 -07001360 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001361
Colin Crossaf4fd212017-07-28 14:32:36 -07001362 propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001363 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001364 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001365 }
1366
Colin Crossc32c4792016-06-09 15:52:30 -07001367 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001368 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001369 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001370 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001371 }
1372
Colin Cross7ad621c2015-01-07 16:22:45 -08001373 return module, nil
1374}
1375
Colin Cross23d7aa12015-06-30 16:05:22 -07001376func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001377 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001378 if name == "" {
1379 return []error{
1380 &BlueprintError{
1381 Err: fmt.Errorf("property 'name' is missing from a module"),
1382 Pos: module.pos,
1383 },
1384 }
1385 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001386 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001387
Colin Cross0b7e83e2016-05-17 14:58:05 -07001388 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001389 name: name,
1390 modules: []*moduleInfo{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001391 }
1392 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001393 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001394 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001395 ModuleGroup{moduleGroup: group},
1396 module.logicModule)
1397 if len(errs) > 0 {
1398 for i := range errs {
1399 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1400 }
1401 return errs
1402 }
1403 group.namespace = namespace
1404
Colin Cross0b7e83e2016-05-17 14:58:05 -07001405 c.moduleGroups = append(c.moduleGroups, group)
1406
Colin Cross23d7aa12015-06-30 16:05:22 -07001407 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001408}
1409
Jamie Gennisd4e10182014-06-12 20:06:50 -07001410// ResolveDependencies checks that the dependencies specified by all of the
1411// modules defined in the parsed Blueprints files are valid. This means that
1412// the modules depended upon are defined and that no circular dependencies
1413// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001414func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001415 return c.resolveDependencies(c.Context, config)
1416}
Colin Cross5f03f112017-11-07 13:29:54 -08001417
Colin Cross3a8c0252019-01-23 13:21:48 -08001418func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1419 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
1420 c.liveGlobals = newLiveTracker(config)
1421
1422 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1423 if len(errs) > 0 {
1424 return
1425 }
1426
1427 errs = c.updateDependencies()
1428 if len(errs) > 0 {
1429 return
1430 }
1431
1432 var mutatorDeps []string
1433 mutatorDeps, errs = c.runMutators(ctx, config)
1434 if len(errs) > 0 {
1435 return
1436 }
1437 deps = append(deps, mutatorDeps...)
1438
1439 c.cloneModules()
1440
1441 c.dependenciesReady = true
1442 })
1443
Colin Cross5f03f112017-11-07 13:29:54 -08001444 if len(errs) > 0 {
1445 return nil, errs
1446 }
1447
Colin Cross874a3462017-07-31 17:26:06 -07001448 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001449}
1450
Colin Cross763b6f12015-10-29 15:32:56 -07001451// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001452// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001453// module names returned by its DynamicDependencies method and those added by calling
1454// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001455func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001456 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001457 func() {
1458 defer func() {
1459 if r := recover(); r != nil {
1460 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1461 }
1462 }()
1463 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001464
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001465 if ctx.Failed() {
1466 return
1467 }
Colin Cross763b6f12015-10-29 15:32:56 -07001468
Colin Cross2c1f3d12016-04-11 15:47:28 -07001469 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001470 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001471 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001472}
1473
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001474// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1475// and returns the matching module, or nil if one is not found.
Colin Crossd03b59d2019-11-13 20:10:12 -08001476func (c *Context) findMatchingVariant(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
1477 if len(possible.modules) == 1 {
1478 return possible.modules[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001479 } else {
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001480 var variantToMatch variationMap
1481 if !reverse {
1482 // For forward dependency, ignore local variants by matching against
1483 // dependencyVariant which doesn't have the local variants
1484 variantToMatch = module.dependencyVariant
1485 } else {
1486 // For reverse dependency, use all the variants
1487 variantToMatch = module.variant
1488 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001489 for _, m := range possible.modules {
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001490 if m.variant.equal(variantToMatch) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001491 return m
1492 }
1493 }
Colin Crossf7beb892019-11-13 20:11:14 -08001494 for _, m := range possible.aliases {
1495 if m.variant.equal(variantToMatch) {
1496 return m.target
1497 }
1498 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001499 }
1500
1501 return nil
1502}
1503
Colin Cross2c1f3d12016-04-11 15:47:28 -07001504func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001505 if _, ok := tag.(BaseDependencyTag); ok {
1506 panic("BaseDependencyTag is not allowed to be used directly!")
1507 }
1508
Colin Cross0b7e83e2016-05-17 14:58:05 -07001509 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001510 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001511 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001512 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001513 }}
1514 }
1515
Colin Crossd03b59d2019-11-13 20:10:12 -08001516 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001517 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001518 return c.discoveredMissingDependencies(module, depName)
Colin Crossc9028482014-12-18 16:28:54 -08001519 }
1520
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001521 if m := c.findMatchingVariant(module, possibleDeps, false); m != nil {
Colin Cross99bdb2a2019-03-29 16:35:02 -07001522 module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001523 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001524 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001525 }
Colin Crossc9028482014-12-18 16:28:54 -08001526
Colin Cross2c628442016-10-07 17:13:10 -07001527 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001528 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001529 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001530 c.prettyPrintVariant(module.dependencyVariant),
Colin Crossd03b59d2019-11-13 20:10:12 -08001531 c.prettyPrintGroupVariants(possibleDeps)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001532 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001533 }}
1534}
1535
Colin Cross8d8a7af2015-11-03 16:41:29 -08001536func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001537 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001538 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001539 Err: fmt.Errorf("%q depends on itself", destName),
1540 Pos: module.pos,
1541 }}
1542 }
1543
Colin Crossd03b59d2019-11-13 20:10:12 -08001544 possibleDeps := c.moduleGroupFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001545 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001546 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001547 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001548 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001549 Pos: module.pos,
1550 }}
1551 }
1552
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001553 if m := c.findMatchingVariant(module, possibleDeps, true); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001554 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001555 }
1556
Colin Cross2c628442016-10-07 17:13:10 -07001557 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001558 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001559 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001560 c.prettyPrintVariant(module.dependencyVariant),
Colin Crossd03b59d2019-11-13 20:10:12 -08001561 c.prettyPrintGroupVariants(possibleDeps)),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001562 Pos: module.pos,
1563 }}
1564}
1565
Colin Crossf5e34b92015-03-13 16:02:36 -07001566func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001567 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001568 if _, ok := tag.(BaseDependencyTag); ok {
1569 panic("BaseDependencyTag is not allowed to be used directly!")
1570 }
Colin Cross65569e42015-03-10 20:08:19 -07001571
Colin Crossd03b59d2019-11-13 20:10:12 -08001572 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001573 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001574 return c.discoveredMissingDependencies(module, depName)
Colin Cross65569e42015-03-10 20:08:19 -07001575 }
1576
1577 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1578 // compare the strings because the result won't be in mutator registration order.
1579 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001580 var newVariant variationMap
1581 if !far {
1582 newVariant = module.dependencyVariant.clone()
Colin Cross89486232015-05-08 11:14:54 -07001583 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001584 for _, v := range variations {
Colin Cross9403b5a2019-11-13 20:11:04 -08001585 if newVariant == nil {
1586 newVariant = make(variationMap)
1587 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001588 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001589 }
1590
Colin Crossd03b59d2019-11-13 20:10:12 -08001591 check := func(variant variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -07001592 if far {
Colin Crossd03b59d2019-11-13 20:10:12 -08001593 return variant.subset(newVariant)
Colin Cross89486232015-05-08 11:14:54 -07001594 } else {
Colin Crossd03b59d2019-11-13 20:10:12 -08001595 return variant.equal(newVariant)
Colin Cross65569e42015-03-10 20:08:19 -07001596 }
1597 }
1598
Colin Crossd03b59d2019-11-13 20:10:12 -08001599 var foundDep *moduleInfo
1600 for _, m := range possibleDeps.modules {
1601 if check(m.variant) {
1602 foundDep = m
1603 break
1604 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001605 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001606
Colin Crossd03b59d2019-11-13 20:10:12 -08001607 if foundDep == nil {
Colin Crossf7beb892019-11-13 20:11:14 -08001608 for _, m := range possibleDeps.aliases {
1609 if check(m.variant) {
1610 foundDep = m.target
1611 break
1612 }
1613 }
1614 }
1615
1616 if foundDep == nil {
Colin Crossd03b59d2019-11-13 20:10:12 -08001617 return []error{&BlueprintError{
1618 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
1619 depName, module.Name(),
1620 c.prettyPrintVariant(newVariant),
1621 c.prettyPrintGroupVariants(possibleDeps)),
1622 Pos: module.pos,
1623 }}
1624 }
1625
1626 if module == foundDep {
1627 return []error{&BlueprintError{
1628 Err: fmt.Errorf("%q depends on itself", depName),
1629 Pos: module.pos,
1630 }}
1631 }
1632 // AddVariationDependency allows adding a dependency on itself, but only if
1633 // that module is earlier in the module list than this one, since we always
1634 // run GenerateBuildActions in order for the variants of a module
1635 if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
1636 return []error{&BlueprintError{
1637 Err: fmt.Errorf("%q depends on later version of itself", depName),
1638 Pos: module.pos,
1639 }}
1640 }
1641 module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
1642 atomic.AddUint32(&c.depsModified, 1)
1643 return nil
Colin Crossc9028482014-12-18 16:28:54 -08001644}
1645
Colin Crossf1875462016-04-11 17:33:13 -07001646func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1647 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001648 if _, ok := tag.(BaseDependencyTag); ok {
1649 panic("BaseDependencyTag is not allowed to be used directly!")
1650 }
Colin Crossf1875462016-04-11 17:33:13 -07001651
1652 var fromInfo, toInfo *moduleInfo
1653 for _, m := range origModule.splitModules {
1654 if m.logicModule == from {
1655 fromInfo = m
1656 }
1657 if m.logicModule == to {
1658 toInfo = m
1659 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001660 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001661 }
1662 }
1663 }
1664
1665 if fromInfo == nil || toInfo == nil {
1666 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001667 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001668 }
1669
Colin Cross99bdb2a2019-03-29 16:35:02 -07001670 fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001671 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001672}
1673
Jeff Gastonc3e28442017-08-09 15:13:12 -07001674// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1675// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1676// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1677func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1678 // make mapping from dir path to file path
1679 filesByDir := make(map[string]string, len(paths))
1680 for _, path := range paths {
1681 dir := filepath.Dir(path)
1682 _, alreadyFound := filesByDir[dir]
1683 if alreadyFound {
1684 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1685 }
1686 filesByDir[dir] = path
1687 }
1688
Jeff Gaston656870f2017-11-29 18:37:31 -08001689 findAncestor := func(childFile string) (ancestor string) {
1690 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001691 for {
1692 ancestorDir := filepath.Dir(prevAncestorDir)
1693 if ancestorDir == prevAncestorDir {
1694 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001695 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001696 }
1697
1698 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1699 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001700 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001701 }
1702 prevAncestorDir = ancestorDir
1703 }
1704 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001705 // generate the descendants map
1706 descendants = make(map[string][]string, len(filesByDir))
1707 for _, childFile := range filesByDir {
1708 ancestorFile := findAncestor(childFile)
1709 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1710 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001711 return descendants, nil
1712}
1713
Colin Cross3702ac72016-08-11 11:09:00 -07001714type visitOrderer interface {
1715 // returns the number of modules that this module needs to wait for
1716 waitCount(module *moduleInfo) int
1717 // returns the list of modules that are waiting for this module
1718 propagate(module *moduleInfo) []*moduleInfo
1719 // visit modules in order
1720 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1721}
1722
Colin Cross7e723372018-03-28 11:50:12 -07001723type unorderedVisitorImpl struct{}
1724
1725func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1726 return 0
1727}
1728
1729func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1730 return nil
1731}
1732
1733func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1734 for _, module := range modules {
1735 if visit(module) {
1736 return
1737 }
1738 }
1739}
1740
Colin Cross3702ac72016-08-11 11:09:00 -07001741type bottomUpVisitorImpl struct{}
1742
1743func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1744 return len(module.forwardDeps)
1745}
1746
1747func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1748 return module.reverseDeps
1749}
1750
1751func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1752 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001753 if visit(module) {
1754 return
1755 }
1756 }
1757}
1758
Colin Cross3702ac72016-08-11 11:09:00 -07001759type topDownVisitorImpl struct{}
1760
1761func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1762 return len(module.reverseDeps)
1763}
1764
1765func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1766 return module.forwardDeps
1767}
1768
1769func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1770 for i := 0; i < len(modules); i++ {
1771 module := modules[len(modules)-1-i]
1772 if visit(module) {
1773 return
1774 }
1775 }
1776}
1777
1778var (
1779 bottomUpVisitor bottomUpVisitorImpl
1780 topDownVisitor topDownVisitorImpl
1781)
1782
Colin Cross49c279a2016-08-05 22:30:44 -07001783// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1784// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001785func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001786 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001787 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001788 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001789 cancel := false
Colin Cross7e723372018-03-28 11:50:12 -07001790 var backlog []*moduleInfo
1791 const limit = 1000
Colin Cross691a60d2015-01-07 18:08:56 -08001792
Colin Cross7addea32015-03-11 15:43:52 -07001793 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001794 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001795 }
1796
Colin Cross7addea32015-03-11 15:43:52 -07001797 visitOne := func(module *moduleInfo) {
Colin Cross7e723372018-03-28 11:50:12 -07001798 if count < limit {
1799 count++
1800 go func() {
1801 ret := visit(module)
1802 if ret {
1803 cancelCh <- true
1804 }
1805 doneCh <- module
1806 }()
1807 } else {
1808 backlog = append(backlog, module)
1809 }
Colin Cross691a60d2015-01-07 18:08:56 -08001810 }
1811
Colin Cross7addea32015-03-11 15:43:52 -07001812 for _, module := range c.modulesSorted {
1813 if module.waitingCount == 0 {
1814 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001815 }
1816 }
1817
Colin Cross7e723372018-03-28 11:50:12 -07001818 for count > 0 || len(backlog) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001819 select {
Colin Cross7e723372018-03-28 11:50:12 -07001820 case <-cancelCh:
1821 cancel = true
1822 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07001823 case doneModule := <-doneCh:
Colin Cross7e723372018-03-28 11:50:12 -07001824 count--
Colin Cross8900e9b2015-03-02 14:03:01 -08001825 if !cancel {
Colin Cross7e723372018-03-28 11:50:12 -07001826 for count < limit && len(backlog) > 0 {
1827 toVisit := backlog[0]
1828 backlog = backlog[1:]
1829 visitOne(toVisit)
1830 }
Colin Cross3702ac72016-08-11 11:09:00 -07001831 for _, module := range order.propagate(doneModule) {
1832 module.waitingCount--
1833 if module.waitingCount == 0 {
1834 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001835 }
Colin Cross691a60d2015-01-07 18:08:56 -08001836 }
1837 }
Colin Cross691a60d2015-01-07 18:08:56 -08001838 }
1839 }
1840}
1841
1842// updateDependencies recursively walks the module dependency graph and updates
1843// additional fields based on the dependencies. It builds a sorted list of modules
1844// such that dependencies of a module always appear first, and populates reverse
1845// dependency links and counts of total dependencies. It also reports errors when
1846// it encounters dependency cycles. This should called after resolveDependencies,
1847// as well as after any mutator pass has called addDependency
1848func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001849 visited := make(map[*moduleInfo]bool) // modules that were already checked
1850 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001851
Colin Cross7addea32015-03-11 15:43:52 -07001852 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001853
Colin Cross7addea32015-03-11 15:43:52 -07001854 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001855
Colin Cross7addea32015-03-11 15:43:52 -07001856 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001857 // We are the "start" of the cycle, so we're responsible
1858 // for generating the errors. The cycle list is in
1859 // reverse order because all the 'check' calls append
1860 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001861 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001862 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001863 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001864 })
1865
1866 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001867 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001868 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001869 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001870 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001871 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001872 curModule.Name(),
1873 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001874 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001875 })
Colin Cross7addea32015-03-11 15:43:52 -07001876 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001877 }
1878 }
1879
Colin Cross7addea32015-03-11 15:43:52 -07001880 check = func(module *moduleInfo) []*moduleInfo {
1881 visited[module] = true
1882 checking[module] = true
1883 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001884
Colin Cross7addea32015-03-11 15:43:52 -07001885 deps := make(map[*moduleInfo]bool)
1886
1887 // Add an implicit dependency ordering on all earlier modules in the same module group
1888 for _, dep := range module.group.modules {
1889 if dep == module {
1890 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001891 }
Colin Cross7addea32015-03-11 15:43:52 -07001892 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001893 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001894
Colin Cross7addea32015-03-11 15:43:52 -07001895 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001896 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001897 }
1898
1899 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001900 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001901
Colin Crossbbfa51a2014-12-17 16:12:41 -08001902 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001903 if checking[dep] {
1904 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001905 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001906 }
1907
1908 if !visited[dep] {
1909 cycle := check(dep)
1910 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001911 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001912 // We are the "start" of the cycle, so we're responsible
1913 // for generating the errors. The cycle list is in
1914 // reverse order because all the 'check' calls append
1915 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001916 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001917
1918 // We can continue processing this module's children to
1919 // find more cycles. Since all the modules that were
1920 // part of the found cycle were marked as visited we
1921 // won't run into that cycle again.
1922 } else {
1923 // We're not the "start" of the cycle, so we just append
1924 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001925 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001926 }
1927 }
1928 }
Colin Cross691a60d2015-01-07 18:08:56 -08001929
Colin Cross3702ac72016-08-11 11:09:00 -07001930 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001931 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001932 }
1933
Colin Cross7addea32015-03-11 15:43:52 -07001934 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001935
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001936 return nil
1937 }
1938
Colin Cross7addea32015-03-11 15:43:52 -07001939 for _, module := range c.moduleInfo {
1940 if !visited[module] {
1941 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001942 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001943 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001944 panic("inconceivable!")
1945 }
1946 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001947 }
1948 }
1949 }
1950
Colin Cross7addea32015-03-11 15:43:52 -07001951 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001952
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001953 return
1954}
1955
Jamie Gennisd4e10182014-06-12 20:06:50 -07001956// PrepareBuildActions generates an internal representation of all the build
1957// actions that need to be performed. This process involves invoking the
1958// GenerateBuildActions method on each of the Module objects created during the
1959// parse phase and then on each of the registered Singleton objects.
1960//
1961// If the ResolveDependencies method has not already been called it is called
1962// automatically by this method.
1963//
1964// The config argument is made available to all of the Module and Singleton
1965// objects via the Config method on the ModuleContext and SingletonContext
1966// objects passed to GenerateBuildActions. It is also passed to the functions
1967// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1968// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001969//
1970// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001971// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1972// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1973// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001974func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001975 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
1976 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001977
Colin Cross3a8c0252019-01-23 13:21:48 -08001978 if !c.dependenciesReady {
1979 var extraDeps []string
1980 extraDeps, errs = c.resolveDependencies(ctx, config)
1981 if len(errs) > 0 {
1982 return
1983 }
1984 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001985 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001986
Colin Cross3a8c0252019-01-23 13:21:48 -08001987 var depsModules []string
1988 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
1989 if len(errs) > 0 {
1990 return
1991 }
1992
1993 var depsSingletons []string
1994 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
1995 if len(errs) > 0 {
1996 return
1997 }
1998
1999 deps = append(deps, depsModules...)
2000 deps = append(deps, depsSingletons...)
2001
2002 if c.ninjaBuildDir != nil {
2003 err := c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
2004 if err != nil {
2005 errs = []error{err}
2006 return
2007 }
2008 }
2009
2010 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2011
2012 deps = append(deps, depsPackages...)
2013
2014 // This will panic if it finds a problem since it's a programming error.
2015 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
2016
2017 c.pkgNames = pkgNames
2018 c.globalVariables = c.liveGlobals.variables
2019 c.globalPools = c.liveGlobals.pools
2020 c.globalRules = c.liveGlobals.rules
2021
2022 c.buildActionsReady = true
2023 })
2024
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002025 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002026 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002027 }
2028
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002029 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002030}
2031
Colin Cross3a8c0252019-01-23 13:21:48 -08002032func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07002033 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07002034
Colin Cross3a8c0252019-01-23 13:21:48 -08002035 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
2036 mutators = append(mutators, c.earlyMutatorInfo...)
2037 mutators = append(mutators, c.mutatorInfo...)
Colin Crossf8b50422016-08-10 12:56:40 -07002038
Colin Cross3a8c0252019-01-23 13:21:48 -08002039 for _, mutator := range mutators {
2040 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
2041 var newDeps []string
2042 if mutator.topDownMutator != nil {
2043 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
2044 } else if mutator.bottomUpMutator != nil {
2045 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
2046 } else {
2047 panic("no mutator set on " + mutator.name)
2048 }
2049 if len(errs) > 0 {
2050 return
2051 }
2052 deps = append(deps, newDeps...)
2053 })
2054 if len(errs) > 0 {
2055 return
2056 }
Colin Crossc9028482014-12-18 16:28:54 -08002057 }
Colin Cross3a8c0252019-01-23 13:21:48 -08002058 })
2059
2060 if len(errs) > 0 {
2061 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08002062 }
2063
Colin Cross874a3462017-07-31 17:26:06 -07002064 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08002065}
2066
Colin Cross3702ac72016-08-11 11:09:00 -07002067type mutatorDirection interface {
2068 run(mutator *mutatorInfo, ctx *mutatorContext)
2069 orderer() visitOrderer
2070 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08002071}
2072
Colin Cross3702ac72016-08-11 11:09:00 -07002073type bottomUpMutatorImpl struct{}
2074
2075func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2076 mutator.bottomUpMutator(ctx)
2077}
2078
2079func (bottomUpMutatorImpl) orderer() visitOrderer {
2080 return bottomUpVisitor
2081}
2082
2083func (bottomUpMutatorImpl) String() string {
2084 return "bottom up mutator"
2085}
2086
2087type topDownMutatorImpl struct{}
2088
2089func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2090 mutator.topDownMutator(ctx)
2091}
2092
2093func (topDownMutatorImpl) orderer() visitOrderer {
2094 return topDownVisitor
2095}
2096
2097func (topDownMutatorImpl) String() string {
2098 return "top down mutator"
2099}
2100
2101var (
2102 topDownMutator topDownMutatorImpl
2103 bottomUpMutator bottomUpMutatorImpl
2104)
2105
Colin Cross49c279a2016-08-05 22:30:44 -07002106type reverseDep struct {
2107 module *moduleInfo
2108 dep depInfo
2109}
2110
Colin Cross3702ac72016-08-11 11:09:00 -07002111func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002112 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002113
2114 newModuleInfo := make(map[Module]*moduleInfo)
2115 for k, v := range c.moduleInfo {
2116 newModuleInfo[k] = v
2117 }
Colin Crossc9028482014-12-18 16:28:54 -08002118
Colin Cross0ce142c2016-12-09 10:29:05 -08002119 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002120 reverse []reverseDep
2121 rename []rename
2122 replace []replace
2123 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002124 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002125 }
2126
Colin Cross2c1f3d12016-04-11 15:47:28 -07002127 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002128 var rename []rename
2129 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002130 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002131
Colin Cross49c279a2016-08-05 22:30:44 -07002132 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002133 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07002134 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07002135 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002136
Colin Cross3702ac72016-08-11 11:09:00 -07002137 c.depsModified = 0
2138
Colin Cross49c279a2016-08-05 22:30:44 -07002139 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002140 if module.splitModules != nil {
2141 panic("split module found in sorted module list")
2142 }
2143
Colin Cross7addea32015-03-11 15:43:52 -07002144 mctx := &mutatorContext{
2145 baseModuleContext: baseModuleContext{
2146 context: c,
2147 config: config,
2148 module: module,
2149 },
Colin Cross49c279a2016-08-05 22:30:44 -07002150 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07002151 }
Colin Crossc9028482014-12-18 16:28:54 -08002152
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002153 func() {
2154 defer func() {
2155 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002156 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002157 if err, ok := r.(panicError); ok {
2158 err.addIn(in)
2159 mctx.error(err)
2160 } else {
2161 mctx.error(newPanicErrorf(r, in))
2162 }
2163 }
2164 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002165 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002166 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002167
Colin Cross7addea32015-03-11 15:43:52 -07002168 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002169 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002170 return true
Colin Cross7addea32015-03-11 15:43:52 -07002171 }
Colin Crossc9028482014-12-18 16:28:54 -08002172
Colin Cross5fe225f2017-07-28 15:22:46 -07002173 if len(mctx.newVariations) > 0 {
2174 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002175 }
2176
Colin Crossaf4fd212017-07-28 14:32:36 -07002177 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08002178 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002179 reverse: mctx.reverseDeps,
2180 replace: mctx.replace,
2181 rename: mctx.rename,
2182 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002183 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002184 }
Colin Cross49c279a2016-08-05 22:30:44 -07002185 }
2186
2187 return false
2188 }
2189
2190 // Process errs and reverseDeps in a single goroutine
2191 go func() {
2192 for {
2193 select {
2194 case newErrs := <-errsCh:
2195 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002196 case globalStateChange := <-globalStateCh:
2197 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002198 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2199 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002200 replace = append(replace, globalStateChange.replace...)
2201 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002202 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002203 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002204 case newVariations := <-newVariationsCh:
2205 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002206 newModuleInfo[m.logicModule] = m
2207 }
2208 case <-done:
2209 return
Colin Crossc9028482014-12-18 16:28:54 -08002210 }
2211 }
Colin Cross49c279a2016-08-05 22:30:44 -07002212 }()
Colin Crossc9028482014-12-18 16:28:54 -08002213
Colin Cross49c279a2016-08-05 22:30:44 -07002214 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002215 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002216 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002217 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002218 }
2219
2220 done <- true
2221
2222 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002223 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002224 }
2225
2226 c.moduleInfo = newModuleInfo
2227
2228 for _, group := range c.moduleGroups {
2229 for i := 0; i < len(group.modules); i++ {
2230 module := group.modules[i]
2231
2232 // Update module group to contain newly split variants
2233 if module.splitModules != nil {
2234 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2235 }
2236
Colin Crossf7beb892019-11-13 20:11:14 -08002237 // Create any new aliases.
2238 if module.aliasTarget != nil {
2239 group.aliases = append(group.aliases, &moduleAlias{
2240 variantName: module.variantName,
2241 variant: module.variant,
2242 dependencyVariant: module.dependencyVariant,
2243 target: module.aliasTarget,
2244 })
2245 }
2246
Colin Cross49c279a2016-08-05 22:30:44 -07002247 // Fix up any remaining dependencies on modules that were split into variants
2248 // by replacing them with the first variant
2249 for j, dep := range module.directDeps {
2250 if dep.module.logicModule == nil {
2251 module.directDeps[j].module = dep.module.splitModules[0]
2252 }
2253 }
Colin Cross99bdb2a2019-03-29 16:35:02 -07002254
Colin Cross322cc012019-05-20 13:55:14 -07002255 if module.createdBy != nil && module.createdBy.logicModule == nil {
2256 module.createdBy = module.createdBy.splitModules[0]
2257 }
2258
Colin Cross99bdb2a2019-03-29 16:35:02 -07002259 // Add in any new direct dependencies that were added by the mutator
2260 module.directDeps = append(module.directDeps, module.newDirectDeps...)
2261 module.newDirectDeps = nil
Colin Cross7addea32015-03-11 15:43:52 -07002262 }
Colin Crossf7beb892019-11-13 20:11:14 -08002263
2264 // Forward or delete any dangling aliases.
2265 for i := 0; i < len(group.aliases); i++ {
2266 alias := group.aliases[i]
2267
2268 if alias.target.logicModule == nil {
2269 if alias.target.aliasTarget != nil {
2270 alias.target = alias.target.aliasTarget
2271 } else {
2272 // The alias was left dangling, remove it.
2273 group.aliases = append(group.aliases[:i], group.aliases[i+1:]...)
2274 i--
2275 }
2276 }
2277 }
Colin Crossc9028482014-12-18 16:28:54 -08002278 }
2279
Colin Cross99bdb2a2019-03-29 16:35:02 -07002280 // Add in any new reverse dependencies that were added by the mutator
Colin Cross8d8a7af2015-11-03 16:41:29 -08002281 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002282 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002283 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002284 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002285 }
2286
Colin Crossaf4fd212017-07-28 14:32:36 -07002287 for _, module := range newModules {
2288 errs = c.addModule(module)
2289 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002290 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002291 }
2292 atomic.AddUint32(&c.depsModified, 1)
2293 }
2294
Colin Cross0ce142c2016-12-09 10:29:05 -08002295 errs = c.handleRenames(rename)
2296 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002297 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002298 }
2299
2300 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002301 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002302 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002303 }
2304
Colin Cross3702ac72016-08-11 11:09:00 -07002305 if c.depsModified > 0 {
2306 errs = c.updateDependencies()
2307 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002308 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002309 }
Colin Crossc9028482014-12-18 16:28:54 -08002310 }
2311
Colin Cross874a3462017-07-31 17:26:06 -07002312 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002313}
2314
Colin Cross910242b2016-04-11 15:41:52 -07002315// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2316// a mutator sets a non-property member variable on a module, which works until a later mutator
2317// creates variants of that module.
2318func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002319 type update struct {
2320 orig Module
2321 clone *moduleInfo
2322 }
Colin Cross7e723372018-03-28 11:50:12 -07002323 ch := make(chan update)
2324 doneCh := make(chan bool)
2325 go func() {
2326 c.parallelVisit(unorderedVisitorImpl{}, func(m *moduleInfo) bool {
Colin Crossc93490c2016-08-09 14:21:02 -07002327 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002328 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002329 ch <- update{origLogicModule, m}
Colin Cross7e723372018-03-28 11:50:12 -07002330 return false
2331 })
2332 doneCh <- true
2333 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002334
Colin Cross7e723372018-03-28 11:50:12 -07002335 done := false
2336 for !done {
2337 select {
2338 case <-doneCh:
2339 done = true
2340 case update := <-ch:
2341 delete(c.moduleInfo, update.orig)
2342 c.moduleInfo[update.clone.logicModule] = update.clone
2343 }
Colin Cross910242b2016-04-11 15:41:52 -07002344 }
2345}
2346
Colin Cross49c279a2016-08-05 22:30:44 -07002347// Removes modules[i] from the list and inserts newModules... where it was located, returning
2348// the new slice and the index of the last inserted element
2349func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002350 spliceSize := len(newModules)
2351 newLen := len(modules) + spliceSize - 1
2352 var dest []*moduleInfo
2353 if cap(modules) >= len(modules)-1+len(newModules) {
2354 // We can fit the splice in the existing capacity, do everything in place
2355 dest = modules[:newLen]
2356 } else {
2357 dest = make([]*moduleInfo, newLen)
2358 copy(dest, modules[:i])
2359 }
2360
2361 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002362 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002363
2364 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002365 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002366
Colin Cross49c279a2016-08-05 22:30:44 -07002367 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002368}
2369
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002370func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002371 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002372
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002373 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002374 var errs []error
2375
Colin Cross691a60d2015-01-07 18:08:56 -08002376 cancelCh := make(chan struct{})
2377 errsCh := make(chan []error)
2378 depsCh := make(chan []string)
2379
2380 go func() {
2381 for {
2382 select {
2383 case <-cancelCh:
2384 close(cancelCh)
2385 return
2386 case newErrs := <-errsCh:
2387 errs = append(errs, newErrs...)
2388 case newDeps := <-depsCh:
2389 deps = append(deps, newDeps...)
2390
2391 }
2392 }
2393 }()
2394
Colin Cross3702ac72016-08-11 11:09:00 -07002395 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08002396
2397 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2398 sanitizedName := toNinjaName(uniqueName)
2399
2400 prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variantName)
2401
Colin Cross7addea32015-03-11 15:43:52 -07002402 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2403 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2404 // just set it to nil.
Colin Cross7addea32015-03-11 15:43:52 -07002405 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002406
Colin Cross7addea32015-03-11 15:43:52 -07002407 mctx := &moduleContext{
2408 baseModuleContext: baseModuleContext{
2409 context: c,
2410 config: config,
2411 module: module,
2412 },
Colin Cross036a1df2015-12-17 15:49:30 -08002413 scope: scope,
2414 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002415 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002416
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002417 func() {
2418 defer func() {
2419 if r := recover(); r != nil {
2420 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2421 if err, ok := r.(panicError); ok {
2422 err.addIn(in)
2423 mctx.error(err)
2424 } else {
2425 mctx.error(newPanicErrorf(r, in))
2426 }
2427 }
2428 }()
2429 mctx.module.logicModule.GenerateBuildActions(mctx)
2430 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002431
Colin Cross7addea32015-03-11 15:43:52 -07002432 if len(mctx.errs) > 0 {
2433 errsCh <- mctx.errs
2434 return true
2435 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002436
Colin Cross036a1df2015-12-17 15:49:30 -08002437 if module.missingDeps != nil && !mctx.handledMissingDeps {
2438 var errs []error
2439 for _, depName := range module.missingDeps {
Jeff Gastond70bf752017-11-10 15:12:08 -08002440 errs = append(errs, c.missingDependencyError(module, depName))
Colin Cross036a1df2015-12-17 15:49:30 -08002441 }
2442 errsCh <- errs
2443 return true
2444 }
2445
Colin Cross7addea32015-03-11 15:43:52 -07002446 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002447
Colin Crossab6d7902015-03-11 16:17:52 -07002448 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002449 &mctx.actionDefs, liveGlobals)
2450 if len(newErrs) > 0 {
2451 errsCh <- newErrs
2452 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002453 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002454 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002455 })
2456
2457 cancelCh <- struct{}{}
2458 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002459
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002460 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002461}
2462
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002463func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002464 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002465
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002466 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002467 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002468
Colin Cross5f03f112017-11-07 13:29:54 -08002469 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002470 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2471 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2472 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002473 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002474
2475 sctx := &singletonContext{
Colin Cross9226d6c2019-02-25 18:07:44 -08002476 name: info.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002477 context: c,
2478 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002479 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002480 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002481 }
2482
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002483 func() {
2484 defer func() {
2485 if r := recover(); r != nil {
2486 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2487 if err, ok := r.(panicError); ok {
2488 err.addIn(in)
2489 sctx.error(err)
2490 } else {
2491 sctx.error(newPanicErrorf(r, in))
2492 }
2493 }
2494 }()
2495 info.singleton.GenerateBuildActions(sctx)
2496 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002497
2498 if len(sctx.errs) > 0 {
2499 errs = append(errs, sctx.errs...)
2500 if len(errs) > maxErrors {
2501 break
2502 }
2503 continue
2504 }
2505
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002506 deps = append(deps, sctx.ninjaFileDeps...)
2507
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002508 newErrs := c.processLocalBuildActions(&info.actionDefs,
2509 &sctx.actionDefs, liveGlobals)
2510 errs = append(errs, newErrs...)
2511 if len(errs) > maxErrors {
2512 break
2513 }
2514 }
2515
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002516 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002517}
2518
2519func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2520 liveGlobals *liveTracker) []error {
2521
2522 var errs []error
2523
2524 // First we go through and add everything referenced by the module's
2525 // buildDefs to the live globals set. This will end up adding the live
2526 // locals to the set as well, but we'll take them out after.
2527 for _, def := range in.buildDefs {
2528 err := liveGlobals.AddBuildDefDeps(def)
2529 if err != nil {
2530 errs = append(errs, err)
2531 }
2532 }
2533
2534 if len(errs) > 0 {
2535 return errs
2536 }
2537
Colin Crossc9028482014-12-18 16:28:54 -08002538 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002539
2540 // We use the now-incorrect set of live "globals" to determine which local
2541 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002542 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002543 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002544 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002545 if isLive {
2546 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002547 }
2548 }
2549
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002550 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002551 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002552 if isLive {
2553 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002554 }
2555 }
2556
2557 return nil
2558}
2559
Colin Cross9607a9f2018-06-20 11:16:37 -07002560func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07002561 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002562
2563 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002564 var visiting *moduleInfo
2565
2566 defer func() {
2567 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002568 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2569 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002570 }
2571 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002572
2573 var walk func(module *moduleInfo)
2574 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002575 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07002576 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002577 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002578 recurse := true
2579 if visitDown != nil {
2580 recurse = visitDown(dep, module)
2581 }
Colin Cross526e02f2018-06-21 13:31:53 -07002582 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002583 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002584 }
Colin Cross526e02f2018-06-21 13:31:53 -07002585 visited[dep.module] = true
Colin Crossbafd5f52016-08-06 22:52:01 -07002586 if visitUp != nil {
2587 visitUp(dep, module)
2588 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002589 }
2590 }
2591 }
2592
2593 walk(topModule)
2594}
2595
Colin Cross9cfd1982016-10-11 09:58:53 -07002596type replace struct {
2597 from, to *moduleInfo
2598}
2599
Colin Crossc4e5b812016-10-12 10:45:05 -07002600type rename struct {
2601 group *moduleGroup
2602 name string
2603}
2604
Colin Cross0ce142c2016-12-09 10:29:05 -08002605func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Crossd03b59d2019-11-13 20:10:12 -08002606 group := c.moduleGroupFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07002607
Colin Crossd03b59d2019-11-13 20:10:12 -08002608 if group == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002609 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002610 }
2611
Colin Crossd03b59d2019-11-13 20:10:12 -08002612 for _, m := range group.modules {
Colin Cross9cfd1982016-10-11 09:58:53 -07002613 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002614 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002615 }
2616 }
2617
Colin Crossf7beb892019-11-13 20:11:14 -08002618 for _, m := range group.aliases {
2619 if module.variantName == m.variantName {
2620 return m.target
2621 }
2622 }
2623
Colin Cross0ce142c2016-12-09 10:29:05 -08002624 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002625}
2626
Colin Cross0ce142c2016-12-09 10:29:05 -08002627func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002628 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002629 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002630 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08002631 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07002632 continue
2633 }
2634
Jeff Gastond70bf752017-11-10 15:12:08 -08002635 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07002636 }
2637
Colin Cross0ce142c2016-12-09 10:29:05 -08002638 return errs
2639}
2640
2641func (c *Context) handleReplacements(replacements []replace) []error {
2642 var errs []error
2643 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002644 for _, m := range replace.from.reverseDeps {
2645 for i, d := range m.directDeps {
2646 if d.module == replace.from {
2647 m.directDeps[i].module = replace.to
2648 }
2649 }
2650 }
2651
2652 atomic.AddUint32(&c.depsModified, 1)
2653 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002654
Colin Crossc4e5b812016-10-12 10:45:05 -07002655 return errs
2656}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002657
Jeff Gastond70bf752017-11-10 15:12:08 -08002658func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
2659 if c.allowMissingDependencies {
2660 module.missingDeps = append(module.missingDeps, depName)
2661 return nil
2662 }
2663 return []error{c.missingDependencyError(module, depName)}
2664}
2665
2666func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
2667 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
2668
2669 return &BlueprintError{
2670 Err: err,
2671 Pos: module.pos,
2672 }
2673}
2674
Colin Crossd03b59d2019-11-13 20:10:12 -08002675func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
Jeff Gastond70bf752017-11-10 15:12:08 -08002676 group, exists := c.nameInterface.ModuleFromName(name, namespace)
2677 if exists {
Colin Crossd03b59d2019-11-13 20:10:12 -08002678 return group.moduleGroup
Colin Cross0b7e83e2016-05-17 14:58:05 -07002679 }
2680 return nil
2681}
2682
Jeff Gastond70bf752017-11-10 15:12:08 -08002683func (c *Context) sortedModuleGroups() []*moduleGroup {
2684 if c.cachedSortedModuleGroups == nil {
2685 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
2686 result := make([]*moduleGroup, 0, len(wrappers))
2687 for _, group := range wrappers {
2688 result = append(result, group.moduleGroup)
2689 }
2690 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07002691 }
Jeff Gastond70bf752017-11-10 15:12:08 -08002692
2693 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Jamie Gennisc15544d2014-09-24 20:26:52 -07002694 }
2695
Jeff Gastond70bf752017-11-10 15:12:08 -08002696 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07002697}
2698
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002699func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002700 var module *moduleInfo
2701
2702 defer func() {
2703 if r := recover(); r != nil {
2704 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2705 funcName(visit), module))
2706 }
2707 }()
2708
Jeff Gastond70bf752017-11-10 15:12:08 -08002709 for _, moduleGroup := range c.sortedModuleGroups() {
2710 for _, module = range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002711 visit(module.logicModule)
2712 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002713 }
2714}
2715
2716func (c *Context) visitAllModulesIf(pred func(Module) bool,
2717 visit func(Module)) {
2718
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002719 var module *moduleInfo
2720
2721 defer func() {
2722 if r := recover(); r != nil {
2723 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2724 funcName(pred), funcName(visit), module))
2725 }
2726 }()
2727
Jeff Gastond70bf752017-11-10 15:12:08 -08002728 for _, moduleGroup := range c.sortedModuleGroups() {
2729 for _, module := range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002730 if pred(module.logicModule) {
2731 visit(module.logicModule)
2732 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002733 }
2734 }
2735}
2736
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002737func (c *Context) visitAllModuleVariants(module *moduleInfo,
2738 visit func(Module)) {
2739
2740 var variant *moduleInfo
2741
2742 defer func() {
2743 if r := recover(); r != nil {
2744 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2745 module, funcName(visit), variant))
2746 }
2747 }()
2748
2749 for _, variant = range module.group.modules {
2750 visit(variant.logicModule)
2751 }
2752}
2753
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002754func (c *Context) requireNinjaVersion(major, minor, micro int) {
2755 if major != 1 {
2756 panic("ninja version with major version != 1 not supported")
2757 }
2758 if c.requiredNinjaMinor < minor {
2759 c.requiredNinjaMinor = minor
2760 c.requiredNinjaMicro = micro
2761 }
2762 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2763 c.requiredNinjaMicro = micro
2764 }
2765}
2766
Colin Crossa2599452015-11-18 16:01:01 -08002767func (c *Context) setNinjaBuildDir(value *ninjaString) {
2768 if c.ninjaBuildDir == nil {
2769 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002770 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002771}
2772
2773func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002774 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002775
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002776 pkgs := make(map[string]*packageContext)
2777 pkgNames := make(map[*packageContext]string)
2778 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002779
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002780 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002781 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002782 // This is a built-in rule and has no package.
2783 return
2784 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002785 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002786 // We've already processed this package.
2787 return
2788 }
2789
Jamie Gennis2fb20952014-10-03 02:49:58 -07002790 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002791 if present {
2792 // Short name collision. Both this package and the one that's
2793 // already there need to use their full names. We leave the short
2794 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002795 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002796 longPkgNames[otherPkg] = true
2797 } else {
2798 // No collision so far. Tentatively set the package's name to be
2799 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002800 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002801 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002802 }
2803 }
2804
2805 // We try to give all packages their short name, but when we get collisions
2806 // we need to use the full unique package name.
2807 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002808 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002809 }
2810 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002811 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002812 }
2813 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002814 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002815 }
2816
2817 // Add the packages that had collisions using their full unique names. This
2818 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002819 for pctx := range longPkgNames {
2820 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002821 }
2822
Dan Willemsena481ae22015-12-18 15:18:03 -08002823 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2824 deps := []string{}
2825 for _, pkg := range pkgs {
2826 deps = append(deps, pkg.ninjaFileDeps...)
2827 }
2828
2829 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002830}
2831
2832func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002833 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002834
2835 visited := make(map[Variable]bool) // variables that were already checked
2836 checking := make(map[Variable]bool) // variables actively being checked
2837
2838 var check func(v Variable) []Variable
2839
2840 check = func(v Variable) []Variable {
2841 visited[v] = true
2842 checking[v] = true
2843 defer delete(checking, v)
2844
2845 value := variables[v]
2846 for _, dep := range value.variables {
2847 if checking[dep] {
2848 // This is a cycle.
2849 return []Variable{dep, v}
2850 }
2851
2852 if !visited[dep] {
2853 cycle := check(dep)
2854 if cycle != nil {
2855 if cycle[0] == v {
2856 // We are the "start" of the cycle, so we're responsible
2857 // for generating the errors. The cycle list is in
2858 // reverse order because all the 'check' calls append
2859 // their own module to the list.
2860 msgs := []string{"detected variable reference cycle:"}
2861
2862 // Iterate backwards through the cycle list.
2863 curName := v.fullName(pkgNames)
2864 curValue := value.Value(pkgNames)
2865 for i := len(cycle) - 1; i >= 0; i-- {
2866 next := cycle[i]
2867 nextName := next.fullName(pkgNames)
2868 nextValue := variables[next].Value(pkgNames)
2869
2870 msgs = append(msgs, fmt.Sprintf(
2871 " %q depends on %q", curName, nextName))
2872 msgs = append(msgs, fmt.Sprintf(
2873 " [%s = %s]", curName, curValue))
2874
2875 curName = nextName
2876 curValue = nextValue
2877 }
2878
2879 // Variable reference cycles are a programming error,
2880 // not the fault of the Blueprint file authors.
2881 panic(strings.Join(msgs, "\n"))
2882 } else {
2883 // We're not the "start" of the cycle, so we just append
2884 // our module to the list and return it.
2885 return append(cycle, v)
2886 }
2887 }
2888 }
2889 }
2890
2891 return nil
2892 }
2893
2894 for v := range variables {
2895 if !visited[v] {
2896 cycle := check(v)
2897 if cycle != nil {
2898 panic("inconceivable!")
2899 }
2900 }
2901 }
2902}
2903
Jamie Gennisaf435562014-10-27 22:34:56 -07002904// AllTargets returns a map all the build target names to the rule used to build
2905// them. This is the same information that is output by running 'ninja -t
2906// targets all'. If this is called before PrepareBuildActions successfully
2907// completes then ErrbuildActionsNotReady is returned.
2908func (c *Context) AllTargets() (map[string]string, error) {
2909 if !c.buildActionsReady {
2910 return nil, ErrBuildActionsNotReady
2911 }
2912
2913 targets := map[string]string{}
2914
2915 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002916 for _, module := range c.moduleInfo {
2917 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002918 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002919 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002920 outputValue, err := output.Eval(c.globalVariables)
2921 if err != nil {
2922 return nil, err
2923 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002924 targets[outputValue] = ruleName
2925 }
2926 }
2927 }
2928
2929 // Collect all the singleton build targets.
2930 for _, info := range c.singletonInfo {
2931 for _, buildDef := range info.actionDefs.buildDefs {
2932 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002933 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002934 outputValue, err := output.Eval(c.globalVariables)
2935 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002936 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002937 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002938 targets[outputValue] = ruleName
2939 }
2940 }
2941 }
2942
2943 return targets, nil
2944}
2945
Colin Crossa2599452015-11-18 16:01:01 -08002946func (c *Context) NinjaBuildDir() (string, error) {
2947 if c.ninjaBuildDir != nil {
2948 return c.ninjaBuildDir.Eval(c.globalVariables)
2949 } else {
2950 return "", nil
2951 }
2952}
2953
Colin Cross4572edd2015-05-13 14:36:24 -07002954// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2955// property structs returned by the factory for that module type.
2956func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2957 ret := make(map[string][]interface{})
2958 for moduleType, factory := range c.moduleFactories {
2959 _, ret[moduleType] = factory()
2960 }
2961
2962 return ret
2963}
2964
Jaewoong Jung781f6b22019-02-06 16:20:17 -08002965func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
2966 ret := make(map[string]ModuleFactory)
2967 for k, v := range c.moduleFactories {
2968 ret[k] = v
2969 }
2970 return ret
2971}
2972
Colin Cross4572edd2015-05-13 14:36:24 -07002973func (c *Context) ModuleName(logicModule Module) string {
2974 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002975 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002976}
2977
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002978func (c *Context) ModulePath(logicModule Module) string {
Colin Cross4572edd2015-05-13 14:36:24 -07002979 module := c.moduleInfo[logicModule]
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002980 return module.relBlueprintsFile
2981}
2982
2983func (c *Context) ModuleDir(logicModule Module) string {
2984 return filepath.Dir(c.ModulePath(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07002985}
2986
Colin Cross8c602f72015-12-17 18:02:11 -08002987func (c *Context) ModuleSubDir(logicModule Module) string {
2988 module := c.moduleInfo[logicModule]
2989 return module.variantName
2990}
2991
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002992func (c *Context) ModuleType(logicModule Module) string {
2993 module := c.moduleInfo[logicModule]
2994 return module.typeName
2995}
2996
Colin Cross4572edd2015-05-13 14:36:24 -07002997func (c *Context) BlueprintFile(logicModule Module) string {
2998 module := c.moduleInfo[logicModule]
2999 return module.relBlueprintsFile
3000}
3001
3002func (c *Context) ModuleErrorf(logicModule Module, format string,
3003 args ...interface{}) error {
3004
3005 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07003006 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07003007 Err: fmt.Errorf(format, args...),
3008 Pos: module.pos,
3009 }
3010}
3011
3012func (c *Context) VisitAllModules(visit func(Module)) {
3013 c.visitAllModules(visit)
3014}
3015
3016func (c *Context) VisitAllModulesIf(pred func(Module) bool,
3017 visit func(Module)) {
3018
3019 c.visitAllModulesIf(pred, visit)
3020}
3021
Colin Cross080c1332017-03-17 13:09:05 -07003022func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
3023 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07003024
Colin Cross080c1332017-03-17 13:09:05 -07003025 var visiting *moduleInfo
3026
3027 defer func() {
3028 if r := recover(); r != nil {
3029 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
3030 topModule, funcName(visit), visiting))
3031 }
3032 }()
3033
3034 for _, dep := range topModule.directDeps {
3035 visiting = dep.module
3036 visit(dep.module.logicModule)
3037 }
3038}
3039
3040func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
3041 topModule := c.moduleInfo[module]
3042
3043 var visiting *moduleInfo
3044
3045 defer func() {
3046 if r := recover(); r != nil {
3047 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
3048 topModule, funcName(pred), funcName(visit), visiting))
3049 }
3050 }()
3051
3052 for _, dep := range topModule.directDeps {
3053 visiting = dep.module
3054 if pred(dep.module.logicModule) {
3055 visit(dep.module.logicModule)
3056 }
3057 }
3058}
3059
3060func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003061 topModule := c.moduleInfo[module]
3062
3063 var visiting *moduleInfo
3064
3065 defer func() {
3066 if r := recover(); r != nil {
3067 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
3068 topModule, funcName(visit), visiting))
3069 }
3070 }()
3071
Colin Cross9607a9f2018-06-20 11:16:37 -07003072 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003073 visiting = dep.module
3074 visit(dep.module.logicModule)
3075 })
Colin Cross4572edd2015-05-13 14:36:24 -07003076}
3077
Colin Cross080c1332017-03-17 13:09:05 -07003078func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003079 topModule := c.moduleInfo[module]
3080
3081 var visiting *moduleInfo
3082
3083 defer func() {
3084 if r := recover(); r != nil {
3085 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
3086 topModule, funcName(pred), funcName(visit), visiting))
3087 }
3088 }()
3089
Colin Cross9607a9f2018-06-20 11:16:37 -07003090 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003091 if pred(dep.module.logicModule) {
3092 visiting = dep.module
3093 visit(dep.module.logicModule)
3094 }
3095 })
Colin Cross4572edd2015-05-13 14:36:24 -07003096}
3097
Colin Cross24ad5872015-11-17 16:22:29 -08003098func (c *Context) PrimaryModule(module Module) Module {
3099 return c.moduleInfo[module].group.modules[0].logicModule
3100}
3101
3102func (c *Context) FinalModule(module Module) Module {
3103 modules := c.moduleInfo[module].group.modules
3104 return modules[len(modules)-1].logicModule
3105}
3106
3107func (c *Context) VisitAllModuleVariants(module Module,
3108 visit func(Module)) {
3109
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003110 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08003111}
3112
Colin Cross9226d6c2019-02-25 18:07:44 -08003113// Singletons returns a list of all registered Singletons.
3114func (c *Context) Singletons() []Singleton {
3115 var ret []Singleton
3116 for _, s := range c.singletonInfo {
3117 ret = append(ret, s.singleton)
3118 }
3119 return ret
3120}
3121
3122// SingletonName returns the name that the given singleton was registered with.
3123func (c *Context) SingletonName(singleton Singleton) string {
3124 for _, s := range c.singletonInfo {
3125 if s.singleton == singleton {
3126 return s.name
3127 }
3128 }
3129 return ""
3130}
3131
Jamie Gennisd4e10182014-06-12 20:06:50 -07003132// WriteBuildFile writes the Ninja manifeset text for the generated build
3133// actions to w. If this is called before PrepareBuildActions successfully
3134// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003135func (c *Context) WriteBuildFile(w io.Writer) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08003136 var err error
3137 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
3138 if !c.buildActionsReady {
3139 err = ErrBuildActionsNotReady
3140 return
3141 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003142
Colin Cross3a8c0252019-01-23 13:21:48 -08003143 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003144
Colin Cross3a8c0252019-01-23 13:21:48 -08003145 err = c.writeBuildFileHeader(nw)
3146 if err != nil {
3147 return
3148 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003149
Colin Cross3a8c0252019-01-23 13:21:48 -08003150 err = c.writeNinjaRequiredVersion(nw)
3151 if err != nil {
3152 return
3153 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003154
Colin Cross3a8c0252019-01-23 13:21:48 -08003155 err = c.writeSubninjas(nw)
3156 if err != nil {
3157 return
3158 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003159
Colin Cross3a8c0252019-01-23 13:21:48 -08003160 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003161
Colin Cross3a8c0252019-01-23 13:21:48 -08003162 err = c.writeGlobalVariables(nw)
3163 if err != nil {
3164 return
3165 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003166
Colin Cross3a8c0252019-01-23 13:21:48 -08003167 err = c.writeGlobalPools(nw)
3168 if err != nil {
3169 return
3170 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003171
Colin Cross3a8c0252019-01-23 13:21:48 -08003172 err = c.writeBuildDir(nw)
3173 if err != nil {
3174 return
3175 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003176
Colin Cross3a8c0252019-01-23 13:21:48 -08003177 err = c.writeGlobalRules(nw)
3178 if err != nil {
3179 return
3180 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003181
Colin Cross3a8c0252019-01-23 13:21:48 -08003182 err = c.writeAllModuleActions(nw)
3183 if err != nil {
3184 return
3185 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003186
Colin Cross3a8c0252019-01-23 13:21:48 -08003187 err = c.writeAllSingletonActions(nw)
3188 if err != nil {
3189 return
3190 }
3191 })
3192
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003193 if err != nil {
3194 return err
3195 }
3196
3197 return nil
3198}
3199
Jamie Gennisc15544d2014-09-24 20:26:52 -07003200type pkgAssociation struct {
3201 PkgName string
3202 PkgPath string
3203}
3204
3205type pkgAssociationSorter struct {
3206 pkgs []pkgAssociation
3207}
3208
3209func (s *pkgAssociationSorter) Len() int {
3210 return len(s.pkgs)
3211}
3212
3213func (s *pkgAssociationSorter) Less(i, j int) bool {
3214 iName := s.pkgs[i].PkgName
3215 jName := s.pkgs[j].PkgName
3216 return iName < jName
3217}
3218
3219func (s *pkgAssociationSorter) Swap(i, j int) {
3220 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3221}
3222
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003223func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3224 headerTemplate := template.New("fileHeader")
3225 _, err := headerTemplate.Parse(fileHeaderTemplate)
3226 if err != nil {
3227 // This is a programming error.
3228 panic(err)
3229 }
3230
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003231 var pkgs []pkgAssociation
3232 maxNameLen := 0
3233 for pkg, name := range c.pkgNames {
3234 pkgs = append(pkgs, pkgAssociation{
3235 PkgName: name,
3236 PkgPath: pkg.pkgPath,
3237 })
3238 if len(name) > maxNameLen {
3239 maxNameLen = len(name)
3240 }
3241 }
3242
3243 for i := range pkgs {
3244 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3245 }
3246
Jamie Gennisc15544d2014-09-24 20:26:52 -07003247 sort.Sort(&pkgAssociationSorter{pkgs})
3248
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003249 params := map[string]interface{}{
3250 "Pkgs": pkgs,
3251 }
3252
3253 buf := bytes.NewBuffer(nil)
3254 err = headerTemplate.Execute(buf, params)
3255 if err != nil {
3256 return err
3257 }
3258
3259 return nw.Comment(buf.String())
3260}
3261
3262func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3263 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3264 c.requiredNinjaMicro)
3265
3266 err := nw.Assign("ninja_required_version", value)
3267 if err != nil {
3268 return err
3269 }
3270
3271 return nw.BlankLine()
3272}
3273
Dan Willemsenab223a52018-07-05 21:56:59 -07003274func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3275 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003276 err := nw.Subninja(subninja)
3277 if err != nil {
3278 return err
3279 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003280 }
3281 return nw.BlankLine()
3282}
3283
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003284func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08003285 if c.ninjaBuildDir != nil {
3286 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003287 if err != nil {
3288 return err
3289 }
3290
3291 err = nw.BlankLine()
3292 if err != nil {
3293 return err
3294 }
3295 }
3296 return nil
3297}
3298
Jamie Gennisc15544d2014-09-24 20:26:52 -07003299type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003300 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003301}
3302
Jamie Gennisc15544d2014-09-24 20:26:52 -07003303type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003304 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003305 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003306}
3307
Jamie Gennisc15544d2014-09-24 20:26:52 -07003308func (s *globalEntitySorter) Len() int {
3309 return len(s.entities)
3310}
3311
3312func (s *globalEntitySorter) Less(i, j int) bool {
3313 iName := s.entities[i].fullName(s.pkgNames)
3314 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003315 return iName < jName
3316}
3317
Jamie Gennisc15544d2014-09-24 20:26:52 -07003318func (s *globalEntitySorter) Swap(i, j int) {
3319 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003320}
3321
3322func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3323 visited := make(map[Variable]bool)
3324
3325 var walk func(v Variable) error
3326 walk = func(v Variable) error {
3327 visited[v] = true
3328
3329 // First visit variables on which this variable depends.
3330 value := c.globalVariables[v]
3331 for _, dep := range value.variables {
3332 if !visited[dep] {
3333 err := walk(dep)
3334 if err != nil {
3335 return err
3336 }
3337 }
3338 }
3339
3340 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3341 if err != nil {
3342 return err
3343 }
3344
3345 err = nw.BlankLine()
3346 if err != nil {
3347 return err
3348 }
3349
3350 return nil
3351 }
3352
Jamie Gennisc15544d2014-09-24 20:26:52 -07003353 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3354 for variable := range c.globalVariables {
3355 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003356 }
3357
Jamie Gennisc15544d2014-09-24 20:26:52 -07003358 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003359
Jamie Gennisc15544d2014-09-24 20:26:52 -07003360 for _, entity := range globalVariables {
3361 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003362 if !visited[v] {
3363 err := walk(v)
3364 if err != nil {
3365 return nil
3366 }
3367 }
3368 }
3369
3370 return nil
3371}
3372
3373func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003374 globalPools := make([]globalEntity, 0, len(c.globalPools))
3375 for pool := range c.globalPools {
3376 globalPools = append(globalPools, pool)
3377 }
3378
3379 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3380
3381 for _, entity := range globalPools {
3382 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003383 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003384 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003385 err := def.WriteTo(nw, name)
3386 if err != nil {
3387 return err
3388 }
3389
3390 err = nw.BlankLine()
3391 if err != nil {
3392 return err
3393 }
3394 }
3395
3396 return nil
3397}
3398
3399func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003400 globalRules := make([]globalEntity, 0, len(c.globalRules))
3401 for rule := range c.globalRules {
3402 globalRules = append(globalRules, rule)
3403 }
3404
3405 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3406
3407 for _, entity := range globalRules {
3408 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003409 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003410 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003411 err := def.WriteTo(nw, name, c.pkgNames)
3412 if err != nil {
3413 return err
3414 }
3415
3416 err = nw.BlankLine()
3417 if err != nil {
3418 return err
3419 }
3420 }
3421
3422 return nil
3423}
3424
Colin Cross2c1f3d12016-04-11 15:47:28 -07003425type depSorter []depInfo
3426
3427func (s depSorter) Len() int {
3428 return len(s)
3429}
3430
3431func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003432 iName := s[i].module.Name()
3433 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003434 if iName == jName {
3435 iName = s[i].module.variantName
3436 jName = s[j].module.variantName
3437 }
3438 return iName < jName
3439}
3440
3441func (s depSorter) Swap(i, j int) {
3442 s[i], s[j] = s[j], s[i]
3443}
3444
Jeff Gaston0e907592017-12-01 17:10:52 -08003445type moduleSorter struct {
3446 modules []*moduleInfo
3447 nameInterface NameInterface
3448}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003449
Colin Crossab6d7902015-03-11 16:17:52 -07003450func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003451 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003452}
3453
Colin Crossab6d7902015-03-11 16:17:52 -07003454func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003455 iMod := s.modules[i]
3456 jMod := s.modules[j]
3457 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3458 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003459 if iName == jName {
Jeff Gaston0e907592017-12-01 17:10:52 -08003460 iName = s.modules[i].variantName
3461 jName = s.modules[j].variantName
3462 }
3463
3464 if iName == jName {
3465 panic(fmt.Sprintf("duplicate module name: %s: %#v and %#v\n", iName, iMod, jMod))
Colin Crossab6d7902015-03-11 16:17:52 -07003466 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003467 return iName < jName
3468}
3469
Colin Crossab6d7902015-03-11 16:17:52 -07003470func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003471 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003472}
3473
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003474func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3475 headerTemplate := template.New("moduleHeader")
3476 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3477 if err != nil {
3478 // This is a programming error.
3479 panic(err)
3480 }
3481
Colin Crossab6d7902015-03-11 16:17:52 -07003482 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3483 for _, module := range c.moduleInfo {
3484 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003485 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003486 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003487
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003488 buf := bytes.NewBuffer(nil)
3489
Colin Crossab6d7902015-03-11 16:17:52 -07003490 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003491 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3492 continue
3493 }
3494
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003495 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003496
3497 // In order to make the bootstrap build manifest independent of the
3498 // build dir we need to output the Blueprints file locations in the
3499 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003500 relPos := module.pos
3501 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003502
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003503 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003504 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003505 factoryName := factoryFunc.Name()
3506
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003507 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003508 "name": module.Name(),
3509 "typeName": module.typeName,
3510 "goFactory": factoryName,
3511 "pos": relPos,
3512 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003513 }
3514 err = headerTemplate.Execute(buf, infoMap)
3515 if err != nil {
3516 return err
3517 }
3518
3519 err = nw.Comment(buf.String())
3520 if err != nil {
3521 return err
3522 }
3523
3524 err = nw.BlankLine()
3525 if err != nil {
3526 return err
3527 }
3528
Colin Crossab6d7902015-03-11 16:17:52 -07003529 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003530 if err != nil {
3531 return err
3532 }
3533
3534 err = nw.BlankLine()
3535 if err != nil {
3536 return err
3537 }
3538 }
3539
3540 return nil
3541}
3542
3543func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3544 headerTemplate := template.New("singletonHeader")
3545 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3546 if err != nil {
3547 // This is a programming error.
3548 panic(err)
3549 }
3550
3551 buf := bytes.NewBuffer(nil)
3552
Yuchen Wub9103ef2015-08-25 17:58:17 -07003553 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003554 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3555 continue
3556 }
3557
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003558 // Get the name of the factory function for the module.
3559 factory := info.factory
3560 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3561 factoryName := factoryFunc.Name()
3562
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003563 buf.Reset()
3564 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003565 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003566 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003567 }
3568 err = headerTemplate.Execute(buf, infoMap)
3569 if err != nil {
3570 return err
3571 }
3572
3573 err = nw.Comment(buf.String())
3574 if err != nil {
3575 return err
3576 }
3577
3578 err = nw.BlankLine()
3579 if err != nil {
3580 return err
3581 }
3582
3583 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3584 if err != nil {
3585 return err
3586 }
3587
3588 err = nw.BlankLine()
3589 if err != nil {
3590 return err
3591 }
3592 }
3593
3594 return nil
3595}
3596
3597func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3598 defs *localBuildActions) error {
3599
3600 // Write the local variable assignments.
3601 for _, v := range defs.variables {
3602 // A localVariable doesn't need the package names or config to
3603 // determine its name or value.
3604 name := v.fullName(nil)
3605 value, err := v.value(nil)
3606 if err != nil {
3607 panic(err)
3608 }
3609 err = nw.Assign(name, value.Value(c.pkgNames))
3610 if err != nil {
3611 return err
3612 }
3613 }
3614
3615 if len(defs.variables) > 0 {
3616 err := nw.BlankLine()
3617 if err != nil {
3618 return err
3619 }
3620 }
3621
3622 // Write the local rules.
3623 for _, r := range defs.rules {
3624 // A localRule doesn't need the package names or config to determine
3625 // its name or definition.
3626 name := r.fullName(nil)
3627 def, err := r.def(nil)
3628 if err != nil {
3629 panic(err)
3630 }
3631
3632 err = def.WriteTo(nw, name, c.pkgNames)
3633 if err != nil {
3634 return err
3635 }
3636
3637 err = nw.BlankLine()
3638 if err != nil {
3639 return err
3640 }
3641 }
3642
3643 // Write the build definitions.
3644 for _, buildDef := range defs.buildDefs {
3645 err := buildDef.WriteTo(nw, c.pkgNames)
3646 if err != nil {
3647 return err
3648 }
3649
3650 if len(buildDef.Args) > 0 {
3651 err = nw.BlankLine()
3652 if err != nil {
3653 return err
3654 }
3655 }
3656 }
3657
3658 return nil
3659}
3660
Colin Cross65569e42015-03-10 20:08:19 -07003661func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3662 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003663 if a == b {
3664 return false
3665 }
Colin Cross65569e42015-03-10 20:08:19 -07003666 for _, l := range list {
3667 if l == a {
3668 found = true
3669 } else if l == b {
3670 return found
3671 }
3672 }
3673
3674 missing := a
3675 if found {
3676 missing = b
3677 }
3678 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3679}
3680
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003681type panicError struct {
3682 panic interface{}
3683 stack []byte
3684 in string
3685}
3686
3687func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3688 buf := make([]byte, 4096)
3689 count := runtime.Stack(buf, false)
3690 return panicError{
3691 panic: panic,
3692 in: fmt.Sprintf(in, a...),
3693 stack: buf[:count],
3694 }
3695}
3696
3697func (p panicError) Error() string {
3698 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3699}
3700
3701func (p *panicError) addIn(in string) {
3702 p.in += " in " + in
3703}
3704
3705func funcName(f interface{}) string {
3706 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3707}
3708
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003709var fileHeaderTemplate = `******************************************************************************
3710*** This file is generated and should not be edited ***
3711******************************************************************************
3712{{if .Pkgs}}
3713This file contains variables, rules, and pools with name prefixes indicating
3714they were generated by the following Go packages:
3715{{range .Pkgs}}
3716 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3717
3718`
3719
3720var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003721Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003722Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003723Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003724Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003725Defined: {{.pos}}
3726`
3727
3728var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3729Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003730Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003731`