blob: 33a74873ad7be024a2dae9b49a1ae6efc3c01755 [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
Chris Parsons18ebb232022-03-25 00:56:02 -040037 "github.com/google/blueprint/metrics"
Colin Cross1fef5362015-04-20 16:50:54 -070038 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080039 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070040 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070041)
42
43var ErrBuildActionsNotReady = errors.New("build actions are not ready")
44
45const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080046const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070047
Jamie Gennisd4e10182014-06-12 20:06:50 -070048// A Context contains all the state needed to parse a set of Blueprints files
49// and generate a Ninja file. The process of generating a Ninja file proceeds
50// through a series of four phases. Each phase corresponds with a some methods
51// on the Context object
52//
53// Phase Methods
54// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070055// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070056//
57// 2. Parse ParseBlueprintsFiles, Parse
58//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070059// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070060//
61// 4. Write WriteBuildFile
62//
63// The registration phase prepares the context to process Blueprints files
64// containing various types of modules. The parse phase reads in one or more
65// Blueprints files and validates their contents against the module types that
66// have been registered. The generate phase then analyzes the parsed Blueprints
67// contents to create an internal representation for the build actions that must
68// be performed. This phase also performs validation of the module dependencies
69// and property values defined in the parsed Blueprints files. Finally, the
70// write phase generates the Ninja manifest text based on the generated build
71// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070072type Context struct {
Colin Cross3a8c0252019-01-23 13:21:48 -080073 context.Context
74
Chris Parsons18ebb232022-03-25 00:56:02 -040075 // Used for metrics-related event logging.
76 EventHandler *metrics.EventHandler
77
Colin Cross65569e42015-03-10 20:08:19 -070078 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080079 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070080 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070081 moduleInfo map[Module]*moduleInfo
82 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080083 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070084 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070085 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070086 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070087 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070088
Colin Cross3702ac72016-08-11 11:09:00 -070089 depsModified uint32 // positive if a mutator modified the dependencies
90
Jamie Gennis1bc967e2014-05-27 16:34:41 -070091 dependenciesReady bool // set to true on a successful ResolveDependencies
92 buildActionsReady bool // set to true on a successful PrepareBuildActions
93
94 // set by SetIgnoreUnknownModuleTypes
95 ignoreUnknownModuleTypes bool
96
Colin Cross036a1df2015-12-17 15:49:30 -080097 // set by SetAllowMissingDependencies
98 allowMissingDependencies bool
99
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800101 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -0800102 liveGlobals *liveTracker
Colin Cross2ce594e2020-01-29 12:58:03 -0800103 globalVariables map[Variable]ninjaString
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700104 globalPools map[Pool]*poolDef
105 globalRules map[Rule]*ruleDef
106
107 // set during PrepareBuildActions
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200108 outDir ninjaString // The builddir special Ninja variable
Colin Cross2ce594e2020-01-29 12:58:03 -0800109 requiredNinjaMajor int // For the ninja_required_version variable
110 requiredNinjaMinor int // For the ninja_required_version variable
111 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700112
Dan Willemsenab223a52018-07-05 21:56:59 -0700113 subninjas []string
114
Jeff Gastond70bf752017-11-10 15:12:08 -0800115 // set lazily by sortedModuleGroups
116 cachedSortedModuleGroups []*moduleGroup
Liz Kammer9ae14f12020-11-30 16:30:45 -0700117 // cache deps modified to determine whether cachedSortedModuleGroups needs to be recalculated
118 cachedDepsModified bool
Colin Crossd7b0f602016-06-02 15:30:20 -0700119
Colin Cross25236982021-04-05 17:20:34 -0700120 globs map[globKey]pathtools.GlobResult
Colin Cross127d2ea2016-11-01 11:10:51 -0700121 globLock sync.Mutex
122
Colin Crossc5fa50e2019-12-17 13:12:35 -0800123 srcDir string
Jeff Gastonc3e28442017-08-09 15:13:12 -0700124 fs pathtools.FileSystem
125 moduleListFile string
Colin Cross2da84922020-07-02 10:08:12 -0700126
127 // Mutators indexed by the ID of the provider associated with them. Not all mutators will
128 // have providers, and not all providers will have a mutator, or if they do the mutator may
129 // not be registered in this Context.
130 providerMutators []*mutatorInfo
131
132 // The currently running mutator
133 startedMutator *mutatorInfo
134 // True for any mutators that have already run over all modules
135 finishedMutators map[*mutatorInfo]bool
136
137 // Can be set by tests to avoid invalidating Module values after mutators.
138 skipCloneModulesAfterMutators bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700139}
140
Jamie Gennisd4e10182014-06-12 20:06:50 -0700141// An Error describes a problem that was encountered that is related to a
142// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700143type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700144 Err error // the error that occurred
145 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700146}
147
Colin Cross2c628442016-10-07 17:13:10 -0700148// A ModuleError describes a problem that was encountered that is related to a
149// particular module in a Blueprints file
150type ModuleError struct {
151 BlueprintError
152 module *moduleInfo
153}
154
155// A PropertyError describes a problem that was encountered that is related to a
156// particular property in a Blueprints file
157type PropertyError struct {
158 ModuleError
159 property string
160}
161
162func (e *BlueprintError) Error() string {
163 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
164}
165
166func (e *ModuleError) Error() string {
167 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
168}
169
170func (e *PropertyError) Error() string {
171 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
172}
173
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700174type localBuildActions struct {
175 variables []*localVariable
176 rules []*localRule
177 buildDefs []*buildDef
178}
179
Colin Crossf7beb892019-11-13 20:11:14 -0800180type moduleAlias struct {
Colin Crossedc41762020-08-13 12:07:30 -0700181 variant variant
182 target *moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800183}
184
Colin Cross5df74a82020-08-24 16:18:21 -0700185func (m *moduleAlias) alias() *moduleAlias { return m }
186func (m *moduleAlias) module() *moduleInfo { return nil }
187func (m *moduleAlias) moduleOrAliasTarget() *moduleInfo { return m.target }
188func (m *moduleAlias) moduleOrAliasVariant() variant { return m.variant }
189
190func (m *moduleInfo) alias() *moduleAlias { return nil }
191func (m *moduleInfo) module() *moduleInfo { return m }
192func (m *moduleInfo) moduleOrAliasTarget() *moduleInfo { return m }
193func (m *moduleInfo) moduleOrAliasVariant() variant { return m.variant }
194
195type moduleOrAlias interface {
196 alias() *moduleAlias
197 module() *moduleInfo
198 moduleOrAliasTarget() *moduleInfo
199 moduleOrAliasVariant() variant
200}
201
202type modulesOrAliases []moduleOrAlias
203
204func (l modulesOrAliases) firstModule() *moduleInfo {
205 for _, moduleOrAlias := range l {
206 if m := moduleOrAlias.module(); m != nil {
207 return m
208 }
209 }
210 panic(fmt.Errorf("no first module!"))
211}
212
213func (l modulesOrAliases) lastModule() *moduleInfo {
214 for i := range l {
215 if m := l[len(l)-1-i].module(); m != nil {
216 return m
217 }
218 }
219 panic(fmt.Errorf("no last module!"))
220}
221
Colin Crossbbfa51a2014-12-17 16:12:41 -0800222type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700223 name string
224 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700225
Colin Cross5df74a82020-08-24 16:18:21 -0700226 modules modulesOrAliases
Jeff Gastond70bf752017-11-10 15:12:08 -0800227
228 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700229}
230
Colin Cross5df74a82020-08-24 16:18:21 -0700231func (group *moduleGroup) moduleOrAliasByVariantName(name string) moduleOrAlias {
232 for _, module := range group.modules {
233 if module.moduleOrAliasVariant().name == name {
234 return module
235 }
236 }
237 return nil
238}
239
240func (group *moduleGroup) moduleByVariantName(name string) *moduleInfo {
241 return group.moduleOrAliasByVariantName(name).module()
242}
243
Colin Crossbbfa51a2014-12-17 16:12:41 -0800244type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700245 // set during Parse
246 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700247 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700248 relBlueprintsFile string
249 pos scanner.Position
250 propertyPos map[string]scanner.Position
Colin Cross322cc012019-05-20 13:55:14 -0700251 createdBy *moduleInfo
Colin Crossed342d92015-03-11 00:57:25 -0700252
Colin Crossedc41762020-08-13 12:07:30 -0700253 variant variant
Colin Crosse7daa222015-03-11 14:35:41 -0700254
Colin Crossd2f4ac12017-07-28 14:31:03 -0700255 logicModule Module
256 group *moduleGroup
257 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800258
259 // set during ResolveDependencies
Colin Cross99bdb2a2019-03-29 16:35:02 -0700260 missingDeps []string
261 newDirectDeps []depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800262
Colin Cross7addea32015-03-11 15:43:52 -0700263 // set during updateDependencies
264 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700265 forwardDeps []*moduleInfo
Colin Cross99bdb2a2019-03-29 16:35:02 -0700266 directDeps []depInfo
Colin Cross7addea32015-03-11 15:43:52 -0700267
Colin Crossc4773d92020-08-25 17:12:59 -0700268 // used by parallelVisit
Colin Cross7addea32015-03-11 15:43:52 -0700269 waitingCount int
270
Colin Crossc9028482014-12-18 16:28:54 -0800271 // set during each runMutator
Colin Cross5df74a82020-08-24 16:18:21 -0700272 splitModules modulesOrAliases
Colin Crossab6d7902015-03-11 16:17:52 -0700273
274 // set during PrepareBuildActions
275 actionDefs localBuildActions
Colin Cross2da84922020-07-02 10:08:12 -0700276
277 providers []interface{}
278
279 startedMutator *mutatorInfo
280 finishedMutator *mutatorInfo
281
282 startedGenerateBuildActions bool
283 finishedGenerateBuildActions bool
Colin Crossc9028482014-12-18 16:28:54 -0800284}
285
Colin Crossedc41762020-08-13 12:07:30 -0700286type variant struct {
287 name string
288 variations variationMap
289 dependencyVariations variationMap
290}
291
Colin Cross2c1f3d12016-04-11 15:47:28 -0700292type depInfo struct {
293 module *moduleInfo
294 tag DependencyTag
295}
296
Colin Cross0b7e83e2016-05-17 14:58:05 -0700297func (module *moduleInfo) Name() string {
Paul Duffin244033b2020-05-04 11:00:03 +0100298 // If this is called from a LoadHook (which is run before the module has been registered)
299 // then group will not be set and so the name is retrieved from logicModule.Name().
300 // Usually, using that method is not safe as it does not track renames (group.name does).
301 // However, when called from LoadHook it is safe as there is no way to rename a module
302 // until after the LoadHook has run and the module has been registered.
303 if module.group != nil {
304 return module.group.name
305 } else {
306 return module.logicModule.Name()
307 }
Colin Cross0b7e83e2016-05-17 14:58:05 -0700308}
309
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800310func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700311 s := fmt.Sprintf("module %q", module.Name())
Colin Crossedc41762020-08-13 12:07:30 -0700312 if module.variant.name != "" {
313 s += fmt.Sprintf(" variant %q", module.variant.name)
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800314 }
Colin Cross322cc012019-05-20 13:55:14 -0700315 if module.createdBy != nil {
316 s += fmt.Sprintf(" (created by %s)", module.createdBy)
317 }
318
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800319 return s
320}
321
Jeff Gastond70bf752017-11-10 15:12:08 -0800322func (module *moduleInfo) namespace() Namespace {
323 return module.group.namespace
324}
325
Colin Crossf5e34b92015-03-13 16:02:36 -0700326// A Variation is a way that a variant of a module differs from other variants of the same module.
327// For example, two variants of the same module might have Variation{"arch","arm"} and
328// Variation{"arch","arm64"}
329type Variation struct {
330 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700331 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700332 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
333 // "shared" or "static" for link.
334 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700335}
336
Colin Crossf5e34b92015-03-13 16:02:36 -0700337// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
338type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700339
Colin Crossf5e34b92015-03-13 16:02:36 -0700340func (vm variationMap) clone() variationMap {
Colin Cross9403b5a2019-11-13 20:11:04 -0800341 if vm == nil {
342 return nil
343 }
Colin Crossf5e34b92015-03-13 16:02:36 -0700344 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700345 for k, v := range vm {
346 newVm[k] = v
347 }
348
349 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800350}
351
Colin Cross89486232015-05-08 11:14:54 -0700352// Compare this variationMap to another one. Returns true if the every entry in this map
Colin Cross5dc67592020-08-24 14:46:13 -0700353// exists and has the same value in the other map.
354func (vm variationMap) subsetOf(other variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -0700355 for k, v1 := range vm {
Colin Cross5dc67592020-08-24 14:46:13 -0700356 if v2, ok := other[k]; !ok || v1 != v2 {
Colin Cross89486232015-05-08 11:14:54 -0700357 return false
358 }
359 }
360 return true
361}
362
Colin Crossf5e34b92015-03-13 16:02:36 -0700363func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700364 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800365}
366
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700367type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700368 // set during RegisterSingletonType
369 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700370 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700371 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700372
373 // set during PrepareBuildActions
374 actionDefs localBuildActions
375}
376
Colin Crossc9028482014-12-18 16:28:54 -0800377type mutatorInfo struct {
378 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800379 topDownMutator TopDownMutator
380 bottomUpMutator BottomUpMutator
381 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700382 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800383}
384
Colin Crossaf4fd212017-07-28 14:32:36 -0700385func newContext() *Context {
Chris Parsons18ebb232022-03-25 00:56:02 -0400386 eventHandler := metrics.EventHandler{}
Colin Crossaf4fd212017-07-28 14:32:36 -0700387 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800388 Context: context.Background(),
Chris Parsons18ebb232022-03-25 00:56:02 -0400389 EventHandler: &eventHandler,
Colin Cross5f03f112017-11-07 13:29:54 -0800390 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800391 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800392 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross25236982021-04-05 17:20:34 -0700393 globs: make(map[globKey]pathtools.GlobResult),
Colin Cross5f03f112017-11-07 13:29:54 -0800394 fs: pathtools.OsFs,
Colin Cross2da84922020-07-02 10:08:12 -0700395 finishedMutators: make(map[*mutatorInfo]bool),
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200396 outDir: nil,
Colin Cross5f03f112017-11-07 13:29:54 -0800397 requiredNinjaMajor: 1,
398 requiredNinjaMinor: 7,
399 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700400 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700401}
402
403// NewContext creates a new Context object. The created context initially has
404// no module or singleton factories registered, so the RegisterModuleFactory and
405// RegisterSingletonFactory methods must be called before it can do anything
406// useful.
407func NewContext() *Context {
408 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700409
410 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
411
412 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700413}
414
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700415// A ModuleFactory function creates a new Module object. See the
416// Context.RegisterModuleType method for details about how a registered
417// ModuleFactory is used by a Context.
418type ModuleFactory func() (m Module, propertyStructs []interface{})
419
Jamie Gennisd4e10182014-06-12 20:06:50 -0700420// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700421// Blueprints file) with a Module factory function. When the given module type
422// name is encountered in a Blueprints file during parsing, the Module factory
423// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800424// generation for the module. If a Mutator splits a module into multiple variants,
425// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700426//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700427// The module type names given here must be unique for the context. The factory
428// function should be a named function so that its package and name can be
429// included in the generated Ninja file for debugging purposes.
430//
431// The factory function returns two values. The first is the newly created
432// Module object. The second is a slice of pointers to that Module object's
433// properties structs. Each properties struct is examined when parsing a module
434// definition of this type in a Blueprints file. Exported fields of the
435// properties structs are automatically set to the property values specified in
436// the Blueprints file. The properties struct field names determine the name of
437// the Blueprints file properties that are used - the Blueprints property name
438// matches that of the properties struct field name with the first letter
439// converted to lower-case.
440//
441// The fields of the properties struct must be either []string, a string, or
442// bool. The Context will panic if a Module gets instantiated with a properties
443// struct containing a field that is not one these supported types.
444//
445// Any properties that appear in the Blueprints files that are not built-in
446// module properties (such as "name" and "deps") and do not have a corresponding
447// field in the returned module properties struct result in an error during the
448// Context's parse phase.
449//
450// As an example, the follow code:
451//
452// type myModule struct {
453// properties struct {
454// Foo string
455// Bar []string
456// }
457// }
458//
459// func NewMyModule() (blueprint.Module, []interface{}) {
460// module := new(myModule)
461// properties := &module.properties
462// return module, []interface{}{properties}
463// }
464//
465// func main() {
466// ctx := blueprint.NewContext()
467// ctx.RegisterModuleType("my_module", NewMyModule)
468// // ...
469// }
470//
471// would support parsing a module defined in a Blueprints file as follows:
472//
473// my_module {
474// name: "myName",
475// foo: "my foo string",
476// bar: ["my", "bar", "strings"],
477// }
478//
Colin Cross7ad621c2015-01-07 16:22:45 -0800479// The factory function may be called from multiple goroutines. Any accesses
480// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700481func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
482 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700483 panic(errors.New("module type name is already registered"))
484 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700485 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700486}
487
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700488// A SingletonFactory function creates a new Singleton object. See the
489// Context.RegisterSingletonType method for details about how a registered
490// SingletonFactory is used by a Context.
491type SingletonFactory func() Singleton
492
493// RegisterSingletonType registers a singleton type that will be invoked to
Usta Shresthaee7a5d72022-01-10 22:46:23 -0500494// generate build actions. Each registered singleton type is instantiated
Yuchen Wub9103ef2015-08-25 17:58:17 -0700495// and invoked exactly once as part of the generate phase. Each registered
496// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700497//
498// The singleton type names given here must be unique for the context. The
499// factory function should be a named function so that its package and name can
500// be included in the generated Ninja file for debugging purposes.
501func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700502 for _, s := range c.singletonInfo {
503 if s.name == name {
504 panic(errors.New("singleton name is already registered"))
505 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700506 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700507
Yuchen Wub9103ef2015-08-25 17:58:17 -0700508 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700509 factory: factory,
510 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700511 name: name,
512 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700513}
514
Colin Cross5f03f112017-11-07 13:29:54 -0800515// RegisterPreSingletonType registers a presingleton type that will be invoked to
516// generate build actions before any Blueprint files have been read. Each registered
517// presingleton type is instantiated and invoked exactly once at the beginning of the
518// parse phase. Each registered presingleton is invoked in registration order.
519//
520// The presingleton type names given here must be unique for the context. The
521// factory function should be a named function so that its package and name can
522// be included in the generated Ninja file for debugging purposes.
523func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
524 for _, s := range c.preSingletonInfo {
525 if s.name == name {
526 panic(errors.New("presingleton name is already registered"))
527 }
528 }
529
530 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
531 factory: factory,
532 singleton: factory(),
533 name: name,
534 })
535}
536
Jeff Gastond70bf752017-11-10 15:12:08 -0800537func (c *Context) SetNameInterface(i NameInterface) {
538 c.nameInterface = i
539}
540
Colin Crossc5fa50e2019-12-17 13:12:35 -0800541func (c *Context) SetSrcDir(path string) {
542 c.srcDir = path
543 c.fs = pathtools.NewOsFs(path)
544}
545
546func (c *Context) SrcDir() string {
547 return c.srcDir
548}
549
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700550func singletonPkgPath(singleton Singleton) string {
551 typ := reflect.TypeOf(singleton)
552 for typ.Kind() == reflect.Ptr {
553 typ = typ.Elem()
554 }
555 return typ.PkgPath()
556}
557
558func singletonTypeName(singleton Singleton) string {
559 typ := reflect.TypeOf(singleton)
560 for typ.Kind() == reflect.Ptr {
561 typ = typ.Elem()
562 }
563 return typ.PkgPath() + "." + typ.Name()
564}
565
Colin Cross3702ac72016-08-11 11:09:00 -0700566// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
567// top-down between Modules. Each registered mutator is invoked in registration order (mixing
568// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
569// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800570//
Colin Cross65569e42015-03-10 20:08:19 -0700571// The mutator type names given here must be unique to all top down mutators in
572// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700573//
574// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
575// parallel while maintaining ordering.
576func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800577 for _, m := range c.mutatorInfo {
578 if m.name == name && m.topDownMutator != nil {
579 panic(fmt.Errorf("mutator name %s is already registered", name))
580 }
581 }
582
Colin Cross3702ac72016-08-11 11:09:00 -0700583 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800584 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800585 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700586 }
587
588 c.mutatorInfo = append(c.mutatorInfo, info)
589
590 return info
Colin Crossc9028482014-12-18 16:28:54 -0800591}
592
Colin Cross3702ac72016-08-11 11:09:00 -0700593// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
594// Each registered mutator is invoked in registration order (mixing TopDownMutators and
595// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
596// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800597//
Colin Cross65569e42015-03-10 20:08:19 -0700598// The mutator type names given here must be unique to all bottom up or early
599// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700600//
Colin Cross3702ac72016-08-11 11:09:00 -0700601// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
602// parallel while maintaining ordering.
603func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700604 for _, m := range c.variantMutatorNames {
605 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800606 panic(fmt.Errorf("mutator name %s is already registered", name))
607 }
608 }
609
Colin Cross49c279a2016-08-05 22:30:44 -0700610 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800611 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800612 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700613 }
614 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700615
616 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700617
618 return info
619}
620
Colin Cross3702ac72016-08-11 11:09:00 -0700621type MutatorHandle interface {
622 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
623 // method on the mutator context is thread-safe, but the mutator must handle synchronization
624 // for any modifications to global state or any modules outside the one it was invoked on.
625 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700626}
627
Colin Cross3702ac72016-08-11 11:09:00 -0700628func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700629 mutator.parallel = true
630 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700631}
632
633// RegisterEarlyMutator registers a mutator that will be invoked to split
634// Modules into multiple variant Modules before any dependencies have been
635// created. Each registered mutator is invoked in registration order once
636// per Module (including each variant from previous early mutators). Module
637// order is unpredictable.
638//
639// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700640// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700641//
642// The mutator type names given here must be unique to all bottom up or early
643// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700644//
645// Deprecated, use a BottomUpMutator instead. The only difference between
646// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
647// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700648func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
649 for _, m := range c.variantMutatorNames {
650 if m == name {
651 panic(fmt.Errorf("mutator name %s is already registered", name))
652 }
653 }
654
Colin Crossf8b50422016-08-10 12:56:40 -0700655 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
656 bottomUpMutator: func(mctx BottomUpMutatorContext) {
657 mutator(mctx)
658 },
659 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700660 })
661
662 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800663}
664
Jamie Gennisd4e10182014-06-12 20:06:50 -0700665// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
666// where it encounters an unknown module type while parsing Blueprints files. By
667// default, the context will report unknown module types as an error. If this
668// method is called with ignoreUnknownModuleTypes set to true then the context
669// will silently ignore unknown module types.
670//
671// This method should generally not be used. It exists to facilitate the
672// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700673func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
674 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
675}
676
Colin Cross036a1df2015-12-17 15:49:30 -0800677// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
678// unresolved dependencies. If the module's GenerateBuildActions calls
679// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
680// for missing dependencies.
681func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
682 c.allowMissingDependencies = allowMissingDependencies
683}
684
Jeff Gastonc3e28442017-08-09 15:13:12 -0700685func (c *Context) SetModuleListFile(listFile string) {
686 c.moduleListFile = listFile
687}
688
689func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
690 reader, err := c.fs.Open(c.moduleListFile)
691 if err != nil {
692 return nil, err
693 }
Liz Kammer6e7e6a92022-02-07 10:03:19 -0500694 defer reader.Close()
Jeff Gastonc3e28442017-08-09 15:13:12 -0700695 bytes, err := ioutil.ReadAll(reader)
696 if err != nil {
697 return nil, err
698 }
699 text := string(bytes)
700
701 text = strings.Trim(text, "\n")
702 lines := strings.Split(text, "\n")
703 for i := range lines {
704 lines[i] = filepath.Join(baseDir, lines[i])
705 }
706
707 return lines, nil
708}
709
Jeff Gaston656870f2017-11-29 18:37:31 -0800710// a fileParseContext tells the status of parsing a particular file
711type fileParseContext struct {
712 // name of file
713 fileName string
714
715 // scope to use when resolving variables
716 Scope *parser.Scope
717
718 // pointer to the one in the parent directory
719 parent *fileParseContext
720
721 // is closed once FileHandler has completed for this file
722 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700723}
724
Jamie Gennisd4e10182014-06-12 20:06:50 -0700725// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
726// at rootFile. When it encounters a Blueprints file with a set of subdirs
727// listed it recursively parses any Blueprints files found in those
728// subdirectories.
729//
730// If no errors are encountered while parsing the files, the list of paths on
731// which the future output will depend is returned. This list will include both
732// Blueprints file paths as well as directory paths for cases where wildcard
733// subdirs are found.
Colin Crossda70fd02019-12-30 18:40:09 -0800734func (c *Context) ParseBlueprintsFiles(rootFile string,
735 config interface{}) (deps []string, errs []error) {
736
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800737 baseDir := filepath.Dir(rootFile)
738 pathsToParse, err := c.ListModulePaths(baseDir)
739 if err != nil {
740 return nil, []error{err}
741 }
Colin Crossda70fd02019-12-30 18:40:09 -0800742 return c.ParseFileList(baseDir, pathsToParse, config)
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800743}
744
Colin Crossda70fd02019-12-30 18:40:09 -0800745func (c *Context) ParseFileList(rootDir string, filePaths []string,
746 config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700747
Jeff Gastonc3e28442017-08-09 15:13:12 -0700748 if len(filePaths) < 1 {
749 return nil, []error{fmt.Errorf("no paths provided to parse")}
750 }
751
Colin Cross7ad621c2015-01-07 16:22:45 -0800752 c.dependenciesReady = false
753
Colin Crossda70fd02019-12-30 18:40:09 -0800754 type newModuleInfo struct {
755 *moduleInfo
Colin Cross13b5bef2021-05-19 10:07:19 -0700756 deps []string
Colin Crossda70fd02019-12-30 18:40:09 -0800757 added chan<- struct{}
758 }
759
760 moduleCh := make(chan newModuleInfo)
Colin Cross23d7aa12015-06-30 16:05:22 -0700761 errsCh := make(chan []error)
762 doneCh := make(chan struct{})
763 var numErrs uint32
764 var numGoroutines int32
765
766 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700767 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700768 if atomic.LoadUint32(&numErrs) > maxErrors {
769 return
770 }
771
Colin Crossda70fd02019-12-30 18:40:09 -0800772 addedCh := make(chan struct{})
773
Colin Cross9672d862019-12-30 18:38:20 -0800774 var scopedModuleFactories map[string]ModuleFactory
775
Colin Crossda70fd02019-12-30 18:40:09 -0800776 var addModule func(module *moduleInfo) []error
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100777 addModule = func(module *moduleInfo) []error {
Paul Duffin244033b2020-05-04 11:00:03 +0100778 // Run any load hooks immediately before it is sent to the moduleCh and is
779 // registered by name. This allows load hooks to set and/or modify any aspect
780 // of the module (including names) using information that is not available when
781 // the module factory is called.
Colin Cross13b5bef2021-05-19 10:07:19 -0700782 newModules, newDeps, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
Colin Crossda70fd02019-12-30 18:40:09 -0800783 if len(errs) > 0 {
784 return errs
785 }
Paul Duffin244033b2020-05-04 11:00:03 +0100786
Colin Cross13b5bef2021-05-19 10:07:19 -0700787 moduleCh <- newModuleInfo{module, newDeps, addedCh}
Paul Duffin244033b2020-05-04 11:00:03 +0100788 <-addedCh
Colin Crossda70fd02019-12-30 18:40:09 -0800789 for _, n := range newModules {
790 errs = addModule(n)
791 if len(errs) > 0 {
792 return errs
793 }
794 }
795 return nil
796 }
797
Jeff Gaston656870f2017-11-29 18:37:31 -0800798 for _, def := range file.Defs {
Jeff Gaston656870f2017-11-29 18:37:31 -0800799 switch def := def.(type) {
800 case *parser.Module:
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100801 module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes)
Colin Crossda70fd02019-12-30 18:40:09 -0800802 if len(errs) == 0 && module != nil {
803 errs = addModule(module)
804 }
805
806 if len(errs) > 0 {
807 atomic.AddUint32(&numErrs, uint32(len(errs)))
808 errsCh <- errs
809 }
810
Jeff Gaston656870f2017-11-29 18:37:31 -0800811 case *parser.Assignment:
812 // Already handled via Scope object
813 default:
814 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700815 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800816
Jeff Gaston656870f2017-11-29 18:37:31 -0800817 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700818 }
819
820 atomic.AddInt32(&numGoroutines, 1)
821 go func() {
822 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700823 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700824 if len(errs) > 0 {
825 errsCh <- errs
826 }
827 doneCh <- struct{}{}
828 }()
829
Colin Cross13b5bef2021-05-19 10:07:19 -0700830 var hookDeps []string
Colin Cross23d7aa12015-06-30 16:05:22 -0700831loop:
832 for {
833 select {
834 case newErrs := <-errsCh:
835 errs = append(errs, newErrs...)
836 case module := <-moduleCh:
Colin Crossda70fd02019-12-30 18:40:09 -0800837 newErrs := c.addModule(module.moduleInfo)
Colin Cross13b5bef2021-05-19 10:07:19 -0700838 hookDeps = append(hookDeps, module.deps...)
Colin Crossda70fd02019-12-30 18:40:09 -0800839 if module.added != nil {
840 module.added <- struct{}{}
841 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700842 if len(newErrs) > 0 {
843 errs = append(errs, newErrs...)
844 }
845 case <-doneCh:
846 n := atomic.AddInt32(&numGoroutines, -1)
847 if n == 0 {
848 break loop
849 }
850 }
851 }
852
Colin Cross13b5bef2021-05-19 10:07:19 -0700853 deps = append(deps, hookDeps...)
Colin Cross23d7aa12015-06-30 16:05:22 -0700854 return deps, errs
855}
856
857type FileHandler func(*parser.File)
858
Jeff Gastonc3e28442017-08-09 15:13:12 -0700859// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
860// calling the given file handler on each
861//
862// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
863// it recursively parses any Blueprints files found in those subdirectories.
864//
865// If any of the file paths is an ancestor directory of any other of file path, the ancestor
866// will be parsed and visited first.
867//
868// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700869//
870// If no errors are encountered while parsing the files, the list of paths on
871// which the future output will depend is returned. This list will include both
872// Blueprints file paths as well as directory paths for cases where wildcard
873// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800874//
875// visitor will be called asynchronously, and will only be called once visitor for each
876// ancestor directory has completed.
877//
878// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700879func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
880 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700881
Jeff Gastonc3e28442017-08-09 15:13:12 -0700882 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
883 descendantsMap, err := findBlueprintDescendants(filePaths)
884 if err != nil {
885 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700886 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800887 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700888
Jeff Gaston5800d042017-12-05 14:57:58 -0800889 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800890 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800891 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800892 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700893
Jeff Gaston5800d042017-12-05 14:57:58 -0800894 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800895 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700896
Colin Cross7ad621c2015-01-07 16:22:45 -0800897 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700898 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800899 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700900 tooManyErrors := false
901
902 // Limit concurrent calls to parseBlueprintFiles to 200
903 // Darwin has a default limit of 256 open files
904 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800905
Jeff Gaston656870f2017-11-29 18:37:31 -0800906 // count the number of pending calls to visitor()
907 visitorWaitGroup := sync.WaitGroup{}
908
909 startParseBlueprintsFile := func(blueprint fileParseContext) {
910 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700911 return
912 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800913 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700914 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800915 deps = append(deps, blueprint.fileName)
916 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800917 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800918 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
919 &blueprint)
920 if len(errs) > 0 {
921 errsCh <- errs
922 }
923 for _, blueprint := range blueprints {
924 blueprintsCh <- blueprint
925 }
926 for _, dep := range deps {
927 depsCh <- dep
928 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800929 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700930
Jeff Gaston656870f2017-11-29 18:37:31 -0800931 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
932 // wait for visitor() of parent to complete
933 <-blueprint.parent.doneVisiting
934 }
935
Jeff Gastona7e408a2017-12-05 15:11:55 -0800936 if len(errs) == 0 {
937 // process this file
938 visitor(file)
939 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800940 if blueprint.doneVisiting != nil {
941 close(blueprint.doneVisiting)
942 }
943 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800944 }()
945 }
946
Jeff Gaston656870f2017-11-29 18:37:31 -0800947 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700948 if activeCount >= maxActiveCount {
949 pending = append(pending, blueprint)
950 } else {
951 startParseBlueprintsFile(blueprint)
952 }
953 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800954
Jeff Gaston656870f2017-11-29 18:37:31 -0800955 startParseDescendants := func(blueprint fileParseContext) {
956 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700957 if hasDescendants {
958 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800959 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700960 }
961 }
962 }
Colin Cross4a02a302017-05-16 10:33:58 -0700963
Jeff Gastonc3e28442017-08-09 15:13:12 -0700964 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800965 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800966
967loop:
968 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700969 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800970 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700971 }
972
Colin Cross7ad621c2015-01-07 16:22:45 -0800973 select {
974 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700975 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800976 case dep := <-depsCh:
977 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800978 case blueprint := <-blueprintsCh:
979 if tooManyErrors {
980 continue
981 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700982 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800983 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700984 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700985 if !tooManyErrors {
986 startParseDescendants(blueprint)
987 }
988 if activeCount < maxActiveCount && len(pending) > 0 {
989 // start to process the next one from the queue
990 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700991 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700992 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700993 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700994 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800995 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700996 }
997 }
998 }
999
Jeff Gastonc3e28442017-08-09 15:13:12 -07001000 sort.Strings(deps)
1001
Jeff Gaston656870f2017-11-29 18:37:31 -08001002 // wait for every visitor() to complete
1003 visitorWaitGroup.Wait()
1004
Colin Cross7ad621c2015-01-07 16:22:45 -08001005 return
1006}
1007
Colin Crossd7b0f602016-06-02 15:30:20 -07001008// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
1009// filenames to contents stored as a byte slice.
1010func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -08001011 // look for a module list file
1012 _, ok := files[MockModuleListFile]
1013 if !ok {
1014 // no module list file specified; find every file named Blueprints
1015 pathsToParse := []string{}
1016 for candidate := range files {
Lukacs T. Berkieef56852021-09-02 11:34:06 +02001017 if filepath.Base(candidate) == "Android.bp" {
Jeff Gaston9f630902017-11-15 14:49:48 -08001018 pathsToParse = append(pathsToParse, candidate)
1019 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001020 }
Jeff Gaston9f630902017-11-15 14:49:48 -08001021 if len(pathsToParse) < 1 {
1022 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
1023 }
1024 // put the list of Blueprints files into a list file
1025 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -07001026 }
Jeff Gaston9f630902017-11-15 14:49:48 -08001027 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001028
1029 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -08001030 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -07001031}
1032
Colin Cross8cde4252019-12-17 13:11:21 -08001033func (c *Context) SetFs(fs pathtools.FileSystem) {
1034 c.fs = fs
1035}
1036
Jeff Gaston8fd95782017-12-05 15:03:51 -08001037// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -08001038func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -08001039 parent *fileParseContext) (file *parser.File,
1040 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -08001041
Colin Crossd7b0f602016-06-02 15:30:20 -07001042 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -08001043 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -07001044 // couldn't open the file; see if we can provide a clearer error than "could not open file"
1045 stats, statErr := c.fs.Lstat(filename)
1046 if statErr == nil {
1047 isSymlink := stats.Mode()&os.ModeSymlink != 0
1048 if isSymlink {
1049 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
1050 target, readlinkErr := os.Readlink(filename)
1051 if readlinkErr == nil {
1052 _, targetStatsErr := c.fs.Lstat(target)
1053 if targetStatsErr != nil {
1054 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
1055 }
1056 }
1057 } else {
1058 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
1059 }
1060 }
Jeff Gaston8fd95782017-12-05 15:03:51 -08001061 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001062 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001063
Jeff Gaston8fd95782017-12-05 15:03:51 -08001064 func() {
1065 defer func() {
1066 err = f.Close()
1067 if err != nil {
1068 errs = append(errs, err)
1069 }
1070 }()
1071 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -07001072 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001073
Colin Cross7ad621c2015-01-07 16:22:45 -08001074 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001075 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -08001076 }
1077
Colin Cross1fef5362015-04-20 16:50:54 -07001078 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001079 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -07001080 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001081
Jeff Gaston8fd95782017-12-05 15:03:51 -08001082 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -07001083}
1084
Jeff Gastona12f22f2017-08-08 14:45:56 -07001085// parseOne parses a single Blueprints file from the given reader, creating Module
1086// objects for each of the module definitions encountered. If the Blueprints
1087// file contains an assignment to the "subdirs" variable, then the
1088// subdirectories listed are searched for Blueprints files returned in the
1089// subBlueprints return value. If the Blueprints file contains an assignment
1090// to the "build" variable, then the file listed are returned in the
1091// subBlueprints return value.
1092//
1093// rootDir specifies the path to the root directory of the source tree, while
1094// filename specifies the path to the Blueprints file. These paths are used for
1095// error reporting and for determining the module's directory.
1096func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -08001097 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -07001098
1099 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
1100 if err != nil {
1101 return nil, nil, []error{err}
1102 }
1103
Jeff Gastona12f22f2017-08-08 14:45:56 -07001104 scope.Remove("subdirs")
1105 scope.Remove("optional_subdirs")
1106 scope.Remove("build")
1107 file, errs = parser.ParseAndEval(filename, reader, scope)
1108 if len(errs) > 0 {
1109 for i, err := range errs {
1110 if parseErr, ok := err.(*parser.ParseError); ok {
1111 err = &BlueprintError{
1112 Err: parseErr.Err,
1113 Pos: parseErr.Pos,
1114 }
1115 errs[i] = err
1116 }
1117 }
1118
1119 // If there were any parse errors don't bother trying to interpret the
1120 // result.
1121 return nil, nil, errs
1122 }
1123 file.Name = relBlueprintsFile
1124
Jeff Gastona12f22f2017-08-08 14:45:56 -07001125 build, buildPos, err := getLocalStringListFromScope(scope, "build")
1126 if err != nil {
1127 errs = append(errs, err)
1128 }
Jeff Gastonf23e3662017-11-30 17:31:43 -08001129 for _, buildEntry := range build {
1130 if strings.Contains(buildEntry, "/") {
1131 errs = append(errs, &BlueprintError{
1132 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1133 Pos: buildPos,
1134 })
1135 }
1136 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001137
Jeff Gastona12f22f2017-08-08 14:45:56 -07001138 if err != nil {
1139 errs = append(errs, err)
1140 }
1141
Jeff Gastona12f22f2017-08-08 14:45:56 -07001142 var blueprints []string
1143
1144 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1145 blueprints = append(blueprints, newBlueprints...)
1146 errs = append(errs, newErrs...)
1147
Jeff Gaston656870f2017-11-29 18:37:31 -08001148 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -07001149 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -08001150 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -07001151 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001152 return file, subBlueprintsAndScope, errs
1153}
1154
Colin Cross7f507402015-12-16 13:03:41 -08001155func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -07001156 buildPos scanner.Position) ([]string, []error) {
1157
1158 var blueprints []string
1159 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001160
1161 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001162 pattern := filepath.Join(dir, file)
1163 var matches []string
1164 var err error
1165
Colin Cross08e49542016-11-14 15:23:33 -08001166 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001167
Colin Cross7f507402015-12-16 13:03:41 -08001168 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001169 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001170 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001171 Pos: buildPos,
1172 })
1173 continue
1174 }
1175
1176 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001177 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001178 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001179 Pos: buildPos,
1180 })
1181 }
1182
Colin Cross7f507402015-12-16 13:03:41 -08001183 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001184 if strings.HasSuffix(foundBlueprints, "/") {
1185 errs = append(errs, &BlueprintError{
1186 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1187 Pos: buildPos,
1188 })
1189 }
Colin Cross7f507402015-12-16 13:03:41 -08001190 blueprints = append(blueprints, foundBlueprints)
1191 }
1192 }
1193
Colin Cross127d2ea2016-11-01 11:10:51 -07001194 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001195}
1196
1197func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001198 subBlueprintsName string, optional bool) ([]string, []error) {
1199
1200 var blueprints []string
1201 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001202
1203 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001204 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1205 var matches []string
1206 var err error
1207
Colin Cross08e49542016-11-14 15:23:33 -08001208 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001209
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001210 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001211 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001212 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001213 Pos: subdirsPos,
1214 })
1215 continue
1216 }
1217
Colin Cross7f507402015-12-16 13:03:41 -08001218 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001219 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001220 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001221 Pos: subdirsPos,
1222 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001223 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001224
Colin Cross127d2ea2016-11-01 11:10:51 -07001225 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001226 if strings.HasSuffix(subBlueprints, "/") {
1227 errs = append(errs, &BlueprintError{
1228 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1229 Pos: subdirsPos,
1230 })
1231 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001232 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001233 }
1234 }
Colin Cross1fef5362015-04-20 16:50:54 -07001235
Colin Cross127d2ea2016-11-01 11:10:51 -07001236 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001237}
1238
Colin Cross6d8780f2015-07-10 17:51:55 -07001239func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1240 if assignment, local := scope.Get(v); assignment == nil || !local {
1241 return nil, scanner.Position{}, nil
1242 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001243 switch value := assignment.Value.Eval().(type) {
1244 case *parser.List:
1245 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001246
Colin Crosse32cc802016-06-07 12:28:16 -07001247 for _, listValue := range value.Values {
1248 s, ok := listValue.(*parser.String)
1249 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001250 // The parser should not produce this.
1251 panic("non-string value found in list")
1252 }
1253
Colin Crosse32cc802016-06-07 12:28:16 -07001254 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001255 }
1256
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001257 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001258 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001259 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001260 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001261 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001262 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001263 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001264 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001265 }
1266 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001267}
1268
Colin Cross29394222015-04-27 13:18:21 -07001269func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001270 if assignment, _ := scope.Get(v); assignment == nil {
1271 return "", scanner.Position{}, nil
1272 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001273 switch value := assignment.Value.Eval().(type) {
1274 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001275 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001276 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001277 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001278 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001279 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001280 }
1281 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001282 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001283 }
1284 }
Colin Cross29394222015-04-27 13:18:21 -07001285}
1286
Colin Cross910242b2016-04-11 15:41:52 -07001287// Clones a build logic module by calling the factory method for its module type, and then cloning
1288// property values. Any values stored in the module object that are not stored in properties
1289// structs will be lost.
1290func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001291 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001292
Colin Crossd2f4ac12017-07-28 14:31:03 -07001293 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001294 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001295 }
1296
1297 for i := range newProperties {
Colin Cross5d57b2d2020-01-27 16:14:31 -08001298 dst := reflect.ValueOf(newProperties[i])
1299 src := reflect.ValueOf(origModule.properties[i])
Colin Cross910242b2016-04-11 15:41:52 -07001300
1301 proptools.CopyProperties(dst, src)
1302 }
1303
1304 return newLogicModule, newProperties
1305}
1306
Colin Crossedc41762020-08-13 12:07:30 -07001307func newVariant(module *moduleInfo, mutatorName string, variationName string,
1308 local bool) variant {
1309
1310 newVariantName := module.variant.name
1311 if variationName != "" {
1312 if newVariantName == "" {
1313 newVariantName = variationName
1314 } else {
1315 newVariantName += "_" + variationName
1316 }
1317 }
1318
1319 newVariations := module.variant.variations.clone()
1320 if newVariations == nil {
1321 newVariations = make(variationMap)
1322 }
1323 newVariations[mutatorName] = variationName
1324
1325 newDependencyVariations := module.variant.dependencyVariations.clone()
1326 if !local {
1327 if newDependencyVariations == nil {
1328 newDependencyVariations = make(variationMap)
1329 }
1330 newDependencyVariations[mutatorName] = variationName
1331 }
1332
1333 return variant{newVariantName, newVariations, newDependencyVariations}
1334}
1335
Colin Crossf5e34b92015-03-13 16:02:36 -07001336func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
Colin Cross5df74a82020-08-24 16:18:21 -07001337 defaultVariationName *string, variationNames []string, local bool) (modulesOrAliases, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001338
Colin Crossf4d18a62015-03-18 17:43:15 -07001339 if len(variationNames) == 0 {
1340 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001341 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001342 }
1343
Colin Cross5df74a82020-08-24 16:18:21 -07001344 var newModules modulesOrAliases
Colin Crossc9028482014-12-18 16:28:54 -08001345
Colin Cross174ae052015-03-03 17:37:03 -08001346 var errs []error
1347
Colin Crossf5e34b92015-03-13 16:02:36 -07001348 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001349 var newLogicModule Module
1350 var newProperties []interface{}
1351
1352 if i == 0 {
1353 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001354 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1355 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001356 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001357 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001358 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001359 }
1360
Colin Crossed342d92015-03-11 00:57:25 -07001361 m := *origModule
1362 newModule := &m
Colin Cross2da84922020-07-02 10:08:12 -07001363 newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
Colin Cross7ff2e8d2021-01-21 22:39:28 -08001364 newModule.reverseDeps = nil
1365 newModule.forwardDeps = nil
Colin Crossed342d92015-03-11 00:57:25 -07001366 newModule.logicModule = newLogicModule
Colin Crossedc41762020-08-13 12:07:30 -07001367 newModule.variant = newVariant(origModule, mutatorName, variationName, local)
Colin Crossd2f4ac12017-07-28 14:31:03 -07001368 newModule.properties = newProperties
Colin Cross2da84922020-07-02 10:08:12 -07001369 newModule.providers = append([]interface{}(nil), origModule.providers...)
Colin Crossc9028482014-12-18 16:28:54 -08001370
1371 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001372
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001373 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName)
Colin Cross174ae052015-03-03 17:37:03 -08001374 if len(newErrs) > 0 {
1375 errs = append(errs, newErrs...)
1376 }
Colin Crossc9028482014-12-18 16:28:54 -08001377 }
1378
1379 // Mark original variant as invalid. Modules that depend on this module will still
1380 // depend on origModule, but we'll fix it when the mutator is called on them.
1381 origModule.logicModule = nil
1382 origModule.splitModules = newModules
1383
Colin Cross3702ac72016-08-11 11:09:00 -07001384 atomic.AddUint32(&c.depsModified, 1)
1385
Colin Cross174ae052015-03-03 17:37:03 -08001386 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001387}
1388
Colin Crossf5e34b92015-03-13 16:02:36 -07001389func (c *Context) convertDepsToVariation(module *moduleInfo,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001390 mutatorName, variationName string, defaultVariationName *string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001391
Colin Crossc9028482014-12-18 16:28:54 -08001392 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001393 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001394 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001395 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001396 if m.moduleOrAliasVariant().variations[mutatorName] == variationName {
1397 newDep = m.moduleOrAliasTarget()
Colin Crossc9028482014-12-18 16:28:54 -08001398 break
1399 }
1400 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001401 if newDep == nil && defaultVariationName != nil {
1402 // give it a second chance; match with defaultVariationName
1403 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001404 if m.moduleOrAliasVariant().variations[mutatorName] == *defaultVariationName {
1405 newDep = m.moduleOrAliasTarget()
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001406 break
1407 }
1408 }
1409 }
Colin Crossc9028482014-12-18 16:28:54 -08001410 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001411 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001412 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001413 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001414 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001415 })
1416 continue
Colin Crossc9028482014-12-18 16:28:54 -08001417 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001418 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001419 }
1420 }
Colin Cross174ae052015-03-03 17:37:03 -08001421
1422 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001423}
1424
Colin Crossedc41762020-08-13 12:07:30 -07001425func (c *Context) prettyPrintVariant(variations variationMap) string {
1426 names := make([]string, 0, len(variations))
Colin Cross65569e42015-03-10 20:08:19 -07001427 for _, m := range c.variantMutatorNames {
Colin Crossedc41762020-08-13 12:07:30 -07001428 if v, ok := variations[m]; ok {
Colin Cross65569e42015-03-10 20:08:19 -07001429 names = append(names, m+":"+v)
1430 }
1431 }
1432
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001433 return strings.Join(names, ",")
Colin Cross65569e42015-03-10 20:08:19 -07001434}
1435
Colin Crossd03b59d2019-11-13 20:10:12 -08001436func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1437 var variants []string
Colin Cross5df74a82020-08-24 16:18:21 -07001438 for _, moduleOrAlias := range group.modules {
1439 if mod := moduleOrAlias.module(); mod != nil {
1440 variants = append(variants, c.prettyPrintVariant(mod.variant.variations))
1441 } else if alias := moduleOrAlias.alias(); alias != nil {
1442 variants = append(variants, c.prettyPrintVariant(alias.variant.variations)+
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001443 " (alias to "+c.prettyPrintVariant(alias.target.variant.variations)+")")
Colin Cross5df74a82020-08-24 16:18:21 -07001444 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001445 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001446 return strings.Join(variants, "\n ")
1447}
1448
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001449func newModule(factory ModuleFactory) *moduleInfo {
Colin Crossaf4fd212017-07-28 14:32:36 -07001450 logicModule, properties := factory()
1451
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001452 return &moduleInfo{
Colin Crossaf4fd212017-07-28 14:32:36 -07001453 logicModule: logicModule,
1454 factory: factory,
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001455 properties: properties,
Colin Crossaf4fd212017-07-28 14:32:36 -07001456 }
Colin Crossaf4fd212017-07-28 14:32:36 -07001457}
1458
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001459func processModuleDef(moduleDef *parser.Module,
1460 relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001461
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001462 factory, ok := moduleFactories[moduleDef.Type]
Colin Cross9672d862019-12-30 18:38:20 -08001463 if !ok && scopedModuleFactories != nil {
1464 factory, ok = scopedModuleFactories[moduleDef.Type]
1465 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001466 if !ok {
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001467 if ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001468 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469 }
1470
Colin Cross7ad621c2015-01-07 16:22:45 -08001471 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001472 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001473 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1474 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001475 },
1476 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001477 }
1478
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001479 module := newModule(factory)
Colin Crossaf4fd212017-07-28 14:32:36 -07001480 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001481
Colin Crossaf4fd212017-07-28 14:32:36 -07001482 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001483
Colin Crossf27c5e42020-01-02 09:37:49 -08001484 propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001485 if len(errs) > 0 {
Colin Crossf27c5e42020-01-02 09:37:49 -08001486 for i, err := range errs {
1487 if unpackErr, ok := err.(*proptools.UnpackError); ok {
1488 err = &BlueprintError{
1489 Err: unpackErr.Err,
1490 Pos: unpackErr.Pos,
1491 }
1492 errs[i] = err
1493 }
1494 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001495 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001496 }
1497
Colin Crossc32c4792016-06-09 15:52:30 -07001498 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001499 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001500 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001501 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001502 }
1503
Colin Cross7ad621c2015-01-07 16:22:45 -08001504 return module, nil
1505}
1506
Colin Cross23d7aa12015-06-30 16:05:22 -07001507func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001508 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001509 if name == "" {
1510 return []error{
1511 &BlueprintError{
1512 Err: fmt.Errorf("property 'name' is missing from a module"),
1513 Pos: module.pos,
1514 },
1515 }
1516 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001517 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001518
Colin Cross0b7e83e2016-05-17 14:58:05 -07001519 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001520 name: name,
Colin Cross5df74a82020-08-24 16:18:21 -07001521 modules: modulesOrAliases{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001522 }
1523 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001524 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001525 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001526 ModuleGroup{moduleGroup: group},
1527 module.logicModule)
1528 if len(errs) > 0 {
1529 for i := range errs {
1530 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1531 }
1532 return errs
1533 }
1534 group.namespace = namespace
1535
Colin Cross0b7e83e2016-05-17 14:58:05 -07001536 c.moduleGroups = append(c.moduleGroups, group)
1537
Colin Cross23d7aa12015-06-30 16:05:22 -07001538 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001539}
1540
Jamie Gennisd4e10182014-06-12 20:06:50 -07001541// ResolveDependencies checks that the dependencies specified by all of the
1542// modules defined in the parsed Blueprints files are valid. This means that
1543// the modules depended upon are defined and that no circular dependencies
1544// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001545func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Chris Parsons18ebb232022-03-25 00:56:02 -04001546 c.BeginEvent("resolve_deps")
1547 defer c.EndEvent("resolve_deps")
Colin Cross3a8c0252019-01-23 13:21:48 -08001548 return c.resolveDependencies(c.Context, config)
1549}
Colin Cross5f03f112017-11-07 13:29:54 -08001550
Colin Cross3a8c0252019-01-23 13:21:48 -08001551func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1552 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
Colin Cross2da84922020-07-02 10:08:12 -07001553 c.initProviders()
1554
Colin Cross3a8c0252019-01-23 13:21:48 -08001555 c.liveGlobals = newLiveTracker(config)
1556
1557 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1558 if len(errs) > 0 {
1559 return
1560 }
1561
1562 errs = c.updateDependencies()
1563 if len(errs) > 0 {
1564 return
1565 }
1566
1567 var mutatorDeps []string
1568 mutatorDeps, errs = c.runMutators(ctx, config)
1569 if len(errs) > 0 {
1570 return
1571 }
1572 deps = append(deps, mutatorDeps...)
1573
Colin Cross2da84922020-07-02 10:08:12 -07001574 if !c.skipCloneModulesAfterMutators {
1575 c.cloneModules()
1576 }
Colin Cross3a8c0252019-01-23 13:21:48 -08001577
1578 c.dependenciesReady = true
1579 })
1580
Colin Cross5f03f112017-11-07 13:29:54 -08001581 if len(errs) > 0 {
1582 return nil, errs
1583 }
1584
Colin Cross874a3462017-07-31 17:26:06 -07001585 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001586}
1587
Colin Cross763b6f12015-10-29 15:32:56 -07001588// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001589// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001590// module names returned by its DynamicDependencies method and those added by calling
1591// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001592func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001593 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001594 func() {
1595 defer func() {
1596 if r := recover(); r != nil {
1597 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1598 }
1599 }()
1600 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001601
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001602 if ctx.Failed() {
1603 return
1604 }
Colin Cross763b6f12015-10-29 15:32:56 -07001605
Colin Cross2c1f3d12016-04-11 15:47:28 -07001606 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001607 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001608 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001609}
1610
Colin Cross39644c02020-08-21 18:20:38 -07001611// findExactVariantOrSingle searches the moduleGroup for a module with the same variant as module,
1612// and returns the matching module, or nil if one is not found. A group with exactly one module
1613// is always considered matching.
1614func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07001615 found, _ := findVariant(module, possible, nil, false, reverse)
1616 if found == nil {
1617 for _, moduleOrAlias := range possible.modules {
1618 if m := moduleOrAlias.module(); m != nil {
1619 if found != nil {
1620 // more than one possible match, give up
1621 return nil
1622 }
1623 found = m
1624 }
1625 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001626 }
Colin Cross5df74a82020-08-24 16:18:21 -07001627 return found
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001628}
1629
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001630func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) (*moduleInfo, []error) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001631 if _, ok := tag.(BaseDependencyTag); ok {
1632 panic("BaseDependencyTag is not allowed to be used directly!")
1633 }
1634
Colin Cross0b7e83e2016-05-17 14:58:05 -07001635 if depName == module.Name() {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001636 return nil, []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001637 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001638 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001639 }}
1640 }
1641
Colin Crossd03b59d2019-11-13 20:10:12 -08001642 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001643 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001644 return nil, c.discoveredMissingDependencies(module, depName, nil)
Colin Crossc9028482014-12-18 16:28:54 -08001645 }
1646
Colin Cross39644c02020-08-21 18:20:38 -07001647 if m := findExactVariantOrSingle(module, possibleDeps, false); m != nil {
Colin Cross99bdb2a2019-03-29 16:35:02 -07001648 module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001649 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001650 return m, nil
Colin Cross65569e42015-03-10 20:08:19 -07001651 }
Colin Crossc9028482014-12-18 16:28:54 -08001652
Paul Duffinb77556b2020-03-24 19:01:20 +00001653 if c.allowMissingDependencies {
1654 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001655 return nil, c.discoveredMissingDependencies(module, depName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001656 }
1657
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001658 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001659 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001660 depName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001661 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001662 c.prettyPrintGroupVariants(possibleDeps)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001663 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001664 }}
1665}
1666
Colin Cross8d8a7af2015-11-03 16:41:29 -08001667func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001668 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001669 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001670 Err: fmt.Errorf("%q depends on itself", destName),
1671 Pos: module.pos,
1672 }}
1673 }
1674
Colin Crossd03b59d2019-11-13 20:10:12 -08001675 possibleDeps := c.moduleGroupFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001676 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001677 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001678 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001679 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001680 Pos: module.pos,
1681 }}
1682 }
1683
Colin Cross39644c02020-08-21 18:20:38 -07001684 if m := findExactVariantOrSingle(module, possibleDeps, true); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001685 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001686 }
1687
Paul Duffinb77556b2020-03-24 19:01:20 +00001688 if c.allowMissingDependencies {
1689 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001690 return module, c.discoveredMissingDependencies(module, destName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001691 }
1692
Colin Cross2c628442016-10-07 17:13:10 -07001693 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001694 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001695 destName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001696 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001697 c.prettyPrintGroupVariants(possibleDeps)),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001698 Pos: module.pos,
1699 }}
1700}
1701
Colin Cross39644c02020-08-21 18:20:38 -07001702func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
Colin Crossedc41762020-08-13 12:07:30 -07001703 // We can't just append variant.Variant to module.dependencyVariant.variantName and
Colin Cross65569e42015-03-10 20:08:19 -07001704 // compare the strings because the result won't be in mutator registration order.
1705 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001706 var newVariant variationMap
1707 if !far {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001708 if !reverse {
1709 // For forward dependency, ignore local variants by matching against
1710 // dependencyVariant which doesn't have the local variants
Colin Crossedc41762020-08-13 12:07:30 -07001711 newVariant = module.variant.dependencyVariations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001712 } else {
1713 // For reverse dependency, use all the variants
Colin Crossedc41762020-08-13 12:07:30 -07001714 newVariant = module.variant.variations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001715 }
Colin Cross89486232015-05-08 11:14:54 -07001716 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001717 for _, v := range variations {
Colin Cross9403b5a2019-11-13 20:11:04 -08001718 if newVariant == nil {
1719 newVariant = make(variationMap)
1720 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001721 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001722 }
1723
Colin Crossd03b59d2019-11-13 20:10:12 -08001724 check := func(variant variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -07001725 if far {
Colin Cross5dc67592020-08-24 14:46:13 -07001726 return newVariant.subsetOf(variant)
Colin Cross89486232015-05-08 11:14:54 -07001727 } else {
Colin Crossd03b59d2019-11-13 20:10:12 -08001728 return variant.equal(newVariant)
Colin Cross65569e42015-03-10 20:08:19 -07001729 }
1730 }
1731
Colin Crossd03b59d2019-11-13 20:10:12 -08001732 var foundDep *moduleInfo
1733 for _, m := range possibleDeps.modules {
Colin Cross5df74a82020-08-24 16:18:21 -07001734 if check(m.moduleOrAliasVariant().variations) {
1735 foundDep = m.moduleOrAliasTarget()
Colin Crossd03b59d2019-11-13 20:10:12 -08001736 break
1737 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001738 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001739
Martin Stjernholm2f212472020-03-06 00:29:24 +00001740 return foundDep, newVariant
1741}
1742
1743func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001744 tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001745 if _, ok := tag.(BaseDependencyTag); ok {
1746 panic("BaseDependencyTag is not allowed to be used directly!")
1747 }
1748
1749 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
1750 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001751 return nil, c.discoveredMissingDependencies(module, depName, nil)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001752 }
1753
Colin Cross5df74a82020-08-24 16:18:21 -07001754 foundDep, newVariant := findVariant(module, possibleDeps, variations, far, false)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001755
Colin Crossf7beb892019-11-13 20:11:14 -08001756 if foundDep == nil {
Paul Duffinb77556b2020-03-24 19:01:20 +00001757 if c.allowMissingDependencies {
1758 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001759 return nil, c.discoveredMissingDependencies(module, depName, newVariant)
Paul Duffinb77556b2020-03-24 19:01:20 +00001760 }
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001761 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001762 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
1763 depName, module.Name(),
1764 c.prettyPrintVariant(newVariant),
1765 c.prettyPrintGroupVariants(possibleDeps)),
1766 Pos: module.pos,
1767 }}
1768 }
1769
1770 if module == foundDep {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001771 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001772 Err: fmt.Errorf("%q depends on itself", depName),
1773 Pos: module.pos,
1774 }}
1775 }
1776 // AddVariationDependency allows adding a dependency on itself, but only if
1777 // that module is earlier in the module list than this one, since we always
1778 // run GenerateBuildActions in order for the variants of a module
1779 if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001780 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001781 Err: fmt.Errorf("%q depends on later version of itself", depName),
1782 Pos: module.pos,
1783 }}
1784 }
1785 module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
1786 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001787 return foundDep, nil
Colin Crossc9028482014-12-18 16:28:54 -08001788}
1789
Colin Crossf1875462016-04-11 17:33:13 -07001790func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001791 from, to Module) *moduleInfo {
Nan Zhang346b2d02017-03-10 16:39:27 -08001792 if _, ok := tag.(BaseDependencyTag); ok {
1793 panic("BaseDependencyTag is not allowed to be used directly!")
1794 }
Colin Crossf1875462016-04-11 17:33:13 -07001795
1796 var fromInfo, toInfo *moduleInfo
Colin Cross5df74a82020-08-24 16:18:21 -07001797 for _, moduleOrAlias := range origModule.splitModules {
1798 if m := moduleOrAlias.module(); m != nil {
1799 if m.logicModule == from {
1800 fromInfo = m
1801 }
1802 if m.logicModule == to {
1803 toInfo = m
1804 if fromInfo != nil {
1805 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
1806 }
Colin Crossf1875462016-04-11 17:33:13 -07001807 }
1808 }
1809 }
1810
1811 if fromInfo == nil || toInfo == nil {
1812 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001813 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001814 }
1815
Colin Cross99bdb2a2019-03-29 16:35:02 -07001816 fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001817 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001818 return toInfo
Colin Crossf1875462016-04-11 17:33:13 -07001819}
1820
Lukacs T. Berkieef56852021-09-02 11:34:06 +02001821// findBlueprintDescendants returns a map linking parent Blueprint files to child Blueprints files
1822// For example, if paths = []string{"a/b/c/Android.bp", "a/Android.bp"},
1823// then descendants = {"":[]string{"a/Android.bp"}, "a/Android.bp":[]string{"a/b/c/Android.bp"}}
Jeff Gastonc3e28442017-08-09 15:13:12 -07001824func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1825 // make mapping from dir path to file path
1826 filesByDir := make(map[string]string, len(paths))
1827 for _, path := range paths {
1828 dir := filepath.Dir(path)
1829 _, alreadyFound := filesByDir[dir]
1830 if alreadyFound {
1831 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1832 }
1833 filesByDir[dir] = path
1834 }
1835
Jeff Gaston656870f2017-11-29 18:37:31 -08001836 findAncestor := func(childFile string) (ancestor string) {
1837 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001838 for {
1839 ancestorDir := filepath.Dir(prevAncestorDir)
1840 if ancestorDir == prevAncestorDir {
1841 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001842 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001843 }
1844
1845 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1846 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001847 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001848 }
1849 prevAncestorDir = ancestorDir
1850 }
1851 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001852 // generate the descendants map
1853 descendants = make(map[string][]string, len(filesByDir))
1854 for _, childFile := range filesByDir {
1855 ancestorFile := findAncestor(childFile)
1856 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1857 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001858 return descendants, nil
1859}
1860
Colin Cross3702ac72016-08-11 11:09:00 -07001861type visitOrderer interface {
1862 // returns the number of modules that this module needs to wait for
1863 waitCount(module *moduleInfo) int
1864 // returns the list of modules that are waiting for this module
1865 propagate(module *moduleInfo) []*moduleInfo
1866 // visit modules in order
Colin Crossc4773d92020-08-25 17:12:59 -07001867 visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool)
Colin Cross3702ac72016-08-11 11:09:00 -07001868}
1869
Colin Cross7e723372018-03-28 11:50:12 -07001870type unorderedVisitorImpl struct{}
1871
1872func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1873 return 0
1874}
1875
1876func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1877 return nil
1878}
1879
Colin Crossc4773d92020-08-25 17:12:59 -07001880func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross7e723372018-03-28 11:50:12 -07001881 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001882 if visit(module, nil) {
Colin Cross7e723372018-03-28 11:50:12 -07001883 return
1884 }
1885 }
1886}
1887
Colin Cross3702ac72016-08-11 11:09:00 -07001888type bottomUpVisitorImpl struct{}
1889
1890func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1891 return len(module.forwardDeps)
1892}
1893
1894func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1895 return module.reverseDeps
1896}
1897
Colin Crossc4773d92020-08-25 17:12:59 -07001898func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001899 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001900 if visit(module, nil) {
Colin Cross49c279a2016-08-05 22:30:44 -07001901 return
1902 }
1903 }
1904}
1905
Colin Cross3702ac72016-08-11 11:09:00 -07001906type topDownVisitorImpl struct{}
1907
1908func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1909 return len(module.reverseDeps)
1910}
1911
1912func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1913 return module.forwardDeps
1914}
1915
Colin Crossc4773d92020-08-25 17:12:59 -07001916func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001917 for i := 0; i < len(modules); i++ {
1918 module := modules[len(modules)-1-i]
Colin Crossc4773d92020-08-25 17:12:59 -07001919 if visit(module, nil) {
Colin Cross3702ac72016-08-11 11:09:00 -07001920 return
1921 }
1922 }
1923}
1924
1925var (
1926 bottomUpVisitor bottomUpVisitorImpl
1927 topDownVisitor topDownVisitorImpl
1928)
1929
Colin Crossc4773d92020-08-25 17:12:59 -07001930// pauseSpec describes a pause that a module needs to occur until another module has been visited,
1931// at which point the unpause channel will be closed.
1932type pauseSpec struct {
1933 paused *moduleInfo
1934 until *moduleInfo
1935 unpause unpause
1936}
1937
1938type unpause chan struct{}
1939
1940const parallelVisitLimit = 1000
1941
Colin Cross49c279a2016-08-05 22:30:44 -07001942// 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 -07001943// of its dependencies has finished. A visit function can write a pauseSpec to the pause channel
1944// to wait for another dependency to be visited. If a visit function returns true to cancel
1945// while another visitor is paused, the paused visitor will never be resumed and its goroutine
1946// will stay paused forever.
1947func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
1948 visit func(module *moduleInfo, pause chan<- pauseSpec) bool) []error {
1949
Colin Cross7addea32015-03-11 15:43:52 -07001950 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001951 cancelCh := make(chan bool)
Colin Crossc4773d92020-08-25 17:12:59 -07001952 pauseCh := make(chan pauseSpec)
Colin Cross8900e9b2015-03-02 14:03:01 -08001953 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001954
Colin Crossc4773d92020-08-25 17:12:59 -07001955 var backlog []*moduleInfo // Visitors that are ready to start but backlogged due to limit.
1956 var unpauseBacklog []pauseSpec // Visitors that are ready to unpause but backlogged due to limit.
1957
1958 active := 0 // Number of visitors running, not counting paused visitors.
1959 visited := 0 // Number of finished visitors.
1960
1961 pauseMap := make(map[*moduleInfo][]pauseSpec)
1962
1963 for _, module := range modules {
Colin Cross3702ac72016-08-11 11:09:00 -07001964 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001965 }
1966
Colin Crossc4773d92020-08-25 17:12:59 -07001967 // Call the visitor on a module if there are fewer active visitors than the parallelism
1968 // limit, otherwise add it to the backlog.
1969 startOrBacklog := func(module *moduleInfo) {
1970 if active < limit {
1971 active++
Colin Cross7e723372018-03-28 11:50:12 -07001972 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07001973 ret := visit(module, pauseCh)
Colin Cross7e723372018-03-28 11:50:12 -07001974 if ret {
1975 cancelCh <- true
1976 }
1977 doneCh <- module
1978 }()
1979 } else {
1980 backlog = append(backlog, module)
1981 }
Colin Cross691a60d2015-01-07 18:08:56 -08001982 }
1983
Colin Crossc4773d92020-08-25 17:12:59 -07001984 // Unpause the already-started but paused visitor on a module if there are fewer active
1985 // visitors than the parallelism limit, otherwise add it to the backlog.
1986 unpauseOrBacklog := func(pauseSpec pauseSpec) {
1987 if active < limit {
1988 active++
1989 close(pauseSpec.unpause)
1990 } else {
1991 unpauseBacklog = append(unpauseBacklog, pauseSpec)
Colin Cross691a60d2015-01-07 18:08:56 -08001992 }
1993 }
1994
Colin Crossc4773d92020-08-25 17:12:59 -07001995 // Start any modules in the backlog up to the parallelism limit. Unpause paused modules first
1996 // since they may already be holding resources.
1997 unpauseOrStartFromBacklog := func() {
1998 for active < limit && len(unpauseBacklog) > 0 {
1999 unpause := unpauseBacklog[0]
2000 unpauseBacklog = unpauseBacklog[1:]
2001 unpauseOrBacklog(unpause)
2002 }
2003 for active < limit && len(backlog) > 0 {
2004 toVisit := backlog[0]
2005 backlog = backlog[1:]
2006 startOrBacklog(toVisit)
2007 }
2008 }
2009
2010 toVisit := len(modules)
2011
2012 // Start or backlog any modules that are not waiting for any other modules.
2013 for _, module := range modules {
2014 if module.waitingCount == 0 {
2015 startOrBacklog(module)
2016 }
2017 }
2018
2019 for active > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08002020 select {
Colin Cross7e723372018-03-28 11:50:12 -07002021 case <-cancelCh:
2022 cancel = true
2023 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07002024 case doneModule := <-doneCh:
Colin Crossc4773d92020-08-25 17:12:59 -07002025 active--
Colin Cross8900e9b2015-03-02 14:03:01 -08002026 if !cancel {
Colin Crossc4773d92020-08-25 17:12:59 -07002027 // Mark this module as done.
2028 doneModule.waitingCount = -1
2029 visited++
2030
2031 // Unpause or backlog any modules that were waiting for this one.
2032 if unpauses, ok := pauseMap[doneModule]; ok {
2033 delete(pauseMap, doneModule)
2034 for _, unpause := range unpauses {
2035 unpauseOrBacklog(unpause)
2036 }
Colin Cross7e723372018-03-28 11:50:12 -07002037 }
Colin Crossc4773d92020-08-25 17:12:59 -07002038
2039 // Start any backlogged modules up to limit.
2040 unpauseOrStartFromBacklog()
2041
2042 // Decrement waitingCount on the next modules in the tree based
2043 // on propagation order, and start or backlog them if they are
2044 // ready to start.
Colin Cross3702ac72016-08-11 11:09:00 -07002045 for _, module := range order.propagate(doneModule) {
2046 module.waitingCount--
2047 if module.waitingCount == 0 {
Colin Crossc4773d92020-08-25 17:12:59 -07002048 startOrBacklog(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08002049 }
Colin Cross691a60d2015-01-07 18:08:56 -08002050 }
2051 }
Colin Crossc4773d92020-08-25 17:12:59 -07002052 case pauseSpec := <-pauseCh:
2053 if pauseSpec.until.waitingCount == -1 {
2054 // Module being paused for is already finished, resume immediately.
2055 close(pauseSpec.unpause)
2056 } else {
2057 // Register for unpausing.
2058 pauseMap[pauseSpec.until] = append(pauseMap[pauseSpec.until], pauseSpec)
2059
2060 // Don't count paused visitors as active so that this can't deadlock
2061 // if 1000 visitors are paused simultaneously.
2062 active--
2063 unpauseOrStartFromBacklog()
2064 }
Colin Cross691a60d2015-01-07 18:08:56 -08002065 }
2066 }
Colin Crossc4773d92020-08-25 17:12:59 -07002067
2068 if !cancel {
2069 // Invariant check: no backlogged modules, these weren't waiting on anything except
2070 // the parallelism limit so they should have run.
2071 if len(backlog) > 0 {
2072 panic(fmt.Errorf("parallelVisit finished with %d backlogged visitors", len(backlog)))
2073 }
2074
2075 // Invariant check: no backlogged paused modules, these weren't waiting on anything
2076 // except the parallelism limit so they should have run.
2077 if len(unpauseBacklog) > 0 {
2078 panic(fmt.Errorf("parallelVisit finished with %d backlogged unpaused visitors", len(unpauseBacklog)))
2079 }
2080
2081 if len(pauseMap) > 0 {
Colin Cross7d4958d2021-02-08 15:34:08 -08002082 // Probably a deadlock due to a newly added dependency cycle. Start from each module in
2083 // the order of the input modules list and perform a depth-first search for the module
2084 // it is paused on, ignoring modules that are marked as done. Note this traverses from
2085 // modules to the modules that would have been unblocked when that module finished, i.e
2086 // the reverse of the visitOrderer.
Colin Crossc4773d92020-08-25 17:12:59 -07002087
Colin Cross9793b0a2021-04-27 15:20:15 -07002088 // In order to reduce duplicated work, once a module has been checked and determined
2089 // not to be part of a cycle add it and everything that depends on it to the checked
2090 // map.
2091 checked := make(map[*moduleInfo]struct{})
2092
Colin Cross7d4958d2021-02-08 15:34:08 -08002093 var check func(module, end *moduleInfo) []*moduleInfo
2094 check = func(module, end *moduleInfo) []*moduleInfo {
Colin Crossc4773d92020-08-25 17:12:59 -07002095 if module.waitingCount == -1 {
2096 // This module was finished, it can't be part of a loop.
2097 return nil
2098 }
2099 if module == end {
2100 // This module is the end of the loop, start rolling up the cycle.
2101 return []*moduleInfo{module}
2102 }
2103
Colin Cross9793b0a2021-04-27 15:20:15 -07002104 if _, alreadyChecked := checked[module]; alreadyChecked {
2105 return nil
2106 }
2107
Colin Crossc4773d92020-08-25 17:12:59 -07002108 for _, dep := range order.propagate(module) {
Colin Cross7d4958d2021-02-08 15:34:08 -08002109 cycle := check(dep, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002110 if cycle != nil {
2111 return append([]*moduleInfo{module}, cycle...)
2112 }
2113 }
2114 for _, depPauseSpec := range pauseMap[module] {
Colin Cross7d4958d2021-02-08 15:34:08 -08002115 cycle := check(depPauseSpec.paused, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002116 if cycle != nil {
2117 return append([]*moduleInfo{module}, cycle...)
2118 }
2119 }
2120
Colin Cross9793b0a2021-04-27 15:20:15 -07002121 checked[module] = struct{}{}
Colin Crossc4773d92020-08-25 17:12:59 -07002122 return nil
2123 }
2124
Colin Cross7d4958d2021-02-08 15:34:08 -08002125 // Iterate over the modules list instead of pauseMap to provide deterministic ordering.
2126 for _, module := range modules {
2127 for _, pauseSpec := range pauseMap[module] {
2128 cycle := check(pauseSpec.paused, pauseSpec.until)
2129 if len(cycle) > 0 {
2130 return cycleError(cycle)
2131 }
2132 }
Colin Crossc4773d92020-08-25 17:12:59 -07002133 }
2134 }
2135
2136 // Invariant check: if there was no deadlock and no cancellation every module
2137 // should have been visited.
2138 if visited != toVisit {
2139 panic(fmt.Errorf("parallelVisit ran %d visitors, expected %d", visited, toVisit))
2140 }
2141
2142 // Invariant check: if there was no deadlock and no cancellation every module
2143 // should have been visited, so there is nothing left to be paused on.
2144 if len(pauseMap) > 0 {
2145 panic(fmt.Errorf("parallelVisit finished with %d paused visitors", len(pauseMap)))
2146 }
2147 }
2148
2149 return nil
2150}
2151
2152func cycleError(cycle []*moduleInfo) (errs []error) {
2153 // The cycle list is in reverse order because all the 'check' calls append
2154 // their own module to the list.
2155 errs = append(errs, &BlueprintError{
2156 Err: fmt.Errorf("encountered dependency cycle:"),
2157 Pos: cycle[len(cycle)-1].pos,
2158 })
2159
2160 // Iterate backwards through the cycle list.
2161 curModule := cycle[0]
2162 for i := len(cycle) - 1; i >= 0; i-- {
2163 nextModule := cycle[i]
2164 errs = append(errs, &BlueprintError{
Colin Crosse5ff7702021-04-27 15:33:49 -07002165 Err: fmt.Errorf(" %s depends on %s",
2166 curModule, nextModule),
Colin Crossc4773d92020-08-25 17:12:59 -07002167 Pos: curModule.pos,
2168 })
2169 curModule = nextModule
2170 }
2171
2172 return errs
Colin Cross691a60d2015-01-07 18:08:56 -08002173}
2174
2175// updateDependencies recursively walks the module dependency graph and updates
2176// additional fields based on the dependencies. It builds a sorted list of modules
2177// such that dependencies of a module always appear first, and populates reverse
2178// dependency links and counts of total dependencies. It also reports errors when
Usta Shresthaee7a5d72022-01-10 22:46:23 -05002179// it encounters dependency cycles. This should be called after resolveDependencies,
Colin Cross691a60d2015-01-07 18:08:56 -08002180// as well as after any mutator pass has called addDependency
2181func (c *Context) updateDependencies() (errs []error) {
Liz Kammer9ae14f12020-11-30 16:30:45 -07002182 c.cachedDepsModified = true
Colin Cross7addea32015-03-11 15:43:52 -07002183 visited := make(map[*moduleInfo]bool) // modules that were already checked
2184 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002185
Colin Cross7addea32015-03-11 15:43:52 -07002186 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08002187
Colin Cross7addea32015-03-11 15:43:52 -07002188 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002189
Colin Cross7addea32015-03-11 15:43:52 -07002190 check = func(module *moduleInfo) []*moduleInfo {
2191 visited[module] = true
2192 checking[module] = true
2193 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002194
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002195 // Reset the forward and reverse deps without reducing their capacity to avoid reallocation.
2196 module.reverseDeps = module.reverseDeps[:0]
2197 module.forwardDeps = module.forwardDeps[:0]
Colin Cross7addea32015-03-11 15:43:52 -07002198
2199 // Add an implicit dependency ordering on all earlier modules in the same module group
2200 for _, dep := range module.group.modules {
2201 if dep == module {
2202 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08002203 }
Colin Cross5df74a82020-08-24 16:18:21 -07002204 if depModule := dep.module(); depModule != nil {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002205 module.forwardDeps = append(module.forwardDeps, depModule)
Colin Cross5df74a82020-08-24 16:18:21 -07002206 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002207 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002208
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002209 outer:
Colin Cross7addea32015-03-11 15:43:52 -07002210 for _, dep := range module.directDeps {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002211 // use a loop to check for duplicates, average number of directDeps measured to be 9.5.
2212 for _, exists := range module.forwardDeps {
2213 if dep.module == exists {
2214 continue outer
2215 }
2216 }
2217 module.forwardDeps = append(module.forwardDeps, dep.module)
Colin Cross7addea32015-03-11 15:43:52 -07002218 }
2219
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002220 for _, dep := range module.forwardDeps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002221 if checking[dep] {
2222 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07002223 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002224 }
2225
2226 if !visited[dep] {
2227 cycle := check(dep)
2228 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002229 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002230 // We are the "start" of the cycle, so we're responsible
Colin Crossc4773d92020-08-25 17:12:59 -07002231 // for generating the errors.
2232 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002233
2234 // We can continue processing this module's children to
2235 // find more cycles. Since all the modules that were
2236 // part of the found cycle were marked as visited we
2237 // won't run into that cycle again.
2238 } else {
2239 // We're not the "start" of the cycle, so we just append
2240 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07002241 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002242 }
2243 }
2244 }
Colin Cross691a60d2015-01-07 18:08:56 -08002245
Colin Cross7addea32015-03-11 15:43:52 -07002246 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002247 }
2248
Colin Cross7addea32015-03-11 15:43:52 -07002249 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08002250
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002251 return nil
2252 }
2253
Colin Cross7addea32015-03-11 15:43:52 -07002254 for _, module := range c.moduleInfo {
2255 if !visited[module] {
2256 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002257 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002258 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07002259 panic("inconceivable!")
2260 }
Colin Crossc4773d92020-08-25 17:12:59 -07002261 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002262 }
2263 }
2264 }
2265
Colin Cross7addea32015-03-11 15:43:52 -07002266 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08002267
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002268 return
2269}
2270
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002271type jsonVariationMap map[string]string
2272
2273type jsonModuleName struct {
2274 Name string
2275 Variations jsonVariationMap
2276 DependencyVariations jsonVariationMap
2277}
2278
2279type jsonDep struct {
2280 jsonModuleName
2281 Tag string
2282}
2283
Lukacs T. Berki16022262021-06-25 09:10:56 +02002284type JsonModule struct {
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002285 jsonModuleName
2286 Deps []jsonDep
2287 Type string
2288 Blueprint string
Lukacs T. Berki16022262021-06-25 09:10:56 +02002289 Module map[string]interface{}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002290}
2291
2292func toJsonVariationMap(vm variationMap) jsonVariationMap {
2293 return jsonVariationMap(vm)
2294}
2295
2296func jsonModuleNameFromModuleInfo(m *moduleInfo) *jsonModuleName {
2297 return &jsonModuleName{
2298 Name: m.Name(),
2299 Variations: toJsonVariationMap(m.variant.variations),
2300 DependencyVariations: toJsonVariationMap(m.variant.dependencyVariations),
2301 }
2302}
2303
Lukacs T. Berki16022262021-06-25 09:10:56 +02002304type JSONDataSupplier interface {
2305 AddJSONData(d *map[string]interface{})
2306}
2307
2308func jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule {
2309 result := &JsonModule{
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002310 jsonModuleName: *jsonModuleNameFromModuleInfo(m),
2311 Deps: make([]jsonDep, 0),
2312 Type: m.typeName,
2313 Blueprint: m.relBlueprintsFile,
Lukacs T. Berki16022262021-06-25 09:10:56 +02002314 Module: make(map[string]interface{}),
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002315 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002316 if j, ok := m.logicModule.(JSONDataSupplier); ok {
2317 j.AddJSONData(&result.Module)
2318 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002319 for _, p := range m.providers {
2320 if j, ok := p.(JSONDataSupplier); ok {
2321 j.AddJSONData(&result.Module)
2322 }
2323 }
2324 return result
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002325}
2326
kguia78b0202022-01-25 16:19:25 +08002327func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule {
2328 result := &JsonModule{
2329 jsonModuleName: jsonModuleName{
2330 Name: m.Name(),
2331 },
2332 Deps: make([]jsonDep, 0),
2333 Type: m.typeName,
2334 Blueprint: m.relBlueprintsFile,
2335 Module: make(map[string]interface{}),
2336 }
2337 var actions []map[string]interface{}
2338 for _, bDef := range m.actionDefs.buildDefs {
2339 actions = append(actions, map[string]interface{}{
2340 "Inputs": append(
2341 getNinjaStringsWithNilPkgNames(bDef.Inputs),
2342 getNinjaStringsWithNilPkgNames(bDef.Implicits)...),
2343 "Outputs": append(
2344 getNinjaStringsWithNilPkgNames(bDef.Outputs),
2345 getNinjaStringsWithNilPkgNames(bDef.ImplicitOutputs)...),
2346 })
2347 }
2348 result.Module["Actions"] = actions
2349 return result
2350}
2351
2352// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value with
2353// nil pkgNames on each of the input ninjaStrings.
2354func getNinjaStringsWithNilPkgNames(nStrs []ninjaString) []string {
2355 var strs []string
2356 for _, nstr := range nStrs {
2357 strs = append(strs, nstr.Value(nil))
2358 }
2359 return strs
2360}
2361
2362// PrintJSONGraph prints info of modules in a JSON file.
2363func (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) {
2364 modulesToGraph := make([]*JsonModule, 0)
2365 modulesToActions := make([]*JsonModule, 0)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002366 for _, m := range c.modulesSorted {
2367 jm := jsonModuleFromModuleInfo(m)
kguia78b0202022-01-25 16:19:25 +08002368 jmWithActions := jsonModuleWithActionsFromModuleInfo(m)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002369 for _, d := range m.directDeps {
2370 jm.Deps = append(jm.Deps, jsonDep{
2371 jsonModuleName: *jsonModuleNameFromModuleInfo(d.module),
2372 Tag: fmt.Sprintf("%T %+v", d.tag, d.tag),
2373 })
kguia78b0202022-01-25 16:19:25 +08002374 jmWithActions.Deps = append(jmWithActions.Deps, jsonDep{
2375 jsonModuleName: jsonModuleName{
2376 Name: d.module.Name(),
2377 },
2378 })
2379
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002380 }
kguia78b0202022-01-25 16:19:25 +08002381 modulesToGraph = append(modulesToGraph, jm)
2382 modulesToActions = append(modulesToActions, jmWithActions)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002383 }
kguia78b0202022-01-25 16:19:25 +08002384 writeJson(wGraph, modulesToGraph)
2385 writeJson(wActions, modulesToActions)
2386}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002387
kguia78b0202022-01-25 16:19:25 +08002388func writeJson(w io.Writer, modules []*JsonModule) {
Liz Kammer6e4ee8d2021-08-17 17:32:42 -04002389 e := json.NewEncoder(w)
2390 e.SetIndent("", "\t")
2391 e.Encode(modules)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002392}
2393
Jamie Gennisd4e10182014-06-12 20:06:50 -07002394// PrepareBuildActions generates an internal representation of all the build
2395// actions that need to be performed. This process involves invoking the
2396// GenerateBuildActions method on each of the Module objects created during the
2397// parse phase and then on each of the registered Singleton objects.
2398//
2399// If the ResolveDependencies method has not already been called it is called
2400// automatically by this method.
2401//
2402// The config argument is made available to all of the Module and Singleton
2403// objects via the Config method on the ModuleContext and SingletonContext
2404// objects passed to GenerateBuildActions. It is also passed to the functions
2405// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
2406// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002407//
2408// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08002409// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
2410// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
2411// methods.
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002412
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002413func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Chris Parsons18ebb232022-03-25 00:56:02 -04002414 c.BeginEvent("prepare_build_actions")
2415 defer c.EndEvent("prepare_build_actions")
Colin Cross3a8c0252019-01-23 13:21:48 -08002416 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
2417 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002418
Colin Cross3a8c0252019-01-23 13:21:48 -08002419 if !c.dependenciesReady {
2420 var extraDeps []string
2421 extraDeps, errs = c.resolveDependencies(ctx, config)
2422 if len(errs) > 0 {
2423 return
2424 }
2425 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002426 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002427
Colin Cross3a8c0252019-01-23 13:21:48 -08002428 var depsModules []string
2429 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
2430 if len(errs) > 0 {
2431 return
2432 }
2433
2434 var depsSingletons []string
2435 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
2436 if len(errs) > 0 {
2437 return
2438 }
2439
2440 deps = append(deps, depsModules...)
2441 deps = append(deps, depsSingletons...)
2442
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02002443 if c.outDir != nil {
2444 err := c.liveGlobals.addNinjaStringDeps(c.outDir)
Colin Cross3a8c0252019-01-23 13:21:48 -08002445 if err != nil {
2446 errs = []error{err}
2447 return
2448 }
2449 }
2450
2451 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2452
2453 deps = append(deps, depsPackages...)
2454
Colin Cross92054a42021-01-21 16:49:25 -08002455 c.memoizeFullNames(c.liveGlobals, pkgNames)
2456
Colin Cross3a8c0252019-01-23 13:21:48 -08002457 // This will panic if it finds a problem since it's a programming error.
2458 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
2459
2460 c.pkgNames = pkgNames
2461 c.globalVariables = c.liveGlobals.variables
2462 c.globalPools = c.liveGlobals.pools
2463 c.globalRules = c.liveGlobals.rules
2464
2465 c.buildActionsReady = true
2466 })
2467
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002468 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002469 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002470 }
2471
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002472 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002473}
2474
Colin Cross3a8c0252019-01-23 13:21:48 -08002475func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07002476 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07002477
Colin Cross3a8c0252019-01-23 13:21:48 -08002478 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
2479 mutators = append(mutators, c.earlyMutatorInfo...)
2480 mutators = append(mutators, c.mutatorInfo...)
Colin Crossf8b50422016-08-10 12:56:40 -07002481
Colin Cross3a8c0252019-01-23 13:21:48 -08002482 for _, mutator := range mutators {
2483 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
2484 var newDeps []string
2485 if mutator.topDownMutator != nil {
2486 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
2487 } else if mutator.bottomUpMutator != nil {
2488 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
2489 } else {
2490 panic("no mutator set on " + mutator.name)
2491 }
2492 if len(errs) > 0 {
2493 return
2494 }
2495 deps = append(deps, newDeps...)
2496 })
2497 if len(errs) > 0 {
2498 return
2499 }
Colin Crossc9028482014-12-18 16:28:54 -08002500 }
Colin Cross3a8c0252019-01-23 13:21:48 -08002501 })
2502
2503 if len(errs) > 0 {
2504 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08002505 }
2506
Colin Cross874a3462017-07-31 17:26:06 -07002507 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08002508}
2509
Colin Cross3702ac72016-08-11 11:09:00 -07002510type mutatorDirection interface {
2511 run(mutator *mutatorInfo, ctx *mutatorContext)
2512 orderer() visitOrderer
2513 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08002514}
2515
Colin Cross3702ac72016-08-11 11:09:00 -07002516type bottomUpMutatorImpl struct{}
2517
2518func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2519 mutator.bottomUpMutator(ctx)
2520}
2521
2522func (bottomUpMutatorImpl) orderer() visitOrderer {
2523 return bottomUpVisitor
2524}
2525
2526func (bottomUpMutatorImpl) String() string {
2527 return "bottom up mutator"
2528}
2529
2530type topDownMutatorImpl struct{}
2531
2532func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2533 mutator.topDownMutator(ctx)
2534}
2535
2536func (topDownMutatorImpl) orderer() visitOrderer {
2537 return topDownVisitor
2538}
2539
2540func (topDownMutatorImpl) String() string {
2541 return "top down mutator"
2542}
2543
2544var (
2545 topDownMutator topDownMutatorImpl
2546 bottomUpMutator bottomUpMutatorImpl
2547)
2548
Colin Cross49c279a2016-08-05 22:30:44 -07002549type reverseDep struct {
2550 module *moduleInfo
2551 dep depInfo
2552}
2553
Colin Cross3702ac72016-08-11 11:09:00 -07002554func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002555 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002556
2557 newModuleInfo := make(map[Module]*moduleInfo)
2558 for k, v := range c.moduleInfo {
2559 newModuleInfo[k] = v
2560 }
Colin Crossc9028482014-12-18 16:28:54 -08002561
Colin Cross0ce142c2016-12-09 10:29:05 -08002562 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002563 reverse []reverseDep
2564 rename []rename
2565 replace []replace
2566 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002567 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002568 }
2569
Colin Cross2c1f3d12016-04-11 15:47:28 -07002570 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002571 var rename []rename
2572 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002573 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002574
Colin Cross49c279a2016-08-05 22:30:44 -07002575 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002576 globalStateCh := make(chan globalStateChange)
Colin Cross5df74a82020-08-24 16:18:21 -07002577 newVariationsCh := make(chan modulesOrAliases)
Colin Cross49c279a2016-08-05 22:30:44 -07002578 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002579
Colin Cross3702ac72016-08-11 11:09:00 -07002580 c.depsModified = 0
2581
Colin Crossc4773d92020-08-25 17:12:59 -07002582 visit := func(module *moduleInfo, pause chan<- pauseSpec) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002583 if module.splitModules != nil {
2584 panic("split module found in sorted module list")
2585 }
2586
Colin Cross7addea32015-03-11 15:43:52 -07002587 mctx := &mutatorContext{
2588 baseModuleContext: baseModuleContext{
2589 context: c,
2590 config: config,
2591 module: module,
2592 },
Colin Crossc4773d92020-08-25 17:12:59 -07002593 name: mutator.name,
2594 pauseCh: pause,
Colin Cross7addea32015-03-11 15:43:52 -07002595 }
Colin Crossc9028482014-12-18 16:28:54 -08002596
Colin Cross2da84922020-07-02 10:08:12 -07002597 module.startedMutator = mutator
2598
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002599 func() {
2600 defer func() {
2601 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002602 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002603 if err, ok := r.(panicError); ok {
2604 err.addIn(in)
2605 mctx.error(err)
2606 } else {
2607 mctx.error(newPanicErrorf(r, in))
2608 }
2609 }
2610 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002611 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002612 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002613
Colin Cross2da84922020-07-02 10:08:12 -07002614 module.finishedMutator = mutator
2615
Colin Cross7addea32015-03-11 15:43:52 -07002616 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002617 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002618 return true
Colin Cross7addea32015-03-11 15:43:52 -07002619 }
Colin Crossc9028482014-12-18 16:28:54 -08002620
Colin Cross5fe225f2017-07-28 15:22:46 -07002621 if len(mctx.newVariations) > 0 {
2622 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002623 }
2624
Colin Crossab0a83f2020-03-03 14:23:27 -08002625 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 -08002626 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002627 reverse: mctx.reverseDeps,
2628 replace: mctx.replace,
2629 rename: mctx.rename,
2630 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002631 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002632 }
Colin Cross49c279a2016-08-05 22:30:44 -07002633 }
2634
2635 return false
2636 }
2637
2638 // Process errs and reverseDeps in a single goroutine
2639 go func() {
2640 for {
2641 select {
2642 case newErrs := <-errsCh:
2643 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002644 case globalStateChange := <-globalStateCh:
2645 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002646 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2647 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002648 replace = append(replace, globalStateChange.replace...)
2649 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002650 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002651 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002652 case newVariations := <-newVariationsCh:
Colin Cross5df74a82020-08-24 16:18:21 -07002653 for _, moduleOrAlias := range newVariations {
2654 if m := moduleOrAlias.module(); m != nil {
2655 newModuleInfo[m.logicModule] = m
2656 }
Colin Cross49c279a2016-08-05 22:30:44 -07002657 }
2658 case <-done:
2659 return
Colin Crossc9028482014-12-18 16:28:54 -08002660 }
2661 }
Colin Cross49c279a2016-08-05 22:30:44 -07002662 }()
Colin Crossc9028482014-12-18 16:28:54 -08002663
Colin Cross2da84922020-07-02 10:08:12 -07002664 c.startedMutator = mutator
2665
Colin Crossc4773d92020-08-25 17:12:59 -07002666 var visitErrs []error
Colin Cross49c279a2016-08-05 22:30:44 -07002667 if mutator.parallel {
Colin Crossc4773d92020-08-25 17:12:59 -07002668 visitErrs = parallelVisit(c.modulesSorted, direction.orderer(), parallelVisitLimit, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002669 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002670 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002671 }
2672
Colin Crossc4773d92020-08-25 17:12:59 -07002673 if len(visitErrs) > 0 {
2674 return nil, visitErrs
2675 }
2676
Colin Cross2da84922020-07-02 10:08:12 -07002677 c.finishedMutators[mutator] = true
2678
Colin Cross49c279a2016-08-05 22:30:44 -07002679 done <- true
2680
2681 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002682 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002683 }
2684
2685 c.moduleInfo = newModuleInfo
2686
2687 for _, group := range c.moduleGroups {
2688 for i := 0; i < len(group.modules); i++ {
Colin Cross5df74a82020-08-24 16:18:21 -07002689 module := group.modules[i].module()
2690 if module == nil {
2691 // Existing alias, skip it
2692 continue
2693 }
Colin Cross49c279a2016-08-05 22:30:44 -07002694
2695 // Update module group to contain newly split variants
2696 if module.splitModules != nil {
2697 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2698 }
2699
2700 // Fix up any remaining dependencies on modules that were split into variants
2701 // by replacing them with the first variant
2702 for j, dep := range module.directDeps {
2703 if dep.module.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002704 module.directDeps[j].module = dep.module.splitModules.firstModule()
Colin Cross49c279a2016-08-05 22:30:44 -07002705 }
2706 }
Colin Cross99bdb2a2019-03-29 16:35:02 -07002707
Colin Cross322cc012019-05-20 13:55:14 -07002708 if module.createdBy != nil && module.createdBy.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002709 module.createdBy = module.createdBy.splitModules.firstModule()
Colin Cross322cc012019-05-20 13:55:14 -07002710 }
2711
Colin Cross99bdb2a2019-03-29 16:35:02 -07002712 // Add in any new direct dependencies that were added by the mutator
2713 module.directDeps = append(module.directDeps, module.newDirectDeps...)
2714 module.newDirectDeps = nil
Colin Cross7addea32015-03-11 15:43:52 -07002715 }
Colin Crossf7beb892019-11-13 20:11:14 -08002716
Colin Cross279489c2020-08-13 12:11:52 -07002717 findAliasTarget := func(variant variant) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07002718 for _, moduleOrAlias := range group.modules {
2719 if alias := moduleOrAlias.alias(); alias != nil {
2720 if alias.variant.variations.equal(variant.variations) {
2721 return alias.target
2722 }
Colin Cross279489c2020-08-13 12:11:52 -07002723 }
2724 }
2725 return nil
2726 }
2727
Colin Crossf7beb892019-11-13 20:11:14 -08002728 // Forward or delete any dangling aliases.
Colin Cross5df74a82020-08-24 16:18:21 -07002729 // Use a manual loop instead of range because len(group.modules) can
2730 // change inside the loop
2731 for i := 0; i < len(group.modules); i++ {
2732 if alias := group.modules[i].alias(); alias != nil {
2733 if alias.target.logicModule == nil {
2734 newTarget := findAliasTarget(alias.target.variant)
2735 if newTarget != nil {
2736 alias.target = newTarget
2737 } else {
2738 // The alias was left dangling, remove it.
2739 group.modules = append(group.modules[:i], group.modules[i+1:]...)
2740 i--
2741 }
Colin Crossf7beb892019-11-13 20:11:14 -08002742 }
2743 }
2744 }
Colin Crossc9028482014-12-18 16:28:54 -08002745 }
2746
Colin Cross99bdb2a2019-03-29 16:35:02 -07002747 // Add in any new reverse dependencies that were added by the mutator
Colin Cross8d8a7af2015-11-03 16:41:29 -08002748 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002749 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002750 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002751 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002752 }
2753
Colin Crossaf4fd212017-07-28 14:32:36 -07002754 for _, module := range newModules {
2755 errs = c.addModule(module)
2756 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002757 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002758 }
2759 atomic.AddUint32(&c.depsModified, 1)
2760 }
2761
Colin Cross0ce142c2016-12-09 10:29:05 -08002762 errs = c.handleRenames(rename)
2763 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002764 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002765 }
2766
2767 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002768 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002769 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002770 }
2771
Colin Cross3702ac72016-08-11 11:09:00 -07002772 if c.depsModified > 0 {
2773 errs = c.updateDependencies()
2774 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002775 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002776 }
Colin Crossc9028482014-12-18 16:28:54 -08002777 }
2778
Colin Cross874a3462017-07-31 17:26:06 -07002779 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002780}
2781
Colin Cross910242b2016-04-11 15:41:52 -07002782// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2783// a mutator sets a non-property member variable on a module, which works until a later mutator
2784// creates variants of that module.
2785func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002786 type update struct {
2787 orig Module
2788 clone *moduleInfo
2789 }
Colin Cross7e723372018-03-28 11:50:12 -07002790 ch := make(chan update)
2791 doneCh := make(chan bool)
2792 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07002793 errs := parallelVisit(c.modulesSorted, unorderedVisitorImpl{}, parallelVisitLimit,
2794 func(m *moduleInfo, pause chan<- pauseSpec) bool {
2795 origLogicModule := m.logicModule
2796 m.logicModule, m.properties = c.cloneLogicModule(m)
2797 ch <- update{origLogicModule, m}
2798 return false
2799 })
2800 if len(errs) > 0 {
2801 panic(errs)
2802 }
Colin Cross7e723372018-03-28 11:50:12 -07002803 doneCh <- true
2804 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002805
Colin Cross7e723372018-03-28 11:50:12 -07002806 done := false
2807 for !done {
2808 select {
2809 case <-doneCh:
2810 done = true
2811 case update := <-ch:
2812 delete(c.moduleInfo, update.orig)
2813 c.moduleInfo[update.clone.logicModule] = update.clone
2814 }
Colin Cross910242b2016-04-11 15:41:52 -07002815 }
2816}
2817
Colin Cross49c279a2016-08-05 22:30:44 -07002818// Removes modules[i] from the list and inserts newModules... where it was located, returning
2819// the new slice and the index of the last inserted element
Colin Cross5df74a82020-08-24 16:18:21 -07002820func spliceModules(modules modulesOrAliases, i int, newModules modulesOrAliases) (modulesOrAliases, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002821 spliceSize := len(newModules)
2822 newLen := len(modules) + spliceSize - 1
Colin Cross5df74a82020-08-24 16:18:21 -07002823 var dest modulesOrAliases
Colin Cross7addea32015-03-11 15:43:52 -07002824 if cap(modules) >= len(modules)-1+len(newModules) {
2825 // We can fit the splice in the existing capacity, do everything in place
2826 dest = modules[:newLen]
2827 } else {
Colin Cross5df74a82020-08-24 16:18:21 -07002828 dest = make(modulesOrAliases, newLen)
Colin Cross7addea32015-03-11 15:43:52 -07002829 copy(dest, modules[:i])
2830 }
2831
2832 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002833 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002834
2835 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002836 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002837
Colin Cross49c279a2016-08-05 22:30:44 -07002838 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002839}
2840
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002841func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002842 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002843
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002844 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002845 var errs []error
2846
Colin Cross691a60d2015-01-07 18:08:56 -08002847 cancelCh := make(chan struct{})
2848 errsCh := make(chan []error)
2849 depsCh := make(chan []string)
2850
2851 go func() {
2852 for {
2853 select {
2854 case <-cancelCh:
2855 close(cancelCh)
2856 return
2857 case newErrs := <-errsCh:
2858 errs = append(errs, newErrs...)
2859 case newDeps := <-depsCh:
2860 deps = append(deps, newDeps...)
2861
2862 }
2863 }
2864 }()
2865
Colin Crossc4773d92020-08-25 17:12:59 -07002866 visitErrs := parallelVisit(c.modulesSorted, bottomUpVisitor, parallelVisitLimit,
2867 func(module *moduleInfo, pause chan<- pauseSpec) bool {
2868 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2869 sanitizedName := toNinjaName(uniqueName)
Yi Konga08e7222021-12-21 15:50:57 +08002870 sanitizedVariant := toNinjaName(module.variant.name)
Jeff Gaston0e907592017-12-01 17:10:52 -08002871
Yi Konga08e7222021-12-21 15:50:57 +08002872 prefix := moduleNamespacePrefix(sanitizedName + "_" + sanitizedVariant)
Jeff Gaston0e907592017-12-01 17:10:52 -08002873
Colin Crossc4773d92020-08-25 17:12:59 -07002874 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2875 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2876 // just set it to nil.
2877 scope := newLocalScope(nil, prefix)
Jeff Gaston0e907592017-12-01 17:10:52 -08002878
Colin Crossc4773d92020-08-25 17:12:59 -07002879 mctx := &moduleContext{
2880 baseModuleContext: baseModuleContext{
2881 context: c,
2882 config: config,
2883 module: module,
2884 },
2885 scope: scope,
2886 handledMissingDeps: module.missingDeps == nil,
Colin Cross036a1df2015-12-17 15:49:30 -08002887 }
Colin Cross036a1df2015-12-17 15:49:30 -08002888
Colin Cross2da84922020-07-02 10:08:12 -07002889 mctx.module.startedGenerateBuildActions = true
2890
Colin Crossc4773d92020-08-25 17:12:59 -07002891 func() {
2892 defer func() {
2893 if r := recover(); r != nil {
2894 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2895 if err, ok := r.(panicError); ok {
2896 err.addIn(in)
2897 mctx.error(err)
2898 } else {
2899 mctx.error(newPanicErrorf(r, in))
2900 }
2901 }
2902 }()
2903 mctx.module.logicModule.GenerateBuildActions(mctx)
2904 }()
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002905
Colin Cross2da84922020-07-02 10:08:12 -07002906 mctx.module.finishedGenerateBuildActions = true
2907
Colin Crossc4773d92020-08-25 17:12:59 -07002908 if len(mctx.errs) > 0 {
2909 errsCh <- mctx.errs
2910 return true
2911 }
2912
2913 if module.missingDeps != nil && !mctx.handledMissingDeps {
2914 var errs []error
2915 for _, depName := range module.missingDeps {
2916 errs = append(errs, c.missingDependencyError(module, depName))
2917 }
2918 errsCh <- errs
2919 return true
2920 }
2921
2922 depsCh <- mctx.ninjaFileDeps
2923
2924 newErrs := c.processLocalBuildActions(&module.actionDefs,
2925 &mctx.actionDefs, liveGlobals)
2926 if len(newErrs) > 0 {
2927 errsCh <- newErrs
2928 return true
2929 }
2930 return false
2931 })
Colin Cross691a60d2015-01-07 18:08:56 -08002932
2933 cancelCh <- struct{}{}
2934 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002935
Colin Crossc4773d92020-08-25 17:12:59 -07002936 errs = append(errs, visitErrs...)
2937
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002938 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002939}
2940
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002941func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002942 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002943
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002944 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002945 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002946
Colin Cross5f03f112017-11-07 13:29:54 -08002947 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002948 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2949 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2950 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002951 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002952
2953 sctx := &singletonContext{
Colin Cross9226d6c2019-02-25 18:07:44 -08002954 name: info.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002955 context: c,
2956 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002957 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002958 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002959 }
2960
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002961 func() {
2962 defer func() {
2963 if r := recover(); r != nil {
2964 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2965 if err, ok := r.(panicError); ok {
2966 err.addIn(in)
2967 sctx.error(err)
2968 } else {
2969 sctx.error(newPanicErrorf(r, in))
2970 }
2971 }
2972 }()
2973 info.singleton.GenerateBuildActions(sctx)
2974 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002975
2976 if len(sctx.errs) > 0 {
2977 errs = append(errs, sctx.errs...)
2978 if len(errs) > maxErrors {
2979 break
2980 }
2981 continue
2982 }
2983
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002984 deps = append(deps, sctx.ninjaFileDeps...)
2985
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002986 newErrs := c.processLocalBuildActions(&info.actionDefs,
2987 &sctx.actionDefs, liveGlobals)
2988 errs = append(errs, newErrs...)
2989 if len(errs) > maxErrors {
2990 break
2991 }
2992 }
2993
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002994 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002995}
2996
2997func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2998 liveGlobals *liveTracker) []error {
2999
3000 var errs []error
3001
3002 // First we go through and add everything referenced by the module's
3003 // buildDefs to the live globals set. This will end up adding the live
3004 // locals to the set as well, but we'll take them out after.
3005 for _, def := range in.buildDefs {
3006 err := liveGlobals.AddBuildDefDeps(def)
3007 if err != nil {
3008 errs = append(errs, err)
3009 }
3010 }
3011
3012 if len(errs) > 0 {
3013 return errs
3014 }
3015
Colin Crossc9028482014-12-18 16:28:54 -08003016 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003017
3018 // We use the now-incorrect set of live "globals" to determine which local
3019 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08003020 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003021 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07003022 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003023 if isLive {
3024 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003025 }
3026 }
3027
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003028 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07003029 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003030 if isLive {
3031 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003032 }
3033 }
3034
3035 return nil
3036}
3037
Colin Cross9607a9f2018-06-20 11:16:37 -07003038func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07003039 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07003040
3041 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003042 var visiting *moduleInfo
3043
3044 defer func() {
3045 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07003046 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
3047 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003048 }
3049 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07003050
3051 var walk func(module *moduleInfo)
3052 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003053 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07003054 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003055 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07003056 recurse := true
3057 if visitDown != nil {
3058 recurse = visitDown(dep, module)
3059 }
Colin Cross526e02f2018-06-21 13:31:53 -07003060 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003061 walk(dep.module)
Paul Duffin72bab172020-04-02 10:51:33 +01003062 visited[dep.module] = true
Yuchen Wu222e2452015-10-06 14:03:27 -07003063 }
Colin Crossbafd5f52016-08-06 22:52:01 -07003064 if visitUp != nil {
3065 visitUp(dep, module)
3066 }
Yuchen Wu222e2452015-10-06 14:03:27 -07003067 }
3068 }
3069 }
3070
3071 walk(topModule)
3072}
3073
Colin Cross9cfd1982016-10-11 09:58:53 -07003074type replace struct {
Paul Duffin8969cb62020-06-30 12:15:26 +01003075 from, to *moduleInfo
3076 predicate ReplaceDependencyPredicate
Colin Cross9cfd1982016-10-11 09:58:53 -07003077}
3078
Colin Crossc4e5b812016-10-12 10:45:05 -07003079type rename struct {
3080 group *moduleGroup
3081 name string
3082}
3083
Colin Cross0ce142c2016-12-09 10:29:05 -08003084func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Crossd03b59d2019-11-13 20:10:12 -08003085 group := c.moduleGroupFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07003086
Colin Crossd03b59d2019-11-13 20:10:12 -08003087 if group == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08003088 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003089 }
3090
Colin Crossd03b59d2019-11-13 20:10:12 -08003091 for _, m := range group.modules {
Colin Crossedbdb8c2020-09-11 19:22:27 -07003092 if module.variant.name == m.moduleOrAliasVariant().name {
Colin Cross5df74a82020-08-24 16:18:21 -07003093 return m.moduleOrAliasTarget()
Colin Crossf7beb892019-11-13 20:11:14 -08003094 }
3095 }
3096
Colin Cross0ce142c2016-12-09 10:29:05 -08003097 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003098}
3099
Colin Cross0ce142c2016-12-09 10:29:05 -08003100func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07003101 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08003102 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07003103 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08003104 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07003105 continue
3106 }
3107
Jeff Gastond70bf752017-11-10 15:12:08 -08003108 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07003109 }
3110
Colin Cross0ce142c2016-12-09 10:29:05 -08003111 return errs
3112}
3113
3114func (c *Context) handleReplacements(replacements []replace) []error {
3115 var errs []error
Paul Duffin8969cb62020-06-30 12:15:26 +01003116 changedDeps := false
Colin Cross0ce142c2016-12-09 10:29:05 -08003117 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07003118 for _, m := range replace.from.reverseDeps {
3119 for i, d := range m.directDeps {
3120 if d.module == replace.from {
Paul Duffin8969cb62020-06-30 12:15:26 +01003121 // If the replacement has a predicate then check it.
3122 if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) {
3123 m.directDeps[i].module = replace.to
3124 changedDeps = true
3125 }
Colin Cross9cfd1982016-10-11 09:58:53 -07003126 }
3127 }
3128 }
3129
Colin Cross9cfd1982016-10-11 09:58:53 -07003130 }
Colin Cross0ce142c2016-12-09 10:29:05 -08003131
Paul Duffin8969cb62020-06-30 12:15:26 +01003132 if changedDeps {
3133 atomic.AddUint32(&c.depsModified, 1)
3134 }
Colin Crossc4e5b812016-10-12 10:45:05 -07003135 return errs
3136}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003137
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00003138func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string, depVariations variationMap) (errs []error) {
3139 if depVariations != nil {
3140 depName = depName + "{" + c.prettyPrintVariant(depVariations) + "}"
3141 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003142 if c.allowMissingDependencies {
3143 module.missingDeps = append(module.missingDeps, depName)
3144 return nil
3145 }
3146 return []error{c.missingDependencyError(module, depName)}
3147}
3148
3149func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
3150 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
3151
3152 return &BlueprintError{
3153 Err: err,
3154 Pos: module.pos,
3155 }
3156}
3157
Colin Crossd03b59d2019-11-13 20:10:12 -08003158func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
Jeff Gastond70bf752017-11-10 15:12:08 -08003159 group, exists := c.nameInterface.ModuleFromName(name, namespace)
3160 if exists {
Colin Crossd03b59d2019-11-13 20:10:12 -08003161 return group.moduleGroup
Colin Cross0b7e83e2016-05-17 14:58:05 -07003162 }
3163 return nil
3164}
3165
Jeff Gastond70bf752017-11-10 15:12:08 -08003166func (c *Context) sortedModuleGroups() []*moduleGroup {
Liz Kammer9ae14f12020-11-30 16:30:45 -07003167 if c.cachedSortedModuleGroups == nil || c.cachedDepsModified {
Jeff Gastond70bf752017-11-10 15:12:08 -08003168 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
3169 result := make([]*moduleGroup, 0, len(wrappers))
3170 for _, group := range wrappers {
3171 result = append(result, group.moduleGroup)
3172 }
3173 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07003174 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003175
3176 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Liz Kammer9ae14f12020-11-30 16:30:45 -07003177 c.cachedDepsModified = false
Jamie Gennisc15544d2014-09-24 20:26:52 -07003178 }
3179
Jeff Gastond70bf752017-11-10 15:12:08 -08003180 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07003181}
3182
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003183func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003184 var module *moduleInfo
3185
3186 defer func() {
3187 if r := recover(); r != nil {
3188 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
3189 funcName(visit), module))
3190 }
3191 }()
3192
Jeff Gastond70bf752017-11-10 15:12:08 -08003193 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003194 for _, moduleOrAlias := range moduleGroup.modules {
3195 if module = moduleOrAlias.module(); module != nil {
3196 visit(module.logicModule)
3197 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003198 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003199 }
3200}
3201
3202func (c *Context) visitAllModulesIf(pred func(Module) bool,
3203 visit func(Module)) {
3204
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003205 var module *moduleInfo
3206
3207 defer func() {
3208 if r := recover(); r != nil {
3209 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
3210 funcName(pred), funcName(visit), module))
3211 }
3212 }()
3213
Jeff Gastond70bf752017-11-10 15:12:08 -08003214 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003215 for _, moduleOrAlias := range moduleGroup.modules {
3216 if module = moduleOrAlias.module(); module != nil {
3217 if pred(module.logicModule) {
3218 visit(module.logicModule)
3219 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003220 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003221 }
3222 }
3223}
3224
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003225func (c *Context) visitAllModuleVariants(module *moduleInfo,
3226 visit func(Module)) {
3227
3228 var variant *moduleInfo
3229
3230 defer func() {
3231 if r := recover(); r != nil {
3232 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
3233 module, funcName(visit), variant))
3234 }
3235 }()
3236
Colin Cross5df74a82020-08-24 16:18:21 -07003237 for _, moduleOrAlias := range module.group.modules {
3238 if variant = moduleOrAlias.module(); variant != nil {
3239 visit(variant.logicModule)
3240 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003241 }
3242}
3243
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003244func (c *Context) requireNinjaVersion(major, minor, micro int) {
3245 if major != 1 {
3246 panic("ninja version with major version != 1 not supported")
3247 }
3248 if c.requiredNinjaMinor < minor {
3249 c.requiredNinjaMinor = minor
3250 c.requiredNinjaMicro = micro
3251 }
3252 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
3253 c.requiredNinjaMicro = micro
3254 }
3255}
3256
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003257func (c *Context) setOutDir(value ninjaString) {
3258 if c.outDir == nil {
3259 c.outDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003260 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003261}
3262
3263func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08003264 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003265
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003266 pkgs := make(map[string]*packageContext)
3267 pkgNames := make(map[*packageContext]string)
3268 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003269
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003270 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003271 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003272 // This is a built-in rule and has no package.
3273 return
3274 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07003275 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003276 // We've already processed this package.
3277 return
3278 }
3279
Jamie Gennis2fb20952014-10-03 02:49:58 -07003280 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003281 if present {
3282 // Short name collision. Both this package and the one that's
3283 // already there need to use their full names. We leave the short
3284 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003285 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003286 longPkgNames[otherPkg] = true
3287 } else {
3288 // No collision so far. Tentatively set the package's name to be
3289 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003290 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07003291 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003292 }
3293 }
3294
3295 // We try to give all packages their short name, but when we get collisions
3296 // we need to use the full unique package name.
3297 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003298 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003299 }
3300 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003301 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003302 }
3303 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003304 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003305 }
3306
3307 // Add the packages that had collisions using their full unique names. This
3308 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003309 for pctx := range longPkgNames {
3310 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003311 }
3312
Dan Willemsena481ae22015-12-18 15:18:03 -08003313 // Create deps list from calls to PackageContext.AddNinjaFileDeps
3314 deps := []string{}
3315 for _, pkg := range pkgs {
3316 deps = append(deps, pkg.ninjaFileDeps...)
3317 }
3318
3319 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003320}
3321
Colin Cross92054a42021-01-21 16:49:25 -08003322// memoizeFullNames stores the full name of each live global variable, rule and pool since each is
3323// guaranteed to be used at least twice, once in the definition and once for each usage, and many
3324// are used much more than once.
3325func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) {
3326 for v := range liveGlobals.variables {
3327 v.memoizeFullName(pkgNames)
3328 }
3329 for r := range liveGlobals.rules {
3330 r.memoizeFullName(pkgNames)
3331 }
3332 for p := range liveGlobals.pools {
3333 p.memoizeFullName(pkgNames)
3334 }
3335}
3336
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003337func (c *Context) checkForVariableReferenceCycles(
Colin Cross2ce594e2020-01-29 12:58:03 -08003338 variables map[Variable]ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003339
3340 visited := make(map[Variable]bool) // variables that were already checked
3341 checking := make(map[Variable]bool) // variables actively being checked
3342
3343 var check func(v Variable) []Variable
3344
3345 check = func(v Variable) []Variable {
3346 visited[v] = true
3347 checking[v] = true
3348 defer delete(checking, v)
3349
3350 value := variables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003351 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003352 if checking[dep] {
3353 // This is a cycle.
3354 return []Variable{dep, v}
3355 }
3356
3357 if !visited[dep] {
3358 cycle := check(dep)
3359 if cycle != nil {
3360 if cycle[0] == v {
3361 // We are the "start" of the cycle, so we're responsible
3362 // for generating the errors. The cycle list is in
3363 // reverse order because all the 'check' calls append
3364 // their own module to the list.
3365 msgs := []string{"detected variable reference cycle:"}
3366
3367 // Iterate backwards through the cycle list.
3368 curName := v.fullName(pkgNames)
3369 curValue := value.Value(pkgNames)
3370 for i := len(cycle) - 1; i >= 0; i-- {
3371 next := cycle[i]
3372 nextName := next.fullName(pkgNames)
3373 nextValue := variables[next].Value(pkgNames)
3374
3375 msgs = append(msgs, fmt.Sprintf(
3376 " %q depends on %q", curName, nextName))
3377 msgs = append(msgs, fmt.Sprintf(
3378 " [%s = %s]", curName, curValue))
3379
3380 curName = nextName
3381 curValue = nextValue
3382 }
3383
3384 // Variable reference cycles are a programming error,
3385 // not the fault of the Blueprint file authors.
3386 panic(strings.Join(msgs, "\n"))
3387 } else {
3388 // We're not the "start" of the cycle, so we just append
3389 // our module to the list and return it.
3390 return append(cycle, v)
3391 }
3392 }
3393 }
3394 }
3395
3396 return nil
3397 }
3398
3399 for v := range variables {
3400 if !visited[v] {
3401 cycle := check(v)
3402 if cycle != nil {
3403 panic("inconceivable!")
3404 }
3405 }
3406 }
3407}
3408
Jamie Gennisaf435562014-10-27 22:34:56 -07003409// AllTargets returns a map all the build target names to the rule used to build
3410// them. This is the same information that is output by running 'ninja -t
3411// targets all'. If this is called before PrepareBuildActions successfully
3412// completes then ErrbuildActionsNotReady is returned.
3413func (c *Context) AllTargets() (map[string]string, error) {
3414 if !c.buildActionsReady {
3415 return nil, ErrBuildActionsNotReady
3416 }
3417
3418 targets := map[string]string{}
3419
3420 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07003421 for _, module := range c.moduleInfo {
3422 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07003423 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003424 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003425 outputValue, err := output.Eval(c.globalVariables)
3426 if err != nil {
3427 return nil, err
3428 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003429 targets[outputValue] = ruleName
3430 }
3431 }
3432 }
3433
3434 // Collect all the singleton build targets.
3435 for _, info := range c.singletonInfo {
3436 for _, buildDef := range info.actionDefs.buildDefs {
3437 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003438 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003439 outputValue, err := output.Eval(c.globalVariables)
3440 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08003441 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08003442 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003443 targets[outputValue] = ruleName
3444 }
3445 }
3446 }
3447
3448 return targets, nil
3449}
3450
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003451func (c *Context) OutDir() (string, error) {
3452 if c.outDir != nil {
3453 return c.outDir.Eval(c.globalVariables)
Colin Crossa2599452015-11-18 16:01:01 -08003454 } else {
3455 return "", nil
3456 }
3457}
3458
Colin Cross4572edd2015-05-13 14:36:24 -07003459// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
3460// property structs returned by the factory for that module type.
3461func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
3462 ret := make(map[string][]interface{})
3463 for moduleType, factory := range c.moduleFactories {
3464 _, ret[moduleType] = factory()
3465 }
3466
3467 return ret
3468}
3469
Jaewoong Jung781f6b22019-02-06 16:20:17 -08003470func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
3471 ret := make(map[string]ModuleFactory)
3472 for k, v := range c.moduleFactories {
3473 ret[k] = v
3474 }
3475 return ret
3476}
3477
Colin Cross4572edd2015-05-13 14:36:24 -07003478func (c *Context) ModuleName(logicModule Module) string {
3479 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07003480 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07003481}
3482
Jeff Gaston3c8c3342017-11-30 17:30:42 -08003483func (c *Context) ModuleDir(logicModule Module) string {
Colin Cross8e454c52020-07-06 12:18:59 -07003484 return filepath.Dir(c.BlueprintFile(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07003485}
3486
Colin Cross8c602f72015-12-17 18:02:11 -08003487func (c *Context) ModuleSubDir(logicModule Module) string {
3488 module := c.moduleInfo[logicModule]
Colin Crossedc41762020-08-13 12:07:30 -07003489 return module.variant.name
Colin Cross8c602f72015-12-17 18:02:11 -08003490}
3491
Dan Willemsenc98e55b2016-07-25 15:51:50 -07003492func (c *Context) ModuleType(logicModule Module) string {
3493 module := c.moduleInfo[logicModule]
3494 return module.typeName
3495}
3496
Colin Cross2da84922020-07-02 10:08:12 -07003497// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
3498// provider was not set it returns the zero value of the type of the provider, which means the
3499// return value can always be type-asserted to the type of the provider. The return value should
3500// always be considered read-only. It panics if called before the appropriate mutator or
3501// GenerateBuildActions pass for the provider on the module. The value returned may be a deep
3502// copy of the value originally passed to SetProvider.
3503func (c *Context) ModuleProvider(logicModule Module, provider ProviderKey) interface{} {
3504 module := c.moduleInfo[logicModule]
3505 value, _ := c.provider(module, provider)
3506 return value
3507}
3508
3509// ModuleHasProvider returns true if the provider for the given module has been set.
3510func (c *Context) ModuleHasProvider(logicModule Module, provider ProviderKey) bool {
3511 module := c.moduleInfo[logicModule]
3512 _, ok := c.provider(module, provider)
3513 return ok
3514}
3515
Colin Cross4572edd2015-05-13 14:36:24 -07003516func (c *Context) BlueprintFile(logicModule Module) string {
3517 module := c.moduleInfo[logicModule]
3518 return module.relBlueprintsFile
3519}
3520
3521func (c *Context) ModuleErrorf(logicModule Module, format string,
3522 args ...interface{}) error {
3523
3524 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07003525 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07003526 Err: fmt.Errorf(format, args...),
3527 Pos: module.pos,
3528 }
3529}
3530
3531func (c *Context) VisitAllModules(visit func(Module)) {
3532 c.visitAllModules(visit)
3533}
3534
3535func (c *Context) VisitAllModulesIf(pred func(Module) bool,
3536 visit func(Module)) {
3537
3538 c.visitAllModulesIf(pred, visit)
3539}
3540
Colin Cross080c1332017-03-17 13:09:05 -07003541func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
3542 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07003543
Colin Cross080c1332017-03-17 13:09:05 -07003544 var visiting *moduleInfo
3545
3546 defer func() {
3547 if r := recover(); r != nil {
3548 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
3549 topModule, funcName(visit), visiting))
3550 }
3551 }()
3552
3553 for _, dep := range topModule.directDeps {
3554 visiting = dep.module
3555 visit(dep.module.logicModule)
3556 }
3557}
3558
3559func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
3560 topModule := c.moduleInfo[module]
3561
3562 var visiting *moduleInfo
3563
3564 defer func() {
3565 if r := recover(); r != nil {
3566 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
3567 topModule, funcName(pred), funcName(visit), visiting))
3568 }
3569 }()
3570
3571 for _, dep := range topModule.directDeps {
3572 visiting = dep.module
3573 if pred(dep.module.logicModule) {
3574 visit(dep.module.logicModule)
3575 }
3576 }
3577}
3578
3579func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003580 topModule := c.moduleInfo[module]
3581
3582 var visiting *moduleInfo
3583
3584 defer func() {
3585 if r := recover(); r != nil {
3586 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
3587 topModule, funcName(visit), visiting))
3588 }
3589 }()
3590
Colin Cross9607a9f2018-06-20 11:16:37 -07003591 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003592 visiting = dep.module
3593 visit(dep.module.logicModule)
3594 })
Colin Cross4572edd2015-05-13 14:36:24 -07003595}
3596
Colin Cross080c1332017-03-17 13:09:05 -07003597func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003598 topModule := c.moduleInfo[module]
3599
3600 var visiting *moduleInfo
3601
3602 defer func() {
3603 if r := recover(); r != nil {
3604 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
3605 topModule, funcName(pred), funcName(visit), visiting))
3606 }
3607 }()
3608
Colin Cross9607a9f2018-06-20 11:16:37 -07003609 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003610 if pred(dep.module.logicModule) {
3611 visiting = dep.module
3612 visit(dep.module.logicModule)
3613 }
3614 })
Colin Cross4572edd2015-05-13 14:36:24 -07003615}
3616
Colin Cross24ad5872015-11-17 16:22:29 -08003617func (c *Context) PrimaryModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003618 return c.moduleInfo[module].group.modules.firstModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003619}
3620
3621func (c *Context) FinalModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003622 return c.moduleInfo[module].group.modules.lastModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003623}
3624
3625func (c *Context) VisitAllModuleVariants(module Module,
3626 visit func(Module)) {
3627
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003628 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08003629}
3630
Colin Cross9226d6c2019-02-25 18:07:44 -08003631// Singletons returns a list of all registered Singletons.
3632func (c *Context) Singletons() []Singleton {
3633 var ret []Singleton
3634 for _, s := range c.singletonInfo {
3635 ret = append(ret, s.singleton)
3636 }
3637 return ret
3638}
3639
3640// SingletonName returns the name that the given singleton was registered with.
3641func (c *Context) SingletonName(singleton Singleton) string {
3642 for _, s := range c.singletonInfo {
3643 if s.singleton == singleton {
3644 return s.name
3645 }
3646 }
3647 return ""
3648}
3649
Jamie Gennisd4e10182014-06-12 20:06:50 -07003650// WriteBuildFile writes the Ninja manifeset text for the generated build
3651// actions to w. If this is called before PrepareBuildActions successfully
3652// completes then ErrBuildActionsNotReady is returned.
Colin Cross0335e092021-01-21 15:26:21 -08003653func (c *Context) WriteBuildFile(w io.StringWriter) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08003654 var err error
3655 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
3656 if !c.buildActionsReady {
3657 err = ErrBuildActionsNotReady
3658 return
3659 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003660
Colin Cross3a8c0252019-01-23 13:21:48 -08003661 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003662
Colin Cross3a8c0252019-01-23 13:21:48 -08003663 err = c.writeBuildFileHeader(nw)
3664 if err != nil {
3665 return
3666 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003667
Colin Cross3a8c0252019-01-23 13:21:48 -08003668 err = c.writeNinjaRequiredVersion(nw)
3669 if err != nil {
3670 return
3671 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003672
Colin Cross3a8c0252019-01-23 13:21:48 -08003673 err = c.writeSubninjas(nw)
3674 if err != nil {
3675 return
3676 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003677
Colin Cross3a8c0252019-01-23 13:21:48 -08003678 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003679
Colin Cross3a8c0252019-01-23 13:21:48 -08003680 err = c.writeGlobalVariables(nw)
3681 if err != nil {
3682 return
3683 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003684
Colin Cross3a8c0252019-01-23 13:21:48 -08003685 err = c.writeGlobalPools(nw)
3686 if err != nil {
3687 return
3688 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003689
Colin Cross3a8c0252019-01-23 13:21:48 -08003690 err = c.writeBuildDir(nw)
3691 if err != nil {
3692 return
3693 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003694
Colin Cross3a8c0252019-01-23 13:21:48 -08003695 err = c.writeGlobalRules(nw)
3696 if err != nil {
3697 return
3698 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003699
Colin Cross3a8c0252019-01-23 13:21:48 -08003700 err = c.writeAllModuleActions(nw)
3701 if err != nil {
3702 return
3703 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003704
Colin Cross3a8c0252019-01-23 13:21:48 -08003705 err = c.writeAllSingletonActions(nw)
3706 if err != nil {
3707 return
3708 }
3709 })
3710
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003711 if err != nil {
3712 return err
3713 }
3714
3715 return nil
3716}
3717
Jamie Gennisc15544d2014-09-24 20:26:52 -07003718type pkgAssociation struct {
3719 PkgName string
3720 PkgPath string
3721}
3722
3723type pkgAssociationSorter struct {
3724 pkgs []pkgAssociation
3725}
3726
3727func (s *pkgAssociationSorter) Len() int {
3728 return len(s.pkgs)
3729}
3730
3731func (s *pkgAssociationSorter) Less(i, j int) bool {
3732 iName := s.pkgs[i].PkgName
3733 jName := s.pkgs[j].PkgName
3734 return iName < jName
3735}
3736
3737func (s *pkgAssociationSorter) Swap(i, j int) {
3738 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3739}
3740
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003741func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3742 headerTemplate := template.New("fileHeader")
3743 _, err := headerTemplate.Parse(fileHeaderTemplate)
3744 if err != nil {
3745 // This is a programming error.
3746 panic(err)
3747 }
3748
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003749 var pkgs []pkgAssociation
3750 maxNameLen := 0
3751 for pkg, name := range c.pkgNames {
3752 pkgs = append(pkgs, pkgAssociation{
3753 PkgName: name,
3754 PkgPath: pkg.pkgPath,
3755 })
3756 if len(name) > maxNameLen {
3757 maxNameLen = len(name)
3758 }
3759 }
3760
3761 for i := range pkgs {
3762 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3763 }
3764
Jamie Gennisc15544d2014-09-24 20:26:52 -07003765 sort.Sort(&pkgAssociationSorter{pkgs})
3766
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003767 params := map[string]interface{}{
3768 "Pkgs": pkgs,
3769 }
3770
3771 buf := bytes.NewBuffer(nil)
3772 err = headerTemplate.Execute(buf, params)
3773 if err != nil {
3774 return err
3775 }
3776
3777 return nw.Comment(buf.String())
3778}
3779
3780func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3781 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3782 c.requiredNinjaMicro)
3783
3784 err := nw.Assign("ninja_required_version", value)
3785 if err != nil {
3786 return err
3787 }
3788
3789 return nw.BlankLine()
3790}
3791
Dan Willemsenab223a52018-07-05 21:56:59 -07003792func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3793 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003794 err := nw.Subninja(subninja)
3795 if err != nil {
3796 return err
3797 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003798 }
3799 return nw.BlankLine()
3800}
3801
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003802func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003803 if c.outDir != nil {
3804 err := nw.Assign("builddir", c.outDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003805 if err != nil {
3806 return err
3807 }
3808
3809 err = nw.BlankLine()
3810 if err != nil {
3811 return err
3812 }
3813 }
3814 return nil
3815}
3816
Jamie Gennisc15544d2014-09-24 20:26:52 -07003817type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003818 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003819}
3820
Jamie Gennisc15544d2014-09-24 20:26:52 -07003821type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003822 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003823 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003824}
3825
Jamie Gennisc15544d2014-09-24 20:26:52 -07003826func (s *globalEntitySorter) Len() int {
3827 return len(s.entities)
3828}
3829
3830func (s *globalEntitySorter) Less(i, j int) bool {
3831 iName := s.entities[i].fullName(s.pkgNames)
3832 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003833 return iName < jName
3834}
3835
Jamie Gennisc15544d2014-09-24 20:26:52 -07003836func (s *globalEntitySorter) Swap(i, j int) {
3837 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003838}
3839
3840func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3841 visited := make(map[Variable]bool)
3842
3843 var walk func(v Variable) error
3844 walk = func(v Variable) error {
3845 visited[v] = true
3846
3847 // First visit variables on which this variable depends.
3848 value := c.globalVariables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003849 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003850 if !visited[dep] {
3851 err := walk(dep)
3852 if err != nil {
3853 return err
3854 }
3855 }
3856 }
3857
3858 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3859 if err != nil {
3860 return err
3861 }
3862
3863 err = nw.BlankLine()
3864 if err != nil {
3865 return err
3866 }
3867
3868 return nil
3869 }
3870
Jamie Gennisc15544d2014-09-24 20:26:52 -07003871 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3872 for variable := range c.globalVariables {
3873 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003874 }
3875
Jamie Gennisc15544d2014-09-24 20:26:52 -07003876 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003877
Jamie Gennisc15544d2014-09-24 20:26:52 -07003878 for _, entity := range globalVariables {
3879 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003880 if !visited[v] {
3881 err := walk(v)
3882 if err != nil {
3883 return nil
3884 }
3885 }
3886 }
3887
3888 return nil
3889}
3890
3891func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003892 globalPools := make([]globalEntity, 0, len(c.globalPools))
3893 for pool := range c.globalPools {
3894 globalPools = append(globalPools, pool)
3895 }
3896
3897 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3898
3899 for _, entity := range globalPools {
3900 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003901 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003902 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003903 err := def.WriteTo(nw, name)
3904 if err != nil {
3905 return err
3906 }
3907
3908 err = nw.BlankLine()
3909 if err != nil {
3910 return err
3911 }
3912 }
3913
3914 return nil
3915}
3916
3917func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003918 globalRules := make([]globalEntity, 0, len(c.globalRules))
3919 for rule := range c.globalRules {
3920 globalRules = append(globalRules, rule)
3921 }
3922
3923 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3924
3925 for _, entity := range globalRules {
3926 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003927 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003928 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003929 err := def.WriteTo(nw, name, c.pkgNames)
3930 if err != nil {
3931 return err
3932 }
3933
3934 err = nw.BlankLine()
3935 if err != nil {
3936 return err
3937 }
3938 }
3939
3940 return nil
3941}
3942
Colin Cross2c1f3d12016-04-11 15:47:28 -07003943type depSorter []depInfo
3944
3945func (s depSorter) Len() int {
3946 return len(s)
3947}
3948
3949func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003950 iName := s[i].module.Name()
3951 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003952 if iName == jName {
Colin Crossedc41762020-08-13 12:07:30 -07003953 iName = s[i].module.variant.name
3954 jName = s[j].module.variant.name
Colin Cross2c1f3d12016-04-11 15:47:28 -07003955 }
3956 return iName < jName
3957}
3958
3959func (s depSorter) Swap(i, j int) {
3960 s[i], s[j] = s[j], s[i]
3961}
3962
Jeff Gaston0e907592017-12-01 17:10:52 -08003963type moduleSorter struct {
3964 modules []*moduleInfo
3965 nameInterface NameInterface
3966}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003967
Colin Crossab6d7902015-03-11 16:17:52 -07003968func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003969 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003970}
3971
Colin Crossab6d7902015-03-11 16:17:52 -07003972func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003973 iMod := s.modules[i]
3974 jMod := s.modules[j]
3975 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3976 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003977 if iName == jName {
Colin Cross279489c2020-08-13 12:11:52 -07003978 iVariantName := s.modules[i].variant.name
3979 jVariantName := s.modules[j].variant.name
3980 if iVariantName == jVariantName {
3981 panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
3982 iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
3983 } else {
3984 return iVariantName < jVariantName
3985 }
3986 } else {
3987 return iName < jName
Jeff Gaston0e907592017-12-01 17:10:52 -08003988 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003989}
3990
Colin Crossab6d7902015-03-11 16:17:52 -07003991func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003992 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003993}
3994
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003995func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3996 headerTemplate := template.New("moduleHeader")
3997 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3998 if err != nil {
3999 // This is a programming error.
4000 panic(err)
4001 }
4002
Colin Crossab6d7902015-03-11 16:17:52 -07004003 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
4004 for _, module := range c.moduleInfo {
4005 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07004006 }
Jeff Gaston0e907592017-12-01 17:10:52 -08004007 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07004008
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004009 buf := bytes.NewBuffer(nil)
4010
Colin Crossab6d7902015-03-11 16:17:52 -07004011 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07004012 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
4013 continue
4014 }
4015
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004016 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07004017
4018 // In order to make the bootstrap build manifest independent of the
4019 // build dir we need to output the Blueprints file locations in the
4020 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07004021 relPos := module.pos
4022 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07004023
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004024 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07004025 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004026 factoryName := factoryFunc.Name()
4027
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004028 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07004029 "name": module.Name(),
4030 "typeName": module.typeName,
4031 "goFactory": factoryName,
4032 "pos": relPos,
Colin Crossedc41762020-08-13 12:07:30 -07004033 "variant": module.variant.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004034 }
4035 err = headerTemplate.Execute(buf, infoMap)
4036 if err != nil {
4037 return err
4038 }
4039
4040 err = nw.Comment(buf.String())
4041 if err != nil {
4042 return err
4043 }
4044
4045 err = nw.BlankLine()
4046 if err != nil {
4047 return err
4048 }
4049
Colin Crossab6d7902015-03-11 16:17:52 -07004050 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004051 if err != nil {
4052 return err
4053 }
4054
4055 err = nw.BlankLine()
4056 if err != nil {
4057 return err
4058 }
4059 }
4060
4061 return nil
4062}
4063
4064func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
4065 headerTemplate := template.New("singletonHeader")
4066 _, err := headerTemplate.Parse(singletonHeaderTemplate)
4067 if err != nil {
4068 // This is a programming error.
4069 panic(err)
4070 }
4071
4072 buf := bytes.NewBuffer(nil)
4073
Yuchen Wub9103ef2015-08-25 17:58:17 -07004074 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07004075 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
4076 continue
4077 }
4078
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004079 // Get the name of the factory function for the module.
4080 factory := info.factory
4081 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
4082 factoryName := factoryFunc.Name()
4083
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004084 buf.Reset()
4085 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07004086 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004087 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004088 }
4089 err = headerTemplate.Execute(buf, infoMap)
4090 if err != nil {
4091 return err
4092 }
4093
4094 err = nw.Comment(buf.String())
4095 if err != nil {
4096 return err
4097 }
4098
4099 err = nw.BlankLine()
4100 if err != nil {
4101 return err
4102 }
4103
4104 err = c.writeLocalBuildActions(nw, &info.actionDefs)
4105 if err != nil {
4106 return err
4107 }
4108
4109 err = nw.BlankLine()
4110 if err != nil {
4111 return err
4112 }
4113 }
4114
4115 return nil
4116}
4117
Chris Parsons18ebb232022-03-25 00:56:02 -04004118func (c *Context) BeginEvent(name string) {
4119 c.EventHandler.Begin(name)
4120}
4121
4122func (c *Context) EndEvent(name string) {
4123 c.EventHandler.End(name)
4124}
4125
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004126func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
4127 defs *localBuildActions) error {
4128
4129 // Write the local variable assignments.
4130 for _, v := range defs.variables {
4131 // A localVariable doesn't need the package names or config to
4132 // determine its name or value.
4133 name := v.fullName(nil)
4134 value, err := v.value(nil)
4135 if err != nil {
4136 panic(err)
4137 }
4138 err = nw.Assign(name, value.Value(c.pkgNames))
4139 if err != nil {
4140 return err
4141 }
4142 }
4143
4144 if len(defs.variables) > 0 {
4145 err := nw.BlankLine()
4146 if err != nil {
4147 return err
4148 }
4149 }
4150
4151 // Write the local rules.
4152 for _, r := range defs.rules {
4153 // A localRule doesn't need the package names or config to determine
4154 // its name or definition.
4155 name := r.fullName(nil)
4156 def, err := r.def(nil)
4157 if err != nil {
4158 panic(err)
4159 }
4160
4161 err = def.WriteTo(nw, name, c.pkgNames)
4162 if err != nil {
4163 return err
4164 }
4165
4166 err = nw.BlankLine()
4167 if err != nil {
4168 return err
4169 }
4170 }
4171
4172 // Write the build definitions.
4173 for _, buildDef := range defs.buildDefs {
4174 err := buildDef.WriteTo(nw, c.pkgNames)
4175 if err != nil {
4176 return err
4177 }
4178
4179 if len(buildDef.Args) > 0 {
4180 err = nw.BlankLine()
4181 if err != nil {
4182 return err
4183 }
4184 }
4185 }
4186
4187 return nil
4188}
4189
Colin Cross5df74a82020-08-24 16:18:21 -07004190func beforeInModuleList(a, b *moduleInfo, list modulesOrAliases) bool {
Colin Cross65569e42015-03-10 20:08:19 -07004191 found := false
Colin Cross045a5972015-11-03 16:58:48 -08004192 if a == b {
4193 return false
4194 }
Colin Cross65569e42015-03-10 20:08:19 -07004195 for _, l := range list {
Colin Cross5df74a82020-08-24 16:18:21 -07004196 if l.module() == a {
Colin Cross65569e42015-03-10 20:08:19 -07004197 found = true
Colin Cross5df74a82020-08-24 16:18:21 -07004198 } else if l.module() == b {
Colin Cross65569e42015-03-10 20:08:19 -07004199 return found
4200 }
4201 }
4202
4203 missing := a
4204 if found {
4205 missing = b
4206 }
4207 panic(fmt.Errorf("element %v not found in list %v", missing, list))
4208}
4209
Colin Cross0aa6a5f2016-01-07 13:43:09 -08004210type panicError struct {
4211 panic interface{}
4212 stack []byte
4213 in string
4214}
4215
4216func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
4217 buf := make([]byte, 4096)
4218 count := runtime.Stack(buf, false)
4219 return panicError{
4220 panic: panic,
4221 in: fmt.Sprintf(in, a...),
4222 stack: buf[:count],
4223 }
4224}
4225
4226func (p panicError) Error() string {
4227 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
4228}
4229
4230func (p *panicError) addIn(in string) {
4231 p.in += " in " + in
4232}
4233
4234func funcName(f interface{}) string {
4235 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
4236}
4237
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004238var fileHeaderTemplate = `******************************************************************************
4239*** This file is generated and should not be edited ***
4240******************************************************************************
4241{{if .Pkgs}}
4242This file contains variables, rules, and pools with name prefixes indicating
4243they were generated by the following Go packages:
4244{{range .Pkgs}}
4245 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
4246
4247`
4248
4249var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07004250Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07004251Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004252Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004253Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004254Defined: {{.pos}}
4255`
4256
4257var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
4258Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004259Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004260`