blob: 64969486c93560e7575b666ce795c95358025c74 [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 Cross65569e42015-03-10 20:08:19 -070086 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087
Colin Cross3702ac72016-08-11 11:09:00 -070088 depsModified uint32 // positive if a mutator modified the dependencies
89
Jamie Gennis1bc967e2014-05-27 16:34:41 -070090 dependenciesReady bool // set to true on a successful ResolveDependencies
91 buildActionsReady bool // set to true on a successful PrepareBuildActions
92
93 // set by SetIgnoreUnknownModuleTypes
94 ignoreUnknownModuleTypes bool
95
Colin Cross036a1df2015-12-17 15:49:30 -080096 // set by SetAllowMissingDependencies
97 allowMissingDependencies bool
98
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -0800100 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -0800101 liveGlobals *liveTracker
Colin Cross2ce594e2020-01-29 12:58:03 -0800102 globalVariables map[Variable]ninjaString
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700103 globalPools map[Pool]*poolDef
104 globalRules map[Rule]*ruleDef
105
106 // set during PrepareBuildActions
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200107 outDir ninjaString // The builddir special Ninja variable
Colin Cross2ce594e2020-01-29 12:58:03 -0800108 requiredNinjaMajor int // For the ninja_required_version variable
109 requiredNinjaMinor int // For the ninja_required_version variable
110 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700111
Dan Willemsenab223a52018-07-05 21:56:59 -0700112 subninjas []string
113
Jeff Gastond70bf752017-11-10 15:12:08 -0800114 // set lazily by sortedModuleGroups
115 cachedSortedModuleGroups []*moduleGroup
Liz Kammer9ae14f12020-11-30 16:30:45 -0700116 // cache deps modified to determine whether cachedSortedModuleGroups needs to be recalculated
117 cachedDepsModified bool
Colin Crossd7b0f602016-06-02 15:30:20 -0700118
Colin Cross25236982021-04-05 17:20:34 -0700119 globs map[globKey]pathtools.GlobResult
Colin Cross127d2ea2016-11-01 11:10:51 -0700120 globLock sync.Mutex
121
Colin Crossc5fa50e2019-12-17 13:12:35 -0800122 srcDir string
Jeff Gastonc3e28442017-08-09 15:13:12 -0700123 fs pathtools.FileSystem
124 moduleListFile string
Colin Cross2da84922020-07-02 10:08:12 -0700125
126 // Mutators indexed by the ID of the provider associated with them. Not all mutators will
127 // have providers, and not all providers will have a mutator, or if they do the mutator may
128 // not be registered in this Context.
129 providerMutators []*mutatorInfo
130
131 // The currently running mutator
132 startedMutator *mutatorInfo
133 // True for any mutators that have already run over all modules
134 finishedMutators map[*mutatorInfo]bool
135
136 // Can be set by tests to avoid invalidating Module values after mutators.
137 skipCloneModulesAfterMutators bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700138}
139
Jamie Gennisd4e10182014-06-12 20:06:50 -0700140// An Error describes a problem that was encountered that is related to a
141// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700142type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700143 Err error // the error that occurred
144 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700145}
146
Colin Cross2c628442016-10-07 17:13:10 -0700147// A ModuleError describes a problem that was encountered that is related to a
148// particular module in a Blueprints file
149type ModuleError struct {
150 BlueprintError
151 module *moduleInfo
152}
153
154// A PropertyError describes a problem that was encountered that is related to a
155// particular property in a Blueprints file
156type PropertyError struct {
157 ModuleError
158 property string
159}
160
161func (e *BlueprintError) Error() string {
162 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
163}
164
165func (e *ModuleError) Error() string {
166 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
167}
168
169func (e *PropertyError) Error() string {
170 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
171}
172
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700173type localBuildActions struct {
174 variables []*localVariable
175 rules []*localRule
176 buildDefs []*buildDef
177}
178
Colin Crossf7beb892019-11-13 20:11:14 -0800179type moduleAlias struct {
Colin Crossedc41762020-08-13 12:07:30 -0700180 variant variant
181 target *moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800182}
183
Colin Cross5df74a82020-08-24 16:18:21 -0700184func (m *moduleAlias) alias() *moduleAlias { return m }
185func (m *moduleAlias) module() *moduleInfo { return nil }
186func (m *moduleAlias) moduleOrAliasTarget() *moduleInfo { return m.target }
187func (m *moduleAlias) moduleOrAliasVariant() variant { return m.variant }
188
189func (m *moduleInfo) alias() *moduleAlias { return nil }
190func (m *moduleInfo) module() *moduleInfo { return m }
191func (m *moduleInfo) moduleOrAliasTarget() *moduleInfo { return m }
192func (m *moduleInfo) moduleOrAliasVariant() variant { return m.variant }
193
194type moduleOrAlias interface {
195 alias() *moduleAlias
196 module() *moduleInfo
197 moduleOrAliasTarget() *moduleInfo
198 moduleOrAliasVariant() variant
199}
200
201type modulesOrAliases []moduleOrAlias
202
203func (l modulesOrAliases) firstModule() *moduleInfo {
204 for _, moduleOrAlias := range l {
205 if m := moduleOrAlias.module(); m != nil {
206 return m
207 }
208 }
209 panic(fmt.Errorf("no first module!"))
210}
211
212func (l modulesOrAliases) lastModule() *moduleInfo {
213 for i := range l {
214 if m := l[len(l)-1-i].module(); m != nil {
215 return m
216 }
217 }
218 panic(fmt.Errorf("no last module!"))
219}
220
Colin Crossbbfa51a2014-12-17 16:12:41 -0800221type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700222 name string
223 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700224
Colin Cross5df74a82020-08-24 16:18:21 -0700225 modules modulesOrAliases
Jeff Gastond70bf752017-11-10 15:12:08 -0800226
227 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700228}
229
Colin Cross5df74a82020-08-24 16:18:21 -0700230func (group *moduleGroup) moduleOrAliasByVariantName(name string) moduleOrAlias {
231 for _, module := range group.modules {
232 if module.moduleOrAliasVariant().name == name {
233 return module
234 }
235 }
236 return nil
237}
238
239func (group *moduleGroup) moduleByVariantName(name string) *moduleInfo {
240 return group.moduleOrAliasByVariantName(name).module()
241}
242
Colin Crossbbfa51a2014-12-17 16:12:41 -0800243type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700244 // set during Parse
245 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700246 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700247 relBlueprintsFile string
248 pos scanner.Position
249 propertyPos map[string]scanner.Position
Colin Cross322cc012019-05-20 13:55:14 -0700250 createdBy *moduleInfo
Colin Crossed342d92015-03-11 00:57:25 -0700251
Colin Crossedc41762020-08-13 12:07:30 -0700252 variant variant
Colin Crosse7daa222015-03-11 14:35:41 -0700253
Colin Crossd2f4ac12017-07-28 14:31:03 -0700254 logicModule Module
255 group *moduleGroup
256 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800257
258 // set during ResolveDependencies
Colin Cross99bdb2a2019-03-29 16:35:02 -0700259 missingDeps []string
260 newDirectDeps []depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800261
Colin Cross7addea32015-03-11 15:43:52 -0700262 // set during updateDependencies
263 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700264 forwardDeps []*moduleInfo
Colin Cross99bdb2a2019-03-29 16:35:02 -0700265 directDeps []depInfo
Colin Cross7addea32015-03-11 15:43:52 -0700266
Colin Crossc4773d92020-08-25 17:12:59 -0700267 // used by parallelVisit
Colin Cross7addea32015-03-11 15:43:52 -0700268 waitingCount int
269
Colin Crossc9028482014-12-18 16:28:54 -0800270 // set during each runMutator
Colin Cross5df74a82020-08-24 16:18:21 -0700271 splitModules modulesOrAliases
Colin Crossab6d7902015-03-11 16:17:52 -0700272
273 // set during PrepareBuildActions
274 actionDefs localBuildActions
Colin Cross2da84922020-07-02 10:08:12 -0700275
276 providers []interface{}
277
278 startedMutator *mutatorInfo
279 finishedMutator *mutatorInfo
280
281 startedGenerateBuildActions bool
282 finishedGenerateBuildActions bool
Colin Crossc9028482014-12-18 16:28:54 -0800283}
284
Colin Crossedc41762020-08-13 12:07:30 -0700285type variant struct {
286 name string
287 variations variationMap
288 dependencyVariations variationMap
289}
290
Colin Cross2c1f3d12016-04-11 15:47:28 -0700291type depInfo struct {
292 module *moduleInfo
293 tag DependencyTag
294}
295
Colin Cross0b7e83e2016-05-17 14:58:05 -0700296func (module *moduleInfo) Name() string {
Paul Duffin244033b2020-05-04 11:00:03 +0100297 // If this is called from a LoadHook (which is run before the module has been registered)
298 // then group will not be set and so the name is retrieved from logicModule.Name().
299 // Usually, using that method is not safe as it does not track renames (group.name does).
300 // However, when called from LoadHook it is safe as there is no way to rename a module
301 // until after the LoadHook has run and the module has been registered.
302 if module.group != nil {
303 return module.group.name
304 } else {
305 return module.logicModule.Name()
306 }
Colin Cross0b7e83e2016-05-17 14:58:05 -0700307}
308
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800309func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700310 s := fmt.Sprintf("module %q", module.Name())
Colin Crossedc41762020-08-13 12:07:30 -0700311 if module.variant.name != "" {
312 s += fmt.Sprintf(" variant %q", module.variant.name)
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800313 }
Colin Cross322cc012019-05-20 13:55:14 -0700314 if module.createdBy != nil {
315 s += fmt.Sprintf(" (created by %s)", module.createdBy)
316 }
317
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800318 return s
319}
320
Jeff Gastond70bf752017-11-10 15:12:08 -0800321func (module *moduleInfo) namespace() Namespace {
322 return module.group.namespace
323}
324
Colin Crossf5e34b92015-03-13 16:02:36 -0700325// A Variation is a way that a variant of a module differs from other variants of the same module.
326// For example, two variants of the same module might have Variation{"arch","arm"} and
327// Variation{"arch","arm64"}
328type Variation struct {
329 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700330 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700331 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
332 // "shared" or "static" for link.
333 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700334}
335
Colin Crossf5e34b92015-03-13 16:02:36 -0700336// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
337type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700338
Colin Crossf5e34b92015-03-13 16:02:36 -0700339func (vm variationMap) clone() variationMap {
Colin Cross9403b5a2019-11-13 20:11:04 -0800340 if vm == nil {
341 return nil
342 }
Colin Crossf5e34b92015-03-13 16:02:36 -0700343 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700344 for k, v := range vm {
345 newVm[k] = v
346 }
347
348 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800349}
350
Colin Cross89486232015-05-08 11:14:54 -0700351// Compare this variationMap to another one. Returns true if the every entry in this map
Colin Cross5dc67592020-08-24 14:46:13 -0700352// exists and has the same value in the other map.
353func (vm variationMap) subsetOf(other variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -0700354 for k, v1 := range vm {
Colin Cross5dc67592020-08-24 14:46:13 -0700355 if v2, ok := other[k]; !ok || v1 != v2 {
Colin Cross89486232015-05-08 11:14:54 -0700356 return false
357 }
358 }
359 return true
360}
361
Colin Crossf5e34b92015-03-13 16:02:36 -0700362func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700363 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800364}
365
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700366type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700367 // set during RegisterSingletonType
368 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700369 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700370 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700371
372 // set during PrepareBuildActions
373 actionDefs localBuildActions
374}
375
Colin Crossc9028482014-12-18 16:28:54 -0800376type mutatorInfo struct {
377 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800378 topDownMutator TopDownMutator
379 bottomUpMutator BottomUpMutator
380 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700381 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800382}
383
Colin Crossaf4fd212017-07-28 14:32:36 -0700384func newContext() *Context {
Chris Parsons18ebb232022-03-25 00:56:02 -0400385 eventHandler := metrics.EventHandler{}
Colin Crossaf4fd212017-07-28 14:32:36 -0700386 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800387 Context: context.Background(),
Chris Parsons18ebb232022-03-25 00:56:02 -0400388 EventHandler: &eventHandler,
Colin Cross5f03f112017-11-07 13:29:54 -0800389 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800390 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800391 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross25236982021-04-05 17:20:34 -0700392 globs: make(map[globKey]pathtools.GlobResult),
Colin Cross5f03f112017-11-07 13:29:54 -0800393 fs: pathtools.OsFs,
Colin Cross2da84922020-07-02 10:08:12 -0700394 finishedMutators: make(map[*mutatorInfo]bool),
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +0200395 outDir: nil,
Colin Cross5f03f112017-11-07 13:29:54 -0800396 requiredNinjaMajor: 1,
397 requiredNinjaMinor: 7,
398 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700399 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700400}
401
402// NewContext creates a new Context object. The created context initially has
403// no module or singleton factories registered, so the RegisterModuleFactory and
404// RegisterSingletonFactory methods must be called before it can do anything
405// useful.
406func NewContext() *Context {
407 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700408
409 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
410
411 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700412}
413
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700414// A ModuleFactory function creates a new Module object. See the
415// Context.RegisterModuleType method for details about how a registered
416// ModuleFactory is used by a Context.
417type ModuleFactory func() (m Module, propertyStructs []interface{})
418
Jamie Gennisd4e10182014-06-12 20:06:50 -0700419// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700420// Blueprints file) with a Module factory function. When the given module type
421// name is encountered in a Blueprints file during parsing, the Module factory
422// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800423// generation for the module. If a Mutator splits a module into multiple variants,
424// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700425//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700426// The module type names given here must be unique for the context. The factory
427// function should be a named function so that its package and name can be
428// included in the generated Ninja file for debugging purposes.
429//
430// The factory function returns two values. The first is the newly created
431// Module object. The second is a slice of pointers to that Module object's
432// properties structs. Each properties struct is examined when parsing a module
433// definition of this type in a Blueprints file. Exported fields of the
434// properties structs are automatically set to the property values specified in
435// the Blueprints file. The properties struct field names determine the name of
436// the Blueprints file properties that are used - the Blueprints property name
437// matches that of the properties struct field name with the first letter
438// converted to lower-case.
439//
440// The fields of the properties struct must be either []string, a string, or
441// bool. The Context will panic if a Module gets instantiated with a properties
442// struct containing a field that is not one these supported types.
443//
444// Any properties that appear in the Blueprints files that are not built-in
445// module properties (such as "name" and "deps") and do not have a corresponding
446// field in the returned module properties struct result in an error during the
447// Context's parse phase.
448//
449// As an example, the follow code:
450//
451// type myModule struct {
452// properties struct {
453// Foo string
454// Bar []string
455// }
456// }
457//
458// func NewMyModule() (blueprint.Module, []interface{}) {
459// module := new(myModule)
460// properties := &module.properties
461// return module, []interface{}{properties}
462// }
463//
464// func main() {
465// ctx := blueprint.NewContext()
466// ctx.RegisterModuleType("my_module", NewMyModule)
467// // ...
468// }
469//
470// would support parsing a module defined in a Blueprints file as follows:
471//
472// my_module {
473// name: "myName",
474// foo: "my foo string",
475// bar: ["my", "bar", "strings"],
476// }
477//
Colin Cross7ad621c2015-01-07 16:22:45 -0800478// The factory function may be called from multiple goroutines. Any accesses
479// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700480func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
481 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700482 panic(errors.New("module type name is already registered"))
483 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700484 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700485}
486
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700487// A SingletonFactory function creates a new Singleton object. See the
488// Context.RegisterSingletonType method for details about how a registered
489// SingletonFactory is used by a Context.
490type SingletonFactory func() Singleton
491
492// RegisterSingletonType registers a singleton type that will be invoked to
Usta Shresthaee7a5d72022-01-10 22:46:23 -0500493// generate build actions. Each registered singleton type is instantiated
Yuchen Wub9103ef2015-08-25 17:58:17 -0700494// and invoked exactly once as part of the generate phase. Each registered
495// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700496//
497// The singleton type names given here must be unique for the context. The
498// factory function should be a named function so that its package and name can
499// be included in the generated Ninja file for debugging purposes.
500func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700501 for _, s := range c.singletonInfo {
502 if s.name == name {
503 panic(errors.New("singleton name is already registered"))
504 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700505 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700506
Yuchen Wub9103ef2015-08-25 17:58:17 -0700507 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700508 factory: factory,
509 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700510 name: name,
511 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700512}
513
Colin Cross5f03f112017-11-07 13:29:54 -0800514// RegisterPreSingletonType registers a presingleton type that will be invoked to
515// generate build actions before any Blueprint files have been read. Each registered
516// presingleton type is instantiated and invoked exactly once at the beginning of the
517// parse phase. Each registered presingleton is invoked in registration order.
518//
519// The presingleton type names given here must be unique for the context. The
520// factory function should be a named function so that its package and name can
521// be included in the generated Ninja file for debugging purposes.
522func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
523 for _, s := range c.preSingletonInfo {
524 if s.name == name {
525 panic(errors.New("presingleton name is already registered"))
526 }
527 }
528
529 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
530 factory: factory,
531 singleton: factory(),
532 name: name,
533 })
534}
535
Jeff Gastond70bf752017-11-10 15:12:08 -0800536func (c *Context) SetNameInterface(i NameInterface) {
537 c.nameInterface = i
538}
539
Colin Crossc5fa50e2019-12-17 13:12:35 -0800540func (c *Context) SetSrcDir(path string) {
541 c.srcDir = path
542 c.fs = pathtools.NewOsFs(path)
543}
544
545func (c *Context) SrcDir() string {
546 return c.srcDir
547}
548
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700549func singletonPkgPath(singleton Singleton) string {
550 typ := reflect.TypeOf(singleton)
551 for typ.Kind() == reflect.Ptr {
552 typ = typ.Elem()
553 }
554 return typ.PkgPath()
555}
556
557func singletonTypeName(singleton Singleton) string {
558 typ := reflect.TypeOf(singleton)
559 for typ.Kind() == reflect.Ptr {
560 typ = typ.Elem()
561 }
562 return typ.PkgPath() + "." + typ.Name()
563}
564
Colin Cross3702ac72016-08-11 11:09:00 -0700565// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
566// top-down between Modules. Each registered mutator is invoked in registration order (mixing
567// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
568// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800569//
Colin Cross65569e42015-03-10 20:08:19 -0700570// The mutator type names given here must be unique to all top down mutators in
571// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700572//
573// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
574// parallel while maintaining ordering.
575func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800576 for _, m := range c.mutatorInfo {
577 if m.name == name && m.topDownMutator != nil {
578 panic(fmt.Errorf("mutator name %s is already registered", name))
579 }
580 }
581
Colin Cross3702ac72016-08-11 11:09:00 -0700582 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800583 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800584 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700585 }
586
587 c.mutatorInfo = append(c.mutatorInfo, info)
588
589 return info
Colin Crossc9028482014-12-18 16:28:54 -0800590}
591
Colin Cross3702ac72016-08-11 11:09:00 -0700592// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
593// Each registered mutator is invoked in registration order (mixing TopDownMutators and
594// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
595// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800596//
Colin Cross65569e42015-03-10 20:08:19 -0700597// The mutator type names given here must be unique to all bottom up or early
598// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700599//
Colin Cross3702ac72016-08-11 11:09:00 -0700600// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
601// parallel while maintaining ordering.
602func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700603 for _, m := range c.variantMutatorNames {
604 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800605 panic(fmt.Errorf("mutator name %s is already registered", name))
606 }
607 }
608
Colin Cross49c279a2016-08-05 22:30:44 -0700609 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800610 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800611 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700612 }
613 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700614
615 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700616
617 return info
618}
619
Colin Cross3702ac72016-08-11 11:09:00 -0700620type MutatorHandle interface {
621 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
622 // method on the mutator context is thread-safe, but the mutator must handle synchronization
623 // for any modifications to global state or any modules outside the one it was invoked on.
624 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700625}
626
Colin Cross3702ac72016-08-11 11:09:00 -0700627func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700628 mutator.parallel = true
629 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700630}
631
Jamie Gennisd4e10182014-06-12 20:06:50 -0700632// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
633// where it encounters an unknown module type while parsing Blueprints files. By
634// default, the context will report unknown module types as an error. If this
635// method is called with ignoreUnknownModuleTypes set to true then the context
636// will silently ignore unknown module types.
637//
638// This method should generally not be used. It exists to facilitate the
639// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700640func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
641 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
642}
643
Colin Cross036a1df2015-12-17 15:49:30 -0800644// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
645// unresolved dependencies. If the module's GenerateBuildActions calls
646// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
647// for missing dependencies.
648func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
649 c.allowMissingDependencies = allowMissingDependencies
650}
651
Jeff Gastonc3e28442017-08-09 15:13:12 -0700652func (c *Context) SetModuleListFile(listFile string) {
653 c.moduleListFile = listFile
654}
655
656func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
657 reader, err := c.fs.Open(c.moduleListFile)
658 if err != nil {
659 return nil, err
660 }
Liz Kammer6e7e6a92022-02-07 10:03:19 -0500661 defer reader.Close()
Jeff Gastonc3e28442017-08-09 15:13:12 -0700662 bytes, err := ioutil.ReadAll(reader)
663 if err != nil {
664 return nil, err
665 }
666 text := string(bytes)
667
668 text = strings.Trim(text, "\n")
669 lines := strings.Split(text, "\n")
670 for i := range lines {
671 lines[i] = filepath.Join(baseDir, lines[i])
672 }
673
674 return lines, nil
675}
676
Jeff Gaston656870f2017-11-29 18:37:31 -0800677// a fileParseContext tells the status of parsing a particular file
678type fileParseContext struct {
679 // name of file
680 fileName string
681
682 // scope to use when resolving variables
683 Scope *parser.Scope
684
685 // pointer to the one in the parent directory
686 parent *fileParseContext
687
688 // is closed once FileHandler has completed for this file
689 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700690}
691
Jamie Gennisd4e10182014-06-12 20:06:50 -0700692// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
693// at rootFile. When it encounters a Blueprints file with a set of subdirs
694// listed it recursively parses any Blueprints files found in those
695// subdirectories.
696//
697// If no errors are encountered while parsing the files, the list of paths on
698// which the future output will depend is returned. This list will include both
699// Blueprints file paths as well as directory paths for cases where wildcard
700// subdirs are found.
Colin Crossda70fd02019-12-30 18:40:09 -0800701func (c *Context) ParseBlueprintsFiles(rootFile string,
702 config interface{}) (deps []string, errs []error) {
703
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800704 baseDir := filepath.Dir(rootFile)
705 pathsToParse, err := c.ListModulePaths(baseDir)
706 if err != nil {
707 return nil, []error{err}
708 }
Colin Crossda70fd02019-12-30 18:40:09 -0800709 return c.ParseFileList(baseDir, pathsToParse, config)
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800710}
711
Colin Crossda70fd02019-12-30 18:40:09 -0800712func (c *Context) ParseFileList(rootDir string, filePaths []string,
713 config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700714
Jeff Gastonc3e28442017-08-09 15:13:12 -0700715 if len(filePaths) < 1 {
716 return nil, []error{fmt.Errorf("no paths provided to parse")}
717 }
718
Colin Cross7ad621c2015-01-07 16:22:45 -0800719 c.dependenciesReady = false
720
Colin Crossda70fd02019-12-30 18:40:09 -0800721 type newModuleInfo struct {
722 *moduleInfo
Colin Cross13b5bef2021-05-19 10:07:19 -0700723 deps []string
Colin Crossda70fd02019-12-30 18:40:09 -0800724 added chan<- struct{}
725 }
726
727 moduleCh := make(chan newModuleInfo)
Colin Cross23d7aa12015-06-30 16:05:22 -0700728 errsCh := make(chan []error)
729 doneCh := make(chan struct{})
730 var numErrs uint32
731 var numGoroutines int32
732
733 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700734 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700735 if atomic.LoadUint32(&numErrs) > maxErrors {
736 return
737 }
738
Colin Crossda70fd02019-12-30 18:40:09 -0800739 addedCh := make(chan struct{})
740
Colin Cross9672d862019-12-30 18:38:20 -0800741 var scopedModuleFactories map[string]ModuleFactory
742
Colin Crossda70fd02019-12-30 18:40:09 -0800743 var addModule func(module *moduleInfo) []error
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100744 addModule = func(module *moduleInfo) []error {
Paul Duffin244033b2020-05-04 11:00:03 +0100745 // Run any load hooks immediately before it is sent to the moduleCh and is
746 // registered by name. This allows load hooks to set and/or modify any aspect
747 // of the module (including names) using information that is not available when
748 // the module factory is called.
Colin Cross13b5bef2021-05-19 10:07:19 -0700749 newModules, newDeps, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
Colin Crossda70fd02019-12-30 18:40:09 -0800750 if len(errs) > 0 {
751 return errs
752 }
Paul Duffin244033b2020-05-04 11:00:03 +0100753
Colin Cross13b5bef2021-05-19 10:07:19 -0700754 moduleCh <- newModuleInfo{module, newDeps, addedCh}
Paul Duffin244033b2020-05-04 11:00:03 +0100755 <-addedCh
Colin Crossda70fd02019-12-30 18:40:09 -0800756 for _, n := range newModules {
757 errs = addModule(n)
758 if len(errs) > 0 {
759 return errs
760 }
761 }
762 return nil
763 }
764
Jeff Gaston656870f2017-11-29 18:37:31 -0800765 for _, def := range file.Defs {
Jeff Gaston656870f2017-11-29 18:37:31 -0800766 switch def := def.(type) {
767 case *parser.Module:
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100768 module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes)
Colin Crossda70fd02019-12-30 18:40:09 -0800769 if len(errs) == 0 && module != nil {
770 errs = addModule(module)
771 }
772
773 if len(errs) > 0 {
774 atomic.AddUint32(&numErrs, uint32(len(errs)))
775 errsCh <- errs
776 }
777
Jeff Gaston656870f2017-11-29 18:37:31 -0800778 case *parser.Assignment:
779 // Already handled via Scope object
780 default:
781 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700782 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800783
Jeff Gaston656870f2017-11-29 18:37:31 -0800784 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700785 }
786
787 atomic.AddInt32(&numGoroutines, 1)
788 go func() {
789 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700790 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700791 if len(errs) > 0 {
792 errsCh <- errs
793 }
794 doneCh <- struct{}{}
795 }()
796
Colin Cross13b5bef2021-05-19 10:07:19 -0700797 var hookDeps []string
Colin Cross23d7aa12015-06-30 16:05:22 -0700798loop:
799 for {
800 select {
801 case newErrs := <-errsCh:
802 errs = append(errs, newErrs...)
803 case module := <-moduleCh:
Colin Crossda70fd02019-12-30 18:40:09 -0800804 newErrs := c.addModule(module.moduleInfo)
Colin Cross13b5bef2021-05-19 10:07:19 -0700805 hookDeps = append(hookDeps, module.deps...)
Colin Crossda70fd02019-12-30 18:40:09 -0800806 if module.added != nil {
807 module.added <- struct{}{}
808 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700809 if len(newErrs) > 0 {
810 errs = append(errs, newErrs...)
811 }
812 case <-doneCh:
813 n := atomic.AddInt32(&numGoroutines, -1)
814 if n == 0 {
815 break loop
816 }
817 }
818 }
819
Colin Cross13b5bef2021-05-19 10:07:19 -0700820 deps = append(deps, hookDeps...)
Colin Cross23d7aa12015-06-30 16:05:22 -0700821 return deps, errs
822}
823
824type FileHandler func(*parser.File)
825
Jeff Gastonc3e28442017-08-09 15:13:12 -0700826// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
827// calling the given file handler on each
828//
829// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
830// it recursively parses any Blueprints files found in those subdirectories.
831//
832// If any of the file paths is an ancestor directory of any other of file path, the ancestor
833// will be parsed and visited first.
834//
835// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700836//
837// If no errors are encountered while parsing the files, the list of paths on
838// which the future output will depend is returned. This list will include both
839// Blueprints file paths as well as directory paths for cases where wildcard
840// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800841//
842// visitor will be called asynchronously, and will only be called once visitor for each
843// ancestor directory has completed.
844//
845// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700846func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
847 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700848
Jeff Gastonc3e28442017-08-09 15:13:12 -0700849 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
850 descendantsMap, err := findBlueprintDescendants(filePaths)
851 if err != nil {
852 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700853 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800854 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700855
Jeff Gaston5800d042017-12-05 14:57:58 -0800856 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800857 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800858 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800859 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700860
Jeff Gaston5800d042017-12-05 14:57:58 -0800861 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800862 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700863
Colin Cross7ad621c2015-01-07 16:22:45 -0800864 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700865 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800866 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700867 tooManyErrors := false
868
869 // Limit concurrent calls to parseBlueprintFiles to 200
870 // Darwin has a default limit of 256 open files
871 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800872
Jeff Gaston656870f2017-11-29 18:37:31 -0800873 // count the number of pending calls to visitor()
874 visitorWaitGroup := sync.WaitGroup{}
875
876 startParseBlueprintsFile := func(blueprint fileParseContext) {
877 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700878 return
879 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800880 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700881 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800882 deps = append(deps, blueprint.fileName)
883 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800884 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800885 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
886 &blueprint)
887 if len(errs) > 0 {
888 errsCh <- errs
889 }
890 for _, blueprint := range blueprints {
891 blueprintsCh <- blueprint
892 }
893 for _, dep := range deps {
894 depsCh <- dep
895 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800896 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700897
Jeff Gaston656870f2017-11-29 18:37:31 -0800898 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
899 // wait for visitor() of parent to complete
900 <-blueprint.parent.doneVisiting
901 }
902
Jeff Gastona7e408a2017-12-05 15:11:55 -0800903 if len(errs) == 0 {
904 // process this file
905 visitor(file)
906 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800907 if blueprint.doneVisiting != nil {
908 close(blueprint.doneVisiting)
909 }
910 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800911 }()
912 }
913
Jeff Gaston656870f2017-11-29 18:37:31 -0800914 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700915 if activeCount >= maxActiveCount {
916 pending = append(pending, blueprint)
917 } else {
918 startParseBlueprintsFile(blueprint)
919 }
920 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800921
Jeff Gaston656870f2017-11-29 18:37:31 -0800922 startParseDescendants := func(blueprint fileParseContext) {
923 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700924 if hasDescendants {
925 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800926 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700927 }
928 }
929 }
Colin Cross4a02a302017-05-16 10:33:58 -0700930
Jeff Gastonc3e28442017-08-09 15:13:12 -0700931 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800932 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800933
934loop:
935 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700936 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800937 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700938 }
939
Colin Cross7ad621c2015-01-07 16:22:45 -0800940 select {
941 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700942 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800943 case dep := <-depsCh:
944 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800945 case blueprint := <-blueprintsCh:
946 if tooManyErrors {
947 continue
948 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700949 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800950 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700951 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700952 if !tooManyErrors {
953 startParseDescendants(blueprint)
954 }
955 if activeCount < maxActiveCount && len(pending) > 0 {
956 // start to process the next one from the queue
957 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700958 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700959 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700960 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700961 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800962 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700963 }
964 }
965 }
966
Jeff Gastonc3e28442017-08-09 15:13:12 -0700967 sort.Strings(deps)
968
Jeff Gaston656870f2017-11-29 18:37:31 -0800969 // wait for every visitor() to complete
970 visitorWaitGroup.Wait()
971
Colin Cross7ad621c2015-01-07 16:22:45 -0800972 return
973}
974
Colin Crossd7b0f602016-06-02 15:30:20 -0700975// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
976// filenames to contents stored as a byte slice.
977func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800978 // look for a module list file
979 _, ok := files[MockModuleListFile]
980 if !ok {
981 // no module list file specified; find every file named Blueprints
982 pathsToParse := []string{}
983 for candidate := range files {
Lukacs T. Berkieef56852021-09-02 11:34:06 +0200984 if filepath.Base(candidate) == "Android.bp" {
Jeff Gaston9f630902017-11-15 14:49:48 -0800985 pathsToParse = append(pathsToParse, candidate)
986 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700987 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800988 if len(pathsToParse) < 1 {
989 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
990 }
991 // put the list of Blueprints files into a list file
992 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700993 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800994 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700995
996 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800997 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700998}
999
Colin Cross8cde4252019-12-17 13:11:21 -08001000func (c *Context) SetFs(fs pathtools.FileSystem) {
1001 c.fs = fs
1002}
1003
Jeff Gaston8fd95782017-12-05 15:03:51 -08001004// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -08001005func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -08001006 parent *fileParseContext) (file *parser.File,
1007 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -08001008
Colin Crossd7b0f602016-06-02 15:30:20 -07001009 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -08001010 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -07001011 // couldn't open the file; see if we can provide a clearer error than "could not open file"
1012 stats, statErr := c.fs.Lstat(filename)
1013 if statErr == nil {
1014 isSymlink := stats.Mode()&os.ModeSymlink != 0
1015 if isSymlink {
1016 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
1017 target, readlinkErr := os.Readlink(filename)
1018 if readlinkErr == nil {
1019 _, targetStatsErr := c.fs.Lstat(target)
1020 if targetStatsErr != nil {
1021 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
1022 }
1023 }
1024 } else {
1025 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
1026 }
1027 }
Jeff Gaston8fd95782017-12-05 15:03:51 -08001028 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001029 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001030
Jeff Gaston8fd95782017-12-05 15:03:51 -08001031 func() {
1032 defer func() {
1033 err = f.Close()
1034 if err != nil {
1035 errs = append(errs, err)
1036 }
1037 }()
1038 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -07001039 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001040
Colin Cross7ad621c2015-01-07 16:22:45 -08001041 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001042 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -08001043 }
1044
Colin Cross1fef5362015-04-20 16:50:54 -07001045 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -08001046 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -07001047 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001048
Jeff Gaston8fd95782017-12-05 15:03:51 -08001049 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -07001050}
1051
Jeff Gastona12f22f2017-08-08 14:45:56 -07001052// parseOne parses a single Blueprints file from the given reader, creating Module
1053// objects for each of the module definitions encountered. If the Blueprints
1054// file contains an assignment to the "subdirs" variable, then the
1055// subdirectories listed are searched for Blueprints files returned in the
1056// subBlueprints return value. If the Blueprints file contains an assignment
1057// to the "build" variable, then the file listed are returned in the
1058// subBlueprints return value.
1059//
1060// rootDir specifies the path to the root directory of the source tree, while
1061// filename specifies the path to the Blueprints file. These paths are used for
1062// error reporting and for determining the module's directory.
1063func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -08001064 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -07001065
1066 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
1067 if err != nil {
1068 return nil, nil, []error{err}
1069 }
1070
Jeff Gastona12f22f2017-08-08 14:45:56 -07001071 scope.Remove("subdirs")
1072 scope.Remove("optional_subdirs")
1073 scope.Remove("build")
1074 file, errs = parser.ParseAndEval(filename, reader, scope)
1075 if len(errs) > 0 {
1076 for i, err := range errs {
1077 if parseErr, ok := err.(*parser.ParseError); ok {
1078 err = &BlueprintError{
1079 Err: parseErr.Err,
1080 Pos: parseErr.Pos,
1081 }
1082 errs[i] = err
1083 }
1084 }
1085
1086 // If there were any parse errors don't bother trying to interpret the
1087 // result.
1088 return nil, nil, errs
1089 }
1090 file.Name = relBlueprintsFile
1091
Jeff Gastona12f22f2017-08-08 14:45:56 -07001092 build, buildPos, err := getLocalStringListFromScope(scope, "build")
1093 if err != nil {
1094 errs = append(errs, err)
1095 }
Jeff Gastonf23e3662017-11-30 17:31:43 -08001096 for _, buildEntry := range build {
1097 if strings.Contains(buildEntry, "/") {
1098 errs = append(errs, &BlueprintError{
1099 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1100 Pos: buildPos,
1101 })
1102 }
1103 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001104
Jeff Gastona12f22f2017-08-08 14:45:56 -07001105 if err != nil {
1106 errs = append(errs, err)
1107 }
1108
Jeff Gastona12f22f2017-08-08 14:45:56 -07001109 var blueprints []string
1110
1111 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1112 blueprints = append(blueprints, newBlueprints...)
1113 errs = append(errs, newErrs...)
1114
Jeff Gaston656870f2017-11-29 18:37:31 -08001115 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -07001116 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -08001117 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -07001118 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001119 return file, subBlueprintsAndScope, errs
1120}
1121
Colin Cross7f507402015-12-16 13:03:41 -08001122func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -07001123 buildPos scanner.Position) ([]string, []error) {
1124
1125 var blueprints []string
1126 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001127
1128 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001129 pattern := filepath.Join(dir, file)
1130 var matches []string
1131 var err error
1132
Colin Cross08e49542016-11-14 15:23:33 -08001133 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001134
Colin Cross7f507402015-12-16 13:03:41 -08001135 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001136 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001137 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001138 Pos: buildPos,
1139 })
1140 continue
1141 }
1142
1143 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001144 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001145 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001146 Pos: buildPos,
1147 })
1148 }
1149
Colin Cross7f507402015-12-16 13:03:41 -08001150 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001151 if strings.HasSuffix(foundBlueprints, "/") {
1152 errs = append(errs, &BlueprintError{
1153 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1154 Pos: buildPos,
1155 })
1156 }
Colin Cross7f507402015-12-16 13:03:41 -08001157 blueprints = append(blueprints, foundBlueprints)
1158 }
1159 }
1160
Colin Cross127d2ea2016-11-01 11:10:51 -07001161 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001162}
1163
1164func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001165 subBlueprintsName string, optional bool) ([]string, []error) {
1166
1167 var blueprints []string
1168 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001169
1170 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001171 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1172 var matches []string
1173 var err error
1174
Colin Cross08e49542016-11-14 15:23:33 -08001175 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001176
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001177 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001178 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001179 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001180 Pos: subdirsPos,
1181 })
1182 continue
1183 }
1184
Colin Cross7f507402015-12-16 13:03:41 -08001185 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001186 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001187 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001188 Pos: subdirsPos,
1189 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001190 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001191
Colin Cross127d2ea2016-11-01 11:10:51 -07001192 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001193 if strings.HasSuffix(subBlueprints, "/") {
1194 errs = append(errs, &BlueprintError{
1195 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1196 Pos: subdirsPos,
1197 })
1198 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001199 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001200 }
1201 }
Colin Cross1fef5362015-04-20 16:50:54 -07001202
Colin Cross127d2ea2016-11-01 11:10:51 -07001203 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001204}
1205
Colin Cross6d8780f2015-07-10 17:51:55 -07001206func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1207 if assignment, local := scope.Get(v); assignment == nil || !local {
1208 return nil, scanner.Position{}, nil
1209 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001210 switch value := assignment.Value.Eval().(type) {
1211 case *parser.List:
1212 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001213
Colin Crosse32cc802016-06-07 12:28:16 -07001214 for _, listValue := range value.Values {
1215 s, ok := listValue.(*parser.String)
1216 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001217 // The parser should not produce this.
1218 panic("non-string value found in list")
1219 }
1220
Colin Crosse32cc802016-06-07 12:28:16 -07001221 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001222 }
1223
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001224 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001225 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001226 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001227 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001228 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001229 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001230 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001231 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001232 }
1233 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001234}
1235
Colin Cross29394222015-04-27 13:18:21 -07001236func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001237 if assignment, _ := scope.Get(v); assignment == nil {
1238 return "", scanner.Position{}, nil
1239 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001240 switch value := assignment.Value.Eval().(type) {
1241 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001242 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001243 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001244 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001245 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001246 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001247 }
1248 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001249 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001250 }
1251 }
Colin Cross29394222015-04-27 13:18:21 -07001252}
1253
Colin Cross910242b2016-04-11 15:41:52 -07001254// Clones a build logic module by calling the factory method for its module type, and then cloning
1255// property values. Any values stored in the module object that are not stored in properties
1256// structs will be lost.
1257func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001258 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001259
Colin Crossd2f4ac12017-07-28 14:31:03 -07001260 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001261 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001262 }
1263
1264 for i := range newProperties {
Colin Cross5d57b2d2020-01-27 16:14:31 -08001265 dst := reflect.ValueOf(newProperties[i])
1266 src := reflect.ValueOf(origModule.properties[i])
Colin Cross910242b2016-04-11 15:41:52 -07001267
1268 proptools.CopyProperties(dst, src)
1269 }
1270
1271 return newLogicModule, newProperties
1272}
1273
Colin Crossedc41762020-08-13 12:07:30 -07001274func newVariant(module *moduleInfo, mutatorName string, variationName string,
1275 local bool) variant {
1276
1277 newVariantName := module.variant.name
1278 if variationName != "" {
1279 if newVariantName == "" {
1280 newVariantName = variationName
1281 } else {
1282 newVariantName += "_" + variationName
1283 }
1284 }
1285
1286 newVariations := module.variant.variations.clone()
1287 if newVariations == nil {
1288 newVariations = make(variationMap)
1289 }
1290 newVariations[mutatorName] = variationName
1291
1292 newDependencyVariations := module.variant.dependencyVariations.clone()
1293 if !local {
1294 if newDependencyVariations == nil {
1295 newDependencyVariations = make(variationMap)
1296 }
1297 newDependencyVariations[mutatorName] = variationName
1298 }
1299
1300 return variant{newVariantName, newVariations, newDependencyVariations}
1301}
1302
Colin Crossf5e34b92015-03-13 16:02:36 -07001303func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
Colin Cross5df74a82020-08-24 16:18:21 -07001304 defaultVariationName *string, variationNames []string, local bool) (modulesOrAliases, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001305
Colin Crossf4d18a62015-03-18 17:43:15 -07001306 if len(variationNames) == 0 {
1307 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001308 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001309 }
1310
Colin Cross5df74a82020-08-24 16:18:21 -07001311 var newModules modulesOrAliases
Colin Crossc9028482014-12-18 16:28:54 -08001312
Colin Cross174ae052015-03-03 17:37:03 -08001313 var errs []error
1314
Colin Crossf5e34b92015-03-13 16:02:36 -07001315 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001316 var newLogicModule Module
1317 var newProperties []interface{}
1318
1319 if i == 0 {
1320 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001321 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1322 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001323 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001324 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001325 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001326 }
1327
Colin Crossed342d92015-03-11 00:57:25 -07001328 m := *origModule
1329 newModule := &m
Colin Cross2da84922020-07-02 10:08:12 -07001330 newModule.directDeps = append([]depInfo(nil), origModule.directDeps...)
Colin Cross7ff2e8d2021-01-21 22:39:28 -08001331 newModule.reverseDeps = nil
1332 newModule.forwardDeps = nil
Colin Crossed342d92015-03-11 00:57:25 -07001333 newModule.logicModule = newLogicModule
Colin Crossedc41762020-08-13 12:07:30 -07001334 newModule.variant = newVariant(origModule, mutatorName, variationName, local)
Colin Crossd2f4ac12017-07-28 14:31:03 -07001335 newModule.properties = newProperties
Colin Cross2da84922020-07-02 10:08:12 -07001336 newModule.providers = append([]interface{}(nil), origModule.providers...)
Colin Crossc9028482014-12-18 16:28:54 -08001337
1338 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001339
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001340 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName)
Colin Cross174ae052015-03-03 17:37:03 -08001341 if len(newErrs) > 0 {
1342 errs = append(errs, newErrs...)
1343 }
Colin Crossc9028482014-12-18 16:28:54 -08001344 }
1345
1346 // Mark original variant as invalid. Modules that depend on this module will still
1347 // depend on origModule, but we'll fix it when the mutator is called on them.
1348 origModule.logicModule = nil
1349 origModule.splitModules = newModules
1350
Colin Cross3702ac72016-08-11 11:09:00 -07001351 atomic.AddUint32(&c.depsModified, 1)
1352
Colin Cross174ae052015-03-03 17:37:03 -08001353 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001354}
1355
Colin Crossf5e34b92015-03-13 16:02:36 -07001356func (c *Context) convertDepsToVariation(module *moduleInfo,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001357 mutatorName, variationName string, defaultVariationName *string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001358
Colin Crossc9028482014-12-18 16:28:54 -08001359 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001360 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001361 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001362 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001363 if m.moduleOrAliasVariant().variations[mutatorName] == variationName {
1364 newDep = m.moduleOrAliasTarget()
Colin Crossc9028482014-12-18 16:28:54 -08001365 break
1366 }
1367 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001368 if newDep == nil && defaultVariationName != nil {
1369 // give it a second chance; match with defaultVariationName
1370 for _, m := range dep.module.splitModules {
Colin Cross5df74a82020-08-24 16:18:21 -07001371 if m.moduleOrAliasVariant().variations[mutatorName] == *defaultVariationName {
1372 newDep = m.moduleOrAliasTarget()
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001373 break
1374 }
1375 }
1376 }
Colin Crossc9028482014-12-18 16:28:54 -08001377 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001378 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001379 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001380 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001381 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001382 })
1383 continue
Colin Crossc9028482014-12-18 16:28:54 -08001384 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001385 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001386 }
1387 }
Colin Cross174ae052015-03-03 17:37:03 -08001388
1389 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001390}
1391
Colin Crossedc41762020-08-13 12:07:30 -07001392func (c *Context) prettyPrintVariant(variations variationMap) string {
1393 names := make([]string, 0, len(variations))
Colin Cross65569e42015-03-10 20:08:19 -07001394 for _, m := range c.variantMutatorNames {
Colin Crossedc41762020-08-13 12:07:30 -07001395 if v, ok := variations[m]; ok {
Colin Cross65569e42015-03-10 20:08:19 -07001396 names = append(names, m+":"+v)
1397 }
1398 }
1399
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001400 return strings.Join(names, ",")
Colin Cross65569e42015-03-10 20:08:19 -07001401}
1402
Colin Crossd03b59d2019-11-13 20:10:12 -08001403func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1404 var variants []string
Colin Cross5df74a82020-08-24 16:18:21 -07001405 for _, moduleOrAlias := range group.modules {
1406 if mod := moduleOrAlias.module(); mod != nil {
1407 variants = append(variants, c.prettyPrintVariant(mod.variant.variations))
1408 } else if alias := moduleOrAlias.alias(); alias != nil {
1409 variants = append(variants, c.prettyPrintVariant(alias.variant.variations)+
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001410 " (alias to "+c.prettyPrintVariant(alias.target.variant.variations)+")")
Colin Cross5df74a82020-08-24 16:18:21 -07001411 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001412 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001413 return strings.Join(variants, "\n ")
1414}
1415
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001416func newModule(factory ModuleFactory) *moduleInfo {
Colin Crossaf4fd212017-07-28 14:32:36 -07001417 logicModule, properties := factory()
1418
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001419 return &moduleInfo{
Colin Crossaf4fd212017-07-28 14:32:36 -07001420 logicModule: logicModule,
1421 factory: factory,
Usta Shresthaee7a5d72022-01-10 22:46:23 -05001422 properties: properties,
Colin Crossaf4fd212017-07-28 14:32:36 -07001423 }
Colin Crossaf4fd212017-07-28 14:32:36 -07001424}
1425
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001426func processModuleDef(moduleDef *parser.Module,
1427 relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001428
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001429 factory, ok := moduleFactories[moduleDef.Type]
Colin Cross9672d862019-12-30 18:38:20 -08001430 if !ok && scopedModuleFactories != nil {
1431 factory, ok = scopedModuleFactories[moduleDef.Type]
1432 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001433 if !ok {
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001434 if ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001435 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001436 }
1437
Colin Cross7ad621c2015-01-07 16:22:45 -08001438 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001439 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001440 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1441 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001442 },
1443 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001444 }
1445
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001446 module := newModule(factory)
Colin Crossaf4fd212017-07-28 14:32:36 -07001447 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001448
Colin Crossaf4fd212017-07-28 14:32:36 -07001449 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001450
Colin Crossf27c5e42020-01-02 09:37:49 -08001451 propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001452 if len(errs) > 0 {
Colin Crossf27c5e42020-01-02 09:37:49 -08001453 for i, err := range errs {
1454 if unpackErr, ok := err.(*proptools.UnpackError); ok {
1455 err = &BlueprintError{
1456 Err: unpackErr.Err,
1457 Pos: unpackErr.Pos,
1458 }
1459 errs[i] = err
1460 }
1461 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001462 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001463 }
1464
Colin Crossc32c4792016-06-09 15:52:30 -07001465 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001466 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001467 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001468 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469 }
1470
Colin Cross7ad621c2015-01-07 16:22:45 -08001471 return module, nil
1472}
1473
Colin Cross23d7aa12015-06-30 16:05:22 -07001474func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001475 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001476 if name == "" {
1477 return []error{
1478 &BlueprintError{
1479 Err: fmt.Errorf("property 'name' is missing from a module"),
1480 Pos: module.pos,
1481 },
1482 }
1483 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001484 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001485
Colin Cross0b7e83e2016-05-17 14:58:05 -07001486 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001487 name: name,
Colin Cross5df74a82020-08-24 16:18:21 -07001488 modules: modulesOrAliases{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001489 }
1490 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001491 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001492 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001493 ModuleGroup{moduleGroup: group},
1494 module.logicModule)
1495 if len(errs) > 0 {
1496 for i := range errs {
1497 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1498 }
1499 return errs
1500 }
1501 group.namespace = namespace
1502
Colin Cross0b7e83e2016-05-17 14:58:05 -07001503 c.moduleGroups = append(c.moduleGroups, group)
1504
Colin Cross23d7aa12015-06-30 16:05:22 -07001505 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001506}
1507
Jamie Gennisd4e10182014-06-12 20:06:50 -07001508// ResolveDependencies checks that the dependencies specified by all of the
1509// modules defined in the parsed Blueprints files are valid. This means that
1510// the modules depended upon are defined and that no circular dependencies
1511// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001512func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Chris Parsons18ebb232022-03-25 00:56:02 -04001513 c.BeginEvent("resolve_deps")
1514 defer c.EndEvent("resolve_deps")
Colin Cross3a8c0252019-01-23 13:21:48 -08001515 return c.resolveDependencies(c.Context, config)
1516}
Colin Cross5f03f112017-11-07 13:29:54 -08001517
Colin Cross3a8c0252019-01-23 13:21:48 -08001518func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1519 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
Colin Cross2da84922020-07-02 10:08:12 -07001520 c.initProviders()
1521
Colin Cross3a8c0252019-01-23 13:21:48 -08001522 c.liveGlobals = newLiveTracker(config)
1523
1524 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1525 if len(errs) > 0 {
1526 return
1527 }
1528
1529 errs = c.updateDependencies()
1530 if len(errs) > 0 {
1531 return
1532 }
1533
1534 var mutatorDeps []string
1535 mutatorDeps, errs = c.runMutators(ctx, config)
1536 if len(errs) > 0 {
1537 return
1538 }
1539 deps = append(deps, mutatorDeps...)
1540
Colin Cross2da84922020-07-02 10:08:12 -07001541 if !c.skipCloneModulesAfterMutators {
1542 c.cloneModules()
1543 }
Colin Cross3a8c0252019-01-23 13:21:48 -08001544
1545 c.dependenciesReady = true
1546 })
1547
Colin Cross5f03f112017-11-07 13:29:54 -08001548 if len(errs) > 0 {
1549 return nil, errs
1550 }
1551
Colin Cross874a3462017-07-31 17:26:06 -07001552 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001553}
1554
Colin Cross763b6f12015-10-29 15:32:56 -07001555// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001556// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001557// module names returned by its DynamicDependencies method and those added by calling
1558// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001559func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001560 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001561 func() {
1562 defer func() {
1563 if r := recover(); r != nil {
1564 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1565 }
1566 }()
1567 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001568
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001569 if ctx.Failed() {
1570 return
1571 }
Colin Cross763b6f12015-10-29 15:32:56 -07001572
Colin Cross2c1f3d12016-04-11 15:47:28 -07001573 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001574 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001575 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001576}
1577
Colin Cross39644c02020-08-21 18:20:38 -07001578// findExactVariantOrSingle searches the moduleGroup for a module with the same variant as module,
1579// and returns the matching module, or nil if one is not found. A group with exactly one module
1580// is always considered matching.
1581func findExactVariantOrSingle(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07001582 found, _ := findVariant(module, possible, nil, false, reverse)
1583 if found == nil {
1584 for _, moduleOrAlias := range possible.modules {
1585 if m := moduleOrAlias.module(); m != nil {
1586 if found != nil {
1587 // more than one possible match, give up
1588 return nil
1589 }
1590 found = m
1591 }
1592 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001593 }
Colin Cross5df74a82020-08-24 16:18:21 -07001594 return found
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001595}
1596
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001597func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) (*moduleInfo, []error) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001598 if _, ok := tag.(BaseDependencyTag); ok {
1599 panic("BaseDependencyTag is not allowed to be used directly!")
1600 }
1601
Colin Cross0b7e83e2016-05-17 14:58:05 -07001602 if depName == module.Name() {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001603 return nil, []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001604 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001605 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001606 }}
1607 }
1608
Colin Crossd03b59d2019-11-13 20:10:12 -08001609 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001610 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001611 return nil, c.discoveredMissingDependencies(module, depName, nil)
Colin Crossc9028482014-12-18 16:28:54 -08001612 }
1613
Colin Cross39644c02020-08-21 18:20:38 -07001614 if m := findExactVariantOrSingle(module, possibleDeps, false); m != nil {
Colin Cross99bdb2a2019-03-29 16:35:02 -07001615 module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001616 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001617 return m, nil
Colin Cross65569e42015-03-10 20:08:19 -07001618 }
Colin Crossc9028482014-12-18 16:28:54 -08001619
Paul Duffinb77556b2020-03-24 19:01:20 +00001620 if c.allowMissingDependencies {
1621 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001622 return nil, c.discoveredMissingDependencies(module, depName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001623 }
1624
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001625 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001626 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001627 depName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001628 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001629 c.prettyPrintGroupVariants(possibleDeps)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001630 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001631 }}
1632}
1633
Colin Cross8d8a7af2015-11-03 16:41:29 -08001634func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001635 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001636 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001637 Err: fmt.Errorf("%q depends on itself", destName),
1638 Pos: module.pos,
1639 }}
1640 }
1641
Colin Crossd03b59d2019-11-13 20:10:12 -08001642 possibleDeps := c.moduleGroupFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001643 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001644 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001645 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001646 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001647 Pos: module.pos,
1648 }}
1649 }
1650
Colin Cross39644c02020-08-21 18:20:38 -07001651 if m := findExactVariantOrSingle(module, possibleDeps, true); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001652 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001653 }
1654
Paul Duffinb77556b2020-03-24 19:01:20 +00001655 if c.allowMissingDependencies {
1656 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001657 return module, c.discoveredMissingDependencies(module, destName, module.variant.dependencyVariations)
Paul Duffinb77556b2020-03-24 19:01:20 +00001658 }
1659
Colin Cross2c628442016-10-07 17:13:10 -07001660 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001661 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001662 destName, module.Name(),
Colin Crossedc41762020-08-13 12:07:30 -07001663 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001664 c.prettyPrintGroupVariants(possibleDeps)),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001665 Pos: module.pos,
1666 }}
1667}
1668
Colin Cross39644c02020-08-21 18:20:38 -07001669func findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
Colin Crossedc41762020-08-13 12:07:30 -07001670 // We can't just append variant.Variant to module.dependencyVariant.variantName and
Colin Cross65569e42015-03-10 20:08:19 -07001671 // compare the strings because the result won't be in mutator registration order.
1672 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001673 var newVariant variationMap
1674 if !far {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001675 if !reverse {
1676 // For forward dependency, ignore local variants by matching against
1677 // dependencyVariant which doesn't have the local variants
Colin Crossedc41762020-08-13 12:07:30 -07001678 newVariant = module.variant.dependencyVariations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001679 } else {
1680 // For reverse dependency, use all the variants
Colin Crossedc41762020-08-13 12:07:30 -07001681 newVariant = module.variant.variations.clone()
Martin Stjernholm2f212472020-03-06 00:29:24 +00001682 }
Colin Cross89486232015-05-08 11:14:54 -07001683 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001684 for _, v := range variations {
Colin Cross9403b5a2019-11-13 20:11:04 -08001685 if newVariant == nil {
1686 newVariant = make(variationMap)
1687 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001688 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001689 }
1690
Colin Crossd03b59d2019-11-13 20:10:12 -08001691 check := func(variant variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -07001692 if far {
Colin Cross5dc67592020-08-24 14:46:13 -07001693 return newVariant.subsetOf(variant)
Colin Cross89486232015-05-08 11:14:54 -07001694 } else {
Colin Crossd03b59d2019-11-13 20:10:12 -08001695 return variant.equal(newVariant)
Colin Cross65569e42015-03-10 20:08:19 -07001696 }
1697 }
1698
Colin Crossd03b59d2019-11-13 20:10:12 -08001699 var foundDep *moduleInfo
1700 for _, m := range possibleDeps.modules {
Colin Cross5df74a82020-08-24 16:18:21 -07001701 if check(m.moduleOrAliasVariant().variations) {
1702 foundDep = m.moduleOrAliasTarget()
Colin Crossd03b59d2019-11-13 20:10:12 -08001703 break
1704 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001705 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001706
Martin Stjernholm2f212472020-03-06 00:29:24 +00001707 return foundDep, newVariant
1708}
1709
1710func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001711 tag DependencyTag, depName string, far bool) (*moduleInfo, []error) {
Martin Stjernholm2f212472020-03-06 00:29:24 +00001712 if _, ok := tag.(BaseDependencyTag); ok {
1713 panic("BaseDependencyTag is not allowed to be used directly!")
1714 }
1715
1716 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
1717 if possibleDeps == nil {
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001718 return nil, c.discoveredMissingDependencies(module, depName, nil)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001719 }
1720
Colin Cross5df74a82020-08-24 16:18:21 -07001721 foundDep, newVariant := findVariant(module, possibleDeps, variations, far, false)
Martin Stjernholm2f212472020-03-06 00:29:24 +00001722
Colin Crossf7beb892019-11-13 20:11:14 -08001723 if foundDep == nil {
Paul Duffinb77556b2020-03-24 19:01:20 +00001724 if c.allowMissingDependencies {
1725 // Allow missing variants.
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00001726 return nil, c.discoveredMissingDependencies(module, depName, newVariant)
Paul Duffinb77556b2020-03-24 19:01:20 +00001727 }
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001728 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001729 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
1730 depName, module.Name(),
1731 c.prettyPrintVariant(newVariant),
1732 c.prettyPrintGroupVariants(possibleDeps)),
1733 Pos: module.pos,
1734 }}
1735 }
1736
1737 if module == foundDep {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001738 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001739 Err: fmt.Errorf("%q depends on itself", depName),
1740 Pos: module.pos,
1741 }}
1742 }
1743 // AddVariationDependency allows adding a dependency on itself, but only if
1744 // that module is earlier in the module list than this one, since we always
1745 // run GenerateBuildActions in order for the variants of a module
1746 if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001747 return nil, []error{&BlueprintError{
Colin Crossd03b59d2019-11-13 20:10:12 -08001748 Err: fmt.Errorf("%q depends on later version of itself", depName),
1749 Pos: module.pos,
1750 }}
1751 }
1752 module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
1753 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001754 return foundDep, nil
Colin Crossc9028482014-12-18 16:28:54 -08001755}
1756
Colin Crossf1875462016-04-11 17:33:13 -07001757func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001758 from, to Module) *moduleInfo {
Nan Zhang346b2d02017-03-10 16:39:27 -08001759 if _, ok := tag.(BaseDependencyTag); ok {
1760 panic("BaseDependencyTag is not allowed to be used directly!")
1761 }
Colin Crossf1875462016-04-11 17:33:13 -07001762
1763 var fromInfo, toInfo *moduleInfo
Colin Cross5df74a82020-08-24 16:18:21 -07001764 for _, moduleOrAlias := range origModule.splitModules {
1765 if m := moduleOrAlias.module(); m != nil {
1766 if m.logicModule == from {
1767 fromInfo = m
1768 }
1769 if m.logicModule == to {
1770 toInfo = m
1771 if fromInfo != nil {
1772 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
1773 }
Colin Crossf1875462016-04-11 17:33:13 -07001774 }
1775 }
1776 }
1777
1778 if fromInfo == nil || toInfo == nil {
1779 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001780 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001781 }
1782
Colin Cross99bdb2a2019-03-29 16:35:02 -07001783 fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001784 atomic.AddUint32(&c.depsModified, 1)
Ulya Trafimovich9577bbc2020-08-27 11:20:23 +01001785 return toInfo
Colin Crossf1875462016-04-11 17:33:13 -07001786}
1787
Lukacs T. Berkieef56852021-09-02 11:34:06 +02001788// findBlueprintDescendants returns a map linking parent Blueprint files to child Blueprints files
1789// For example, if paths = []string{"a/b/c/Android.bp", "a/Android.bp"},
1790// then descendants = {"":[]string{"a/Android.bp"}, "a/Android.bp":[]string{"a/b/c/Android.bp"}}
Jeff Gastonc3e28442017-08-09 15:13:12 -07001791func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1792 // make mapping from dir path to file path
1793 filesByDir := make(map[string]string, len(paths))
1794 for _, path := range paths {
1795 dir := filepath.Dir(path)
1796 _, alreadyFound := filesByDir[dir]
1797 if alreadyFound {
1798 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1799 }
1800 filesByDir[dir] = path
1801 }
1802
Jeff Gaston656870f2017-11-29 18:37:31 -08001803 findAncestor := func(childFile string) (ancestor string) {
1804 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001805 for {
1806 ancestorDir := filepath.Dir(prevAncestorDir)
1807 if ancestorDir == prevAncestorDir {
1808 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001809 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001810 }
1811
1812 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1813 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001814 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001815 }
1816 prevAncestorDir = ancestorDir
1817 }
1818 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001819 // generate the descendants map
1820 descendants = make(map[string][]string, len(filesByDir))
1821 for _, childFile := range filesByDir {
1822 ancestorFile := findAncestor(childFile)
1823 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1824 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001825 return descendants, nil
1826}
1827
Colin Cross3702ac72016-08-11 11:09:00 -07001828type visitOrderer interface {
1829 // returns the number of modules that this module needs to wait for
1830 waitCount(module *moduleInfo) int
1831 // returns the list of modules that are waiting for this module
1832 propagate(module *moduleInfo) []*moduleInfo
1833 // visit modules in order
Colin Crossc4773d92020-08-25 17:12:59 -07001834 visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool)
Colin Cross3702ac72016-08-11 11:09:00 -07001835}
1836
Colin Cross7e723372018-03-28 11:50:12 -07001837type unorderedVisitorImpl struct{}
1838
1839func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1840 return 0
1841}
1842
1843func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1844 return nil
1845}
1846
Colin Crossc4773d92020-08-25 17:12:59 -07001847func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross7e723372018-03-28 11:50:12 -07001848 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001849 if visit(module, nil) {
Colin Cross7e723372018-03-28 11:50:12 -07001850 return
1851 }
1852 }
1853}
1854
Colin Cross3702ac72016-08-11 11:09:00 -07001855type bottomUpVisitorImpl struct{}
1856
1857func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1858 return len(module.forwardDeps)
1859}
1860
1861func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1862 return module.reverseDeps
1863}
1864
Colin Crossc4773d92020-08-25 17:12:59 -07001865func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001866 for _, module := range modules {
Colin Crossc4773d92020-08-25 17:12:59 -07001867 if visit(module, nil) {
Colin Cross49c279a2016-08-05 22:30:44 -07001868 return
1869 }
1870 }
1871}
1872
Colin Cross3702ac72016-08-11 11:09:00 -07001873type topDownVisitorImpl struct{}
1874
1875func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1876 return len(module.reverseDeps)
1877}
1878
1879func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1880 return module.forwardDeps
1881}
1882
Colin Crossc4773d92020-08-25 17:12:59 -07001883func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo, chan<- pauseSpec) bool) {
Colin Cross3702ac72016-08-11 11:09:00 -07001884 for i := 0; i < len(modules); i++ {
1885 module := modules[len(modules)-1-i]
Colin Crossc4773d92020-08-25 17:12:59 -07001886 if visit(module, nil) {
Colin Cross3702ac72016-08-11 11:09:00 -07001887 return
1888 }
1889 }
1890}
1891
1892var (
1893 bottomUpVisitor bottomUpVisitorImpl
1894 topDownVisitor topDownVisitorImpl
1895)
1896
Colin Crossc4773d92020-08-25 17:12:59 -07001897// pauseSpec describes a pause that a module needs to occur until another module has been visited,
1898// at which point the unpause channel will be closed.
1899type pauseSpec struct {
1900 paused *moduleInfo
1901 until *moduleInfo
1902 unpause unpause
1903}
1904
1905type unpause chan struct{}
1906
1907const parallelVisitLimit = 1000
1908
Colin Cross49c279a2016-08-05 22:30:44 -07001909// 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 -07001910// of its dependencies has finished. A visit function can write a pauseSpec to the pause channel
1911// to wait for another dependency to be visited. If a visit function returns true to cancel
1912// while another visitor is paused, the paused visitor will never be resumed and its goroutine
1913// will stay paused forever.
1914func parallelVisit(modules []*moduleInfo, order visitOrderer, limit int,
1915 visit func(module *moduleInfo, pause chan<- pauseSpec) bool) []error {
1916
Colin Cross7addea32015-03-11 15:43:52 -07001917 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001918 cancelCh := make(chan bool)
Colin Crossc4773d92020-08-25 17:12:59 -07001919 pauseCh := make(chan pauseSpec)
Colin Cross8900e9b2015-03-02 14:03:01 -08001920 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001921
Colin Crossc4773d92020-08-25 17:12:59 -07001922 var backlog []*moduleInfo // Visitors that are ready to start but backlogged due to limit.
1923 var unpauseBacklog []pauseSpec // Visitors that are ready to unpause but backlogged due to limit.
1924
1925 active := 0 // Number of visitors running, not counting paused visitors.
1926 visited := 0 // Number of finished visitors.
1927
1928 pauseMap := make(map[*moduleInfo][]pauseSpec)
1929
1930 for _, module := range modules {
Colin Cross3702ac72016-08-11 11:09:00 -07001931 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001932 }
1933
Colin Crossc4773d92020-08-25 17:12:59 -07001934 // Call the visitor on a module if there are fewer active visitors than the parallelism
1935 // limit, otherwise add it to the backlog.
1936 startOrBacklog := func(module *moduleInfo) {
1937 if active < limit {
1938 active++
Colin Cross7e723372018-03-28 11:50:12 -07001939 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07001940 ret := visit(module, pauseCh)
Colin Cross7e723372018-03-28 11:50:12 -07001941 if ret {
1942 cancelCh <- true
1943 }
1944 doneCh <- module
1945 }()
1946 } else {
1947 backlog = append(backlog, module)
1948 }
Colin Cross691a60d2015-01-07 18:08:56 -08001949 }
1950
Colin Crossc4773d92020-08-25 17:12:59 -07001951 // Unpause the already-started but paused visitor on a module if there are fewer active
1952 // visitors than the parallelism limit, otherwise add it to the backlog.
1953 unpauseOrBacklog := func(pauseSpec pauseSpec) {
1954 if active < limit {
1955 active++
1956 close(pauseSpec.unpause)
1957 } else {
1958 unpauseBacklog = append(unpauseBacklog, pauseSpec)
Colin Cross691a60d2015-01-07 18:08:56 -08001959 }
1960 }
1961
Colin Crossc4773d92020-08-25 17:12:59 -07001962 // Start any modules in the backlog up to the parallelism limit. Unpause paused modules first
1963 // since they may already be holding resources.
1964 unpauseOrStartFromBacklog := func() {
1965 for active < limit && len(unpauseBacklog) > 0 {
1966 unpause := unpauseBacklog[0]
1967 unpauseBacklog = unpauseBacklog[1:]
1968 unpauseOrBacklog(unpause)
1969 }
1970 for active < limit && len(backlog) > 0 {
1971 toVisit := backlog[0]
1972 backlog = backlog[1:]
1973 startOrBacklog(toVisit)
1974 }
1975 }
1976
1977 toVisit := len(modules)
1978
1979 // Start or backlog any modules that are not waiting for any other modules.
1980 for _, module := range modules {
1981 if module.waitingCount == 0 {
1982 startOrBacklog(module)
1983 }
1984 }
1985
1986 for active > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001987 select {
Colin Cross7e723372018-03-28 11:50:12 -07001988 case <-cancelCh:
1989 cancel = true
1990 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07001991 case doneModule := <-doneCh:
Colin Crossc4773d92020-08-25 17:12:59 -07001992 active--
Colin Cross8900e9b2015-03-02 14:03:01 -08001993 if !cancel {
Colin Crossc4773d92020-08-25 17:12:59 -07001994 // Mark this module as done.
1995 doneModule.waitingCount = -1
1996 visited++
1997
1998 // Unpause or backlog any modules that were waiting for this one.
1999 if unpauses, ok := pauseMap[doneModule]; ok {
2000 delete(pauseMap, doneModule)
2001 for _, unpause := range unpauses {
2002 unpauseOrBacklog(unpause)
2003 }
Colin Cross7e723372018-03-28 11:50:12 -07002004 }
Colin Crossc4773d92020-08-25 17:12:59 -07002005
2006 // Start any backlogged modules up to limit.
2007 unpauseOrStartFromBacklog()
2008
2009 // Decrement waitingCount on the next modules in the tree based
2010 // on propagation order, and start or backlog them if they are
2011 // ready to start.
Colin Cross3702ac72016-08-11 11:09:00 -07002012 for _, module := range order.propagate(doneModule) {
2013 module.waitingCount--
2014 if module.waitingCount == 0 {
Colin Crossc4773d92020-08-25 17:12:59 -07002015 startOrBacklog(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08002016 }
Colin Cross691a60d2015-01-07 18:08:56 -08002017 }
2018 }
Colin Crossc4773d92020-08-25 17:12:59 -07002019 case pauseSpec := <-pauseCh:
2020 if pauseSpec.until.waitingCount == -1 {
2021 // Module being paused for is already finished, resume immediately.
2022 close(pauseSpec.unpause)
2023 } else {
2024 // Register for unpausing.
2025 pauseMap[pauseSpec.until] = append(pauseMap[pauseSpec.until], pauseSpec)
2026
2027 // Don't count paused visitors as active so that this can't deadlock
2028 // if 1000 visitors are paused simultaneously.
2029 active--
2030 unpauseOrStartFromBacklog()
2031 }
Colin Cross691a60d2015-01-07 18:08:56 -08002032 }
2033 }
Colin Crossc4773d92020-08-25 17:12:59 -07002034
2035 if !cancel {
2036 // Invariant check: no backlogged modules, these weren't waiting on anything except
2037 // the parallelism limit so they should have run.
2038 if len(backlog) > 0 {
2039 panic(fmt.Errorf("parallelVisit finished with %d backlogged visitors", len(backlog)))
2040 }
2041
2042 // Invariant check: no backlogged paused modules, these weren't waiting on anything
2043 // except the parallelism limit so they should have run.
2044 if len(unpauseBacklog) > 0 {
2045 panic(fmt.Errorf("parallelVisit finished with %d backlogged unpaused visitors", len(unpauseBacklog)))
2046 }
2047
2048 if len(pauseMap) > 0 {
Colin Cross7d4958d2021-02-08 15:34:08 -08002049 // Probably a deadlock due to a newly added dependency cycle. Start from each module in
2050 // the order of the input modules list and perform a depth-first search for the module
2051 // it is paused on, ignoring modules that are marked as done. Note this traverses from
2052 // modules to the modules that would have been unblocked when that module finished, i.e
2053 // the reverse of the visitOrderer.
Colin Crossc4773d92020-08-25 17:12:59 -07002054
Colin Cross9793b0a2021-04-27 15:20:15 -07002055 // In order to reduce duplicated work, once a module has been checked and determined
2056 // not to be part of a cycle add it and everything that depends on it to the checked
2057 // map.
2058 checked := make(map[*moduleInfo]struct{})
2059
Colin Cross7d4958d2021-02-08 15:34:08 -08002060 var check func(module, end *moduleInfo) []*moduleInfo
2061 check = func(module, end *moduleInfo) []*moduleInfo {
Colin Crossc4773d92020-08-25 17:12:59 -07002062 if module.waitingCount == -1 {
2063 // This module was finished, it can't be part of a loop.
2064 return nil
2065 }
2066 if module == end {
2067 // This module is the end of the loop, start rolling up the cycle.
2068 return []*moduleInfo{module}
2069 }
2070
Colin Cross9793b0a2021-04-27 15:20:15 -07002071 if _, alreadyChecked := checked[module]; alreadyChecked {
2072 return nil
2073 }
2074
Colin Crossc4773d92020-08-25 17:12:59 -07002075 for _, dep := range order.propagate(module) {
Colin Cross7d4958d2021-02-08 15:34:08 -08002076 cycle := check(dep, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002077 if cycle != nil {
2078 return append([]*moduleInfo{module}, cycle...)
2079 }
2080 }
2081 for _, depPauseSpec := range pauseMap[module] {
Colin Cross7d4958d2021-02-08 15:34:08 -08002082 cycle := check(depPauseSpec.paused, end)
Colin Crossc4773d92020-08-25 17:12:59 -07002083 if cycle != nil {
2084 return append([]*moduleInfo{module}, cycle...)
2085 }
2086 }
2087
Colin Cross9793b0a2021-04-27 15:20:15 -07002088 checked[module] = struct{}{}
Colin Crossc4773d92020-08-25 17:12:59 -07002089 return nil
2090 }
2091
Colin Cross7d4958d2021-02-08 15:34:08 -08002092 // Iterate over the modules list instead of pauseMap to provide deterministic ordering.
2093 for _, module := range modules {
2094 for _, pauseSpec := range pauseMap[module] {
2095 cycle := check(pauseSpec.paused, pauseSpec.until)
2096 if len(cycle) > 0 {
2097 return cycleError(cycle)
2098 }
2099 }
Colin Crossc4773d92020-08-25 17:12:59 -07002100 }
2101 }
2102
2103 // Invariant check: if there was no deadlock and no cancellation every module
2104 // should have been visited.
2105 if visited != toVisit {
2106 panic(fmt.Errorf("parallelVisit ran %d visitors, expected %d", visited, toVisit))
2107 }
2108
2109 // Invariant check: if there was no deadlock and no cancellation every module
2110 // should have been visited, so there is nothing left to be paused on.
2111 if len(pauseMap) > 0 {
2112 panic(fmt.Errorf("parallelVisit finished with %d paused visitors", len(pauseMap)))
2113 }
2114 }
2115
2116 return nil
2117}
2118
2119func cycleError(cycle []*moduleInfo) (errs []error) {
2120 // The cycle list is in reverse order because all the 'check' calls append
2121 // their own module to the list.
2122 errs = append(errs, &BlueprintError{
2123 Err: fmt.Errorf("encountered dependency cycle:"),
2124 Pos: cycle[len(cycle)-1].pos,
2125 })
2126
2127 // Iterate backwards through the cycle list.
2128 curModule := cycle[0]
2129 for i := len(cycle) - 1; i >= 0; i-- {
2130 nextModule := cycle[i]
2131 errs = append(errs, &BlueprintError{
Colin Crosse5ff7702021-04-27 15:33:49 -07002132 Err: fmt.Errorf(" %s depends on %s",
2133 curModule, nextModule),
Colin Crossc4773d92020-08-25 17:12:59 -07002134 Pos: curModule.pos,
2135 })
2136 curModule = nextModule
2137 }
2138
2139 return errs
Colin Cross691a60d2015-01-07 18:08:56 -08002140}
2141
2142// updateDependencies recursively walks the module dependency graph and updates
2143// additional fields based on the dependencies. It builds a sorted list of modules
2144// such that dependencies of a module always appear first, and populates reverse
2145// dependency links and counts of total dependencies. It also reports errors when
Usta Shresthaee7a5d72022-01-10 22:46:23 -05002146// it encounters dependency cycles. This should be called after resolveDependencies,
Colin Cross691a60d2015-01-07 18:08:56 -08002147// as well as after any mutator pass has called addDependency
2148func (c *Context) updateDependencies() (errs []error) {
Liz Kammer9ae14f12020-11-30 16:30:45 -07002149 c.cachedDepsModified = true
Colin Cross7addea32015-03-11 15:43:52 -07002150 visited := make(map[*moduleInfo]bool) // modules that were already checked
2151 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002152
Colin Cross7addea32015-03-11 15:43:52 -07002153 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08002154
Colin Cross7addea32015-03-11 15:43:52 -07002155 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002156
Colin Cross7addea32015-03-11 15:43:52 -07002157 check = func(module *moduleInfo) []*moduleInfo {
2158 visited[module] = true
2159 checking[module] = true
2160 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002161
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002162 // Reset the forward and reverse deps without reducing their capacity to avoid reallocation.
2163 module.reverseDeps = module.reverseDeps[:0]
2164 module.forwardDeps = module.forwardDeps[:0]
Colin Cross7addea32015-03-11 15:43:52 -07002165
2166 // Add an implicit dependency ordering on all earlier modules in the same module group
2167 for _, dep := range module.group.modules {
2168 if dep == module {
2169 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08002170 }
Colin Cross5df74a82020-08-24 16:18:21 -07002171 if depModule := dep.module(); depModule != nil {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002172 module.forwardDeps = append(module.forwardDeps, depModule)
Colin Cross5df74a82020-08-24 16:18:21 -07002173 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002174 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002175
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002176 outer:
Colin Cross7addea32015-03-11 15:43:52 -07002177 for _, dep := range module.directDeps {
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002178 // use a loop to check for duplicates, average number of directDeps measured to be 9.5.
2179 for _, exists := range module.forwardDeps {
2180 if dep.module == exists {
2181 continue outer
2182 }
2183 }
2184 module.forwardDeps = append(module.forwardDeps, dep.module)
Colin Cross7addea32015-03-11 15:43:52 -07002185 }
2186
Colin Cross7ff2e8d2021-01-21 22:39:28 -08002187 for _, dep := range module.forwardDeps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002188 if checking[dep] {
2189 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07002190 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002191 }
2192
2193 if !visited[dep] {
2194 cycle := check(dep)
2195 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002196 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002197 // We are the "start" of the cycle, so we're responsible
Colin Crossc4773d92020-08-25 17:12:59 -07002198 // for generating the errors.
2199 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002200
2201 // We can continue processing this module's children to
2202 // find more cycles. Since all the modules that were
2203 // part of the found cycle were marked as visited we
2204 // won't run into that cycle again.
2205 } else {
2206 // We're not the "start" of the cycle, so we just append
2207 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07002208 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002209 }
2210 }
2211 }
Colin Cross691a60d2015-01-07 18:08:56 -08002212
Colin Cross7addea32015-03-11 15:43:52 -07002213 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002214 }
2215
Colin Cross7addea32015-03-11 15:43:52 -07002216 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08002217
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218 return nil
2219 }
2220
Colin Cross7addea32015-03-11 15:43:52 -07002221 for _, module := range c.moduleInfo {
2222 if !visited[module] {
2223 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002224 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002225 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07002226 panic("inconceivable!")
2227 }
Colin Crossc4773d92020-08-25 17:12:59 -07002228 errs = append(errs, cycleError(cycle)...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002229 }
2230 }
2231 }
2232
Colin Cross7addea32015-03-11 15:43:52 -07002233 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08002234
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002235 return
2236}
2237
Liz Kammer8097d1a2022-04-07 16:28:32 -04002238type jsonVariationMap []Variation
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002239
2240type jsonModuleName struct {
2241 Name string
2242 Variations jsonVariationMap
2243 DependencyVariations jsonVariationMap
2244}
2245
2246type jsonDep struct {
2247 jsonModuleName
2248 Tag string
2249}
2250
Lukacs T. Berki16022262021-06-25 09:10:56 +02002251type JsonModule struct {
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002252 jsonModuleName
2253 Deps []jsonDep
2254 Type string
2255 Blueprint string
Lukacs T. Berki16022262021-06-25 09:10:56 +02002256 Module map[string]interface{}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002257}
2258
2259func toJsonVariationMap(vm variationMap) jsonVariationMap {
Liz Kammer8097d1a2022-04-07 16:28:32 -04002260 m := make(jsonVariationMap, 0, len(vm))
2261 for k, v := range vm {
2262 m = append(m, Variation{k, v})
2263 }
2264 sort.Slice(m, func(i, j int) bool {
2265 if m[i].Mutator != m[j].Mutator {
2266 return m[i].Mutator < m[j].Mutator
2267 }
2268 return m[i].Variation < m[j].Variation
2269 })
2270 return m
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002271}
2272
2273func jsonModuleNameFromModuleInfo(m *moduleInfo) *jsonModuleName {
2274 return &jsonModuleName{
2275 Name: m.Name(),
2276 Variations: toJsonVariationMap(m.variant.variations),
2277 DependencyVariations: toJsonVariationMap(m.variant.dependencyVariations),
2278 }
2279}
2280
Lukacs T. Berki16022262021-06-25 09:10:56 +02002281type JSONDataSupplier interface {
2282 AddJSONData(d *map[string]interface{})
2283}
2284
2285func jsonModuleFromModuleInfo(m *moduleInfo) *JsonModule {
2286 result := &JsonModule{
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002287 jsonModuleName: *jsonModuleNameFromModuleInfo(m),
2288 Deps: make([]jsonDep, 0),
2289 Type: m.typeName,
2290 Blueprint: m.relBlueprintsFile,
Lukacs T. Berki16022262021-06-25 09:10:56 +02002291 Module: make(map[string]interface{}),
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002292 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002293 if j, ok := m.logicModule.(JSONDataSupplier); ok {
2294 j.AddJSONData(&result.Module)
2295 }
Lukacs T. Berki16022262021-06-25 09:10:56 +02002296 for _, p := range m.providers {
2297 if j, ok := p.(JSONDataSupplier); ok {
2298 j.AddJSONData(&result.Module)
2299 }
2300 }
2301 return result
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002302}
2303
kguia78b0202022-01-25 16:19:25 +08002304func jsonModuleWithActionsFromModuleInfo(m *moduleInfo) *JsonModule {
2305 result := &JsonModule{
2306 jsonModuleName: jsonModuleName{
2307 Name: m.Name(),
2308 },
2309 Deps: make([]jsonDep, 0),
2310 Type: m.typeName,
2311 Blueprint: m.relBlueprintsFile,
2312 Module: make(map[string]interface{}),
2313 }
2314 var actions []map[string]interface{}
2315 for _, bDef := range m.actionDefs.buildDefs {
2316 actions = append(actions, map[string]interface{}{
2317 "Inputs": append(
2318 getNinjaStringsWithNilPkgNames(bDef.Inputs),
2319 getNinjaStringsWithNilPkgNames(bDef.Implicits)...),
2320 "Outputs": append(
2321 getNinjaStringsWithNilPkgNames(bDef.Outputs),
2322 getNinjaStringsWithNilPkgNames(bDef.ImplicitOutputs)...),
2323 })
2324 }
2325 result.Module["Actions"] = actions
2326 return result
2327}
2328
2329// Gets a list of strings from the given list of ninjaStrings by invoking ninjaString.Value with
2330// nil pkgNames on each of the input ninjaStrings.
2331func getNinjaStringsWithNilPkgNames(nStrs []ninjaString) []string {
2332 var strs []string
2333 for _, nstr := range nStrs {
2334 strs = append(strs, nstr.Value(nil))
2335 }
2336 return strs
2337}
2338
2339// PrintJSONGraph prints info of modules in a JSON file.
2340func (c *Context) PrintJSONGraphAndActions(wGraph io.Writer, wActions io.Writer) {
2341 modulesToGraph := make([]*JsonModule, 0)
2342 modulesToActions := make([]*JsonModule, 0)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002343 for _, m := range c.modulesSorted {
2344 jm := jsonModuleFromModuleInfo(m)
kguia78b0202022-01-25 16:19:25 +08002345 jmWithActions := jsonModuleWithActionsFromModuleInfo(m)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002346 for _, d := range m.directDeps {
2347 jm.Deps = append(jm.Deps, jsonDep{
2348 jsonModuleName: *jsonModuleNameFromModuleInfo(d.module),
2349 Tag: fmt.Sprintf("%T %+v", d.tag, d.tag),
2350 })
kguia78b0202022-01-25 16:19:25 +08002351 jmWithActions.Deps = append(jmWithActions.Deps, jsonDep{
2352 jsonModuleName: jsonModuleName{
2353 Name: d.module.Name(),
2354 },
2355 })
2356
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002357 }
kguia78b0202022-01-25 16:19:25 +08002358 modulesToGraph = append(modulesToGraph, jm)
2359 modulesToActions = append(modulesToActions, jmWithActions)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002360 }
kguia78b0202022-01-25 16:19:25 +08002361 writeJson(wGraph, modulesToGraph)
2362 writeJson(wActions, modulesToActions)
2363}
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002364
kguia78b0202022-01-25 16:19:25 +08002365func writeJson(w io.Writer, modules []*JsonModule) {
Liz Kammer6e4ee8d2021-08-17 17:32:42 -04002366 e := json.NewEncoder(w)
2367 e.SetIndent("", "\t")
2368 e.Encode(modules)
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002369}
2370
Jamie Gennisd4e10182014-06-12 20:06:50 -07002371// PrepareBuildActions generates an internal representation of all the build
2372// actions that need to be performed. This process involves invoking the
2373// GenerateBuildActions method on each of the Module objects created during the
2374// parse phase and then on each of the registered Singleton objects.
2375//
2376// If the ResolveDependencies method has not already been called it is called
2377// automatically by this method.
2378//
2379// The config argument is made available to all of the Module and Singleton
2380// objects via the Config method on the ModuleContext and SingletonContext
2381// objects passed to GenerateBuildActions. It is also passed to the functions
2382// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
2383// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002384//
2385// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08002386// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
2387// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
2388// methods.
Lukacs T. Berki6f682822021-04-01 18:27:31 +02002389
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002390func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Chris Parsons18ebb232022-03-25 00:56:02 -04002391 c.BeginEvent("prepare_build_actions")
2392 defer c.EndEvent("prepare_build_actions")
Colin Cross3a8c0252019-01-23 13:21:48 -08002393 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
2394 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002395
Colin Cross3a8c0252019-01-23 13:21:48 -08002396 if !c.dependenciesReady {
2397 var extraDeps []string
2398 extraDeps, errs = c.resolveDependencies(ctx, config)
2399 if len(errs) > 0 {
2400 return
2401 }
2402 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002403 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002404
Colin Cross3a8c0252019-01-23 13:21:48 -08002405 var depsModules []string
2406 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
2407 if len(errs) > 0 {
2408 return
2409 }
2410
2411 var depsSingletons []string
2412 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
2413 if len(errs) > 0 {
2414 return
2415 }
2416
2417 deps = append(deps, depsModules...)
2418 deps = append(deps, depsSingletons...)
2419
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02002420 if c.outDir != nil {
2421 err := c.liveGlobals.addNinjaStringDeps(c.outDir)
Colin Cross3a8c0252019-01-23 13:21:48 -08002422 if err != nil {
2423 errs = []error{err}
2424 return
2425 }
2426 }
2427
2428 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2429
2430 deps = append(deps, depsPackages...)
2431
Colin Cross92054a42021-01-21 16:49:25 -08002432 c.memoizeFullNames(c.liveGlobals, pkgNames)
2433
Colin Cross3a8c0252019-01-23 13:21:48 -08002434 // This will panic if it finds a problem since it's a programming error.
2435 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
2436
2437 c.pkgNames = pkgNames
2438 c.globalVariables = c.liveGlobals.variables
2439 c.globalPools = c.liveGlobals.pools
2440 c.globalRules = c.liveGlobals.rules
2441
2442 c.buildActionsReady = true
2443 })
2444
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002445 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002446 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002447 }
2448
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002449 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002450}
2451
Colin Cross3a8c0252019-01-23 13:21:48 -08002452func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08002453 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
Lukacs T. Berki83a5a302022-04-19 18:12:03 +02002454 for _, mutator := range c.mutatorInfo {
Colin Cross3a8c0252019-01-23 13:21:48 -08002455 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
2456 var newDeps []string
2457 if mutator.topDownMutator != nil {
2458 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
2459 } else if mutator.bottomUpMutator != nil {
2460 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
2461 } else {
2462 panic("no mutator set on " + mutator.name)
2463 }
2464 if len(errs) > 0 {
2465 return
2466 }
2467 deps = append(deps, newDeps...)
2468 })
2469 if len(errs) > 0 {
2470 return
2471 }
Colin Crossc9028482014-12-18 16:28:54 -08002472 }
Colin Cross3a8c0252019-01-23 13:21:48 -08002473 })
2474
2475 if len(errs) > 0 {
2476 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08002477 }
2478
Colin Cross874a3462017-07-31 17:26:06 -07002479 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08002480}
2481
Colin Cross3702ac72016-08-11 11:09:00 -07002482type mutatorDirection interface {
2483 run(mutator *mutatorInfo, ctx *mutatorContext)
2484 orderer() visitOrderer
2485 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08002486}
2487
Colin Cross3702ac72016-08-11 11:09:00 -07002488type bottomUpMutatorImpl struct{}
2489
2490func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2491 mutator.bottomUpMutator(ctx)
2492}
2493
2494func (bottomUpMutatorImpl) orderer() visitOrderer {
2495 return bottomUpVisitor
2496}
2497
2498func (bottomUpMutatorImpl) String() string {
2499 return "bottom up mutator"
2500}
2501
2502type topDownMutatorImpl struct{}
2503
2504func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2505 mutator.topDownMutator(ctx)
2506}
2507
2508func (topDownMutatorImpl) orderer() visitOrderer {
2509 return topDownVisitor
2510}
2511
2512func (topDownMutatorImpl) String() string {
2513 return "top down mutator"
2514}
2515
2516var (
2517 topDownMutator topDownMutatorImpl
2518 bottomUpMutator bottomUpMutatorImpl
2519)
2520
Colin Cross49c279a2016-08-05 22:30:44 -07002521type reverseDep struct {
2522 module *moduleInfo
2523 dep depInfo
2524}
2525
Colin Cross3702ac72016-08-11 11:09:00 -07002526func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002527 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002528
2529 newModuleInfo := make(map[Module]*moduleInfo)
2530 for k, v := range c.moduleInfo {
2531 newModuleInfo[k] = v
2532 }
Colin Crossc9028482014-12-18 16:28:54 -08002533
Colin Cross0ce142c2016-12-09 10:29:05 -08002534 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002535 reverse []reverseDep
2536 rename []rename
2537 replace []replace
2538 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002539 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002540 }
2541
Colin Cross2c1f3d12016-04-11 15:47:28 -07002542 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002543 var rename []rename
2544 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002545 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002546
Colin Cross49c279a2016-08-05 22:30:44 -07002547 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002548 globalStateCh := make(chan globalStateChange)
Colin Cross5df74a82020-08-24 16:18:21 -07002549 newVariationsCh := make(chan modulesOrAliases)
Colin Cross49c279a2016-08-05 22:30:44 -07002550 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002551
Colin Cross3702ac72016-08-11 11:09:00 -07002552 c.depsModified = 0
2553
Colin Crossc4773d92020-08-25 17:12:59 -07002554 visit := func(module *moduleInfo, pause chan<- pauseSpec) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002555 if module.splitModules != nil {
2556 panic("split module found in sorted module list")
2557 }
2558
Colin Cross7addea32015-03-11 15:43:52 -07002559 mctx := &mutatorContext{
2560 baseModuleContext: baseModuleContext{
2561 context: c,
2562 config: config,
2563 module: module,
2564 },
Colin Crossc4773d92020-08-25 17:12:59 -07002565 name: mutator.name,
2566 pauseCh: pause,
Colin Cross7addea32015-03-11 15:43:52 -07002567 }
Colin Crossc9028482014-12-18 16:28:54 -08002568
Colin Cross2da84922020-07-02 10:08:12 -07002569 module.startedMutator = mutator
2570
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002571 func() {
2572 defer func() {
2573 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002574 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002575 if err, ok := r.(panicError); ok {
2576 err.addIn(in)
2577 mctx.error(err)
2578 } else {
2579 mctx.error(newPanicErrorf(r, in))
2580 }
2581 }
2582 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002583 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002584 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002585
Colin Cross2da84922020-07-02 10:08:12 -07002586 module.finishedMutator = mutator
2587
Colin Cross7addea32015-03-11 15:43:52 -07002588 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002589 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002590 return true
Colin Cross7addea32015-03-11 15:43:52 -07002591 }
Colin Crossc9028482014-12-18 16:28:54 -08002592
Colin Cross5fe225f2017-07-28 15:22:46 -07002593 if len(mctx.newVariations) > 0 {
2594 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002595 }
2596
Colin Crossab0a83f2020-03-03 14:23:27 -08002597 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 -08002598 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002599 reverse: mctx.reverseDeps,
2600 replace: mctx.replace,
2601 rename: mctx.rename,
2602 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002603 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002604 }
Colin Cross49c279a2016-08-05 22:30:44 -07002605 }
2606
2607 return false
2608 }
2609
2610 // Process errs and reverseDeps in a single goroutine
2611 go func() {
2612 for {
2613 select {
2614 case newErrs := <-errsCh:
2615 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002616 case globalStateChange := <-globalStateCh:
2617 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002618 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2619 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002620 replace = append(replace, globalStateChange.replace...)
2621 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002622 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002623 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002624 case newVariations := <-newVariationsCh:
Colin Cross5df74a82020-08-24 16:18:21 -07002625 for _, moduleOrAlias := range newVariations {
2626 if m := moduleOrAlias.module(); m != nil {
2627 newModuleInfo[m.logicModule] = m
2628 }
Colin Cross49c279a2016-08-05 22:30:44 -07002629 }
2630 case <-done:
2631 return
Colin Crossc9028482014-12-18 16:28:54 -08002632 }
2633 }
Colin Cross49c279a2016-08-05 22:30:44 -07002634 }()
Colin Crossc9028482014-12-18 16:28:54 -08002635
Colin Cross2da84922020-07-02 10:08:12 -07002636 c.startedMutator = mutator
2637
Colin Crossc4773d92020-08-25 17:12:59 -07002638 var visitErrs []error
Colin Cross49c279a2016-08-05 22:30:44 -07002639 if mutator.parallel {
Colin Crossc4773d92020-08-25 17:12:59 -07002640 visitErrs = parallelVisit(c.modulesSorted, direction.orderer(), parallelVisitLimit, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002641 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002642 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002643 }
2644
Colin Crossc4773d92020-08-25 17:12:59 -07002645 if len(visitErrs) > 0 {
2646 return nil, visitErrs
2647 }
2648
Colin Cross2da84922020-07-02 10:08:12 -07002649 c.finishedMutators[mutator] = true
2650
Colin Cross49c279a2016-08-05 22:30:44 -07002651 done <- true
2652
2653 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002654 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002655 }
2656
2657 c.moduleInfo = newModuleInfo
2658
2659 for _, group := range c.moduleGroups {
2660 for i := 0; i < len(group.modules); i++ {
Colin Cross5df74a82020-08-24 16:18:21 -07002661 module := group.modules[i].module()
2662 if module == nil {
2663 // Existing alias, skip it
2664 continue
2665 }
Colin Cross49c279a2016-08-05 22:30:44 -07002666
2667 // Update module group to contain newly split variants
2668 if module.splitModules != nil {
2669 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2670 }
2671
2672 // Fix up any remaining dependencies on modules that were split into variants
2673 // by replacing them with the first variant
2674 for j, dep := range module.directDeps {
2675 if dep.module.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002676 module.directDeps[j].module = dep.module.splitModules.firstModule()
Colin Cross49c279a2016-08-05 22:30:44 -07002677 }
2678 }
Colin Cross99bdb2a2019-03-29 16:35:02 -07002679
Colin Cross322cc012019-05-20 13:55:14 -07002680 if module.createdBy != nil && module.createdBy.logicModule == nil {
Colin Cross5df74a82020-08-24 16:18:21 -07002681 module.createdBy = module.createdBy.splitModules.firstModule()
Colin Cross322cc012019-05-20 13:55:14 -07002682 }
2683
Colin Cross99bdb2a2019-03-29 16:35:02 -07002684 // Add in any new direct dependencies that were added by the mutator
2685 module.directDeps = append(module.directDeps, module.newDirectDeps...)
2686 module.newDirectDeps = nil
Colin Cross7addea32015-03-11 15:43:52 -07002687 }
Colin Crossf7beb892019-11-13 20:11:14 -08002688
Colin Cross279489c2020-08-13 12:11:52 -07002689 findAliasTarget := func(variant variant) *moduleInfo {
Colin Cross5df74a82020-08-24 16:18:21 -07002690 for _, moduleOrAlias := range group.modules {
2691 if alias := moduleOrAlias.alias(); alias != nil {
2692 if alias.variant.variations.equal(variant.variations) {
2693 return alias.target
2694 }
Colin Cross279489c2020-08-13 12:11:52 -07002695 }
2696 }
2697 return nil
2698 }
2699
Colin Crossf7beb892019-11-13 20:11:14 -08002700 // Forward or delete any dangling aliases.
Colin Cross5df74a82020-08-24 16:18:21 -07002701 // Use a manual loop instead of range because len(group.modules) can
2702 // change inside the loop
2703 for i := 0; i < len(group.modules); i++ {
2704 if alias := group.modules[i].alias(); alias != nil {
2705 if alias.target.logicModule == nil {
2706 newTarget := findAliasTarget(alias.target.variant)
2707 if newTarget != nil {
2708 alias.target = newTarget
2709 } else {
2710 // The alias was left dangling, remove it.
2711 group.modules = append(group.modules[:i], group.modules[i+1:]...)
2712 i--
2713 }
Colin Crossf7beb892019-11-13 20:11:14 -08002714 }
2715 }
2716 }
Colin Crossc9028482014-12-18 16:28:54 -08002717 }
2718
Colin Cross99bdb2a2019-03-29 16:35:02 -07002719 // Add in any new reverse dependencies that were added by the mutator
Colin Cross8d8a7af2015-11-03 16:41:29 -08002720 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002721 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002722 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002723 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002724 }
2725
Colin Crossaf4fd212017-07-28 14:32:36 -07002726 for _, module := range newModules {
2727 errs = c.addModule(module)
2728 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002729 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002730 }
2731 atomic.AddUint32(&c.depsModified, 1)
2732 }
2733
Colin Cross0ce142c2016-12-09 10:29:05 -08002734 errs = c.handleRenames(rename)
2735 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002736 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002737 }
2738
2739 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002740 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002741 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002742 }
2743
Colin Cross3702ac72016-08-11 11:09:00 -07002744 if c.depsModified > 0 {
2745 errs = c.updateDependencies()
2746 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002747 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002748 }
Colin Crossc9028482014-12-18 16:28:54 -08002749 }
2750
Colin Cross874a3462017-07-31 17:26:06 -07002751 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002752}
2753
Colin Cross910242b2016-04-11 15:41:52 -07002754// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2755// a mutator sets a non-property member variable on a module, which works until a later mutator
2756// creates variants of that module.
2757func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002758 type update struct {
2759 orig Module
2760 clone *moduleInfo
2761 }
Colin Cross7e723372018-03-28 11:50:12 -07002762 ch := make(chan update)
2763 doneCh := make(chan bool)
2764 go func() {
Colin Crossc4773d92020-08-25 17:12:59 -07002765 errs := parallelVisit(c.modulesSorted, unorderedVisitorImpl{}, parallelVisitLimit,
2766 func(m *moduleInfo, pause chan<- pauseSpec) bool {
2767 origLogicModule := m.logicModule
2768 m.logicModule, m.properties = c.cloneLogicModule(m)
2769 ch <- update{origLogicModule, m}
2770 return false
2771 })
2772 if len(errs) > 0 {
2773 panic(errs)
2774 }
Colin Cross7e723372018-03-28 11:50:12 -07002775 doneCh <- true
2776 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002777
Colin Cross7e723372018-03-28 11:50:12 -07002778 done := false
2779 for !done {
2780 select {
2781 case <-doneCh:
2782 done = true
2783 case update := <-ch:
2784 delete(c.moduleInfo, update.orig)
2785 c.moduleInfo[update.clone.logicModule] = update.clone
2786 }
Colin Cross910242b2016-04-11 15:41:52 -07002787 }
2788}
2789
Colin Cross49c279a2016-08-05 22:30:44 -07002790// Removes modules[i] from the list and inserts newModules... where it was located, returning
2791// the new slice and the index of the last inserted element
Colin Cross5df74a82020-08-24 16:18:21 -07002792func spliceModules(modules modulesOrAliases, i int, newModules modulesOrAliases) (modulesOrAliases, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002793 spliceSize := len(newModules)
2794 newLen := len(modules) + spliceSize - 1
Colin Cross5df74a82020-08-24 16:18:21 -07002795 var dest modulesOrAliases
Colin Cross7addea32015-03-11 15:43:52 -07002796 if cap(modules) >= len(modules)-1+len(newModules) {
2797 // We can fit the splice in the existing capacity, do everything in place
2798 dest = modules[:newLen]
2799 } else {
Colin Cross5df74a82020-08-24 16:18:21 -07002800 dest = make(modulesOrAliases, newLen)
Colin Cross7addea32015-03-11 15:43:52 -07002801 copy(dest, modules[:i])
2802 }
2803
2804 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002805 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002806
2807 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002808 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002809
Colin Cross49c279a2016-08-05 22:30:44 -07002810 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002811}
2812
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002813func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002814 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002815
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002816 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002817 var errs []error
2818
Colin Cross691a60d2015-01-07 18:08:56 -08002819 cancelCh := make(chan struct{})
2820 errsCh := make(chan []error)
2821 depsCh := make(chan []string)
2822
2823 go func() {
2824 for {
2825 select {
2826 case <-cancelCh:
2827 close(cancelCh)
2828 return
2829 case newErrs := <-errsCh:
2830 errs = append(errs, newErrs...)
2831 case newDeps := <-depsCh:
2832 deps = append(deps, newDeps...)
2833
2834 }
2835 }
2836 }()
2837
Colin Crossc4773d92020-08-25 17:12:59 -07002838 visitErrs := parallelVisit(c.modulesSorted, bottomUpVisitor, parallelVisitLimit,
2839 func(module *moduleInfo, pause chan<- pauseSpec) bool {
2840 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2841 sanitizedName := toNinjaName(uniqueName)
Yi Konga08e7222021-12-21 15:50:57 +08002842 sanitizedVariant := toNinjaName(module.variant.name)
Jeff Gaston0e907592017-12-01 17:10:52 -08002843
Yi Konga08e7222021-12-21 15:50:57 +08002844 prefix := moduleNamespacePrefix(sanitizedName + "_" + sanitizedVariant)
Jeff Gaston0e907592017-12-01 17:10:52 -08002845
Colin Crossc4773d92020-08-25 17:12:59 -07002846 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2847 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2848 // just set it to nil.
2849 scope := newLocalScope(nil, prefix)
Jeff Gaston0e907592017-12-01 17:10:52 -08002850
Colin Crossc4773d92020-08-25 17:12:59 -07002851 mctx := &moduleContext{
2852 baseModuleContext: baseModuleContext{
2853 context: c,
2854 config: config,
2855 module: module,
2856 },
2857 scope: scope,
2858 handledMissingDeps: module.missingDeps == nil,
Colin Cross036a1df2015-12-17 15:49:30 -08002859 }
Colin Cross036a1df2015-12-17 15:49:30 -08002860
Colin Cross2da84922020-07-02 10:08:12 -07002861 mctx.module.startedGenerateBuildActions = true
2862
Colin Crossc4773d92020-08-25 17:12:59 -07002863 func() {
2864 defer func() {
2865 if r := recover(); r != nil {
2866 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2867 if err, ok := r.(panicError); ok {
2868 err.addIn(in)
2869 mctx.error(err)
2870 } else {
2871 mctx.error(newPanicErrorf(r, in))
2872 }
2873 }
2874 }()
2875 mctx.module.logicModule.GenerateBuildActions(mctx)
2876 }()
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002877
Colin Cross2da84922020-07-02 10:08:12 -07002878 mctx.module.finishedGenerateBuildActions = true
2879
Colin Crossc4773d92020-08-25 17:12:59 -07002880 if len(mctx.errs) > 0 {
2881 errsCh <- mctx.errs
2882 return true
2883 }
2884
2885 if module.missingDeps != nil && !mctx.handledMissingDeps {
2886 var errs []error
2887 for _, depName := range module.missingDeps {
2888 errs = append(errs, c.missingDependencyError(module, depName))
2889 }
2890 errsCh <- errs
2891 return true
2892 }
2893
2894 depsCh <- mctx.ninjaFileDeps
2895
2896 newErrs := c.processLocalBuildActions(&module.actionDefs,
2897 &mctx.actionDefs, liveGlobals)
2898 if len(newErrs) > 0 {
2899 errsCh <- newErrs
2900 return true
2901 }
2902 return false
2903 })
Colin Cross691a60d2015-01-07 18:08:56 -08002904
2905 cancelCh <- struct{}{}
2906 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002907
Colin Crossc4773d92020-08-25 17:12:59 -07002908 errs = append(errs, visitErrs...)
2909
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002910 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002911}
2912
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002913func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002914 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002915
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002916 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002917 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002918
Colin Cross5f03f112017-11-07 13:29:54 -08002919 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002920 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2921 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2922 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002923 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002924
2925 sctx := &singletonContext{
Colin Cross9226d6c2019-02-25 18:07:44 -08002926 name: info.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002927 context: c,
2928 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002929 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002930 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002931 }
2932
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002933 func() {
2934 defer func() {
2935 if r := recover(); r != nil {
2936 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2937 if err, ok := r.(panicError); ok {
2938 err.addIn(in)
2939 sctx.error(err)
2940 } else {
2941 sctx.error(newPanicErrorf(r, in))
2942 }
2943 }
2944 }()
2945 info.singleton.GenerateBuildActions(sctx)
2946 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002947
2948 if len(sctx.errs) > 0 {
2949 errs = append(errs, sctx.errs...)
2950 if len(errs) > maxErrors {
2951 break
2952 }
2953 continue
2954 }
2955
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002956 deps = append(deps, sctx.ninjaFileDeps...)
2957
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002958 newErrs := c.processLocalBuildActions(&info.actionDefs,
2959 &sctx.actionDefs, liveGlobals)
2960 errs = append(errs, newErrs...)
2961 if len(errs) > maxErrors {
2962 break
2963 }
2964 }
2965
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002966 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002967}
2968
2969func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2970 liveGlobals *liveTracker) []error {
2971
2972 var errs []error
2973
2974 // First we go through and add everything referenced by the module's
2975 // buildDefs to the live globals set. This will end up adding the live
2976 // locals to the set as well, but we'll take them out after.
2977 for _, def := range in.buildDefs {
2978 err := liveGlobals.AddBuildDefDeps(def)
2979 if err != nil {
2980 errs = append(errs, err)
2981 }
2982 }
2983
2984 if len(errs) > 0 {
2985 return errs
2986 }
2987
Colin Crossc9028482014-12-18 16:28:54 -08002988 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002989
2990 // We use the now-incorrect set of live "globals" to determine which local
2991 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002992 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002993 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002994 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002995 if isLive {
2996 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002997 }
2998 }
2999
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003000 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07003001 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003002 if isLive {
3003 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003004 }
3005 }
3006
3007 return nil
3008}
3009
Colin Cross9607a9f2018-06-20 11:16:37 -07003010func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07003011 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07003012
3013 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003014 var visiting *moduleInfo
3015
3016 defer func() {
3017 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07003018 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
3019 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003020 }
3021 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07003022
3023 var walk func(module *moduleInfo)
3024 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003025 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07003026 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003027 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07003028 recurse := true
3029 if visitDown != nil {
3030 recurse = visitDown(dep, module)
3031 }
Colin Cross526e02f2018-06-21 13:31:53 -07003032 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07003033 walk(dep.module)
Paul Duffin72bab172020-04-02 10:51:33 +01003034 visited[dep.module] = true
Yuchen Wu222e2452015-10-06 14:03:27 -07003035 }
Colin Crossbafd5f52016-08-06 22:52:01 -07003036 if visitUp != nil {
3037 visitUp(dep, module)
3038 }
Yuchen Wu222e2452015-10-06 14:03:27 -07003039 }
3040 }
3041 }
3042
3043 walk(topModule)
3044}
3045
Colin Cross9cfd1982016-10-11 09:58:53 -07003046type replace struct {
Paul Duffin8969cb62020-06-30 12:15:26 +01003047 from, to *moduleInfo
3048 predicate ReplaceDependencyPredicate
Colin Cross9cfd1982016-10-11 09:58:53 -07003049}
3050
Colin Crossc4e5b812016-10-12 10:45:05 -07003051type rename struct {
3052 group *moduleGroup
3053 name string
3054}
3055
Colin Cross0ce142c2016-12-09 10:29:05 -08003056func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Crossd03b59d2019-11-13 20:10:12 -08003057 group := c.moduleGroupFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07003058
Colin Crossd03b59d2019-11-13 20:10:12 -08003059 if group == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08003060 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003061 }
3062
Colin Crossd03b59d2019-11-13 20:10:12 -08003063 for _, m := range group.modules {
Colin Crossedbdb8c2020-09-11 19:22:27 -07003064 if module.variant.name == m.moduleOrAliasVariant().name {
Colin Cross5df74a82020-08-24 16:18:21 -07003065 return m.moduleOrAliasTarget()
Colin Crossf7beb892019-11-13 20:11:14 -08003066 }
3067 }
3068
Colin Cross0ce142c2016-12-09 10:29:05 -08003069 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07003070}
3071
Colin Cross0ce142c2016-12-09 10:29:05 -08003072func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07003073 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08003074 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07003075 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08003076 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07003077 continue
3078 }
3079
Jeff Gastond70bf752017-11-10 15:12:08 -08003080 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07003081 }
3082
Colin Cross0ce142c2016-12-09 10:29:05 -08003083 return errs
3084}
3085
3086func (c *Context) handleReplacements(replacements []replace) []error {
3087 var errs []error
Paul Duffin8969cb62020-06-30 12:15:26 +01003088 changedDeps := false
Colin Cross0ce142c2016-12-09 10:29:05 -08003089 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07003090 for _, m := range replace.from.reverseDeps {
3091 for i, d := range m.directDeps {
3092 if d.module == replace.from {
Paul Duffin8969cb62020-06-30 12:15:26 +01003093 // If the replacement has a predicate then check it.
3094 if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) {
3095 m.directDeps[i].module = replace.to
3096 changedDeps = true
3097 }
Colin Cross9cfd1982016-10-11 09:58:53 -07003098 }
3099 }
3100 }
3101
Colin Cross9cfd1982016-10-11 09:58:53 -07003102 }
Colin Cross0ce142c2016-12-09 10:29:05 -08003103
Paul Duffin8969cb62020-06-30 12:15:26 +01003104 if changedDeps {
3105 atomic.AddUint32(&c.depsModified, 1)
3106 }
Colin Crossc4e5b812016-10-12 10:45:05 -07003107 return errs
3108}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003109
Martin Stjernholm0f1637b2020-11-16 20:15:36 +00003110func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string, depVariations variationMap) (errs []error) {
3111 if depVariations != nil {
3112 depName = depName + "{" + c.prettyPrintVariant(depVariations) + "}"
3113 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003114 if c.allowMissingDependencies {
3115 module.missingDeps = append(module.missingDeps, depName)
3116 return nil
3117 }
3118 return []error{c.missingDependencyError(module, depName)}
3119}
3120
3121func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
3122 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
3123
3124 return &BlueprintError{
3125 Err: err,
3126 Pos: module.pos,
3127 }
3128}
3129
Colin Crossd03b59d2019-11-13 20:10:12 -08003130func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
Jeff Gastond70bf752017-11-10 15:12:08 -08003131 group, exists := c.nameInterface.ModuleFromName(name, namespace)
3132 if exists {
Colin Crossd03b59d2019-11-13 20:10:12 -08003133 return group.moduleGroup
Colin Cross0b7e83e2016-05-17 14:58:05 -07003134 }
3135 return nil
3136}
3137
Jeff Gastond70bf752017-11-10 15:12:08 -08003138func (c *Context) sortedModuleGroups() []*moduleGroup {
Liz Kammer9ae14f12020-11-30 16:30:45 -07003139 if c.cachedSortedModuleGroups == nil || c.cachedDepsModified {
Jeff Gastond70bf752017-11-10 15:12:08 -08003140 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
3141 result := make([]*moduleGroup, 0, len(wrappers))
3142 for _, group := range wrappers {
3143 result = append(result, group.moduleGroup)
3144 }
3145 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07003146 }
Jeff Gastond70bf752017-11-10 15:12:08 -08003147
3148 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Liz Kammer9ae14f12020-11-30 16:30:45 -07003149 c.cachedDepsModified = false
Jamie Gennisc15544d2014-09-24 20:26:52 -07003150 }
3151
Jeff Gastond70bf752017-11-10 15:12:08 -08003152 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07003153}
3154
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003155func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003156 var module *moduleInfo
3157
3158 defer func() {
3159 if r := recover(); r != nil {
3160 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
3161 funcName(visit), module))
3162 }
3163 }()
3164
Jeff Gastond70bf752017-11-10 15:12:08 -08003165 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003166 for _, moduleOrAlias := range moduleGroup.modules {
3167 if module = moduleOrAlias.module(); module != nil {
3168 visit(module.logicModule)
3169 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003170 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003171 }
3172}
3173
3174func (c *Context) visitAllModulesIf(pred func(Module) bool,
3175 visit func(Module)) {
3176
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003177 var module *moduleInfo
3178
3179 defer func() {
3180 if r := recover(); r != nil {
3181 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
3182 funcName(pred), funcName(visit), module))
3183 }
3184 }()
3185
Jeff Gastond70bf752017-11-10 15:12:08 -08003186 for _, moduleGroup := range c.sortedModuleGroups() {
Colin Cross5df74a82020-08-24 16:18:21 -07003187 for _, moduleOrAlias := range moduleGroup.modules {
3188 if module = moduleOrAlias.module(); module != nil {
3189 if pred(module.logicModule) {
3190 visit(module.logicModule)
3191 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08003192 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003193 }
3194 }
3195}
3196
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003197func (c *Context) visitAllModuleVariants(module *moduleInfo,
3198 visit func(Module)) {
3199
3200 var variant *moduleInfo
3201
3202 defer func() {
3203 if r := recover(); r != nil {
3204 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
3205 module, funcName(visit), variant))
3206 }
3207 }()
3208
Colin Cross5df74a82020-08-24 16:18:21 -07003209 for _, moduleOrAlias := range module.group.modules {
3210 if variant = moduleOrAlias.module(); variant != nil {
3211 visit(variant.logicModule)
3212 }
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003213 }
3214}
3215
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003216func (c *Context) requireNinjaVersion(major, minor, micro int) {
3217 if major != 1 {
3218 panic("ninja version with major version != 1 not supported")
3219 }
3220 if c.requiredNinjaMinor < minor {
3221 c.requiredNinjaMinor = minor
3222 c.requiredNinjaMicro = micro
3223 }
3224 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
3225 c.requiredNinjaMicro = micro
3226 }
3227}
3228
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003229func (c *Context) setOutDir(value ninjaString) {
3230 if c.outDir == nil {
3231 c.outDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003232 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003233}
3234
3235func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08003236 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003237
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003238 pkgs := make(map[string]*packageContext)
3239 pkgNames := make(map[*packageContext]string)
3240 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003241
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003242 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003243 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003244 // This is a built-in rule and has no package.
3245 return
3246 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07003247 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003248 // We've already processed this package.
3249 return
3250 }
3251
Jamie Gennis2fb20952014-10-03 02:49:58 -07003252 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003253 if present {
3254 // Short name collision. Both this package and the one that's
3255 // already there need to use their full names. We leave the short
3256 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003257 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003258 longPkgNames[otherPkg] = true
3259 } else {
3260 // No collision so far. Tentatively set the package's name to be
3261 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003262 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07003263 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003264 }
3265 }
3266
3267 // We try to give all packages their short name, but when we get collisions
3268 // we need to use the full unique package name.
3269 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003270 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003271 }
3272 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003273 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003274 }
3275 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07003276 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003277 }
3278
3279 // Add the packages that had collisions using their full unique names. This
3280 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07003281 for pctx := range longPkgNames {
3282 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003283 }
3284
Dan Willemsena481ae22015-12-18 15:18:03 -08003285 // Create deps list from calls to PackageContext.AddNinjaFileDeps
3286 deps := []string{}
3287 for _, pkg := range pkgs {
3288 deps = append(deps, pkg.ninjaFileDeps...)
3289 }
3290
3291 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003292}
3293
Colin Cross92054a42021-01-21 16:49:25 -08003294// memoizeFullNames stores the full name of each live global variable, rule and pool since each is
3295// guaranteed to be used at least twice, once in the definition and once for each usage, and many
3296// are used much more than once.
3297func (c *Context) memoizeFullNames(liveGlobals *liveTracker, pkgNames map[*packageContext]string) {
3298 for v := range liveGlobals.variables {
3299 v.memoizeFullName(pkgNames)
3300 }
3301 for r := range liveGlobals.rules {
3302 r.memoizeFullName(pkgNames)
3303 }
3304 for p := range liveGlobals.pools {
3305 p.memoizeFullName(pkgNames)
3306 }
3307}
3308
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003309func (c *Context) checkForVariableReferenceCycles(
Colin Cross2ce594e2020-01-29 12:58:03 -08003310 variables map[Variable]ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003311
3312 visited := make(map[Variable]bool) // variables that were already checked
3313 checking := make(map[Variable]bool) // variables actively being checked
3314
3315 var check func(v Variable) []Variable
3316
3317 check = func(v Variable) []Variable {
3318 visited[v] = true
3319 checking[v] = true
3320 defer delete(checking, v)
3321
3322 value := variables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003323 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003324 if checking[dep] {
3325 // This is a cycle.
3326 return []Variable{dep, v}
3327 }
3328
3329 if !visited[dep] {
3330 cycle := check(dep)
3331 if cycle != nil {
3332 if cycle[0] == v {
3333 // We are the "start" of the cycle, so we're responsible
3334 // for generating the errors. The cycle list is in
3335 // reverse order because all the 'check' calls append
3336 // their own module to the list.
3337 msgs := []string{"detected variable reference cycle:"}
3338
3339 // Iterate backwards through the cycle list.
3340 curName := v.fullName(pkgNames)
3341 curValue := value.Value(pkgNames)
3342 for i := len(cycle) - 1; i >= 0; i-- {
3343 next := cycle[i]
3344 nextName := next.fullName(pkgNames)
3345 nextValue := variables[next].Value(pkgNames)
3346
3347 msgs = append(msgs, fmt.Sprintf(
3348 " %q depends on %q", curName, nextName))
3349 msgs = append(msgs, fmt.Sprintf(
3350 " [%s = %s]", curName, curValue))
3351
3352 curName = nextName
3353 curValue = nextValue
3354 }
3355
3356 // Variable reference cycles are a programming error,
3357 // not the fault of the Blueprint file authors.
3358 panic(strings.Join(msgs, "\n"))
3359 } else {
3360 // We're not the "start" of the cycle, so we just append
3361 // our module to the list and return it.
3362 return append(cycle, v)
3363 }
3364 }
3365 }
3366 }
3367
3368 return nil
3369 }
3370
3371 for v := range variables {
3372 if !visited[v] {
3373 cycle := check(v)
3374 if cycle != nil {
3375 panic("inconceivable!")
3376 }
3377 }
3378 }
3379}
3380
Jamie Gennisaf435562014-10-27 22:34:56 -07003381// AllTargets returns a map all the build target names to the rule used to build
3382// them. This is the same information that is output by running 'ninja -t
3383// targets all'. If this is called before PrepareBuildActions successfully
3384// completes then ErrbuildActionsNotReady is returned.
3385func (c *Context) AllTargets() (map[string]string, error) {
3386 if !c.buildActionsReady {
3387 return nil, ErrBuildActionsNotReady
3388 }
3389
3390 targets := map[string]string{}
3391
3392 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07003393 for _, module := range c.moduleInfo {
3394 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07003395 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003396 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003397 outputValue, err := output.Eval(c.globalVariables)
3398 if err != nil {
3399 return nil, err
3400 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003401 targets[outputValue] = ruleName
3402 }
3403 }
3404 }
3405
3406 // Collect all the singleton build targets.
3407 for _, info := range c.singletonInfo {
3408 for _, buildDef := range info.actionDefs.buildDefs {
3409 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003410 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003411 outputValue, err := output.Eval(c.globalVariables)
3412 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08003413 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08003414 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003415 targets[outputValue] = ruleName
3416 }
3417 }
3418 }
3419
3420 return targets, nil
3421}
3422
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003423func (c *Context) OutDir() (string, error) {
3424 if c.outDir != nil {
3425 return c.outDir.Eval(c.globalVariables)
Colin Crossa2599452015-11-18 16:01:01 -08003426 } else {
3427 return "", nil
3428 }
3429}
3430
Colin Cross4572edd2015-05-13 14:36:24 -07003431// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
3432// property structs returned by the factory for that module type.
3433func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
3434 ret := make(map[string][]interface{})
3435 for moduleType, factory := range c.moduleFactories {
3436 _, ret[moduleType] = factory()
3437 }
3438
3439 return ret
3440}
3441
Jaewoong Jung781f6b22019-02-06 16:20:17 -08003442func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
3443 ret := make(map[string]ModuleFactory)
3444 for k, v := range c.moduleFactories {
3445 ret[k] = v
3446 }
3447 return ret
3448}
3449
Colin Cross4572edd2015-05-13 14:36:24 -07003450func (c *Context) ModuleName(logicModule Module) string {
3451 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07003452 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07003453}
3454
Jeff Gaston3c8c3342017-11-30 17:30:42 -08003455func (c *Context) ModuleDir(logicModule Module) string {
Colin Cross8e454c52020-07-06 12:18:59 -07003456 return filepath.Dir(c.BlueprintFile(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07003457}
3458
Colin Cross8c602f72015-12-17 18:02:11 -08003459func (c *Context) ModuleSubDir(logicModule Module) string {
3460 module := c.moduleInfo[logicModule]
Colin Crossedc41762020-08-13 12:07:30 -07003461 return module.variant.name
Colin Cross8c602f72015-12-17 18:02:11 -08003462}
3463
Dan Willemsenc98e55b2016-07-25 15:51:50 -07003464func (c *Context) ModuleType(logicModule Module) string {
3465 module := c.moduleInfo[logicModule]
3466 return module.typeName
3467}
3468
Colin Cross2da84922020-07-02 10:08:12 -07003469// ModuleProvider returns the value, if any, for the provider for a module. If the value for the
3470// provider was not set it returns the zero value of the type of the provider, which means the
3471// return value can always be type-asserted to the type of the provider. The return value should
3472// always be considered read-only. It panics if called before the appropriate mutator or
3473// GenerateBuildActions pass for the provider on the module. The value returned may be a deep
3474// copy of the value originally passed to SetProvider.
3475func (c *Context) ModuleProvider(logicModule Module, provider ProviderKey) interface{} {
3476 module := c.moduleInfo[logicModule]
3477 value, _ := c.provider(module, provider)
3478 return value
3479}
3480
3481// ModuleHasProvider returns true if the provider for the given module has been set.
3482func (c *Context) ModuleHasProvider(logicModule Module, provider ProviderKey) bool {
3483 module := c.moduleInfo[logicModule]
3484 _, ok := c.provider(module, provider)
3485 return ok
3486}
3487
Colin Cross4572edd2015-05-13 14:36:24 -07003488func (c *Context) BlueprintFile(logicModule Module) string {
3489 module := c.moduleInfo[logicModule]
3490 return module.relBlueprintsFile
3491}
3492
3493func (c *Context) ModuleErrorf(logicModule Module, format string,
3494 args ...interface{}) error {
3495
3496 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07003497 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07003498 Err: fmt.Errorf(format, args...),
3499 Pos: module.pos,
3500 }
3501}
3502
3503func (c *Context) VisitAllModules(visit func(Module)) {
3504 c.visitAllModules(visit)
3505}
3506
3507func (c *Context) VisitAllModulesIf(pred func(Module) bool,
3508 visit func(Module)) {
3509
3510 c.visitAllModulesIf(pred, visit)
3511}
3512
Colin Cross080c1332017-03-17 13:09:05 -07003513func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
3514 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07003515
Colin Cross080c1332017-03-17 13:09:05 -07003516 var visiting *moduleInfo
3517
3518 defer func() {
3519 if r := recover(); r != nil {
3520 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
3521 topModule, funcName(visit), visiting))
3522 }
3523 }()
3524
3525 for _, dep := range topModule.directDeps {
3526 visiting = dep.module
3527 visit(dep.module.logicModule)
3528 }
3529}
3530
3531func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
3532 topModule := c.moduleInfo[module]
3533
3534 var visiting *moduleInfo
3535
3536 defer func() {
3537 if r := recover(); r != nil {
3538 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
3539 topModule, funcName(pred), funcName(visit), visiting))
3540 }
3541 }()
3542
3543 for _, dep := range topModule.directDeps {
3544 visiting = dep.module
3545 if pred(dep.module.logicModule) {
3546 visit(dep.module.logicModule)
3547 }
3548 }
3549}
3550
3551func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003552 topModule := c.moduleInfo[module]
3553
3554 var visiting *moduleInfo
3555
3556 defer func() {
3557 if r := recover(); r != nil {
3558 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
3559 topModule, funcName(visit), visiting))
3560 }
3561 }()
3562
Colin Cross9607a9f2018-06-20 11:16:37 -07003563 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003564 visiting = dep.module
3565 visit(dep.module.logicModule)
3566 })
Colin Cross4572edd2015-05-13 14:36:24 -07003567}
3568
Colin Cross080c1332017-03-17 13:09:05 -07003569func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003570 topModule := c.moduleInfo[module]
3571
3572 var visiting *moduleInfo
3573
3574 defer func() {
3575 if r := recover(); r != nil {
3576 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
3577 topModule, funcName(pred), funcName(visit), visiting))
3578 }
3579 }()
3580
Colin Cross9607a9f2018-06-20 11:16:37 -07003581 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003582 if pred(dep.module.logicModule) {
3583 visiting = dep.module
3584 visit(dep.module.logicModule)
3585 }
3586 })
Colin Cross4572edd2015-05-13 14:36:24 -07003587}
3588
Colin Cross24ad5872015-11-17 16:22:29 -08003589func (c *Context) PrimaryModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003590 return c.moduleInfo[module].group.modules.firstModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003591}
3592
3593func (c *Context) FinalModule(module Module) Module {
Colin Cross5df74a82020-08-24 16:18:21 -07003594 return c.moduleInfo[module].group.modules.lastModule().logicModule
Colin Cross24ad5872015-11-17 16:22:29 -08003595}
3596
3597func (c *Context) VisitAllModuleVariants(module Module,
3598 visit func(Module)) {
3599
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003600 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08003601}
3602
Colin Cross9226d6c2019-02-25 18:07:44 -08003603// Singletons returns a list of all registered Singletons.
3604func (c *Context) Singletons() []Singleton {
3605 var ret []Singleton
3606 for _, s := range c.singletonInfo {
3607 ret = append(ret, s.singleton)
3608 }
3609 return ret
3610}
3611
3612// SingletonName returns the name that the given singleton was registered with.
3613func (c *Context) SingletonName(singleton Singleton) string {
3614 for _, s := range c.singletonInfo {
3615 if s.singleton == singleton {
3616 return s.name
3617 }
3618 }
3619 return ""
3620}
3621
Jamie Gennisd4e10182014-06-12 20:06:50 -07003622// WriteBuildFile writes the Ninja manifeset text for the generated build
3623// actions to w. If this is called before PrepareBuildActions successfully
3624// completes then ErrBuildActionsNotReady is returned.
Colin Cross0335e092021-01-21 15:26:21 -08003625func (c *Context) WriteBuildFile(w io.StringWriter) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08003626 var err error
3627 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
3628 if !c.buildActionsReady {
3629 err = ErrBuildActionsNotReady
3630 return
3631 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003632
Colin Cross3a8c0252019-01-23 13:21:48 -08003633 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003634
Colin Cross3a8c0252019-01-23 13:21:48 -08003635 err = c.writeBuildFileHeader(nw)
3636 if err != nil {
3637 return
3638 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003639
Colin Cross3a8c0252019-01-23 13:21:48 -08003640 err = c.writeNinjaRequiredVersion(nw)
3641 if err != nil {
3642 return
3643 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003644
Colin Cross3a8c0252019-01-23 13:21:48 -08003645 err = c.writeSubninjas(nw)
3646 if err != nil {
3647 return
3648 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003649
Colin Cross3a8c0252019-01-23 13:21:48 -08003650 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003651
Colin Cross3a8c0252019-01-23 13:21:48 -08003652 err = c.writeGlobalVariables(nw)
3653 if err != nil {
3654 return
3655 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003656
Colin Cross3a8c0252019-01-23 13:21:48 -08003657 err = c.writeGlobalPools(nw)
3658 if err != nil {
3659 return
3660 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003661
Colin Cross3a8c0252019-01-23 13:21:48 -08003662 err = c.writeBuildDir(nw)
3663 if err != nil {
3664 return
3665 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003666
Colin Cross3a8c0252019-01-23 13:21:48 -08003667 err = c.writeGlobalRules(nw)
3668 if err != nil {
3669 return
3670 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003671
Colin Cross3a8c0252019-01-23 13:21:48 -08003672 err = c.writeAllModuleActions(nw)
3673 if err != nil {
3674 return
3675 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003676
Colin Cross3a8c0252019-01-23 13:21:48 -08003677 err = c.writeAllSingletonActions(nw)
3678 if err != nil {
3679 return
3680 }
3681 })
3682
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003683 if err != nil {
3684 return err
3685 }
3686
3687 return nil
3688}
3689
Jamie Gennisc15544d2014-09-24 20:26:52 -07003690type pkgAssociation struct {
3691 PkgName string
3692 PkgPath string
3693}
3694
3695type pkgAssociationSorter struct {
3696 pkgs []pkgAssociation
3697}
3698
3699func (s *pkgAssociationSorter) Len() int {
3700 return len(s.pkgs)
3701}
3702
3703func (s *pkgAssociationSorter) Less(i, j int) bool {
3704 iName := s.pkgs[i].PkgName
3705 jName := s.pkgs[j].PkgName
3706 return iName < jName
3707}
3708
3709func (s *pkgAssociationSorter) Swap(i, j int) {
3710 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3711}
3712
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003713func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3714 headerTemplate := template.New("fileHeader")
3715 _, err := headerTemplate.Parse(fileHeaderTemplate)
3716 if err != nil {
3717 // This is a programming error.
3718 panic(err)
3719 }
3720
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003721 var pkgs []pkgAssociation
3722 maxNameLen := 0
3723 for pkg, name := range c.pkgNames {
3724 pkgs = append(pkgs, pkgAssociation{
3725 PkgName: name,
3726 PkgPath: pkg.pkgPath,
3727 })
3728 if len(name) > maxNameLen {
3729 maxNameLen = len(name)
3730 }
3731 }
3732
3733 for i := range pkgs {
3734 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3735 }
3736
Jamie Gennisc15544d2014-09-24 20:26:52 -07003737 sort.Sort(&pkgAssociationSorter{pkgs})
3738
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003739 params := map[string]interface{}{
3740 "Pkgs": pkgs,
3741 }
3742
3743 buf := bytes.NewBuffer(nil)
3744 err = headerTemplate.Execute(buf, params)
3745 if err != nil {
3746 return err
3747 }
3748
3749 return nw.Comment(buf.String())
3750}
3751
3752func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3753 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3754 c.requiredNinjaMicro)
3755
3756 err := nw.Assign("ninja_required_version", value)
3757 if err != nil {
3758 return err
3759 }
3760
3761 return nw.BlankLine()
3762}
3763
Dan Willemsenab223a52018-07-05 21:56:59 -07003764func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3765 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003766 err := nw.Subninja(subninja)
3767 if err != nil {
3768 return err
3769 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003770 }
3771 return nw.BlankLine()
3772}
3773
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003774func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Lukacs T. Berki5c4abb12021-08-26 15:08:09 +02003775 if c.outDir != nil {
3776 err := nw.Assign("builddir", c.outDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003777 if err != nil {
3778 return err
3779 }
3780
3781 err = nw.BlankLine()
3782 if err != nil {
3783 return err
3784 }
3785 }
3786 return nil
3787}
3788
Jamie Gennisc15544d2014-09-24 20:26:52 -07003789type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003790 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003791}
3792
Jamie Gennisc15544d2014-09-24 20:26:52 -07003793type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003794 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003795 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003796}
3797
Jamie Gennisc15544d2014-09-24 20:26:52 -07003798func (s *globalEntitySorter) Len() int {
3799 return len(s.entities)
3800}
3801
3802func (s *globalEntitySorter) Less(i, j int) bool {
3803 iName := s.entities[i].fullName(s.pkgNames)
3804 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003805 return iName < jName
3806}
3807
Jamie Gennisc15544d2014-09-24 20:26:52 -07003808func (s *globalEntitySorter) Swap(i, j int) {
3809 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003810}
3811
3812func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3813 visited := make(map[Variable]bool)
3814
3815 var walk func(v Variable) error
3816 walk = func(v Variable) error {
3817 visited[v] = true
3818
3819 // First visit variables on which this variable depends.
3820 value := c.globalVariables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003821 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003822 if !visited[dep] {
3823 err := walk(dep)
3824 if err != nil {
3825 return err
3826 }
3827 }
3828 }
3829
3830 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3831 if err != nil {
3832 return err
3833 }
3834
3835 err = nw.BlankLine()
3836 if err != nil {
3837 return err
3838 }
3839
3840 return nil
3841 }
3842
Jamie Gennisc15544d2014-09-24 20:26:52 -07003843 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3844 for variable := range c.globalVariables {
3845 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003846 }
3847
Jamie Gennisc15544d2014-09-24 20:26:52 -07003848 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003849
Jamie Gennisc15544d2014-09-24 20:26:52 -07003850 for _, entity := range globalVariables {
3851 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003852 if !visited[v] {
3853 err := walk(v)
3854 if err != nil {
3855 return nil
3856 }
3857 }
3858 }
3859
3860 return nil
3861}
3862
3863func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003864 globalPools := make([]globalEntity, 0, len(c.globalPools))
3865 for pool := range c.globalPools {
3866 globalPools = append(globalPools, pool)
3867 }
3868
3869 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3870
3871 for _, entity := range globalPools {
3872 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003873 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003874 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003875 err := def.WriteTo(nw, name)
3876 if err != nil {
3877 return err
3878 }
3879
3880 err = nw.BlankLine()
3881 if err != nil {
3882 return err
3883 }
3884 }
3885
3886 return nil
3887}
3888
3889func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003890 globalRules := make([]globalEntity, 0, len(c.globalRules))
3891 for rule := range c.globalRules {
3892 globalRules = append(globalRules, rule)
3893 }
3894
3895 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3896
3897 for _, entity := range globalRules {
3898 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003899 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003900 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003901 err := def.WriteTo(nw, name, c.pkgNames)
3902 if err != nil {
3903 return err
3904 }
3905
3906 err = nw.BlankLine()
3907 if err != nil {
3908 return err
3909 }
3910 }
3911
3912 return nil
3913}
3914
Colin Cross2c1f3d12016-04-11 15:47:28 -07003915type depSorter []depInfo
3916
3917func (s depSorter) Len() int {
3918 return len(s)
3919}
3920
3921func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003922 iName := s[i].module.Name()
3923 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003924 if iName == jName {
Colin Crossedc41762020-08-13 12:07:30 -07003925 iName = s[i].module.variant.name
3926 jName = s[j].module.variant.name
Colin Cross2c1f3d12016-04-11 15:47:28 -07003927 }
3928 return iName < jName
3929}
3930
3931func (s depSorter) Swap(i, j int) {
3932 s[i], s[j] = s[j], s[i]
3933}
3934
Jeff Gaston0e907592017-12-01 17:10:52 -08003935type moduleSorter struct {
3936 modules []*moduleInfo
3937 nameInterface NameInterface
3938}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003939
Colin Crossab6d7902015-03-11 16:17:52 -07003940func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003941 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003942}
3943
Colin Crossab6d7902015-03-11 16:17:52 -07003944func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003945 iMod := s.modules[i]
3946 jMod := s.modules[j]
3947 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3948 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003949 if iName == jName {
Colin Cross279489c2020-08-13 12:11:52 -07003950 iVariantName := s.modules[i].variant.name
3951 jVariantName := s.modules[j].variant.name
3952 if iVariantName == jVariantName {
3953 panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
3954 iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
3955 } else {
3956 return iVariantName < jVariantName
3957 }
3958 } else {
3959 return iName < jName
Jeff Gaston0e907592017-12-01 17:10:52 -08003960 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003961}
3962
Colin Crossab6d7902015-03-11 16:17:52 -07003963func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003964 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003965}
3966
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003967func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3968 headerTemplate := template.New("moduleHeader")
3969 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3970 if err != nil {
3971 // This is a programming error.
3972 panic(err)
3973 }
3974
Colin Crossab6d7902015-03-11 16:17:52 -07003975 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3976 for _, module := range c.moduleInfo {
3977 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003978 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003979 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003980
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003981 buf := bytes.NewBuffer(nil)
3982
Colin Crossab6d7902015-03-11 16:17:52 -07003983 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003984 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3985 continue
3986 }
3987
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003988 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003989
3990 // In order to make the bootstrap build manifest independent of the
3991 // build dir we need to output the Blueprints file locations in the
3992 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003993 relPos := module.pos
3994 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003995
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003996 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003997 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003998 factoryName := factoryFunc.Name()
3999
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004000 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07004001 "name": module.Name(),
4002 "typeName": module.typeName,
4003 "goFactory": factoryName,
4004 "pos": relPos,
Colin Crossedc41762020-08-13 12:07:30 -07004005 "variant": module.variant.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004006 }
4007 err = headerTemplate.Execute(buf, infoMap)
4008 if err != nil {
4009 return err
4010 }
4011
4012 err = nw.Comment(buf.String())
4013 if err != nil {
4014 return err
4015 }
4016
4017 err = nw.BlankLine()
4018 if err != nil {
4019 return err
4020 }
4021
Colin Crossab6d7902015-03-11 16:17:52 -07004022 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004023 if err != nil {
4024 return err
4025 }
4026
4027 err = nw.BlankLine()
4028 if err != nil {
4029 return err
4030 }
4031 }
4032
4033 return nil
4034}
4035
4036func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
4037 headerTemplate := template.New("singletonHeader")
4038 _, err := headerTemplate.Parse(singletonHeaderTemplate)
4039 if err != nil {
4040 // This is a programming error.
4041 panic(err)
4042 }
4043
4044 buf := bytes.NewBuffer(nil)
4045
Yuchen Wub9103ef2015-08-25 17:58:17 -07004046 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07004047 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
4048 continue
4049 }
4050
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004051 // Get the name of the factory function for the module.
4052 factory := info.factory
4053 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
4054 factoryName := factoryFunc.Name()
4055
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004056 buf.Reset()
4057 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07004058 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004059 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004060 }
4061 err = headerTemplate.Execute(buf, infoMap)
4062 if err != nil {
4063 return err
4064 }
4065
4066 err = nw.Comment(buf.String())
4067 if err != nil {
4068 return err
4069 }
4070
4071 err = nw.BlankLine()
4072 if err != nil {
4073 return err
4074 }
4075
4076 err = c.writeLocalBuildActions(nw, &info.actionDefs)
4077 if err != nil {
4078 return err
4079 }
4080
4081 err = nw.BlankLine()
4082 if err != nil {
4083 return err
4084 }
4085 }
4086
4087 return nil
4088}
4089
Chris Parsons18ebb232022-03-25 00:56:02 -04004090func (c *Context) BeginEvent(name string) {
4091 c.EventHandler.Begin(name)
4092}
4093
4094func (c *Context) EndEvent(name string) {
4095 c.EventHandler.End(name)
4096}
4097
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004098func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
4099 defs *localBuildActions) error {
4100
4101 // Write the local variable assignments.
4102 for _, v := range defs.variables {
4103 // A localVariable doesn't need the package names or config to
4104 // determine its name or value.
4105 name := v.fullName(nil)
4106 value, err := v.value(nil)
4107 if err != nil {
4108 panic(err)
4109 }
4110 err = nw.Assign(name, value.Value(c.pkgNames))
4111 if err != nil {
4112 return err
4113 }
4114 }
4115
4116 if len(defs.variables) > 0 {
4117 err := nw.BlankLine()
4118 if err != nil {
4119 return err
4120 }
4121 }
4122
4123 // Write the local rules.
4124 for _, r := range defs.rules {
4125 // A localRule doesn't need the package names or config to determine
4126 // its name or definition.
4127 name := r.fullName(nil)
4128 def, err := r.def(nil)
4129 if err != nil {
4130 panic(err)
4131 }
4132
4133 err = def.WriteTo(nw, name, c.pkgNames)
4134 if err != nil {
4135 return err
4136 }
4137
4138 err = nw.BlankLine()
4139 if err != nil {
4140 return err
4141 }
4142 }
4143
4144 // Write the build definitions.
4145 for _, buildDef := range defs.buildDefs {
4146 err := buildDef.WriteTo(nw, c.pkgNames)
4147 if err != nil {
4148 return err
4149 }
4150
4151 if len(buildDef.Args) > 0 {
4152 err = nw.BlankLine()
4153 if err != nil {
4154 return err
4155 }
4156 }
4157 }
4158
4159 return nil
4160}
4161
Colin Cross5df74a82020-08-24 16:18:21 -07004162func beforeInModuleList(a, b *moduleInfo, list modulesOrAliases) bool {
Colin Cross65569e42015-03-10 20:08:19 -07004163 found := false
Colin Cross045a5972015-11-03 16:58:48 -08004164 if a == b {
4165 return false
4166 }
Colin Cross65569e42015-03-10 20:08:19 -07004167 for _, l := range list {
Colin Cross5df74a82020-08-24 16:18:21 -07004168 if l.module() == a {
Colin Cross65569e42015-03-10 20:08:19 -07004169 found = true
Colin Cross5df74a82020-08-24 16:18:21 -07004170 } else if l.module() == b {
Colin Cross65569e42015-03-10 20:08:19 -07004171 return found
4172 }
4173 }
4174
4175 missing := a
4176 if found {
4177 missing = b
4178 }
4179 panic(fmt.Errorf("element %v not found in list %v", missing, list))
4180}
4181
Colin Cross0aa6a5f2016-01-07 13:43:09 -08004182type panicError struct {
4183 panic interface{}
4184 stack []byte
4185 in string
4186}
4187
4188func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
4189 buf := make([]byte, 4096)
4190 count := runtime.Stack(buf, false)
4191 return panicError{
4192 panic: panic,
4193 in: fmt.Sprintf(in, a...),
4194 stack: buf[:count],
4195 }
4196}
4197
4198func (p panicError) Error() string {
4199 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
4200}
4201
4202func (p *panicError) addIn(in string) {
4203 p.in += " in " + in
4204}
4205
4206func funcName(f interface{}) string {
4207 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
4208}
4209
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004210var fileHeaderTemplate = `******************************************************************************
4211*** This file is generated and should not be edited ***
4212******************************************************************************
4213{{if .Pkgs}}
4214This file contains variables, rules, and pools with name prefixes indicating
4215they were generated by the following Go packages:
4216{{range .Pkgs}}
4217 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
4218
4219`
4220
4221var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07004222Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07004223Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004224Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004225Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004226Defined: {{.pos}}
4227`
4228
4229var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
4230Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07004231Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07004232`