blob: e50df9041f5bb072ff83459a73040277b50b23f1 [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"
Lukacs T. Berki6f682822021-04-01 18:27:31 +020020 "encoding/json"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070021 "errors"
22 "fmt"
23 "io"
Jeff Gastonc3e28442017-08-09 15:13:12 -070024 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070025 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070026 "path/filepath"
27 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070028 "runtime"
Colin Cross3a8c0252019-01-23 13:21:48 -080029 "runtime/pprof"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070030 "sort"
31 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070032 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070033 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070034 "text/scanner"
35 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070036
37 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080038 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070039 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070040)
41
42var ErrBuildActionsNotReady = errors.New("build actions are not ready")
43
44const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080045const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070046
Jamie Gennisd4e10182014-06-12 20:06:50 -070047// A Context contains all the state needed to parse a set of Blueprints files
48// and generate a Ninja file. The process of generating a Ninja file proceeds
49// through a series of four phases. Each phase corresponds with a some methods
50// on the Context object
51//
52// Phase Methods
53// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070054// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070055//
56// 2. Parse ParseBlueprintsFiles, Parse
57//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070058// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070059//
60// 4. Write WriteBuildFile
61//
62// The registration phase prepares the context to process Blueprints files
63// containing various types of modules. The parse phase reads in one or more
64// Blueprints files and validates their contents against the module types that
65// have been registered. The generate phase then analyzes the parsed Blueprints
66// contents to create an internal representation for the build actions that must
67// be performed. This phase also performs validation of the module dependencies
68// and property values defined in the parsed Blueprints files. Finally, the
69// write phase generates the Ninja manifest text based on the generated build
70// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070071type Context struct {
Colin Cross3a8c0252019-01-23 13:21:48 -080072 context.Context
73
Jamie Gennis1bc967e2014-05-27 16:34:41 -070074 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070075 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080076 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070077 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070078 moduleInfo map[Module]*moduleInfo
79 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080080 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070081 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070082 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070083 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070084 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085
Colin Cross3702ac72016-08-11 11:09:00 -070086 depsModified uint32 // positive if a mutator modified the dependencies
87
Jamie Gennis1bc967e2014-05-27 16:34:41 -070088 dependenciesReady bool // set to true on a successful ResolveDependencies
89 buildActionsReady bool // set to true on a successful PrepareBuildActions
90
91 // set by SetIgnoreUnknownModuleTypes
92 ignoreUnknownModuleTypes bool
93
Colin Cross036a1df2015-12-17 15:49:30 -080094 // set by SetAllowMissingDependencies
95 allowMissingDependencies bool
96
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080098 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080099 liveGlobals *liveTracker
Colin Cross2ce594e2020-01-29 12:58:03 -0800100 globalVariables map[Variable]ninjaString
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700101 globalPools map[Pool]*poolDef
102 globalRules map[Rule]*ruleDef
103
104 // set during PrepareBuildActions
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200105 outDir ninjaString // The builddir special Ninja variable
Colin Cross2ce594e2020-01-29 12:58:03 -0800106 requiredNinjaMajor int // For the ninja_required_version variable
107 requiredNinjaMinor int // For the ninja_required_version variable
108 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700109
Dan Willemsenab223a52018-07-05 21:56:59 -0700110 subninjas []string
111
Jeff Gastond70bf752017-11-10 15:12:08 -0800112 // set lazily by sortedModuleGroups
113 cachedSortedModuleGroups []*moduleGroup
Liz Kammer9ae14f12020-11-30 16:30:45 -0700114 // cache deps modified to determine whether cachedSortedModuleGroups needs to be recalculated
115 cachedDepsModified bool
Colin Crossd7b0f602016-06-02 15:30:20 -0700116
Colin Cross25236982021-04-05 17:20:34 -0700117 globs map[globKey]pathtools.GlobResult
Colin Cross127d2ea2016-11-01 11:10:51 -0700118 globLock sync.Mutex
119
Colin Crossc5fa50e2019-12-17 13:12:35 -0800120 srcDir string
Jeff Gastonc3e28442017-08-09 15:13:12 -0700121 fs pathtools.FileSystem
122 moduleListFile string
Colin Cross2da84922020-07-02 10:08:12 -0700123
124 // Mutators indexed by the ID of the provider associated with them. Not all mutators will
125 // have providers, and not all providers will have a mutator, or if they do the mutator may
126 // not be registered in this Context.
127 providerMutators []*mutatorInfo
128
129 // The currently running mutator
130 startedMutator *mutatorInfo
131 // True for any mutators that have already run over all modules
132 finishedMutators map[*mutatorInfo]bool
133
134 // Can be set by tests to avoid invalidating Module values after mutators.
135 skipCloneModulesAfterMutators bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700136}
137
Jamie Gennisd4e10182014-06-12 20:06:50 -0700138// An Error describes a problem that was encountered that is related to a
139// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700140type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700141 Err error // the error that occurred
142 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700143}
144
Colin Cross2c628442016-10-07 17:13:10 -0700145// A ModuleError describes a problem that was encountered that is related to a
146// particular module in a Blueprints file
147type ModuleError struct {
148 BlueprintError
149 module *moduleInfo
150}
151
152// A PropertyError describes a problem that was encountered that is related to a
153// particular property in a Blueprints file
154type PropertyError struct {
155 ModuleError
156 property string
157}
158
159func (e *BlueprintError) Error() string {
160 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
161}
162
163func (e *ModuleError) Error() string {
164 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
165}
166
167func (e *PropertyError) Error() string {
168 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
169}
170
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700171type localBuildActions struct {
172 variables []*localVariable
173 rules []*localRule
174 buildDefs []*buildDef
175}
176
Colin Crossf7beb892019-11-13 20:11:14 -0800177type moduleAlias struct {
Colin Crossedc41762020-08-13 12:07:30 -0700178 variant variant
179 target *moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800180}
181
Colin Cross5df74a82020-08-24 16:18:21 -0700182func (m *moduleAlias) alias() *moduleAlias { return m }
183func (m *moduleAlias) module() *moduleInfo { return nil }
184func (m *moduleAlias) moduleOrAliasTarget() *moduleInfo { return m.target }
185func (m *moduleAlias) moduleOrAliasVariant() variant { return m.variant }
186
187func (m *moduleInfo) alias() *moduleAlias { return nil }
188func (m *moduleInfo) module() *moduleInfo { return m }
189func (m *moduleInfo) moduleOrAliasTarget() *moduleInfo { return m }
190func (m *moduleInfo) moduleOrAliasVariant() variant { return m.variant }
191
192type moduleOrAlias interface {
193 alias() *moduleAlias
194 module() *moduleInfo
195 moduleOrAliasTarget() *moduleInfo
196 moduleOrAliasVariant() variant
197}
198
199type modulesOrAliases []moduleOrAlias
200
201func (l modulesOrAliases) firstModule() *moduleInfo {
202 for _, moduleOrAlias := range l {
203 if m := moduleOrAlias.module(); m != nil {
204 return m
205 }
206 }
207 panic(fmt.Errorf("no first module!"))
208}
209
210func (l modulesOrAliases) lastModule() *moduleInfo {
211 for i := range l {
212 if m := l[len(l)-1-i].module(); m != nil {
213 return m
214 }
215 }
216 panic(fmt.Errorf("no last module!"))
217}
218
Colin Crossbbfa51a2014-12-17 16:12:41 -0800219type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700220 name string
221 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700222
Colin Cross5df74a82020-08-24 16:18:21 -0700223 modules modulesOrAliases
Jeff Gastond70bf752017-11-10 15:12:08 -0800224
225 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700226}
227
Colin Cross5df74a82020-08-24 16:18:21 -0700228func (group *moduleGroup) moduleOrAliasByVariantName(name string) moduleOrAlias {
229 for _, module := range group.modules {
230 if module.moduleOrAliasVariant().name == name {
231 return module
232 }
233 }
234 return nil
235}
236
237func (group *moduleGroup) moduleByVariantName(name string) *moduleInfo {
238 return group.moduleOrAliasByVariantName(name).module()
239}
240
Colin Crossbbfa51a2014-12-17 16:12:41 -0800241type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700242 // set during Parse
243 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700244 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700245 relBlueprintsFile string
246 pos scanner.Position
247 propertyPos map[string]scanner.Position
Colin Cross322cc012019-05-20 13:55:14 -0700248 createdBy *moduleInfo
Colin Crossed342d92015-03-11 00:57:25 -0700249
Colin Crossedc41762020-08-13 12:07:30 -0700250 variant variant
Colin Crosse7daa222015-03-11 14:35:41 -0700251
Colin Crossd2f4ac12017-07-28 14:31:03 -0700252 logicModule Module
253 group *moduleGroup
254 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800255
256 // set during ResolveDependencies
Colin Cross99bdb2a2019-03-29 16:35:02 -0700257 missingDeps []string
258 newDirectDeps []depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800259
Colin Cross7addea32015-03-11 15:43:52 -0700260 // set during updateDependencies
261 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700262 forwardDeps []*moduleInfo
Colin Cross99bdb2a2019-03-29 16:35:02 -0700263 directDeps []depInfo
Colin Cross7addea32015-03-11 15:43:52 -0700264
Colin Crossc4773d92020-08-25 17:12:59 -0700265 // used by parallelVisit
Colin Cross7addea32015-03-11 15:43:52 -0700266 waitingCount int
267
Colin Crossc9028482014-12-18 16:28:54 -0800268 // set during each runMutator
Colin Cross5df74a82020-08-24 16:18:21 -0700269 splitModules modulesOrAliases
Colin Crossab6d7902015-03-11 16:17:52 -0700270
271 // set during PrepareBuildActions
272 actionDefs localBuildActions
Colin Cross2da84922020-07-02 10:08:12 -0700273
274 providers []interface{}
275
276 startedMutator *mutatorInfo
277 finishedMutator *mutatorInfo
278
279 startedGenerateBuildActions bool
280 finishedGenerateBuildActions bool
Colin Crossc9028482014-12-18 16:28:54 -0800281}
282
Colin Crossedc41762020-08-13 12:07:30 -0700283type variant struct {
284 name string
285 variations variationMap
286 dependencyVariations variationMap
287}
288
Colin Cross2c1f3d12016-04-11 15:47:28 -0700289type depInfo struct {
290 module *moduleInfo
291 tag DependencyTag
292}
293
Colin Cross0b7e83e2016-05-17 14:58:05 -0700294func (module *moduleInfo) Name() string {
Paul Duffin244033b2020-05-04 11:00:03 +0100295 // If this is called from a LoadHook (which is run before the module has been registered)
296 // then group will not be set and so the name is retrieved from logicModule.Name().
297 // Usually, using that method is not safe as it does not track renames (group.name does).
298 // However, when called from LoadHook it is safe as there is no way to rename a module
299 // until after the LoadHook has run and the module has been registered.
300 if module.group != nil {
301 return module.group.name
302 } else {
303 return module.logicModule.Name()
304 }
Colin Cross0b7e83e2016-05-17 14:58:05 -0700305}
306
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800307func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700308 s := fmt.Sprintf("module %q", module.Name())
Colin Crossedc41762020-08-13 12:07:30 -0700309 if module.variant.name != "" {
310 s += fmt.Sprintf(" variant %q", module.variant.name)
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800311 }
Colin Cross322cc012019-05-20 13:55:14 -0700312 if module.createdBy != nil {
313 s += fmt.Sprintf(" (created by %s)", module.createdBy)
314 }
315
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800316 return s
317}
318
Jeff Gastond70bf752017-11-10 15:12:08 -0800319func (module *moduleInfo) namespace() Namespace {
320 return module.group.namespace
321}
322
Colin Crossf5e34b92015-03-13 16:02:36 -0700323// A Variation is a way that a variant of a module differs from other variants of the same module.
324// For example, two variants of the same module might have Variation{"arch","arm"} and
325// Variation{"arch","arm64"}
326type Variation struct {
327 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700328 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700329 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
330 // "shared" or "static" for link.
331 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700332}
333
Colin Crossf5e34b92015-03-13 16:02:36 -0700334// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
335type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700336
Colin Crossf5e34b92015-03-13 16:02:36 -0700337func (vm variationMap) clone() variationMap {
Colin Cross9403b5a2019-11-13 20:11:04 -0800338 if vm == nil {
339 return nil
340 }
Colin Crossf5e34b92015-03-13 16:02:36 -0700341 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700342 for k, v := range vm {
343 newVm[k] = v
344 }
345
346 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800347}
348
Colin Cross89486232015-05-08 11:14:54 -0700349// Compare this variationMap to another one. Returns true if the every entry in this map
Colin Cross5dc67592020-08-24 14:46:13 -0700350// exists and has the same value in the other map.
351func (vm variationMap) subsetOf(other variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -0700352 for k, v1 := range vm {
Colin Cross5dc67592020-08-24 14:46:13 -0700353 if v2, ok := other[k]; !ok || v1 != v2 {
Colin Cross89486232015-05-08 11:14:54 -0700354 return false
355 }
356 }
357 return true
358}
359
Colin Crossf5e34b92015-03-13 16:02:36 -0700360func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700361 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800362}
363
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700364type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700365 // set during RegisterSingletonType
366 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700367 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700368 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700369
370 // set during PrepareBuildActions
371 actionDefs localBuildActions
372}
373
Colin Crossc9028482014-12-18 16:28:54 -0800374type mutatorInfo struct {
375 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800376 topDownMutator TopDownMutator
377 bottomUpMutator BottomUpMutator
378 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700379 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800380}
381
Colin Crossaf4fd212017-07-28 14:32:36 -0700382func newContext() *Context {
383 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800384 Context: context.Background(),
Colin Cross5f03f112017-11-07 13:29:54 -0800385 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800386 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800387 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross25236982021-04-05 17:20:34 -0700388 globs: make(map[globKey]pathtools.GlobResult),
Colin Cross5f03f112017-11-07 13:29:54 -0800389 fs: pathtools.OsFs,
Colin Cross2da84922020-07-02 10:08:12 -0700390 finishedMutators: make(map[*mutatorInfo]bool),
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200391 outDir: nil,
Colin Cross5f03f112017-11-07 13:29:54 -0800392 requiredNinjaMajor: 1,
393 requiredNinjaMinor: 7,
394 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700395 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700396}
397
398// NewContext creates a new Context object. The created context initially has
399// no module or singleton factories registered, so the RegisterModuleFactory and
400// RegisterSingletonFactory methods must be called before it can do anything
401// useful.
402func NewContext() *Context {
403 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700404
405 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
406
407 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700408}
409
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700410// A ModuleFactory function creates a new Module object. See the
411// Context.RegisterModuleType method for details about how a registered
412// ModuleFactory is used by a Context.
413type ModuleFactory func() (m Module, propertyStructs []interface{})
414
Jamie Gennisd4e10182014-06-12 20:06:50 -0700415// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700416// Blueprints file) with a Module factory function. When the given module type
417// name is encountered in a Blueprints file during parsing, the Module factory
418// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800419// generation for the module. If a Mutator splits a module into multiple variants,
420// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700421//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700422// The module type names given here must be unique for the context. The factory
423// function should be a named function so that its package and name can be
424// included in the generated Ninja file for debugging purposes.
425//
426// The factory function returns two values. The first is the newly created
427// Module object. The second is a slice of pointers to that Module object's
428// properties structs. Each properties struct is examined when parsing a module
429// definition of this type in a Blueprints file. Exported fields of the
430// properties structs are automatically set to the property values specified in
431// the Blueprints file. The properties struct field names determine the name of
432// the Blueprints file properties that are used - the Blueprints property name
433// matches that of the properties struct field name with the first letter
434// converted to lower-case.
435//
436// The fields of the properties struct must be either []string, a string, or
437// bool. The Context will panic if a Module gets instantiated with a properties
438// struct containing a field that is not one these supported types.
439//
440// Any properties that appear in the Blueprints files that are not built-in
441// module properties (such as "name" and "deps") and do not have a corresponding
442// field in the returned module properties struct result in an error during the
443// Context's parse phase.
444//
445// As an example, the follow code:
446//
447// type myModule struct {
448// properties struct {
449// Foo string
450// Bar []string
451// }
452// }
453//
454// func NewMyModule() (blueprint.Module, []interface{}) {
455// module := new(myModule)
456// properties := &module.properties
457// return module, []interface{}{properties}
458// }
459//
460// func main() {
461// ctx := blueprint.NewContext()
462// ctx.RegisterModuleType("my_module", NewMyModule)
463// // ...
464// }
465//
466// would support parsing a module defined in a Blueprints file as follows:
467//
468// my_module {
469// name: "myName",
470// foo: "my foo string",
471// bar: ["my", "bar", "strings"],
472// }
473//
Colin Cross7ad621c2015-01-07 16:22:45 -0800474// The factory function may be called from multiple goroutines. Any accesses
475// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700476func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
477 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700478 panic(errors.New("module type name is already registered"))
479 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700480 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700481}
482
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700483// A SingletonFactory function creates a new Singleton object. See the
484// Context.RegisterSingletonType method for details about how a registered
485// SingletonFactory is used by a Context.
486type SingletonFactory func() Singleton
487
488// RegisterSingletonType registers a singleton type that will be invoked to
Usta Shresthaee7a5d72022-01-10 22:46:23 -0500489// generate build actions. Each registered singleton type is instantiated
Yuchen Wub9103ef2015-08-25 17:58:17 -0700490// and invoked exactly once as part of the generate phase. Each registered
491// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700492//
493// The singleton type names given here must be unique for the context. The
494// factory function should be a named function so that its package and name can
495// be included in the generated Ninja file for debugging purposes.
496func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700497 for _, s := range c.singletonInfo {
498 if s.name == name {
499 panic(errors.New("singleton name is already registered"))
500 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700501 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700502
Yuchen Wub9103ef2015-08-25 17:58:17 -0700503 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700504 factory: factory,
505 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700506 name: name,
507 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700508}
509
Colin Cross5f03f112017-11-07 13:29:54 -0800510// RegisterPreSingletonType registers a presingleton type that will be invoked to
511// generate build actions before any Blueprint files have been read. Each registered
512// presingleton type is instantiated and invoked exactly once at the beginning of the
513// parse phase. Each registered presingleton is invoked in registration order.
514//
515// The presingleton type names given here must be unique for the context. The
516// factory function should be a named function so that its package and name can
517// be included in the generated Ninja file for debugging purposes.
518func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
519 for _, s := range c.preSingletonInfo {
520 if s.name == name {
521 panic(errors.New("presingleton name is already registered"))
522 }
523 }
524
525 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
526 factory: factory,
527 singleton: factory(),
528 name: name,
529 })
530}
531
Jeff Gastond70bf752017-11-10 15:12:08 -0800532func (c *Context) SetNameInterface(i NameInterface) {
533 c.nameInterface = i
534}
535
Colin Crossc5fa50e2019-12-17 13:12:35 -0800536func (c *Context) SetSrcDir(path string) {
537 c.srcDir = path
538 c.fs = pathtools.NewOsFs(path)
539}
540
541func (c *Context) SrcDir() string {
542 return c.srcDir
543}
544
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700545func singletonPkgPath(singleton Singleton) string {
546 typ := reflect.TypeOf(singleton)
547 for typ.Kind() == reflect.Ptr {
548 typ = typ.Elem()
549 }
550 return typ.PkgPath()
551}
552
553func singletonTypeName(singleton Singleton) string {
554 typ := reflect.TypeOf(singleton)
555 for typ.Kind() == reflect.Ptr {
556 typ = typ.Elem()
557 }
558 return typ.PkgPath() + "." + typ.Name()
559}
560
Colin Cross3702ac72016-08-11 11:09:00 -0700561// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
562// top-down between Modules. Each registered mutator is invoked in registration order (mixing
563// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
564// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800565//
Colin Cross65569e42015-03-10 20:08:19 -0700566// The mutator type names given here must be unique to all top down mutators in
567// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700568//
569// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
570// parallel while maintaining ordering.
571func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800572 for _, m := range c.mutatorInfo {
573 if m.name == name && m.topDownMutator != nil {
574 panic(fmt.Errorf("mutator name %s is already registered", name))
575 }
576 }
577
Colin Cross3702ac72016-08-11 11:09:00 -0700578 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800579 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800580 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700581 }
582
583 c.mutatorInfo = append(c.mutatorInfo, info)
584
585 return info
Colin Crossc9028482014-12-18 16:28:54 -0800586}
587
Colin Cross3702ac72016-08-11 11:09:00 -0700588// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
589// Each registered mutator is invoked in registration order (mixing TopDownMutators and
590// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
591// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800592//
Colin Cross65569e42015-03-10 20:08:19 -0700593// The mutator type names given here must be unique to all bottom up or early
594// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700595//
Colin Cross3702ac72016-08-11 11:09:00 -0700596// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
597// parallel while maintaining ordering.
598func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700599 for _, m := range c.variantMutatorNames {
600 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800601 panic(fmt.Errorf("mutator name %s is already registered", name))
602 }
603 }
604
Colin Cross49c279a2016-08-05 22:30:44 -0700605 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800606 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800607 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700608 }
609 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700610
611 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700612
613 return info
614}
615
Colin Cross3702ac72016-08-11 11:09:00 -0700616type MutatorHandle interface {
617 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
618 // method on the mutator context is thread-safe, but the mutator must handle synchronization
619 // for any modifications to global state or any modules outside the one it was invoked on.
620 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700621}
622
Colin Cross3702ac72016-08-11 11:09:00 -0700623func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700624 mutator.parallel = true
625 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700626}
627
628// RegisterEarlyMutator registers a mutator that will be invoked to split
629// Modules into multiple variant Modules before any dependencies have been
630// created. Each registered mutator is invoked in registration order once
631// per Module (including each variant from previous early mutators). Module
632// order is unpredictable.
633//
634// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700635// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700636//
637// The mutator type names given here must be unique to all bottom up or early
638// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700639//
640// Deprecated, use a BottomUpMutator instead. The only difference between
641// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
642// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700643func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
644 for _, m := range c.variantMutatorNames {
645 if m == name {
646 panic(fmt.Errorf("mutator name %s is already registered", name))
647 }
648 }
649
Colin Crossf8b50422016-08-10 12:56:40 -0700650 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
651 bottomUpMutator: func(mctx BottomUpMutatorContext) {
652 mutator(mctx)
653 },
654 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700655 })
656
657 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800658}
659
Jamie Gennisd4e10182014-06-12 20:06:50 -0700660// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
661// where it encounters an unknown module type while parsing Blueprints files. By
662// default, the context will report unknown module types as an error. If this
663// method is called with ignoreUnknownModuleTypes set to true then the context
664// will silently ignore unknown module types.
665//
666// This method should generally not be used. It exists to facilitate the
667// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700668func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
669 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
670}
671
Colin Cross036a1df2015-12-17 15:49:30 -0800672// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
673// unresolved dependencies. If the module's GenerateBuildActions calls
674// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
675// for missing dependencies.
676func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
677 c.allowMissingDependencies = allowMissingDependencies
678}
679
Jeff Gastonc3e28442017-08-09 15:13:12 -0700680func (c *Context) SetModuleListFile(listFile string) {
681 c.moduleListFile = listFile
682}
683
684func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
685 reader, err := c.fs.Open(c.moduleListFile)
686 if err != nil {
687 return nil, err
688 }
Liz Kammer6e7e6a92022-02-07 10:03:19 -0500689 defer reader.Close()
Jeff Gastonc3e28442017-08-09 15:13:12 -0700690 bytes, err := ioutil.ReadAll(reader)
691 if err != nil {
692 return nil, err
693 }
694 text := string(bytes)
695
696 text = strings.Trim(text, "\n")
697 lines := strings.Split(text, "\n")
698 for i := range lines {
699 lines[i] = filepath.Join(baseDir, lines[i])
700 }
701
702 return lines, nil
703}
704
Jeff Gaston656870f2017-11-29 18:37:31 -0800705// a fileParseContext tells the status of parsing a particular file
706type fileParseContext struct {
707 // name of file
708 fileName string
709
710 // scope to use when resolving variables
711 Scope *parser.Scope
712
713 // pointer to the one in the parent directory
714 parent *fileParseContext
715
716 // is closed once FileHandler has completed for this file
717 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700718}
719
Jamie Gennisd4e10182014-06-12 20:06:50 -0700720// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
721// at rootFile. When it encounters a Blueprints file with a set of subdirs
722// listed it recursively parses any Blueprints files found in those
723// subdirectories.
724//
725// If no errors are encountered while parsing the files, the list of paths on
726// which the future output will depend is returned. This list will include both
727// Blueprints file paths as well as directory paths for cases where wildcard
728// subdirs are found.
Colin Crossda70fd02019-12-30 18:40:09 -0800729func (c *Context) ParseBlueprintsFiles(rootFile string,
730 config interface{}) (deps []string, errs []error) {
731
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800732 baseDir := filepath.Dir(rootFile)
733 pathsToParse, err := c.ListModulePaths(baseDir)
734 if err != nil {
735 return nil, []error{err}
736 }
Colin Crossda70fd02019-12-30 18:40:09 -0800737 return c.ParseFileList(baseDir, pathsToParse, config)
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800738}
739
Colin Crossda70fd02019-12-30 18:40:09 -0800740func (c *Context) ParseFileList(rootDir string, filePaths []string,
741 config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700742
Jeff Gastonc3e28442017-08-09 15:13:12 -0700743 if len(filePaths) < 1 {
744 return nil, []error{fmt.Errorf("no paths provided to parse")}
745 }
746
Colin Cross7ad621c2015-01-07 16:22:45 -0800747 c.dependenciesReady = false
748
Colin Crossda70fd02019-12-30 18:40:09 -0800749 type newModuleInfo struct {
750 *moduleInfo
Colin Cross13b5bef2021-05-19 10:07:19 -0700751 deps []string
Colin Crossda70fd02019-12-30 18:40:09 -0800752 added chan<- struct{}
753 }
754
755 moduleCh := make(chan newModuleInfo)
Colin Cross23d7aa12015-06-30 16:05:22 -0700756 errsCh := make(chan []error)
757 doneCh := make(chan struct{})
758 var numErrs uint32
759 var numGoroutines int32
760
761 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700762 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700763 if atomic.LoadUint32(&numErrs) > maxErrors {
764 return
765 }
766
Colin Crossda70fd02019-12-30 18:40:09 -0800767 addedCh := make(chan struct{})
768
Colin Cross9672d862019-12-30 18:38:20 -0800769 var scopedModuleFactories map[string]ModuleFactory
770
Colin Crossda70fd02019-12-30 18:40:09 -0800771 var addModule func(module *moduleInfo) []error
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100772 addModule = func(module *moduleInfo) []error {
Paul Duffin244033b2020-05-04 11:00:03 +0100773 // Run any load hooks immediately before it is sent to the moduleCh and is
774 // registered by name. This allows load hooks to set and/or modify any aspect
775 // of the module (including names) using information that is not available when
776 // the module factory is called.
Colin Cross13b5bef2021-05-19 10:07:19 -0700777 newModules, newDeps, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
Colin Crossda70fd02019-12-30 18:40:09 -0800778 if len(errs) > 0 {
779 return errs
780 }
Paul Duffin244033b2020-05-04 11:00:03 +0100781
Colin Cross13b5bef2021-05-19 10:07:19 -0700782 moduleCh <- newModuleInfo{module, newDeps, addedCh}
Paul Duffin244033b2020-05-04 11:00:03 +0100783 <-addedCh
Colin Crossda70fd02019-12-30 18:40:09 -0800784 for _, n := range newModules {
785 errs = addModule(n)
786 if len(errs) > 0 {
787 return errs
788 }
789 }
790 return nil
791 }
792
Jeff Gaston656870f2017-11-29 18:37:31 -0800793 for _, def := range file.Defs {
Jeff Gaston656870f2017-11-29 18:37:31 -0800794 switch def := def.(type) {
795 case *parser.Module:
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100796 module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes)
Colin Crossda70fd02019-12-30 18:40:09 -0800797 if len(errs) == 0 && module != nil {
798 errs = addModule(module)
799 }
800
801 if len(errs) > 0 {
802 atomic.AddUint32(&numErrs, uint32(len(errs)))
803 errsCh <- errs
804 }
805
Jeff Gaston656870f2017-11-29 18:37:31 -0800806 case *parser.Assignment:
807 // Already handled via Scope object
808 default:
809 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700810 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800811
Jeff Gaston656870f2017-11-29 18:37:31 -0800812 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700813 }
814
815 atomic.AddInt32(&numGoroutines, 1)
816 go func() {
817 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700818 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700819 if len(errs) > 0 {
820 errsCh <- errs
821 }
822 doneCh <- struct{}{}
823 }()
824
Colin Cross13b5bef2021-05-19 10:07:19 -0700825 var hookDeps []string
Colin Cross23d7aa12015-06-30 16:05:22 -0700826loop:
827 for {
828 select {
829 case newErrs := <-errsCh:
830 errs = append(errs, newErrs...)
831 case module := <-moduleCh:
Colin Crossda70fd02019-12-30 18:40:09 -0800832 newErrs := c.addModule(module.moduleInfo)
Colin Cross13b5bef2021-05-19 10:07:19 -0700833 hookDeps = append(hookDeps, module.deps...)
Colin Crossda70fd02019-12-30 18:40:09 -0800834 if module.added != nil {
835 module.added <- struct{}{}
836 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700837 if len(newErrs) > 0 {
838 errs = append(errs, newErrs...)
839 }
840 case <-doneCh:
841 n := atomic.AddInt32(&numGoroutines, -1)
842 if n == 0 {
843 break loop
844 }
845 }
846 }
847
Colin Cross13b5bef2021-05-19 10:07:19 -0700848 deps = append(deps, hookDeps...)
Colin Cross23d7aa12015-06-30 16:05:22 -0700849 return deps, errs
850}
851
852type FileHandler func(*parser.File)
853
Jeff Gastonc3e28442017-08-09 15:13:12 -0700854// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
855// calling the given file handler on each
856//
857// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
858// it recursively parses any Blueprints files found in those subdirectories.
859//
860// If any of the file paths is an ancestor directory of any other of file path, the ancestor
861// will be parsed and visited first.
862//
863// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700864//
865// If no errors are encountered while parsing the files, the list of paths on
866// which the future output will depend is returned. This list will include both
867// Blueprints file paths as well as directory paths for cases where wildcard
868// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800869//
870// visitor will be called asynchronously, and will only be called once visitor for each
871// ancestor directory has completed.
872//
873// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700874func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
875 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700876
Jeff Gastonc3e28442017-08-09 15:13:12 -0700877 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
878 descendantsMap, err := findBlueprintDescendants(filePaths)
879 if err != nil {
880 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700881 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800882 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700883
Jeff Gaston5800d042017-12-05 14:57:58 -0800884 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800885 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800886 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800887 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700888
Jeff Gaston5800d042017-12-05 14:57:58 -0800889 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800890 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700891
Colin Cross7ad621c2015-01-07 16:22:45 -0800892 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700893 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800894 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700895 tooManyErrors := false
896
897 // Limit concurrent calls to parseBlueprintFiles to 200
898 // Darwin has a default limit of 256 open files
899 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800900
Jeff Gaston656870f2017-11-29 18:37:31 -0800901 // count the number of pending calls to visitor()
902 visitorWaitGroup := sync.WaitGroup{}
903
904 startParseBlueprintsFile := func(blueprint fileParseContext) {
905 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700906 return
907 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800908 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700909 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800910 deps = append(deps, blueprint.fileName)
911 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800912 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800913 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
914 &blueprint)
915 if len(errs) > 0 {
916 errsCh <- errs
917 }
918 for _, blueprint := range blueprints {
919 blueprintsCh <- blueprint
920 }
921 for _, dep := range deps {
922 depsCh <- dep
923 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800924 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700925
Jeff Gaston656870f2017-11-29 18:37:31 -0800926 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
927 // wait for visitor() of parent to complete
928 <-blueprint.parent.doneVisiting
929 }
930
Jeff Gastona7e408a2017-12-05 15:11:55 -0800931 if len(errs) == 0 {
932 // process this file
933 visitor(file)
934 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800935 if blueprint.doneVisiting != nil {
936 close(blueprint.doneVisiting)
937 }
938 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800939 }()
940 }
941
Jeff Gaston656870f2017-11-29 18:37:31 -0800942 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700943 if activeCount >= maxActiveCount {
944 pending = append(pending, blueprint)
945 } else {
946 startParseBlueprintsFile(blueprint)
947 }
948 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800949
Jeff Gaston656870f2017-11-29 18:37:31 -0800950 startParseDescendants := func(blueprint fileParseContext) {
951 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700952 if hasDescendants {
953 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800954 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700955 }
956 }
957 }
Colin Cross4a02a302017-05-16 10:33:58 -0700958
Jeff Gastonc3e28442017-08-09 15:13:12 -0700959 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800960 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800961
962loop:
963 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700964 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800965 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700966 }
967
Colin Cross7ad621c2015-01-07 16:22:45 -0800968 select {
969 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700970 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800971 case dep := <-depsCh:
972 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800973 case blueprint := <-blueprintsCh:
974 if tooManyErrors {
975 continue
976 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700977 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800978 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700979 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700980 if !tooManyErrors {
981 startParseDescendants(blueprint)
982 }
983 if activeCount < maxActiveCount && len(pending) > 0 {
984 // start to process the next one from the queue
985 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700986 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700987 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700988 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700989 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800990 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700991 }
992 }
993 }
994
Jeff Gastonc3e28442017-08-09 15:13:12 -0700995 sort.Strings(deps)
996
Jeff Gaston656870f2017-11-29 18:37:31 -0800997 // wait for every visitor() to complete
998 visitorWaitGroup.Wait()
999
Colin Cross7ad621c2015-01-07 16:22:45 -08001000 return
1001}
1002
Colin Crossd7b0f602016-06-02 15:30:20 -07001003// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
1004// filenames to contents stored as a byte slice.
1005func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -08001006 // look for a module list file
1007 _, ok := files[MockModuleListFile]
1008 if !ok {
1009 // no module list file specified; find every file named Blueprints
1010 pathsToParse := []string{}
1011 for candidate := range files {
Lukacs T. Berkieef56852021-09-02 11:34:06 +02001012 if filepath.Base(candidate) == "Android.bp" {
Jeff Gaston9f630902017-11-15 14:49:48 -08001013 pathsToParse = append(pathsToParse, candidate)
1014 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001015 }
Jeff Gaston9f630902017-11-15 14:49:48 -08001016 if len(pathsToParse) < 1 {
1017 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
1018 }
1019 // put the list of Blueprints files into a list file
1020 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -07001021 }
Jeff Gaston9f630902017-11-15 14:49:48 -08001022 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001023
1024 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -08001025 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -07001026}
1027
Colin Cross8cde4252019-12-17 13:11:21 -08001028func (c *Context) SetFs(fs pathtools.FileSystem) {
1029 c.fs = fs
1030}
1031
Jeff Gaston8fd95782017-12-05 15:03:51 -08001032// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -08001033func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -08001034 parent *fileParseContext) (file *parser.File,
1035 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -08001036
Colin Crossd7b0f602016-06-02 15:30:20 -07001037 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -08001038 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -07001039 // couldn't open the file; see if we can provide a clearer error than "could not open file"
1040 stats, statErr := c.fs.Lstat(filename)
1041 if statErr == nil {
1042 isSymlink := stats.Mode()&os.ModeSymlink != 0
1043 if isSymlink {
1044 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
1045 target, readlinkErr := os.Readlink(filename)
1046 if readlinkErr == nil {
1047 _, targetStatsErr := c.fs.Lstat(target)
1048 if targetStatsErr != nil {
1049 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
1050 }
1051 }
1052 } else {
1053 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
1054 }
1055 }
Jeff Gaston8fd95782017-12-05 15:03:51 -08001056 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001057 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001058
Jeff Gaston8fd95782017-12-05 15:03:51 -08001059 func() {
1060 defer func() {
1061 err = f.Close()
1062 if err != nil {
1063 errs = append(errs, err)
1064 }
1065 }()
1066 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -07001067 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001068
Colin Cross7ad621c2015-01-07 16:22:45 -08001069 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001070 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -08001071 }
1072
Colin Cross1fef5362015-04-20 16:50:54 -07001073 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001074 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -07001075 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001076
Jeff Gaston8fd95782017-12-05 15:03:51 -08001077 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -07001078}
1079
Jeff Gastona12f22f2017-08-08 14:45:56 -07001080// parseOne parses a single Blueprints file from the given reader, creating Module
1081// objects for each of the module definitions encountered. If the Blueprints
1082// file contains an assignment to the "subdirs" variable, then the
1083// subdirectories listed are searched for Blueprints files returned in the
1084// subBlueprints return value. If the Blueprints file contains an assignment
1085// to the "build" variable, then the file listed are returned in the
1086// subBlueprints return value.
1087//
1088// rootDir specifies the path to the root directory of the source tree, while
1089// filename specifies the path to the Blueprints file. These paths are used for
1090// error reporting and for determining the module's directory.
1091func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -08001092 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -07001093
1094 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
1095 if err != nil {
1096 return nil, nil, []error{err}
1097 }
1098
Jeff Gastona12f22f2017-08-08 14:45:56 -07001099 scope.Remove("subdirs")
1100 scope.Remove("optional_subdirs")
1101 scope.Remove("build")
1102 file, errs = parser.ParseAndEval(filename, reader, scope)
1103 if len(errs) > 0 {
1104 for i, err := range errs {
1105 if parseErr, ok := err.(*parser.ParseError); ok {
1106 err = &BlueprintError{
1107 Err: parseErr.Err,
1108 Pos: parseErr.Pos,
1109 }
1110 errs[i] = err
1111 }
1112 }
1113
1114 // If there were any parse errors don't bother trying to interpret the
1115 // result.
1116 return nil, nil, errs
1117 }
1118 file.Name = relBlueprintsFile
1119
Jeff Gastona12f22f2017-08-08 14:45:56 -07001120 build, buildPos, err := getLocalStringListFromScope(scope, "build")
1121 if err != nil {
1122 errs = append(errs, err)
1123 }
Jeff Gastonf23e3662017-11-30 17:31:43 -08001124 for _, buildEntry := range build {
1125 if strings.Contains(buildEntry, "/") {
1126 errs = append(errs, &BlueprintError{
1127 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1128 Pos: buildPos,
1129 })
1130 }
1131 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001132
Jeff Gastona12f22f2017-08-08 14:45:56 -07001133 if err != nil {
1134 errs = append(errs, err)
1135 }
1136
Jeff Gastona12f22f2017-08-08 14:45:56 -07001137 var blueprints []string
1138
1139 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1140 blueprints = append(blueprints, newBlueprints...)
1141 errs = append(errs, newErrs...)
1142
Jeff Gaston656870f2017-11-29 18:37:31 -08001143 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -07001144 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -08001145 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -07001146 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001147 return file, subBlueprintsAndScope, errs
1148}
1149
Colin Cross7f507402015-12-16 13:03:41 -08001150func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -07001151 buildPos scanner.Position) ([]string, []error) {
1152
1153 var blueprints []string
1154 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001155
1156 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001157 pattern := filepath.Join(dir, file)
1158 var matches []string
1159 var err error
1160
Colin Cross08e49542016-11-14 15:23:33 -08001161 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001162
Colin Cross7f507402015-12-16 13:03:41 -08001163 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001164 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001165 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001166 Pos: buildPos,
1167 })
1168 continue
1169 }
1170
1171 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001172 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001173 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001174 Pos: buildPos,
1175 })
1176 }
1177
Colin Cross7f507402015-12-16 13:03:41 -08001178 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001179 if strings.HasSuffix(foundBlueprints, "/") {
1180 errs = append(errs, &BlueprintError{
1181 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1182 Pos: buildPos,
1183 })
1184 }
Colin Cross7f507402015-12-16 13:03:41 -08001185 blueprints = append(blueprints, foundBlueprints)
1186 }
1187 }
1188
Colin Cross127d2ea2016-11-01 11:10:51 -07001189 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001190}
1191
1192func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001193 subBlueprintsName string, optional bool) ([]string, []error) {
1194
1195 var blueprints []string
1196 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001197
1198 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001199 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1200 var matches []string
1201 var err error
1202
Colin Cross08e49542016-11-14 15:23:33 -08001203 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001204
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001205 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001206 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001207 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001208 Pos: subdirsPos,
1209 })
1210 continue
1211 }
1212
Colin Cross7f507402015-12-16 13:03:41 -08001213 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001214 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001215 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001216 Pos: subdirsPos,
1217 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001218 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001219
Colin Cross127d2ea2016-11-01 11:10:51 -07001220 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001221 if strings.HasSuffix(subBlueprints, "/") {
1222 errs = append(errs, &BlueprintError{
1223 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1224 Pos: subdirsPos,
1225 })
1226 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001227 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001228 }
1229 }
Colin Cross1fef5362015-04-20 16:50:54 -07001230
Colin Cross127d2ea2016-11-01 11:10:51 -07001231 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001232}
1233
Colin Cross6d8780f2015-07-10 17:51:55 -07001234func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1235 if assignment, local := scope.Get(v); assignment == nil || !local {
1236 return nil, scanner.Position{}, nil
1237 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001238 switch value := assignment.Value.Eval().(type) {
1239 case *parser.List:
1240 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001241
Colin Crosse32cc802016-06-07 12:28:16 -07001242 for _, listValue := range value.Values {
1243 s, ok := listValue.(*parser.String)
1244 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001245 // The parser should not produce this.
1246 panic("non-string value found in list")
1247 }
1248
Colin Crosse32cc802016-06-07 12:28:16 -07001249 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001250 }
1251
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001252 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001253 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001254 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001255 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001256 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001257 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001258 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001259 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001260 }
1261 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001262}
1263
Colin Cross29394222015-04-27 13:18:21 -07001264func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001265 if assignment, _ := scope.Get(v); assignment == nil {
1266 return "", scanner.Position{}, nil
1267 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001268 switch value := assignment.Value.Eval().(type) {
1269 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001270 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001271 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001272 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001273 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001274 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001275 }
1276 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001277 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001278 }
1279 }
Colin Cross29394222015-04-27 13:18:21 -07001280}
1281
Colin Cross910242b2016-04-11 15:41:52 -07001282// Clones a build logic module by calling the factory method for its module type, and then cloning
1283// property values. Any values stored in the module object that are not stored in properties
1284// structs will be lost.
1285func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001286 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001287
Colin Crossd2f4ac12017-07-28 14:31:03 -07001288 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001289 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001290 }
1291
1292 for i := range newProperties {
Colin Cross5d57b2d2020-01-27 16:14:31 -08001293 dst := reflect.ValueOf(newProperties[i])
1294 src := reflect.ValueOf(origModule.properties[i])
Colin Cross910242b2016-04-11 15:41:52 -07001295
1296 proptools.CopyProperties(dst, src)
1297 }
1298
1299 return newLogicModule, newProperties
1300}
1301
Colin Crossedc41762020-08-13 12:07:30 -07001302func newVariant(module *moduleInfo, mutatorName string, variationName string,
1303 local bool) variant {
1304
1305 newVariantName := module.variant.name
1306 if variationName != "" {
1307 if newVariantName == "" {
1308 newVariantName = variationName
1309 } else {
1310 newVariantName += "_" + variationName
1311 }
1312 }
1313
1314 newVariations := module.variant.variations.clone()
1315 if newVariations == nil {
1316 newVariations = make(variationMap)
1317 }
1318 newVariations[mutatorName] = variationName
1319
1320 newDependencyVariations := module.variant.dependencyVariations.clone()
1321 if !local {
1322 if newDependencyVariations == nil {
1323 newDependencyVariations = make(variationMap)
1324 }
1325 newDependencyVariations[mutatorName] = variationName
1326 }
1327
1328 return variant{newVariantName, newVariations, newDependencyVariations}
1329}
1330
Colin Crossf5e34b92015-03-13 16:02:36 -07001331func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
Colin Cross5df74a82020-08-24 16:18:21 -07001332 defaultVariationName *string, variationNames []string, local bool) (modulesOrAliases, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001333
Colin Crossf4d18a62015-03-18 17:43:15 -07001334 if len(variationNames) == 0 {
1335 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001336 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001337 }
1338
Colin Cross5df74a82020-08-24 16:18:21 -07001339 var newModules modulesOrAliases
Colin Crossc9028482014-12-18 16:28:54 -08001340
Colin Cross174ae052015-03-03 17:37:03 -08001341 var errs []error
1342
Colin Crossf5e34b92015-03-13 16:02:36 -07001343 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001344 var newLogicModule Module
1345 var newProperties []interface{}
1346
1347 if i == 0 {
1348 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001349 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1350 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001351 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001352 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001353 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001354 }
1355
Colin Crossed342d92015-03-11 00:57:25 -07001356 m := *origModule
1357 newModule := &m
Colin Cross2da84922020-07-02 10:08:12 -07001358 newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
Colin Cross7ff2e8d2021-01-21 22:39:28 -08001359 newModule.reverseDeps = nil
1360 newModule.forwardDeps = nil
Colin Crossed342d92015-03-11 00:57:25 -07001361 newModule.logicModule = newLogicModule
Colin Crossedc41762020-08-13 12:07:30 -07001362 newModule.variant = newVariant(origModule, mutatorName, variationName, local)
Colin Crossd2f4ac12017-07-28 14:31:03 -07001363 newModule.properties = newProperties
Colin Cross2da84922020-07-02 10:08:12 -07001364 newModule.providers = append([]interface{}(nil), origModule.providers...)
Colin Crossc9028482014-12-18 16:28:54 -08001365
1366 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001367
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001368 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName)
Colin Cross174ae052015-03-03 17:37:03 -08001369 if len(newErrs) > 0 {
1370 errs = append(errs, newErrs...)
1371 }
Colin Crossc9028482014-12-18 16:28:54 -08001372 }
1373
1374 // Mark original variant as invalid. Modules that depend on this module will still
1375 // depend on origModule, but we'll fix it when the mutator is called on them.
1376 origModule.logicModule = nil
1377 origModule.splitModules = newModules
1378
Colin Cross3702ac72016-08-11 11:09:00 -07001379 atomic.AddUint32(&c.depsModified, 1)
1380
Colin Cross174ae052015-03-03 17:37:03 -08001381 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001382}
1383
Colin Crossf5e34b92015-03-13 16:02:36 -07001384func (c *Context) convertDepsToVariation(module *moduleInfo,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001385 mutatorName, variationName string, defaultVariationName *string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001386
Colin Crossc9028482014-12-18 16:28:54 -08001387 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001388 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001389 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001390 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001391 if m.moduleOrAliasVariant().variations[mutatorName] == variationName {
1392 newDep = m.moduleOrAliasTarget()
Colin Crossc9028482014-12-18 16:28:54 -08001393 break
1394 }
1395 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001396 if newDep == nil && defaultVariationName != nil {
1397 // give it a second chance; match with defaultVariationName
1398 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001399 if m.moduleOrAliasVariant().variations[mutatorName] == *defaultVariationName {
1400 newDep = m.moduleOrAliasTarget()
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001401 break
1402 }
1403 }
1404 }
Colin Crossc9028482014-12-18 16:28:54 -08001405 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001406 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001407 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001408 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001409 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001410 })
1411 continue
Colin Crossc9028482014-12-18 16:28:54 -08001412 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001413 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001414 }
1415 }
Colin Cross174ae052015-03-03 17:37:03 -08001416
1417 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001418}
1419
Colin Crossedc41762020-08-13 12:07:30 -07001420func (c *Context) prettyPrintVariant(variations variationMap) string {
1421 names := make([]string, 0, len(variations))
Colin Cross65569e42015-03-10 20:08:19 -07001422 for _, m := range c.variantMutatorNames {
Colin Crossedc41762020-08-13 12:07:30 -07001423 if v, ok := variations[m]; ok {
Colin Cross65569e42015-03-10 20:08:19 -07001424 names = append(names, m+":"+v)
1425 }
1426 }
1427
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001428 return strings.Join(names, ",")
Colin Cross65569e42015-03-10 20:08:19 -07001429}
1430
Colin Crossd03b59d2019-11-13 20:10:12 -08001431func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1432 var variants []string
Colin Cross5df74a82020-08-24 16:18:21 -07001433 for _, moduleOrAlias := range group.modules {
1434 if mod := moduleOrAlias.module(); mod != nil {
1435 variants = append(variants, c.prettyPrintVariant(mod.variant.variations))
1436 } else if alias := moduleOrAlias.alias(); alias != nil {
1437 variants = append(variants, c.prettyPrintVariant(alias.variant.variations)+
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001438 " (alias to "+c.prettyPrintVariant(alias.target.variant.variations)+")")
Colin Cross5df74a82020-08-24 16:18:21 -07001439 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001440 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001441 return strings.Join(variants, "\n ")
1442}
1443
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001444func newModule(factory ModuleFactory) *moduleInfo {
Colin Crossaf4fd212017-07-28 14:32:36 -07001445 logicModule, properties := factory()
1446
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001447 return &moduleInfo{
Colin Crossaf4fd212017-07-28 14:32:36 -07001448 logicModule: logicModule,
1449 factory: factory,
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001450 properties: properties,
Colin Crossaf4fd212017-07-28 14:32:36 -07001451 }
Colin Crossaf4fd212017-07-28 14:32:36 -07001452}
1453
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001454func processModuleDef(moduleDef *parser.Module,
1455 relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001456
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001457 factory, ok := moduleFactories[moduleDef.Type]
Colin Cross9672d862019-12-30 18:38:20 -08001458 if !ok && scopedModuleFactories != nil {
1459 factory, ok = scopedModuleFactories[moduleDef.Type]
1460 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001461 if !ok {
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001462 if ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001463 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001464 }
1465
Colin Cross7ad621c2015-01-07 16:22:45 -08001466 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001467 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001468 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1469 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001470 },
1471 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001472 }
1473
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001474 module := newModule(factory)
Colin Crossaf4fd212017-07-28 14:32:36 -07001475 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001476
Colin Crossaf4fd212017-07-28 14:32:36 -07001477 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001478
Colin Crossf27c5e42020-01-02 09:37:49 -08001479 propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001480 if len(errs) > 0 {
Colin Crossf27c5e42020-01-02 09:37:49 -08001481 for i, err := range errs {
1482 if unpackErr, ok := err.(*proptools.UnpackError); ok {
1483 err = &BlueprintError{
1484 Err: unpackErr.Err,
1485 Pos: unpackErr.Pos,
1486 }
1487 errs[i] = err
1488 }
1489 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001490 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001491 }
1492
Colin Crossc32c4792016-06-09 15:52:30 -07001493 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001494 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001495 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001496 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001497 }
1498
Colin Cross7ad621c2015-01-07 16:22:45 -08001499 return module, nil
1500}
1501
Colin Cross23d7aa12015-06-30 16:05:22 -07001502func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001503 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001504 if name == "" {
1505 return []error{
1506 &BlueprintError{
1507 Err: fmt.Errorf("property 'name' is missing from a module"),
1508 Pos: module.pos,
1509 },
1510 }
1511 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001512 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001513
Colin Cross0b7e83e2016-05-17 14:58:05 -07001514 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001515 name: name,
Colin Cross5df74a82020-08-24 16:18:21 -07001516 modules: modulesOrAliases{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001517 }
1518 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001519 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001520 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001521 ModuleGroup{moduleGroup: group},
1522 module.logicModule)
1523 if len(errs) > 0 {
1524 for i := range errs {
1525 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1526 }
1527 return errs
1528 }
1529 group.namespace = namespace
1530
Colin Cross0b7e83e2016-05-17 14:58:05 -07001531 c.moduleGroups = append(c.moduleGroups, group)
1532
Colin Cross23d7aa12015-06-30 16:05:22 -07001533 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001534}
1535
Jamie Gennisd4e10182014-06-12 20:06:50 -07001536// ResolveDependencies checks that the dependencies specified by all of the
1537// modules defined in the parsed Blueprints files are valid. This means that
1538// the modules depended upon are defined and that no circular dependencies
1539// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001540func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001541 return c.resolveDependencies(c.Context, config)
1542}
Colin Cross5f03f112017-11-07 13:29:54 -08001543
Colin Cross3a8c0252019-01-23 13:21:48 -08001544func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1545 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
Colin Cross2da84922020-07-02 10:08:12 -07001546 c.initProviders()
1547
Colin Cross3a8c0252019-01-23 13:21:48 -08001548 c.liveGlobals = newLiveTracker(config)
1549
1550 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1551 if len(errs) > 0 {
1552 return
1553 }
1554
1555 errs = c.updateDependencies()
1556 if len(errs) > 0 {
1557 return
1558 }
1559
1560 var mutatorDeps []string
1561 mutatorDeps, errs = c.runMutators(ctx, config)
1562 if len(errs) > 0 {
1563 return
1564 }
1565 deps = append(deps, mutatorDeps...)
1566
Colin Cross2da84922020-07-02 10:08:12 -07001567 if !c.skipCloneModulesAfterMutators {
1568 c.cloneModules()
1569 }
Colin Cross3a8c0252019-01-23 13:21:48 -08001570
1571 c.dependenciesReady = true
1572 })
1573
Colin Cross5f03f112017-11-07 13:29:54 -08001574 if len(errs) > 0 {
1575 return nil, errs
1576 }
1577
Colin Cross874a3462017-07-31 17:26:06 -07001578 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001579}
1580
Colin Cross763b6f12015-10-29 15:32:56 -07001581// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001582// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001583// module names returned by its DynamicDependencies method and those added by calling
1584// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001585func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001586 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001587 func() {
1588 defer func() {
1589 if r := recover(); r != nil {
1590 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1591 }
1592 }()
1593 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001594
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001595 if ctx.Failed() {
1596 return
1597 }
Colin Cross763b6f12015-10-29 15:32:56 -07001598
Colin Cross2c1f3d12016-04-11 15:47:28 -07001599 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001600 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001601 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001602}
1603
Colin Cross39644c02020-08-21 18:20:38 -07001604// findExactVariantOrSingle searches the moduleGroup for a module with the same variant as module,
1605// and returns the matching module, or nil if one is not found. A group with exactly one module
1606// is always considered matching.
1607func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07001608 found, _ := findVariant(module, possible, nil, false, reverse)
1609 if found == nil {
1610 for _, moduleOrAlias := range possible.modules {
1611 if m := moduleOrAlias.module(); m != nil {
1612 if found != nil {
1613 // more than one possible match, give up
1614 return nil
1615 }
1616 found = m
1617 }
1618 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001619 }
Colin Cross5df74a82020-08-24 16:18:21 -07001620 return found
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001621}
1622
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001623func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) (*moduleInfo, []error) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001624 if _, ok := tag.(BaseDependencyTag); ok {
1625 panic("BaseDependencyTag is not allowed to be used directly!")
1626 }
1627
Colin Cross0b7e83e2016-05-17 14:58:05 -07001628 if depName == module.Name() {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001629 return nil, []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001630 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001631 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001632 }}
1633 }
1634
Colin Crossd03b59d2019-11-13 20:10:12 -08001635 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001636 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001637 return nil, c.discoveredMissingDependencies(module, depName, nil)
Colin Crossc9028482014-12-18 16:28:54 -08001638 }
1639
Colin Cross39644c02020-08-21 18:20:38 -07001640 if m := findExactVariantOrSingle(module, possibleDeps, false); m != nil {
Colin Cross99bdb2a2019-03-29 16:35:02 -07001641 module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001642 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001643 return m, nil
Colin Cross65569e42015-03-10 20:08:19 -07001644 }
Colin Crossc9028482014-12-18 16:28:54 -08001645
Paul Duffinb77556b2020-03-24 19:01:20 +00001646 if c.allowMissingDependencies {
1647 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001648 return nil, c.discoveredMissingDependencies(module, depName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001649 }
1650
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001651 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001652 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001653 depName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001654 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001655 c.prettyPrintGroupVariants(possibleDeps)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001656 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001657 }}
1658}
1659
Colin Cross8d8a7af2015-11-03 16:41:29 -08001660func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001661 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001662 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001663 Err: fmt.Errorf("%q depends on itself", destName),
1664 Pos: module.pos,
1665 }}
1666 }
1667
Colin Crossd03b59d2019-11-13 20:10:12 -08001668 possibleDeps := c.moduleGroupFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001669 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001670 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001671 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001672 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001673 Pos: module.pos,
1674 }}
1675 }
1676
Colin Cross39644c02020-08-21 18:20:38 -07001677 if m := findExactVariantOrSingle(module, possibleDeps, true); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001678 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001679 }
1680
Paul Duffinb77556b2020-03-24 19:01:20 +00001681 if c.allowMissingDependencies {
1682 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001683 return module, c.discoveredMissingDependencies(module, destName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001684 }
1685
Colin Cross2c628442016-10-07 17:13:10 -07001686 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001687 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001688 destName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001689 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001690 c.prettyPrintGroupVariants(possibleDeps)),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001691 Pos: module.pos,
1692 }}
1693}
1694
Colin Cross39644c02020-08-21 18:20:38 -07001695func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
Colin Crossedc41762020-08-13 12:07:30 -07001696 // We can't just append variant.Variant to module.dependencyVariant.variantName and
Colin Cross65569e42015-03-10 20:08:19 -07001697 // compare the strings because the result won't be in mutator registration order.
1698 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001699 var newVariant variationMap
1700 if !far {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001701 if !reverse {
1702 // For forward dependency, ignore local variants by matching against
1703 // dependencyVariant which doesn't have the local variants
Colin Crossedc41762020-08-13 12:07:30 -07001704 newVariant = module.variant.dependencyVariations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001705 } else {
1706 // For reverse dependency, use all the variants
Colin Crossedc41762020-08-13 12:07:30 -07001707 newVariant = module.variant.variations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001708 }
Colin Cross89486232015-05-08 11:14:54 -07001709 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001710 for _, v := range variations {
Colin Cross9403b5a2019-11-13 20:11:04 -08001711 if newVariant == nil {
1712 newVariant = make(variationMap)
1713 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001714 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001715 }
1716
Colin Crossd03b59d2019-11-13 20:10:12 -08001717 check := func(variant variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -07001718 if far {
Colin Cross5dc67592020-08-24 14:46:13 -07001719 return newVariant.subsetOf(variant)
Colin Cross89486232015-05-08 11:14:54 -07001720 } else {
Colin Crossd03b59d2019-11-13 20:10:12 -08001721 return variant.equal(newVariant)
Colin Cross65569e42015-03-10 20:08:19 -07001722 }
1723 }
1724
Colin Crossd03b59d2019-11-13 20:10:12 -08001725 var foundDep *moduleInfo
1726 for _, m := range possibleDeps.modules {
Colin Cross5df74a82020-08-24 16:18:21 -07001727 if check(m.moduleOrAliasVariant().variations) {
1728 foundDep = m.moduleOrAliasTarget()
Colin Crossd03b59d2019-11-13 20:10:12 -08001729 break
1730 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001731 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001732
Martin Stjernholm2f212472020-03-06 00:29:24 +00001733 return foundDep, newVariant
1734}
1735
1736func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001737 tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001738 if _, ok := tag.(BaseDependencyTag); ok {
1739 panic("BaseDependencyTag is not allowed to be used directly!")
1740 }
1741
1742 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
1743 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001744 return nil, c.discoveredMissingDependencies(module, depName, nil)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001745 }
1746
Colin Cross5df74a82020-08-24 16:18:21 -07001747 foundDep, newVariant := findVariant(module, possibleDeps, variations, far, false)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001748
Colin Crossf7beb892019-11-13 20:11:14 -08001749 if foundDep == nil {
Paul Duffinb77556b2020-03-24 19:01:20 +00001750 if c.allowMissingDependencies {
1751 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001752 return nil, c.discoveredMissingDependencies(module, depName, newVariant)
Paul Duffinb77556b2020-03-24 19:01:20 +00001753 }
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001754 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001755 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
1756 depName, module.Name(),
1757 c.prettyPrintVariant(newVariant),
1758 c.prettyPrintGroupVariants(possibleDeps)),
1759 Pos: module.pos,
1760 }}
1761 }
1762
1763 if module == foundDep {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001764 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001765 Err: fmt.Errorf("%q depends on itself", depName),
1766 Pos: module.pos,
1767 }}
1768 }
1769 // AddVariationDependency allows adding a dependency on itself, but only if
1770 // that module is earlier in the module list than this one, since we always
1771 // run GenerateBuildActions in order for the variants of a module
1772 if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001773 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001774 Err: fmt.Errorf("%q depends on later version of itself", depName),
1775 Pos: module.pos,
1776 }}
1777 }
1778 module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
1779 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001780 return foundDep, nil
Colin Crossc9028482014-12-18 16:28:54 -08001781}
1782
Colin Crossf1875462016-04-11 17:33:13 -07001783func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001784 from, to Module) *moduleInfo {
Nan Zhang346b2d02017-03-10 16:39:27 -08001785 if _, ok := tag.(BaseDependencyTag); ok {
1786 panic("BaseDependencyTag is not allowed to be used directly!")
1787 }
Colin Crossf1875462016-04-11 17:33:13 -07001788
1789 var fromInfo, toInfo *moduleInfo
Colin Cross5df74a82020-08-24 16:18:21 -07001790 for _, moduleOrAlias := range origModule.splitModules {
1791 if m := moduleOrAlias.module(); m != nil {
1792 if m.logicModule == from {
1793 fromInfo = m
1794 }
1795 if m.logicModule == to {
1796 toInfo = m
1797 if fromInfo != nil {
1798 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
1799 }
Colin Crossf1875462016-04-11 17:33:13 -07001800 }
1801 }
1802 }
1803
1804 if fromInfo == nil || toInfo == nil {
1805 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001806 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001807 }
1808
Colin Cross99bdb2a2019-03-29 16:35:02 -07001809 fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001810 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001811 return toInfo
Colin Crossf1875462016-04-11 17:33:13 -07001812}
1813
Lukacs T. Berkieef56852021-09-02 11:34:06 +02001814// findBlueprintDescendants returns a map linking parent Blueprint files to child Blueprints files
1815// For example, if paths = []string{"a/b/c/Android.bp", "a/Android.bp"},
1816// then descendants = {"":[]string{"a/Android.bp"}, "a/Android.bp":[]string{"a/b/c/Android.bp"}}
Jeff Gastonc3e28442017-08-09 15:13:12 -07001817func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1818 // make mapping from dir path to file path
1819 filesByDir := make(map[string]string, len(paths))
1820 for _, path := range paths {
1821 dir := filepath.Dir(path)
1822 _, alreadyFound := filesByDir[dir]
1823 if alreadyFound {
1824 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1825 }
1826 filesByDir[dir] = path
1827 }
1828
Jeff Gaston656870f2017-11-29 18:37:31 -08001829 findAncestor := func(childFile string) (ancestor string) {
1830 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001831 for {
1832 ancestorDir := filepath.Dir(prevAncestorDir)
1833 if ancestorDir == prevAncestorDir {
1834 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001835 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001836 }
1837
1838 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1839 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001840 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001841 }
1842 prevAncestorDir = ancestorDir
1843 }
1844 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001845 // generate the descendants map
1846 descendants = make(map[string][]string, len(filesByDir))
1847 for _, childFile := range filesByDir {
1848 ancestorFile := findAncestor(childFile)
1849 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1850 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001851 return descendants, nil
1852}
1853
Colin Cross3702ac72016-08-11 11:09:00 -07001854type visitOrderer interface {
1855 // returns the number of modules that this module needs to wait for
1856 waitCount(module *moduleInfo) int
1857 // returns the list of modules that are waiting for this module
1858 propagate(module *moduleInfo) []*moduleInfo
1859 // visit modules in order
Colin Crossc4773d92020-08-25 17:12:59 -07001860 visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool)
Colin Cross3702ac72016-08-11 11:09:00 -07001861}
1862
Colin Cross7e723372018-03-28 11:50:12 -07001863type unorderedVisitorImpl struct{}
1864
1865func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1866 return 0
1867}
1868
1869func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1870 return nil
1871}
1872
Colin Crossc4773d92020-08-25 17:12:59 -07001873func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross7e723372018-03-28 11:50:12 -07001874 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001875 if visit(module, nil) {
Colin Cross7e723372018-03-28 11:50:12 -07001876 return
1877 }
1878 }
1879}
1880
Colin Cross3702ac72016-08-11 11:09:00 -07001881type bottomUpVisitorImpl struct{}
1882
1883func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1884 return len(module.forwardDeps)
1885}
1886
1887func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1888 return module.reverseDeps
1889}
1890
Colin Crossc4773d92020-08-25 17:12:59 -07001891func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001892 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001893 if visit(module, nil) {
Colin Cross49c279a2016-08-05 22:30:44 -07001894 return
1895 }
1896 }
1897}
1898
Colin Cross3702ac72016-08-11 11:09:00 -07001899type topDownVisitorImpl struct{}
1900
1901func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1902 return len(module.reverseDeps)
1903}
1904
1905func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1906 return module.forwardDeps
1907}
1908
Colin Crossc4773d92020-08-25 17:12:59 -07001909func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001910 for i := 0; i < len(modules); i++ {
1911 module := modules[len(modules)-1-i]
Colin Crossc4773d92020-08-25 17:12:59 -07001912 if visit(module, nil) {
Colin Cross3702ac72016-08-11 11:09:00 -07001913 return
1914 }
1915 }
1916}
1917
1918var (
1919 bottomUpVisitor bottomUpVisitorImpl
1920 topDownVisitor topDownVisitorImpl
1921)
1922
Colin Crossc4773d92020-08-25 17:12:59 -07001923// pauseSpec describes a pause that a module needs to occur until another module has been visited,
1924// at which point the unpause channel will be closed.
1925type pauseSpec struct {
1926 paused *moduleInfo
1927 until *moduleInfo
1928 unpause unpause
1929}
1930
1931type unpause chan struct{}
1932
1933const parallelVisitLimit = 1000
1934
Colin Cross49c279a2016-08-05 22:30:44 -07001935// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
Colin Crossc4773d92020-08-25 17:12:59 -07001936// of its dependencies has finished. A visit function can write a pauseSpec to the pause channel
1937// to wait for another dependency to be visited. If a visit function returns true to cancel
1938// while another visitor is paused, the paused visitor will never be resumed and its goroutine
1939// will stay paused forever.
1940func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
1941 visit func(module *moduleInfo, pause chan<- pauseSpec) bool) []error {
1942
Colin Cross7addea32015-03-11 15:43:52 -07001943 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001944 cancelCh := make(chan bool)
Colin Crossc4773d92020-08-25 17:12:59 -07001945 pauseCh := make(chan pauseSpec)
Colin Cross8900e9b2015-03-02 14:03:01 -08001946 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001947
Colin Crossc4773d92020-08-25 17:12:59 -07001948 var backlog []*moduleInfo // Visitors that are ready to start but backlogged due to limit.
1949 var unpauseBacklog []pauseSpec // Visitors that are ready to unpause but backlogged due to limit.
1950
1951 active := 0 // Number of visitors running, not counting paused visitors.
1952 visited := 0 // Number of finished visitors.
1953
1954 pauseMap := make(map[*moduleInfo][]pauseSpec)
1955
1956 for _, module := range modules {
Colin Cross3702ac72016-08-11 11:09:00 -07001957 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001958 }
1959
Colin Crossc4773d92020-08-25 17:12:59 -07001960 // Call the visitor on a module if there are fewer active visitors than the parallelism
1961 // limit, otherwise add it to the backlog.
1962 startOrBacklog := func(module *moduleInfo) {
1963 if active < limit {
1964 active++
Colin Cross7e723372018-03-28 11:50:12 -07001965 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07001966 ret := visit(module, pauseCh)
Colin Cross7e723372018-03-28 11:50:12 -07001967 if ret {
1968 cancelCh <- true
1969 }
1970 doneCh <- module
1971 }()
1972 } else {
1973 backlog = append(backlog, module)
1974 }
Colin Cross691a60d2015-01-07 18:08:56 -08001975 }
1976
Colin Crossc4773d92020-08-25 17:12:59 -07001977 // Unpause the already-started but paused visitor on a module if there are fewer active
1978 // visitors than the parallelism limit, otherwise add it to the backlog.
1979 unpauseOrBacklog := func(pauseSpec pauseSpec) {
1980 if active < limit {
1981 active++
1982 close(pauseSpec.unpause)
1983 } else {
1984 unpauseBacklog = append(unpauseBacklog, pauseSpec)
Colin Cross691a60d2015-01-07 18:08:56 -08001985 }
1986 }
1987
Colin Crossc4773d92020-08-25 17:12:59 -07001988 // Start any modules in the backlog up to the parallelism limit. Unpause paused modules first
1989 // since they may already be holding resources.
1990 unpauseOrStartFromBacklog := func() {
1991 for active < limit && len(unpauseBacklog) > 0 {
1992 unpause := unpauseBacklog[0]
1993 unpauseBacklog = unpauseBacklog[1:]
1994 unpauseOrBacklog(unpause)
1995 }
1996 for active < limit && len(backlog) > 0 {
1997 toVisit := backlog[0]
1998 backlog = backlog[1:]
1999 startOrBacklog(toVisit)
2000 }
2001 }
2002
2003 toVisit := len(modules)
2004
2005 // Start or backlog any modules that are not waiting for any other modules.
2006 for _, module := range modules {
2007 if module.waitingCount == 0 {
2008 startOrBacklog(module)
2009 }
2010 }
2011
2012 for active > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08002013 select {
Colin Cross7e723372018-03-28 11:50:12 -07002014 case <-cancelCh:
2015 cancel = true
2016 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07002017 case doneModule := <-doneCh:
Colin Crossc4773d92020-08-25 17:12:59 -07002018 active--
Colin Cross8900e9b2015-03-02 14:03:01 -08002019 if !cancel {
Colin Crossc4773d92020-08-25 17:12:59 -07002020 // Mark this module as done.
2021 doneModule.waitingCount = -1
2022 visited++
2023
2024 // Unpause or backlog any modules that were waiting for this one.
2025 if unpauses, ok := pauseMap[doneModule]; ok {
2026 delete(pauseMap, doneModule)
2027 for _, unpause := range unpauses {
2028 unpauseOrBacklog(unpause)
2029 }
Colin Cross7e723372018-03-28 11:50:12 -07002030 }
Colin Crossc4773d92020-08-25 17:12:59 -07002031
2032 // Start any backlogged modules up to limit.
2033 unpauseOrStartFromBacklog()
2034
2035 // Decrement waitingCount on the next modules in the tree based
2036 // on propagation order, and start or backlog them if they are
2037 // ready to start.
Colin Cross3702ac72016-08-11 11:09:00 -07002038 for _, module := range order.propagate(doneModule) {
2039 module.waitingCount--
2040 if module.waitingCount == 0 {
Colin Crossc4773d92020-08-25 17:12:59 -07002041 startOrBacklog(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08002042 }
Colin Cross691a60d2015-01-07 18:08:56 -08002043 }
2044 }
Colin Crossc4773d92020-08-25 17:12:59 -07002045 case pauseSpec := <-pauseCh:
2046 if pauseSpec.until.waitingCount == -1 {
2047 // Module being paused for is already finished, resume immediately.
2048 close(pauseSpec.unpause)
2049 } else {
2050 // Register for unpausing.
2051 pauseMap[pauseSpec.until] = append(pauseMap[pauseSpec.until], pauseSpec)
2052
2053 // Don't count paused visitors as active so that this can't deadlock
2054 // if 1000 visitors are paused simultaneously.
2055 active--
2056 unpauseOrStartFromBacklog()
2057 }
Colin Cross691a60d2015-01-07 18:08:56 -08002058 }
2059 }
Colin Crossc4773d92020-08-25 17:12:59 -07002060
2061 if !cancel {
2062 // Invariant check: no backlogged modules, these weren't waiting on anything except
2063 // the parallelism limit so they should have run.
2064 if len(backlog) > 0 {
2065 panic(fmt.Errorf("parallelVisit finished with %d backlogged visitors", len(backlog)))
2066 }
2067
2068 // Invariant check: no backlogged paused modules, these weren't waiting on anything
2069 // except the parallelism limit so they should have run.
2070 if len(unpauseBacklog) > 0 {
2071 panic(fmt.Errorf("parallelVisit finished with %d backlogged unpaused visitors", len(unpauseBacklog)))
2072 }
2073
2074 if len(pauseMap) > 0 {
Colin Cross7d4958d2021-02-08 15:34:08 -08002075 // Probably a deadlock due to a newly added dependency cycle. Start from each module in
2076 // the order of the input modules list and perform a depth-first search for the module
2077 // it is paused on, ignoring modules that are marked as done. Note this traverses from
2078 // modules to the modules that would have been unblocked when that module finished, i.e
2079 // the reverse of the visitOrderer.
Colin Crossc4773d92020-08-25 17:12:59 -07002080
Colin Cross9793b0a2021-04-27 15:20:15 -07002081 // In order to reduce duplicated work, once a module has been checked and determined
2082 // not to be part of a cycle add it and everything that depends on it to the checked
2083 // map.
2084 checked := make(map[*moduleInfo]struct{})
2085
Colin Cross7d4958d2021-02-08 15:34:08 -08002086 var check func(module, end *moduleInfo) []*moduleInfo
2087 check = func(module, end *moduleInfo) []*moduleInfo {
Colin Crossc4773d92020-08-25 17:12:59 -07002088 if module.waitingCount == -1 {
2089 // This module was finished, it can't be part of a loop.
2090 return nil
2091 }
2092 if module == end {
2093 // This module is the end of the loop, start rolling up the cycle.
2094 return []*moduleInfo{module}
2095 }
2096
Colin Cross9793b0a2021-04-27 15:20:15 -07002097 if _, alreadyChecked := checked[module]; alreadyChecked {
2098 return nil
2099 }
2100
Colin Crossc4773d92020-08-25 17:12:59 -07002101 for _, dep := range order.propagate(module) {
Colin Cross7d4958d2021-02-08 15:34:08 -08002102 cycle := check(dep, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002103 if cycle != nil {
2104 return append([]*moduleInfo{module}, cycle...)
2105 }
2106 }
2107 for _, depPauseSpec := range pauseMap[module] {
Colin Cross7d4958d2021-02-08 15:34:08 -08002108 cycle := check(depPauseSpec.paused, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002109 if cycle != nil {
2110 return append([]*moduleInfo{module}, cycle...)
2111 }
2112 }
2113
Colin Cross9793b0a2021-04-27 15:20:15 -07002114 checked[module] = struct{}{}
Colin Crossc4773d92020-08-25 17:12:59 -07002115 return nil
2116 }
2117
Colin Cross7d4958d2021-02-08 15:34:08 -08002118 // Iterate over the modules list instead of pauseMap to provide deterministic ordering.
2119 for _, module := range modules {
2120 for _, pauseSpec := range pauseMap[module] {
2121 cycle := check(pauseSpec.paused, pauseSpec.until)
2122 if len(cycle) > 0 {
2123 return cycleError(cycle)
2124 }
2125 }
Colin Crossc4773d92020-08-25 17:12:59 -07002126 }
2127 }
2128
2129 // Invariant check: if there was no deadlock and no cancellation every module
2130 // should have been visited.
2131 if visited != toVisit {
2132 panic(fmt.Errorf("parallelVisit ran %d visitors, expected %d", visited, toVisit))
2133 }
2134
2135 // Invariant check: if there was no deadlock and no cancellation every module
2136 // should have been visited, so there is nothing left to be paused on.
2137 if len(pauseMap) > 0 {
2138 panic(fmt.Errorf("parallelVisit finished with %d paused visitors", len(pauseMap)))
2139 }
2140 }
2141
2142 return nil
2143}
2144
2145func cycleError(cycle []*moduleInfo) (errs []error) {
2146 // The cycle list is in reverse order because all the 'check' calls append
2147 // their own module to the list.
2148 errs = append(errs, &BlueprintError{
2149 Err: fmt.Errorf("encountered dependency cycle:"),
2150 Pos: cycle[len(cycle)-1].pos,
2151 })
2152
2153 // Iterate backwards through the cycle list.
2154 curModule := cycle[0]
2155 for i := len(cycle) - 1; i >= 0; i-- {
2156 nextModule := cycle[i]
2157 errs = append(errs, &BlueprintError{
Colin Crosse5ff7702021-04-27 15:33:49 -07002158 Err: fmt.Errorf(" %s depends on %s",
2159 curModule, nextModule),
Colin Crossc4773d92020-08-25 17:12:59 -07002160 Pos: curModule.pos,
2161 })
2162 curModule = nextModule
2163 }
2164
2165 return errs
Colin Cross691a60d2015-01-07 18:08:56 -08002166}
2167
2168// updateDependencies recursively walks the module dependency graph and updates
2169// additional fields based on the dependencies. It builds a sorted list of modules
2170// such that dependencies of a module always appear first, and populates reverse
2171// dependency links and counts of total dependencies. It also reports errors when
Usta Shresthaee7a5d72022-01-10 22:46:23 -05002172// it encounters dependency cycles. This should be called after resolveDependencies,
Colin Cross691a60d2015-01-07 18:08:56 -08002173// as well as after any mutator pass has called addDependency
2174func (c *Context) updateDependencies() (errs []error) {
Liz Kammer9ae14f12020-11-30 16:30:45 -07002175 c.cachedDepsModified = true
Colin Cross7addea32015-03-11 15:43:52 -07002176 visited := make(map[*moduleInfo]bool) // modules that were already checked
2177 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002178
Colin Cross7addea32015-03-11 15:43:52 -07002179 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08002180
Colin Cross7addea32015-03-11 15:43:52 -07002181 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002182
Colin Cross7addea32015-03-11 15:43:52 -07002183 check = func(module *moduleInfo) []*moduleInfo {
2184 visited[module] = true
2185 checking[module] = true
2186 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002187
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002188 // Reset the forward and reverse deps without reducing their capacity to avoid reallocation.
2189 module.reverseDeps = module.reverseDeps[:0]
2190 module.forwardDeps = module.forwardDeps[:0]
Colin Cross7addea32015-03-11 15:43:52 -07002191
2192 // Add an implicit dependency ordering on all earlier modules in the same module group
2193 for _, dep := range module.group.modules {
2194 if dep == module {
2195 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08002196 }
Colin Cross5df74a82020-08-24 16:18:21 -07002197 if depModule := dep.module(); depModule != nil {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002198 module.forwardDeps = append(module.forwardDeps, depModule)
Colin Cross5df74a82020-08-24 16:18:21 -07002199 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002200 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002201
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002202 outer:
Colin Cross7addea32015-03-11 15:43:52 -07002203 for _, dep := range module.directDeps {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002204 // use a loop to check for duplicates, average number of directDeps measured to be 9.5.
2205 for _, exists := range module.forwardDeps {
2206 if dep.module == exists {
2207 continue outer
2208 }
2209 }
2210 module.forwardDeps = append(module.forwardDeps, dep.module)
Colin Cross7addea32015-03-11 15:43:52 -07002211 }
2212
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002213 for _, dep := range module.forwardDeps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002214 if checking[dep] {
2215 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07002216 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002217 }
2218
2219 if !visited[dep] {
2220 cycle := check(dep)
2221 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002222 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002223 // We are the "start" of the cycle, so we're responsible
Colin Crossc4773d92020-08-25 17:12:59 -07002224 // for generating the errors.
2225 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002226
2227 // We can continue processing this module's children to
2228 // find more cycles. Since all the modules that were
2229 // part of the found cycle were marked as visited we
2230 // won't run into that cycle again.
2231 } else {
2232 // We're not the "start" of the cycle, so we just append
2233 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07002234 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002235 }
2236 }
2237 }
Colin Cross691a60d2015-01-07 18:08:56 -08002238
Colin Cross7addea32015-03-11 15:43:52 -07002239 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002240 }
2241
Colin Cross7addea32015-03-11 15:43:52 -07002242 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08002243
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002244 return nil
2245 }
2246
Colin Cross7addea32015-03-11 15:43:52 -07002247 for _, module := range c.moduleInfo {
2248 if !visited[module] {
2249 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002250 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002251 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07002252 panic("inconceivable!")
2253 }
Colin Crossc4773d92020-08-25 17:12:59 -07002254 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002255 }
2256 }
2257 }
2258
Colin Cross7addea32015-03-11 15:43:52 -07002259 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08002260
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002261 return
2262}
2263
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002264type jsonVariationMap map[string]string
2265
2266type jsonModuleName struct {
2267 Name string
2268 Variations jsonVariationMap
2269 DependencyVariations jsonVariationMap
2270}
2271
2272type jsonDep struct {
2273 jsonModuleName
2274 Tag string
2275}
2276
Lukacs T. Berki16022262021-06-25 09:10:56 +02002277type JsonModule struct {
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002278 jsonModuleName
2279 Deps []jsonDep
2280 Type string
2281 Blueprint string
Lukacs T. Berki16022262021-06-25 09:10:56 +02002282 Module map[string]interface{}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002283}
2284
2285func toJsonVariationMap(vm variationMap) jsonVariationMap {
2286 return jsonVariationMap(vm)
2287}
2288
2289func jsonModuleNameFromModuleInfo(m *moduleInfo) *jsonModuleName {
2290 return &jsonModuleName{
2291 Name: m.Name(),
2292 Variations: toJsonVariationMap(m.variant.variations),
2293 DependencyVariations: toJsonVariationMap(m.variant.dependencyVariations),
2294 }
2295}
2296
Lukacs T. Berki16022262021-06-25 09:10:56 +02002297type JSONDataSupplier interface {
2298 AddJSONData(d *map[string]interface{})
2299}
2300
2301func jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule {
2302 result := &JsonModule{
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002303 jsonModuleName: *jsonModuleNameFromModuleInfo(m),
2304 Deps: make([]jsonDep, 0),
2305 Type: m.typeName,
2306 Blueprint: m.relBlueprintsFile,
Lukacs T. Berki16022262021-06-25 09:10:56 +02002307 Module: make(map[string]interface{}),
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002308 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002309 if j, ok := m.logicModule.(JSONDataSupplier); ok {
2310 j.AddJSONData(&result.Module)
2311 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002312 for _, p := range m.providers {
2313 if j, ok := p.(JSONDataSupplier); ok {
2314 j.AddJSONData(&result.Module)
2315 }
2316 }
2317 return result
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002318}
2319
kguia78b0202022-01-25 16:19:25 +08002320func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule {
2321 result := &JsonModule{
2322 jsonModuleName: jsonModuleName{
2323 Name: m.Name(),
2324 },
2325 Deps: make([]jsonDep, 0),
2326 Type: m.typeName,
2327 Blueprint: m.relBlueprintsFile,
2328 Module: make(map[string]interface{}),
2329 }
2330 var actions []map[string]interface{}
2331 for _, bDef := range m.actionDefs.buildDefs {
2332 actions = append(actions, map[string]interface{}{
2333 "Inputs": append(
2334 getNinjaStringsWithNilPkgNames(bDef.Inputs),
2335 getNinjaStringsWithNilPkgNames(bDef.Implicits)...),
2336 "Outputs": append(
2337 getNinjaStringsWithNilPkgNames(bDef.Outputs),
2338 getNinjaStringsWithNilPkgNames(bDef.ImplicitOutputs)...),
2339 })
2340 }
2341 result.Module["Actions"] = actions
2342 return result
2343}
2344
2345// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value with
2346// nil pkgNames on each of the input ninjaStrings.
2347func getNinjaStringsWithNilPkgNames(nStrs []ninjaString) []string {
2348 var strs []string
2349 for _, nstr := range nStrs {
2350 strs = append(strs, nstr.Value(nil))
2351 }
2352 return strs
2353}
2354
2355// PrintJSONGraph prints info of modules in a JSON file.
2356func (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) {
2357 modulesToGraph := make([]*JsonModule, 0)
2358 modulesToActions := make([]*JsonModule, 0)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002359 for _, m := range c.modulesSorted {
2360 jm := jsonModuleFromModuleInfo(m)
kguia78b0202022-01-25 16:19:25 +08002361 jmWithActions := jsonModuleWithActionsFromModuleInfo(m)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002362 for _, d := range m.directDeps {
2363 jm.Deps = append(jm.Deps, jsonDep{
2364 jsonModuleName: *jsonModuleNameFromModuleInfo(d.module),
2365 Tag: fmt.Sprintf("%T %+v", d.tag, d.tag),
2366 })
kguia78b0202022-01-25 16:19:25 +08002367 jmWithActions.Deps = append(jmWithActions.Deps, jsonDep{
2368 jsonModuleName: jsonModuleName{
2369 Name: d.module.Name(),
2370 },
2371 })
2372
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002373 }
kguia78b0202022-01-25 16:19:25 +08002374 modulesToGraph = append(modulesToGraph, jm)
2375 modulesToActions = append(modulesToActions, jmWithActions)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002376 }
kguia78b0202022-01-25 16:19:25 +08002377 writeJson(wGraph, modulesToGraph)
2378 writeJson(wActions, modulesToActions)
2379}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002380
kguia78b0202022-01-25 16:19:25 +08002381func writeJson(w io.Writer, modules []*JsonModule) {
Liz Kammer6e4ee8d2021-08-17 17:32:42 -04002382 e := json.NewEncoder(w)
2383 e.SetIndent("", "\t")
2384 e.Encode(modules)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002385}
2386
Jamie Gennisd4e10182014-06-12 20:06:50 -07002387// PrepareBuildActions generates an internal representation of all the build
2388// actions that need to be performed. This process involves invoking the
2389// GenerateBuildActions method on each of the Module objects created during the
2390// parse phase and then on each of the registered Singleton objects.
2391//
2392// If the ResolveDependencies method has not already been called it is called
2393// automatically by this method.
2394//
2395// The config argument is made available to all of the Module and Singleton
2396// objects via the Config method on the ModuleContext and SingletonContext
2397// objects passed to GenerateBuildActions. It is also passed to the functions
2398// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
2399// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002400//
2401// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08002402// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
2403// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
2404// methods.
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002405
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002406func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08002407 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
2408 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002409
Colin Cross3a8c0252019-01-23 13:21:48 -08002410 if !c.dependenciesReady {
2411 var extraDeps []string
2412 extraDeps, errs = c.resolveDependencies(ctx, config)
2413 if len(errs) > 0 {
2414 return
2415 }
2416 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002417 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002418
Colin Cross3a8c0252019-01-23 13:21:48 -08002419 var depsModules []string
2420 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
2421 if len(errs) > 0 {
2422 return
2423 }
2424
2425 var depsSingletons []string
2426 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
2427 if len(errs) > 0 {
2428 return
2429 }
2430
2431 deps = append(deps, depsModules...)
2432 deps = append(deps, depsSingletons...)
2433
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02002434 if c.outDir != nil {
2435 err := c.liveGlobals.addNinjaStringDeps(c.outDir)
Colin Cross3a8c0252019-01-23 13:21:48 -08002436 if err != nil {
2437 errs = []error{err}
2438 return
2439 }
2440 }
2441
2442 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2443
2444 deps = append(deps, depsPackages...)
2445
Colin Cross92054a42021-01-21 16:49:25 -08002446 c.memoizeFullNames(c.liveGlobals, pkgNames)
2447
Colin Cross3a8c0252019-01-23 13:21:48 -08002448 // This will panic if it finds a problem since it's a programming error.
2449 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
2450
2451 c.pkgNames = pkgNames
2452 c.globalVariables = c.liveGlobals.variables
2453 c.globalPools = c.liveGlobals.pools
2454 c.globalRules = c.liveGlobals.rules
2455
2456 c.buildActionsReady = true
2457 })
2458
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002459 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002460 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002461 }
2462
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002463 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002464}
2465
Colin Cross3a8c0252019-01-23 13:21:48 -08002466func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07002467 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07002468
Colin Cross3a8c0252019-01-23 13:21:48 -08002469 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
2470 mutators = append(mutators, c.earlyMutatorInfo...)
2471 mutators = append(mutators, c.mutatorInfo...)
Colin Crossf8b50422016-08-10 12:56:40 -07002472
Colin Cross3a8c0252019-01-23 13:21:48 -08002473 for _, mutator := range mutators {
2474 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
2475 var newDeps []string
2476 if mutator.topDownMutator != nil {
2477 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
2478 } else if mutator.bottomUpMutator != nil {
2479 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
2480 } else {
2481 panic("no mutator set on " + mutator.name)
2482 }
2483 if len(errs) > 0 {
2484 return
2485 }
2486 deps = append(deps, newDeps...)
2487 })
2488 if len(errs) > 0 {
2489 return
2490 }
Colin Crossc9028482014-12-18 16:28:54 -08002491 }
Colin Cross3a8c0252019-01-23 13:21:48 -08002492 })
2493
2494 if len(errs) > 0 {
2495 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08002496 }
2497
Colin Cross874a3462017-07-31 17:26:06 -07002498 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08002499}
2500
Colin Cross3702ac72016-08-11 11:09:00 -07002501type mutatorDirection interface {
2502 run(mutator *mutatorInfo, ctx *mutatorContext)
2503 orderer() visitOrderer
2504 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08002505}
2506
Colin Cross3702ac72016-08-11 11:09:00 -07002507type bottomUpMutatorImpl struct{}
2508
2509func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2510 mutator.bottomUpMutator(ctx)
2511}
2512
2513func (bottomUpMutatorImpl) orderer() visitOrderer {
2514 return bottomUpVisitor
2515}
2516
2517func (bottomUpMutatorImpl) String() string {
2518 return "bottom up mutator"
2519}
2520
2521type topDownMutatorImpl struct{}
2522
2523func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2524 mutator.topDownMutator(ctx)
2525}
2526
2527func (topDownMutatorImpl) orderer() visitOrderer {
2528 return topDownVisitor
2529}
2530
2531func (topDownMutatorImpl) String() string {
2532 return "top down mutator"
2533}
2534
2535var (
2536 topDownMutator topDownMutatorImpl
2537 bottomUpMutator bottomUpMutatorImpl
2538)
2539
Colin Cross49c279a2016-08-05 22:30:44 -07002540type reverseDep struct {
2541 module *moduleInfo
2542 dep depInfo
2543}
2544
Colin Cross3702ac72016-08-11 11:09:00 -07002545func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002546 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002547
2548 newModuleInfo := make(map[Module]*moduleInfo)
2549 for k, v := range c.moduleInfo {
2550 newModuleInfo[k] = v
2551 }
Colin Crossc9028482014-12-18 16:28:54 -08002552
Colin Cross0ce142c2016-12-09 10:29:05 -08002553 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002554 reverse []reverseDep
2555 rename []rename
2556 replace []replace
2557 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002558 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002559 }
2560
Colin Cross2c1f3d12016-04-11 15:47:28 -07002561 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002562 var rename []rename
2563 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002564 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002565
Colin Cross49c279a2016-08-05 22:30:44 -07002566 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002567 globalStateCh := make(chan globalStateChange)
Colin Cross5df74a82020-08-24 16:18:21 -07002568 newVariationsCh := make(chan modulesOrAliases)
Colin Cross49c279a2016-08-05 22:30:44 -07002569 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002570
Colin Cross3702ac72016-08-11 11:09:00 -07002571 c.depsModified = 0
2572
Colin Crossc4773d92020-08-25 17:12:59 -07002573 visit := func(module *moduleInfo, pause chan<- pauseSpec) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002574 if module.splitModules != nil {
2575 panic("split module found in sorted module list")
2576 }
2577
Colin Cross7addea32015-03-11 15:43:52 -07002578 mctx := &mutatorContext{
2579 baseModuleContext: baseModuleContext{
2580 context: c,
2581 config: config,
2582 module: module,
2583 },
Colin Crossc4773d92020-08-25 17:12:59 -07002584 name: mutator.name,
2585 pauseCh: pause,
Colin Cross7addea32015-03-11 15:43:52 -07002586 }
Colin Crossc9028482014-12-18 16:28:54 -08002587
Colin Cross2da84922020-07-02 10:08:12 -07002588 module.startedMutator = mutator
2589
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002590 func() {
2591 defer func() {
2592 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002593 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002594 if err, ok := r.(panicError); ok {
2595 err.addIn(in)
2596 mctx.error(err)
2597 } else {
2598 mctx.error(newPanicErrorf(r, in))
2599 }
2600 }
2601 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002602 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002603 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002604
Colin Cross2da84922020-07-02 10:08:12 -07002605 module.finishedMutator = mutator
2606
Colin Cross7addea32015-03-11 15:43:52 -07002607 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002608 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002609 return true
Colin Cross7addea32015-03-11 15:43:52 -07002610 }
Colin Crossc9028482014-12-18 16:28:54 -08002611
Colin Cross5fe225f2017-07-28 15:22:46 -07002612 if len(mctx.newVariations) > 0 {
2613 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002614 }
2615
Colin Crossab0a83f2020-03-03 14:23:27 -08002616 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 || len(mctx.ninjaFileDeps) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08002617 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002618 reverse: mctx.reverseDeps,
2619 replace: mctx.replace,
2620 rename: mctx.rename,
2621 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002622 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002623 }
Colin Cross49c279a2016-08-05 22:30:44 -07002624 }
2625
2626 return false
2627 }
2628
2629 // Process errs and reverseDeps in a single goroutine
2630 go func() {
2631 for {
2632 select {
2633 case newErrs := <-errsCh:
2634 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002635 case globalStateChange := <-globalStateCh:
2636 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002637 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2638 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002639 replace = append(replace, globalStateChange.replace...)
2640 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002641 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002642 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002643 case newVariations := <-newVariationsCh:
Colin Cross5df74a82020-08-24 16:18:21 -07002644 for _, moduleOrAlias := range newVariations {
2645 if m := moduleOrAlias.module(); m != nil {
2646 newModuleInfo[m.logicModule] = m
2647 }
Colin Cross49c279a2016-08-05 22:30:44 -07002648 }
2649 case <-done:
2650 return
Colin Crossc9028482014-12-18 16:28:54 -08002651 }
2652 }
Colin Cross49c279a2016-08-05 22:30:44 -07002653 }()
Colin Crossc9028482014-12-18 16:28:54 -08002654
Colin Cross2da84922020-07-02 10:08:12 -07002655 c.startedMutator = mutator
2656
Colin Crossc4773d92020-08-25 17:12:59 -07002657 var visitErrs []error
Colin Cross49c279a2016-08-05 22:30:44 -07002658 if mutator.parallel {
Colin Crossc4773d92020-08-25 17:12:59 -07002659 visitErrs = parallelVisit(c.modulesSorted, direction.orderer(), parallelVisitLimit, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002660 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002661 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002662 }
2663
Colin Crossc4773d92020-08-25 17:12:59 -07002664 if len(visitErrs) > 0 {
2665 return nil, visitErrs
2666 }
2667
Colin Cross2da84922020-07-02 10:08:12 -07002668 c.finishedMutators[mutator] = true
2669
Colin Cross49c279a2016-08-05 22:30:44 -07002670 done <- true
2671
2672 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002673 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002674 }
2675
2676 c.moduleInfo = newModuleInfo
2677
2678 for _, group := range c.moduleGroups {
2679 for i := 0; i < len(group.modules); i++ {
Colin Cross5df74a82020-08-24 16:18:21 -07002680 module := group.modules[i].module()
2681 if module == nil {
2682 // Existing alias, skip it
2683 continue
2684 }
Colin Cross49c279a2016-08-05 22:30:44 -07002685
2686 // Update module group to contain newly split variants
2687 if module.splitModules != nil {
2688 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2689 }
2690
2691 // Fix up any remaining dependencies on modules that were split into variants
2692 // by replacing them with the first variant
2693 for j, dep := range module.directDeps {
2694 if dep.module.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002695 module.directDeps[j].module = dep.module.splitModules.firstModule()
Colin Cross49c279a2016-08-05 22:30:44 -07002696 }
2697 }
Colin Cross99bdb2a2019-03-29 16:35:02 -07002698
Colin Cross322cc012019-05-20 13:55:14 -07002699 if module.createdBy != nil && module.createdBy.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002700 module.createdBy = module.createdBy.splitModules.firstModule()
Colin Cross322cc012019-05-20 13:55:14 -07002701 }
2702
Colin Cross99bdb2a2019-03-29 16:35:02 -07002703 // Add in any new direct dependencies that were added by the mutator
2704 module.directDeps = append(module.directDeps, module.newDirectDeps...)
2705 module.newDirectDeps = nil
Colin Cross7addea32015-03-11 15:43:52 -07002706 }
Colin Crossf7beb892019-11-13 20:11:14 -08002707
Colin Cross279489c2020-08-13 12:11:52 -07002708 findAliasTarget := func(variant variant) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07002709 for _, moduleOrAlias := range group.modules {
2710 if alias := moduleOrAlias.alias(); alias != nil {
2711 if alias.variant.variations.equal(variant.variations) {
2712 return alias.target
2713 }
Colin Cross279489c2020-08-13 12:11:52 -07002714 }
2715 }
2716 return nil
2717 }
2718
Colin Crossf7beb892019-11-13 20:11:14 -08002719 // Forward or delete any dangling aliases.
Colin Cross5df74a82020-08-24 16:18:21 -07002720 // Use a manual loop instead of range because len(group.modules) can
2721 // change inside the loop
2722 for i := 0; i < len(group.modules); i++ {
2723 if alias := group.modules[i].alias(); alias != nil {
2724 if alias.target.logicModule == nil {
2725 newTarget := findAliasTarget(alias.target.variant)
2726 if newTarget != nil {
2727 alias.target = newTarget
2728 } else {
2729 // The alias was left dangling, remove it.
2730 group.modules = append(group.modules[:i], group.modules[i+1:]...)
2731 i--
2732 }
Colin Crossf7beb892019-11-13 20:11:14 -08002733 }
2734 }
2735 }
Colin Crossc9028482014-12-18 16:28:54 -08002736 }
2737
Colin Cross99bdb2a2019-03-29 16:35:02 -07002738 // Add in any new reverse dependencies that were added by the mutator
Colin Cross8d8a7af2015-11-03 16:41:29 -08002739 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002740 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002741 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002742 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002743 }
2744
Colin Crossaf4fd212017-07-28 14:32:36 -07002745 for _, module := range newModules {
2746 errs = c.addModule(module)
2747 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002748 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002749 }
2750 atomic.AddUint32(&c.depsModified, 1)
2751 }
2752
Colin Cross0ce142c2016-12-09 10:29:05 -08002753 errs = c.handleRenames(rename)
2754 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002755 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002756 }
2757
2758 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002759 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002760 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002761 }
2762
Colin Cross3702ac72016-08-11 11:09:00 -07002763 if c.depsModified > 0 {
2764 errs = c.updateDependencies()
2765 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002766 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002767 }
Colin Crossc9028482014-12-18 16:28:54 -08002768 }
2769
Colin Cross874a3462017-07-31 17:26:06 -07002770 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002771}
2772
Colin Cross910242b2016-04-11 15:41:52 -07002773// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2774// a mutator sets a non-property member variable on a module, which works until a later mutator
2775// creates variants of that module.
2776func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002777 type update struct {
2778 orig Module
2779 clone *moduleInfo
2780 }
Colin Cross7e723372018-03-28 11:50:12 -07002781 ch := make(chan update)
2782 doneCh := make(chan bool)
2783 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07002784 errs := parallelVisit(c.modulesSorted, unorderedVisitorImpl{}, parallelVisitLimit,
2785 func(m *moduleInfo, pause chan<- pauseSpec) bool {
2786 origLogicModule := m.logicModule
2787 m.logicModule, m.properties = c.cloneLogicModule(m)
2788 ch <- update{origLogicModule, m}
2789 return false
2790 })
2791 if len(errs) > 0 {
2792 panic(errs)
2793 }
Colin Cross7e723372018-03-28 11:50:12 -07002794 doneCh <- true
2795 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002796
Colin Cross7e723372018-03-28 11:50:12 -07002797 done := false
2798 for !done {
2799 select {
2800 case <-doneCh:
2801 done = true
2802 case update := <-ch:
2803 delete(c.moduleInfo, update.orig)
2804 c.moduleInfo[update.clone.logicModule] = update.clone
2805 }
Colin Cross910242b2016-04-11 15:41:52 -07002806 }
2807}
2808
Colin Cross49c279a2016-08-05 22:30:44 -07002809// Removes modules[i] from the list and inserts newModules... where it was located, returning
2810// the new slice and the index of the last inserted element
Colin Cross5df74a82020-08-24 16:18:21 -07002811func spliceModules(modules modulesOrAliases, i int, newModules modulesOrAliases) (modulesOrAliases, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002812 spliceSize := len(newModules)
2813 newLen := len(modules) + spliceSize - 1
Colin Cross5df74a82020-08-24 16:18:21 -07002814 var dest modulesOrAliases
Colin Cross7addea32015-03-11 15:43:52 -07002815 if cap(modules) >= len(modules)-1+len(newModules) {
2816 // We can fit the splice in the existing capacity, do everything in place
2817 dest = modules[:newLen]
2818 } else {
Colin Cross5df74a82020-08-24 16:18:21 -07002819 dest = make(modulesOrAliases, newLen)
Colin Cross7addea32015-03-11 15:43:52 -07002820 copy(dest, modules[:i])
2821 }
2822
2823 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002824 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002825
2826 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002827 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002828
Colin Cross49c279a2016-08-05 22:30:44 -07002829 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002830}
2831
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002832func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002833 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002834
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002835 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002836 var errs []error
2837
Colin Cross691a60d2015-01-07 18:08:56 -08002838 cancelCh := make(chan struct{})
2839 errsCh := make(chan []error)
2840 depsCh := make(chan []string)
2841
2842 go func() {
2843 for {
2844 select {
2845 case <-cancelCh:
2846 close(cancelCh)
2847 return
2848 case newErrs := <-errsCh:
2849 errs = append(errs, newErrs...)
2850 case newDeps := <-depsCh:
2851 deps = append(deps, newDeps...)
2852
2853 }
2854 }
2855 }()
2856
Colin Crossc4773d92020-08-25 17:12:59 -07002857 visitErrs := parallelVisit(c.modulesSorted, bottomUpVisitor, parallelVisitLimit,
2858 func(module *moduleInfo, pause chan<- pauseSpec) bool {
2859 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2860 sanitizedName := toNinjaName(uniqueName)
Yi Konga08e7222021-12-21 15:50:57 +08002861 sanitizedVariant := toNinjaName(module.variant.name)
Jeff Gaston0e907592017-12-01 17:10:52 -08002862
Yi Konga08e7222021-12-21 15:50:57 +08002863 prefix := moduleNamespacePrefix(sanitizedName + "_" + sanitizedVariant)
Jeff Gaston0e907592017-12-01 17:10:52 -08002864
Colin Crossc4773d92020-08-25 17:12:59 -07002865 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2866 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2867 // just set it to nil.
2868 scope := newLocalScope(nil, prefix)
Jeff Gaston0e907592017-12-01 17:10:52 -08002869
Colin Crossc4773d92020-08-25 17:12:59 -07002870 mctx := &moduleContext{
2871 baseModuleContext: baseModuleContext{
2872 context: c,
2873 config: config,
2874 module: module,
2875 },
2876 scope: scope,
2877 handledMissingDeps: module.missingDeps == nil,
Colin Cross036a1df2015-12-17 15:49:30 -08002878 }
Colin Cross036a1df2015-12-17 15:49:30 -08002879
Colin Cross2da84922020-07-02 10:08:12 -07002880 mctx.module.startedGenerateBuildActions = true
2881
Colin Crossc4773d92020-08-25 17:12:59 -07002882 func() {
2883 defer func() {
2884 if r := recover(); r != nil {
2885 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2886 if err, ok := r.(panicError); ok {
2887 err.addIn(in)
2888 mctx.error(err)
2889 } else {
2890 mctx.error(newPanicErrorf(r, in))
2891 }
2892 }
2893 }()
2894 mctx.module.logicModule.GenerateBuildActions(mctx)
2895 }()
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002896
Colin Cross2da84922020-07-02 10:08:12 -07002897 mctx.module.finishedGenerateBuildActions = true
2898
Colin Crossc4773d92020-08-25 17:12:59 -07002899 if len(mctx.errs) > 0 {
2900 errsCh <- mctx.errs
2901 return true
2902 }
2903
2904 if module.missingDeps != nil && !mctx.handledMissingDeps {
2905 var errs []error
2906 for _, depName := range module.missingDeps {
2907 errs = append(errs, c.missingDependencyError(module, depName))
2908 }
2909 errsCh <- errs
2910 return true
2911 }
2912
2913 depsCh <- mctx.ninjaFileDeps
2914
2915 newErrs := c.processLocalBuildActions(&module.actionDefs,
2916 &mctx.actionDefs, liveGlobals)
2917 if len(newErrs) > 0 {
2918 errsCh <- newErrs
2919 return true
2920 }
2921 return false
2922 })
Colin Cross691a60d2015-01-07 18:08:56 -08002923
2924 cancelCh <- struct{}{}
2925 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002926
Colin Crossc4773d92020-08-25 17:12:59 -07002927 errs = append(errs, visitErrs...)
2928
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002929 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002930}
2931
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002932func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002933 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002934
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002935 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002936 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002937
Colin Cross5f03f112017-11-07 13:29:54 -08002938 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002939 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2940 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2941 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002942 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002943
2944 sctx := &singletonContext{
Colin Cross9226d6c2019-02-25 18:07:44 -08002945 name: info.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002946 context: c,
2947 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002948 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002949 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002950 }
2951
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002952 func() {
2953 defer func() {
2954 if r := recover(); r != nil {
2955 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2956 if err, ok := r.(panicError); ok {
2957 err.addIn(in)
2958 sctx.error(err)
2959 } else {
2960 sctx.error(newPanicErrorf(r, in))
2961 }
2962 }
2963 }()
2964 info.singleton.GenerateBuildActions(sctx)
2965 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002966
2967 if len(sctx.errs) > 0 {
2968 errs = append(errs, sctx.errs...)
2969 if len(errs) > maxErrors {
2970 break
2971 }
2972 continue
2973 }
2974
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002975 deps = append(deps, sctx.ninjaFileDeps...)
2976
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002977 newErrs := c.processLocalBuildActions(&info.actionDefs,
2978 &sctx.actionDefs, liveGlobals)
2979 errs = append(errs, newErrs...)
2980 if len(errs) > maxErrors {
2981 break
2982 }
2983 }
2984
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002985 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002986}
2987
2988func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2989 liveGlobals *liveTracker) []error {
2990
2991 var errs []error
2992
2993 // First we go through and add everything referenced by the module's
2994 // buildDefs to the live globals set. This will end up adding the live
2995 // locals to the set as well, but we'll take them out after.
2996 for _, def := range in.buildDefs {
2997 err := liveGlobals.AddBuildDefDeps(def)
2998 if err != nil {
2999 errs = append(errs, err)
3000 }
3001 }
3002
3003 if len(errs) > 0 {
3004 return errs
3005 }
3006
Colin Crossc9028482014-12-18 16:28:54 -08003007 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003008
3009 // We use the now-incorrect set of live "globals" to determine which local
3010 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08003011 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003012 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07003013 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003014 if isLive {
3015 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003016 }
3017 }
3018
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003019 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07003020 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003021 if isLive {
3022 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003023 }
3024 }
3025
3026 return nil
3027}
3028
Colin Cross9607a9f2018-06-20 11:16:37 -07003029func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07003030 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07003031
3032 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003033 var visiting *moduleInfo
3034
3035 defer func() {
3036 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07003037 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
3038 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003039 }
3040 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07003041
3042 var walk func(module *moduleInfo)
3043 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003044 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07003045 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003046 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07003047 recurse := true
3048 if visitDown != nil {
3049 recurse = visitDown(dep, module)
3050 }
Colin Cross526e02f2018-06-21 13:31:53 -07003051 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003052 walk(dep.module)
Paul Duffin72bab172020-04-02 10:51:33 +01003053 visited[dep.module] = true
Yuchen Wu222e2452015-10-06 14:03:27 -07003054 }
Colin Crossbafd5f52016-08-06 22:52:01 -07003055 if visitUp != nil {
3056 visitUp(dep, module)
3057 }
Yuchen Wu222e2452015-10-06 14:03:27 -07003058 }
3059 }
3060 }
3061
3062 walk(topModule)
3063}
3064
Colin Cross9cfd1982016-10-11 09:58:53 -07003065type replace struct {
Paul Duffin8969cb62020-06-30 12:15:26 +01003066 from, to *moduleInfo
3067 predicate ReplaceDependencyPredicate
Colin Cross9cfd1982016-10-11 09:58:53 -07003068}
3069
Colin Crossc4e5b812016-10-12 10:45:05 -07003070type rename struct {
3071 group *moduleGroup
3072 name string
3073}
3074
Colin Cross0ce142c2016-12-09 10:29:05 -08003075func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Crossd03b59d2019-11-13 20:10:12 -08003076 group := c.moduleGroupFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07003077
Colin Crossd03b59d2019-11-13 20:10:12 -08003078 if group == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08003079 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003080 }
3081
Colin Crossd03b59d2019-11-13 20:10:12 -08003082 for _, m := range group.modules {
Colin Crossedbdb8c2020-09-11 19:22:27 -07003083 if module.variant.name == m.moduleOrAliasVariant().name {
Colin Cross5df74a82020-08-24 16:18:21 -07003084 return m.moduleOrAliasTarget()
Colin Crossf7beb892019-11-13 20:11:14 -08003085 }
3086 }
3087
Colin Cross0ce142c2016-12-09 10:29:05 -08003088 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003089}
3090
Colin Cross0ce142c2016-12-09 10:29:05 -08003091func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07003092 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08003093 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07003094 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08003095 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07003096 continue
3097 }
3098
Jeff Gastond70bf752017-11-10 15:12:08 -08003099 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07003100 }
3101
Colin Cross0ce142c2016-12-09 10:29:05 -08003102 return errs
3103}
3104
3105func (c *Context) handleReplacements(replacements []replace) []error {
3106 var errs []error
Paul Duffin8969cb62020-06-30 12:15:26 +01003107 changedDeps := false
Colin Cross0ce142c2016-12-09 10:29:05 -08003108 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07003109 for _, m := range replace.from.reverseDeps {
3110 for i, d := range m.directDeps {
3111 if d.module == replace.from {
Paul Duffin8969cb62020-06-30 12:15:26 +01003112 // If the replacement has a predicate then check it.
3113 if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) {
3114 m.directDeps[i].module = replace.to
3115 changedDeps = true
3116 }
Colin Cross9cfd1982016-10-11 09:58:53 -07003117 }
3118 }
3119 }
3120
Colin Cross9cfd1982016-10-11 09:58:53 -07003121 }
Colin Cross0ce142c2016-12-09 10:29:05 -08003122
Paul Duffin8969cb62020-06-30 12:15:26 +01003123 if changedDeps {
3124 atomic.AddUint32(&c.depsModified, 1)
3125 }
Colin Crossc4e5b812016-10-12 10:45:05 -07003126 return errs
3127}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003128
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00003129func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string, depVariations variationMap) (errs []error) {
3130 if depVariations != nil {
3131 depName = depName + "{" + c.prettyPrintVariant(depVariations) + "}"
3132 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003133 if c.allowMissingDependencies {
3134 module.missingDeps = append(module.missingDeps, depName)
3135 return nil
3136 }
3137 return []error{c.missingDependencyError(module, depName)}
3138}
3139
3140func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
3141 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
3142
3143 return &BlueprintError{
3144 Err: err,
3145 Pos: module.pos,
3146 }
3147}
3148
Colin Crossd03b59d2019-11-13 20:10:12 -08003149func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
Jeff Gastond70bf752017-11-10 15:12:08 -08003150 group, exists := c.nameInterface.ModuleFromName(name, namespace)
3151 if exists {
Colin Crossd03b59d2019-11-13 20:10:12 -08003152 return group.moduleGroup
Colin Cross0b7e83e2016-05-17 14:58:05 -07003153 }
3154 return nil
3155}
3156
Jeff Gastond70bf752017-11-10 15:12:08 -08003157func (c *Context) sortedModuleGroups() []*moduleGroup {
Liz Kammer9ae14f12020-11-30 16:30:45 -07003158 if c.cachedSortedModuleGroups == nil || c.cachedDepsModified {
Jeff Gastond70bf752017-11-10 15:12:08 -08003159 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
3160 result := make([]*moduleGroup, 0, len(wrappers))
3161 for _, group := range wrappers {
3162 result = append(result, group.moduleGroup)
3163 }
3164 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07003165 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003166
3167 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Liz Kammer9ae14f12020-11-30 16:30:45 -07003168 c.cachedDepsModified = false
Jamie Gennisc15544d2014-09-24 20:26:52 -07003169 }
3170
Jeff Gastond70bf752017-11-10 15:12:08 -08003171 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07003172}
3173
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003174func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003175 var module *moduleInfo
3176
3177 defer func() {
3178 if r := recover(); r != nil {
3179 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
3180 funcName(visit), module))
3181 }
3182 }()
3183
Jeff Gastond70bf752017-11-10 15:12:08 -08003184 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003185 for _, moduleOrAlias := range moduleGroup.modules {
3186 if module = moduleOrAlias.module(); module != nil {
3187 visit(module.logicModule)
3188 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003189 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003190 }
3191}
3192
3193func (c *Context) visitAllModulesIf(pred func(Module) bool,
3194 visit func(Module)) {
3195
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003196 var module *moduleInfo
3197
3198 defer func() {
3199 if r := recover(); r != nil {
3200 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
3201 funcName(pred), funcName(visit), module))
3202 }
3203 }()
3204
Jeff Gastond70bf752017-11-10 15:12:08 -08003205 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003206 for _, moduleOrAlias := range moduleGroup.modules {
3207 if module = moduleOrAlias.module(); module != nil {
3208 if pred(module.logicModule) {
3209 visit(module.logicModule)
3210 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003211 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003212 }
3213 }
3214}
3215
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003216func (c *Context) visitAllModuleVariants(module *moduleInfo,
3217 visit func(Module)) {
3218
3219 var variant *moduleInfo
3220
3221 defer func() {
3222 if r := recover(); r != nil {
3223 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
3224 module, funcName(visit), variant))
3225 }
3226 }()
3227
Colin Cross5df74a82020-08-24 16:18:21 -07003228 for _, moduleOrAlias := range module.group.modules {
3229 if variant = moduleOrAlias.module(); variant != nil {
3230 visit(variant.logicModule)
3231 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003232 }
3233}
3234
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003235func (c *Context) requireNinjaVersion(major, minor, micro int) {
3236 if major != 1 {
3237 panic("ninja version with major version != 1 not supported")
3238 }
3239 if c.requiredNinjaMinor < minor {
3240 c.requiredNinjaMinor = minor
3241 c.requiredNinjaMicro = micro
3242 }
3243 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
3244 c.requiredNinjaMicro = micro
3245 }
3246}
3247
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003248func (c *Context) setOutDir(value ninjaString) {
3249 if c.outDir == nil {
3250 c.outDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003251 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003252}
3253
3254func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08003255 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003256
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003257 pkgs := make(map[string]*packageContext)
3258 pkgNames := make(map[*packageContext]string)
3259 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003260
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003261 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003262 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003263 // This is a built-in rule and has no package.
3264 return
3265 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07003266 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003267 // We've already processed this package.
3268 return
3269 }
3270
Jamie Gennis2fb20952014-10-03 02:49:58 -07003271 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003272 if present {
3273 // Short name collision. Both this package and the one that's
3274 // already there need to use their full names. We leave the short
3275 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003276 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003277 longPkgNames[otherPkg] = true
3278 } else {
3279 // No collision so far. Tentatively set the package's name to be
3280 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003281 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07003282 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003283 }
3284 }
3285
3286 // We try to give all packages their short name, but when we get collisions
3287 // we need to use the full unique package name.
3288 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003289 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003290 }
3291 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003292 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003293 }
3294 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003295 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003296 }
3297
3298 // Add the packages that had collisions using their full unique names. This
3299 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003300 for pctx := range longPkgNames {
3301 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003302 }
3303
Dan Willemsena481ae22015-12-18 15:18:03 -08003304 // Create deps list from calls to PackageContext.AddNinjaFileDeps
3305 deps := []string{}
3306 for _, pkg := range pkgs {
3307 deps = append(deps, pkg.ninjaFileDeps...)
3308 }
3309
3310 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003311}
3312
Colin Cross92054a42021-01-21 16:49:25 -08003313// memoizeFullNames stores the full name of each live global variable, rule and pool since each is
3314// guaranteed to be used at least twice, once in the definition and once for each usage, and many
3315// are used much more than once.
3316func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) {
3317 for v := range liveGlobals.variables {
3318 v.memoizeFullName(pkgNames)
3319 }
3320 for r := range liveGlobals.rules {
3321 r.memoizeFullName(pkgNames)
3322 }
3323 for p := range liveGlobals.pools {
3324 p.memoizeFullName(pkgNames)
3325 }
3326}
3327
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003328func (c *Context) checkForVariableReferenceCycles(
Colin Cross2ce594e2020-01-29 12:58:03 -08003329 variables map[Variable]ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003330
3331 visited := make(map[Variable]bool) // variables that were already checked
3332 checking := make(map[Variable]bool) // variables actively being checked
3333
3334 var check func(v Variable) []Variable
3335
3336 check = func(v Variable) []Variable {
3337 visited[v] = true
3338 checking[v] = true
3339 defer delete(checking, v)
3340
3341 value := variables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003342 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003343 if checking[dep] {
3344 // This is a cycle.
3345 return []Variable{dep, v}
3346 }
3347
3348 if !visited[dep] {
3349 cycle := check(dep)
3350 if cycle != nil {
3351 if cycle[0] == v {
3352 // We are the "start" of the cycle, so we're responsible
3353 // for generating the errors. The cycle list is in
3354 // reverse order because all the 'check' calls append
3355 // their own module to the list.
3356 msgs := []string{"detected variable reference cycle:"}
3357
3358 // Iterate backwards through the cycle list.
3359 curName := v.fullName(pkgNames)
3360 curValue := value.Value(pkgNames)
3361 for i := len(cycle) - 1; i >= 0; i-- {
3362 next := cycle[i]
3363 nextName := next.fullName(pkgNames)
3364 nextValue := variables[next].Value(pkgNames)
3365
3366 msgs = append(msgs, fmt.Sprintf(
3367 " %q depends on %q", curName, nextName))
3368 msgs = append(msgs, fmt.Sprintf(
3369 " [%s = %s]", curName, curValue))
3370
3371 curName = nextName
3372 curValue = nextValue
3373 }
3374
3375 // Variable reference cycles are a programming error,
3376 // not the fault of the Blueprint file authors.
3377 panic(strings.Join(msgs, "\n"))
3378 } else {
3379 // We're not the "start" of the cycle, so we just append
3380 // our module to the list and return it.
3381 return append(cycle, v)
3382 }
3383 }
3384 }
3385 }
3386
3387 return nil
3388 }
3389
3390 for v := range variables {
3391 if !visited[v] {
3392 cycle := check(v)
3393 if cycle != nil {
3394 panic("inconceivable!")
3395 }
3396 }
3397 }
3398}
3399
Jamie Gennisaf435562014-10-27 22:34:56 -07003400// AllTargets returns a map all the build target names to the rule used to build
3401// them. This is the same information that is output by running 'ninja -t
3402// targets all'. If this is called before PrepareBuildActions successfully
3403// completes then ErrbuildActionsNotReady is returned.
3404func (c *Context) AllTargets() (map[string]string, error) {
3405 if !c.buildActionsReady {
3406 return nil, ErrBuildActionsNotReady
3407 }
3408
3409 targets := map[string]string{}
3410
3411 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07003412 for _, module := range c.moduleInfo {
3413 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07003414 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003415 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003416 outputValue, err := output.Eval(c.globalVariables)
3417 if err != nil {
3418 return nil, err
3419 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003420 targets[outputValue] = ruleName
3421 }
3422 }
3423 }
3424
3425 // Collect all the singleton build targets.
3426 for _, info := range c.singletonInfo {
3427 for _, buildDef := range info.actionDefs.buildDefs {
3428 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003429 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003430 outputValue, err := output.Eval(c.globalVariables)
3431 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08003432 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08003433 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003434 targets[outputValue] = ruleName
3435 }
3436 }
3437 }
3438
3439 return targets, nil
3440}
3441
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003442func (c *Context) OutDir() (string, error) {
3443 if c.outDir != nil {
3444 return c.outDir.Eval(c.globalVariables)
Colin Crossa2599452015-11-18 16:01:01 -08003445 } else {
3446 return "", nil
3447 }
3448}
3449
Colin Cross4572edd2015-05-13 14:36:24 -07003450// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
3451// property structs returned by the factory for that module type.
3452func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
3453 ret := make(map[string][]interface{})
3454 for moduleType, factory := range c.moduleFactories {
3455 _, ret[moduleType] = factory()
3456 }
3457
3458 return ret
3459}
3460
Jaewoong Jung781f6b22019-02-06 16:20:17 -08003461func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
3462 ret := make(map[string]ModuleFactory)
3463 for k, v := range c.moduleFactories {
3464 ret[k] = v
3465 }
3466 return ret
3467}
3468
Colin Cross4572edd2015-05-13 14:36:24 -07003469func (c *Context) ModuleName(logicModule Module) string {
3470 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07003471 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07003472}
3473
Jeff Gaston3c8c3342017-11-30 17:30:42 -08003474func (c *Context) ModuleDir(logicModule Module) string {
Colin Cross8e454c52020-07-06 12:18:59 -07003475 return filepath.Dir(c.BlueprintFile(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07003476}
3477
Colin Cross8c602f72015-12-17 18:02:11 -08003478func (c *Context) ModuleSubDir(logicModule Module) string {
3479 module := c.moduleInfo[logicModule]
Colin Crossedc41762020-08-13 12:07:30 -07003480 return module.variant.name
Colin Cross8c602f72015-12-17 18:02:11 -08003481}
3482
Dan Willemsenc98e55b2016-07-25 15:51:50 -07003483func (c *Context) ModuleType(logicModule Module) string {
3484 module := c.moduleInfo[logicModule]
3485 return module.typeName
3486}
3487
Colin Cross2da84922020-07-02 10:08:12 -07003488// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
3489// provider was not set it returns the zero value of the type of the provider, which means the
3490// return value can always be type-asserted to the type of the provider. The return value should
3491// always be considered read-only. It panics if called before the appropriate mutator or
3492// GenerateBuildActions pass for the provider on the module. The value returned may be a deep
3493// copy of the value originally passed to SetProvider.
3494func (c *Context) ModuleProvider(logicModule Module, provider ProviderKey) interface{} {
3495 module := c.moduleInfo[logicModule]
3496 value, _ := c.provider(module, provider)
3497 return value
3498}
3499
3500// ModuleHasProvider returns true if the provider for the given module has been set.
3501func (c *Context) ModuleHasProvider(logicModule Module, provider ProviderKey) bool {
3502 module := c.moduleInfo[logicModule]
3503 _, ok := c.provider(module, provider)
3504 return ok
3505}
3506
Colin Cross4572edd2015-05-13 14:36:24 -07003507func (c *Context) BlueprintFile(logicModule Module) string {
3508 module := c.moduleInfo[logicModule]
3509 return module.relBlueprintsFile
3510}
3511
3512func (c *Context) ModuleErrorf(logicModule Module, format string,
3513 args ...interface{}) error {
3514
3515 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07003516 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07003517 Err: fmt.Errorf(format, args...),
3518 Pos: module.pos,
3519 }
3520}
3521
3522func (c *Context) VisitAllModules(visit func(Module)) {
3523 c.visitAllModules(visit)
3524}
3525
3526func (c *Context) VisitAllModulesIf(pred func(Module) bool,
3527 visit func(Module)) {
3528
3529 c.visitAllModulesIf(pred, visit)
3530}
3531
Colin Cross080c1332017-03-17 13:09:05 -07003532func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
3533 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07003534
Colin Cross080c1332017-03-17 13:09:05 -07003535 var visiting *moduleInfo
3536
3537 defer func() {
3538 if r := recover(); r != nil {
3539 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
3540 topModule, funcName(visit), visiting))
3541 }
3542 }()
3543
3544 for _, dep := range topModule.directDeps {
3545 visiting = dep.module
3546 visit(dep.module.logicModule)
3547 }
3548}
3549
3550func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
3551 topModule := c.moduleInfo[module]
3552
3553 var visiting *moduleInfo
3554
3555 defer func() {
3556 if r := recover(); r != nil {
3557 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
3558 topModule, funcName(pred), funcName(visit), visiting))
3559 }
3560 }()
3561
3562 for _, dep := range topModule.directDeps {
3563 visiting = dep.module
3564 if pred(dep.module.logicModule) {
3565 visit(dep.module.logicModule)
3566 }
3567 }
3568}
3569
3570func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003571 topModule := c.moduleInfo[module]
3572
3573 var visiting *moduleInfo
3574
3575 defer func() {
3576 if r := recover(); r != nil {
3577 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
3578 topModule, funcName(visit), visiting))
3579 }
3580 }()
3581
Colin Cross9607a9f2018-06-20 11:16:37 -07003582 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003583 visiting = dep.module
3584 visit(dep.module.logicModule)
3585 })
Colin Cross4572edd2015-05-13 14:36:24 -07003586}
3587
Colin Cross080c1332017-03-17 13:09:05 -07003588func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003589 topModule := c.moduleInfo[module]
3590
3591 var visiting *moduleInfo
3592
3593 defer func() {
3594 if r := recover(); r != nil {
3595 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
3596 topModule, funcName(pred), funcName(visit), visiting))
3597 }
3598 }()
3599
Colin Cross9607a9f2018-06-20 11:16:37 -07003600 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003601 if pred(dep.module.logicModule) {
3602 visiting = dep.module
3603 visit(dep.module.logicModule)
3604 }
3605 })
Colin Cross4572edd2015-05-13 14:36:24 -07003606}
3607
Colin Cross24ad5872015-11-17 16:22:29 -08003608func (c *Context) PrimaryModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003609 return c.moduleInfo[module].group.modules.firstModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003610}
3611
3612func (c *Context) FinalModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003613 return c.moduleInfo[module].group.modules.lastModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003614}
3615
3616func (c *Context) VisitAllModuleVariants(module Module,
3617 visit func(Module)) {
3618
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003619 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08003620}
3621
Colin Cross9226d6c2019-02-25 18:07:44 -08003622// Singletons returns a list of all registered Singletons.
3623func (c *Context) Singletons() []Singleton {
3624 var ret []Singleton
3625 for _, s := range c.singletonInfo {
3626 ret = append(ret, s.singleton)
3627 }
3628 return ret
3629}
3630
3631// SingletonName returns the name that the given singleton was registered with.
3632func (c *Context) SingletonName(singleton Singleton) string {
3633 for _, s := range c.singletonInfo {
3634 if s.singleton == singleton {
3635 return s.name
3636 }
3637 }
3638 return ""
3639}
3640
Jamie Gennisd4e10182014-06-12 20:06:50 -07003641// WriteBuildFile writes the Ninja manifeset text for the generated build
3642// actions to w. If this is called before PrepareBuildActions successfully
3643// completes then ErrBuildActionsNotReady is returned.
Colin Cross0335e092021-01-21 15:26:21 -08003644func (c *Context) WriteBuildFile(w io.StringWriter) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08003645 var err error
3646 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
3647 if !c.buildActionsReady {
3648 err = ErrBuildActionsNotReady
3649 return
3650 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003651
Colin Cross3a8c0252019-01-23 13:21:48 -08003652 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003653
Colin Cross3a8c0252019-01-23 13:21:48 -08003654 err = c.writeBuildFileHeader(nw)
3655 if err != nil {
3656 return
3657 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003658
Colin Cross3a8c0252019-01-23 13:21:48 -08003659 err = c.writeNinjaRequiredVersion(nw)
3660 if err != nil {
3661 return
3662 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003663
Colin Cross3a8c0252019-01-23 13:21:48 -08003664 err = c.writeSubninjas(nw)
3665 if err != nil {
3666 return
3667 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003668
Colin Cross3a8c0252019-01-23 13:21:48 -08003669 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003670
Colin Cross3a8c0252019-01-23 13:21:48 -08003671 err = c.writeGlobalVariables(nw)
3672 if err != nil {
3673 return
3674 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003675
Colin Cross3a8c0252019-01-23 13:21:48 -08003676 err = c.writeGlobalPools(nw)
3677 if err != nil {
3678 return
3679 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003680
Colin Cross3a8c0252019-01-23 13:21:48 -08003681 err = c.writeBuildDir(nw)
3682 if err != nil {
3683 return
3684 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003685
Colin Cross3a8c0252019-01-23 13:21:48 -08003686 err = c.writeGlobalRules(nw)
3687 if err != nil {
3688 return
3689 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003690
Colin Cross3a8c0252019-01-23 13:21:48 -08003691 err = c.writeAllModuleActions(nw)
3692 if err != nil {
3693 return
3694 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003695
Colin Cross3a8c0252019-01-23 13:21:48 -08003696 err = c.writeAllSingletonActions(nw)
3697 if err != nil {
3698 return
3699 }
3700 })
3701
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003702 if err != nil {
3703 return err
3704 }
3705
3706 return nil
3707}
3708
Jamie Gennisc15544d2014-09-24 20:26:52 -07003709type pkgAssociation struct {
3710 PkgName string
3711 PkgPath string
3712}
3713
3714type pkgAssociationSorter struct {
3715 pkgs []pkgAssociation
3716}
3717
3718func (s *pkgAssociationSorter) Len() int {
3719 return len(s.pkgs)
3720}
3721
3722func (s *pkgAssociationSorter) Less(i, j int) bool {
3723 iName := s.pkgs[i].PkgName
3724 jName := s.pkgs[j].PkgName
3725 return iName < jName
3726}
3727
3728func (s *pkgAssociationSorter) Swap(i, j int) {
3729 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3730}
3731
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003732func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3733 headerTemplate := template.New("fileHeader")
3734 _, err := headerTemplate.Parse(fileHeaderTemplate)
3735 if err != nil {
3736 // This is a programming error.
3737 panic(err)
3738 }
3739
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003740 var pkgs []pkgAssociation
3741 maxNameLen := 0
3742 for pkg, name := range c.pkgNames {
3743 pkgs = append(pkgs, pkgAssociation{
3744 PkgName: name,
3745 PkgPath: pkg.pkgPath,
3746 })
3747 if len(name) > maxNameLen {
3748 maxNameLen = len(name)
3749 }
3750 }
3751
3752 for i := range pkgs {
3753 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3754 }
3755
Jamie Gennisc15544d2014-09-24 20:26:52 -07003756 sort.Sort(&pkgAssociationSorter{pkgs})
3757
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003758 params := map[string]interface{}{
3759 "Pkgs": pkgs,
3760 }
3761
3762 buf := bytes.NewBuffer(nil)
3763 err = headerTemplate.Execute(buf, params)
3764 if err != nil {
3765 return err
3766 }
3767
3768 return nw.Comment(buf.String())
3769}
3770
3771func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3772 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3773 c.requiredNinjaMicro)
3774
3775 err := nw.Assign("ninja_required_version", value)
3776 if err != nil {
3777 return err
3778 }
3779
3780 return nw.BlankLine()
3781}
3782
Dan Willemsenab223a52018-07-05 21:56:59 -07003783func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3784 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003785 err := nw.Subninja(subninja)
3786 if err != nil {
3787 return err
3788 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003789 }
3790 return nw.BlankLine()
3791}
3792
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003793func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003794 if c.outDir != nil {
3795 err := nw.Assign("builddir", c.outDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003796 if err != nil {
3797 return err
3798 }
3799
3800 err = nw.BlankLine()
3801 if err != nil {
3802 return err
3803 }
3804 }
3805 return nil
3806}
3807
Jamie Gennisc15544d2014-09-24 20:26:52 -07003808type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003809 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003810}
3811
Jamie Gennisc15544d2014-09-24 20:26:52 -07003812type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003813 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003814 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003815}
3816
Jamie Gennisc15544d2014-09-24 20:26:52 -07003817func (s *globalEntitySorter) Len() int {
3818 return len(s.entities)
3819}
3820
3821func (s *globalEntitySorter) Less(i, j int) bool {
3822 iName := s.entities[i].fullName(s.pkgNames)
3823 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003824 return iName < jName
3825}
3826
Jamie Gennisc15544d2014-09-24 20:26:52 -07003827func (s *globalEntitySorter) Swap(i, j int) {
3828 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003829}
3830
3831func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3832 visited := make(map[Variable]bool)
3833
3834 var walk func(v Variable) error
3835 walk = func(v Variable) error {
3836 visited[v] = true
3837
3838 // First visit variables on which this variable depends.
3839 value := c.globalVariables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003840 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003841 if !visited[dep] {
3842 err := walk(dep)
3843 if err != nil {
3844 return err
3845 }
3846 }
3847 }
3848
3849 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3850 if err != nil {
3851 return err
3852 }
3853
3854 err = nw.BlankLine()
3855 if err != nil {
3856 return err
3857 }
3858
3859 return nil
3860 }
3861
Jamie Gennisc15544d2014-09-24 20:26:52 -07003862 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3863 for variable := range c.globalVariables {
3864 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003865 }
3866
Jamie Gennisc15544d2014-09-24 20:26:52 -07003867 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003868
Jamie Gennisc15544d2014-09-24 20:26:52 -07003869 for _, entity := range globalVariables {
3870 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003871 if !visited[v] {
3872 err := walk(v)
3873 if err != nil {
3874 return nil
3875 }
3876 }
3877 }
3878
3879 return nil
3880}
3881
3882func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003883 globalPools := make([]globalEntity, 0, len(c.globalPools))
3884 for pool := range c.globalPools {
3885 globalPools = append(globalPools, pool)
3886 }
3887
3888 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3889
3890 for _, entity := range globalPools {
3891 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003892 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003893 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003894 err := def.WriteTo(nw, name)
3895 if err != nil {
3896 return err
3897 }
3898
3899 err = nw.BlankLine()
3900 if err != nil {
3901 return err
3902 }
3903 }
3904
3905 return nil
3906}
3907
3908func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003909 globalRules := make([]globalEntity, 0, len(c.globalRules))
3910 for rule := range c.globalRules {
3911 globalRules = append(globalRules, rule)
3912 }
3913
3914 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3915
3916 for _, entity := range globalRules {
3917 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003918 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003919 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003920 err := def.WriteTo(nw, name, c.pkgNames)
3921 if err != nil {
3922 return err
3923 }
3924
3925 err = nw.BlankLine()
3926 if err != nil {
3927 return err
3928 }
3929 }
3930
3931 return nil
3932}
3933
Colin Cross2c1f3d12016-04-11 15:47:28 -07003934type depSorter []depInfo
3935
3936func (s depSorter) Len() int {
3937 return len(s)
3938}
3939
3940func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003941 iName := s[i].module.Name()
3942 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003943 if iName == jName {
Colin Crossedc41762020-08-13 12:07:30 -07003944 iName = s[i].module.variant.name
3945 jName = s[j].module.variant.name
Colin Cross2c1f3d12016-04-11 15:47:28 -07003946 }
3947 return iName < jName
3948}
3949
3950func (s depSorter) Swap(i, j int) {
3951 s[i], s[j] = s[j], s[i]
3952}
3953
Jeff Gaston0e907592017-12-01 17:10:52 -08003954type moduleSorter struct {
3955 modules []*moduleInfo
3956 nameInterface NameInterface
3957}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003958
Colin Crossab6d7902015-03-11 16:17:52 -07003959func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003960 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003961}
3962
Colin Crossab6d7902015-03-11 16:17:52 -07003963func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003964 iMod := s.modules[i]
3965 jMod := s.modules[j]
3966 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3967 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003968 if iName == jName {
Colin Cross279489c2020-08-13 12:11:52 -07003969 iVariantName := s.modules[i].variant.name
3970 jVariantName := s.modules[j].variant.name
3971 if iVariantName == jVariantName {
3972 panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
3973 iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
3974 } else {
3975 return iVariantName < jVariantName
3976 }
3977 } else {
3978 return iName < jName
Jeff Gaston0e907592017-12-01 17:10:52 -08003979 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003980}
3981
Colin Crossab6d7902015-03-11 16:17:52 -07003982func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003983 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003984}
3985
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003986func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3987 headerTemplate := template.New("moduleHeader")
3988 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3989 if err != nil {
3990 // This is a programming error.
3991 panic(err)
3992 }
3993
Colin Crossab6d7902015-03-11 16:17:52 -07003994 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3995 for _, module := range c.moduleInfo {
3996 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003997 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003998 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003999
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004000 buf := bytes.NewBuffer(nil)
4001
Colin Crossab6d7902015-03-11 16:17:52 -07004002 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07004003 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
4004 continue
4005 }
4006
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004007 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07004008
4009 // In order to make the bootstrap build manifest independent of the
4010 // build dir we need to output the Blueprints file locations in the
4011 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07004012 relPos := module.pos
4013 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07004014
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004015 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07004016 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004017 factoryName := factoryFunc.Name()
4018
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004019 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07004020 "name": module.Name(),
4021 "typeName": module.typeName,
4022 "goFactory": factoryName,
4023 "pos": relPos,
Colin Crossedc41762020-08-13 12:07:30 -07004024 "variant": module.variant.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004025 }
4026 err = headerTemplate.Execute(buf, infoMap)
4027 if err != nil {
4028 return err
4029 }
4030
4031 err = nw.Comment(buf.String())
4032 if err != nil {
4033 return err
4034 }
4035
4036 err = nw.BlankLine()
4037 if err != nil {
4038 return err
4039 }
4040
Colin Crossab6d7902015-03-11 16:17:52 -07004041 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004042 if err != nil {
4043 return err
4044 }
4045
4046 err = nw.BlankLine()
4047 if err != nil {
4048 return err
4049 }
4050 }
4051
4052 return nil
4053}
4054
4055func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
4056 headerTemplate := template.New("singletonHeader")
4057 _, err := headerTemplate.Parse(singletonHeaderTemplate)
4058 if err != nil {
4059 // This is a programming error.
4060 panic(err)
4061 }
4062
4063 buf := bytes.NewBuffer(nil)
4064
Yuchen Wub9103ef2015-08-25 17:58:17 -07004065 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07004066 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
4067 continue
4068 }
4069
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004070 // Get the name of the factory function for the module.
4071 factory := info.factory
4072 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
4073 factoryName := factoryFunc.Name()
4074
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004075 buf.Reset()
4076 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07004077 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004078 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004079 }
4080 err = headerTemplate.Execute(buf, infoMap)
4081 if err != nil {
4082 return err
4083 }
4084
4085 err = nw.Comment(buf.String())
4086 if err != nil {
4087 return err
4088 }
4089
4090 err = nw.BlankLine()
4091 if err != nil {
4092 return err
4093 }
4094
4095 err = c.writeLocalBuildActions(nw, &info.actionDefs)
4096 if err != nil {
4097 return err
4098 }
4099
4100 err = nw.BlankLine()
4101 if err != nil {
4102 return err
4103 }
4104 }
4105
4106 return nil
4107}
4108
4109func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
4110 defs *localBuildActions) error {
4111
4112 // Write the local variable assignments.
4113 for _, v := range defs.variables {
4114 // A localVariable doesn't need the package names or config to
4115 // determine its name or value.
4116 name := v.fullName(nil)
4117 value, err := v.value(nil)
4118 if err != nil {
4119 panic(err)
4120 }
4121 err = nw.Assign(name, value.Value(c.pkgNames))
4122 if err != nil {
4123 return err
4124 }
4125 }
4126
4127 if len(defs.variables) > 0 {
4128 err := nw.BlankLine()
4129 if err != nil {
4130 return err
4131 }
4132 }
4133
4134 // Write the local rules.
4135 for _, r := range defs.rules {
4136 // A localRule doesn't need the package names or config to determine
4137 // its name or definition.
4138 name := r.fullName(nil)
4139 def, err := r.def(nil)
4140 if err != nil {
4141 panic(err)
4142 }
4143
4144 err = def.WriteTo(nw, name, c.pkgNames)
4145 if err != nil {
4146 return err
4147 }
4148
4149 err = nw.BlankLine()
4150 if err != nil {
4151 return err
4152 }
4153 }
4154
4155 // Write the build definitions.
4156 for _, buildDef := range defs.buildDefs {
4157 err := buildDef.WriteTo(nw, c.pkgNames)
4158 if err != nil {
4159 return err
4160 }
4161
4162 if len(buildDef.Args) > 0 {
4163 err = nw.BlankLine()
4164 if err != nil {
4165 return err
4166 }
4167 }
4168 }
4169
4170 return nil
4171}
4172
Colin Cross5df74a82020-08-24 16:18:21 -07004173func beforeInModuleList(a, b *moduleInfo, list modulesOrAliases) bool {
Colin Cross65569e42015-03-10 20:08:19 -07004174 found := false
Colin Cross045a5972015-11-03 16:58:48 -08004175 if a == b {
4176 return false
4177 }
Colin Cross65569e42015-03-10 20:08:19 -07004178 for _, l := range list {
Colin Cross5df74a82020-08-24 16:18:21 -07004179 if l.module() == a {
Colin Cross65569e42015-03-10 20:08:19 -07004180 found = true
Colin Cross5df74a82020-08-24 16:18:21 -07004181 } else if l.module() == b {
Colin Cross65569e42015-03-10 20:08:19 -07004182 return found
4183 }
4184 }
4185
4186 missing := a
4187 if found {
4188 missing = b
4189 }
4190 panic(fmt.Errorf("element %v not found in list %v", missing, list))
4191}
4192
Colin Cross0aa6a5f2016-01-07 13:43:09 -08004193type panicError struct {
4194 panic interface{}
4195 stack []byte
4196 in string
4197}
4198
4199func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
4200 buf := make([]byte, 4096)
4201 count := runtime.Stack(buf, false)
4202 return panicError{
4203 panic: panic,
4204 in: fmt.Sprintf(in, a...),
4205 stack: buf[:count],
4206 }
4207}
4208
4209func (p panicError) Error() string {
4210 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
4211}
4212
4213func (p *panicError) addIn(in string) {
4214 p.in += " in " + in
4215}
4216
4217func funcName(f interface{}) string {
4218 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
4219}
4220
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004221var fileHeaderTemplate = `******************************************************************************
4222*** This file is generated and should not be edited ***
4223******************************************************************************
4224{{if .Pkgs}}
4225This file contains variables, rules, and pools with name prefixes indicating
4226they were generated by the following Go packages:
4227{{range .Pkgs}}
4228 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
4229
4230`
4231
4232var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07004233Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07004234Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004235Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004236Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004237Defined: {{.pos}}
4238`
4239
4240var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
4241Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004242Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004243`