blob: 75e9b000d5d5c2cb8f48cb33438fafd8dc08eee5 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
Colin Cross3a8c0252019-01-23 13:21:48 -080019 "context"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "errors"
21 "fmt"
22 "io"
Jeff Gastonc3e28442017-08-09 15:13:12 -070023 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070024 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Colin Cross3a8c0252019-01-23 13:21:48 -080028 "runtime/pprof"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "sort"
30 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070031 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070032 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070033 "text/scanner"
34 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070035
36 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080037 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070038 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070039)
40
41var ErrBuildActionsNotReady = errors.New("build actions are not ready")
42
43const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080044const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070045
Jamie Gennisd4e10182014-06-12 20:06:50 -070046// A Context contains all the state needed to parse a set of Blueprints files
47// and generate a Ninja file. The process of generating a Ninja file proceeds
48// through a series of four phases. Each phase corresponds with a some methods
49// on the Context object
50//
51// Phase Methods
52// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 2. Parse ParseBlueprintsFiles, Parse
56//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070057// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070058//
59// 4. Write WriteBuildFile
60//
61// The registration phase prepares the context to process Blueprints files
62// containing various types of modules. The parse phase reads in one or more
63// Blueprints files and validates their contents against the module types that
64// have been registered. The generate phase then analyzes the parsed Blueprints
65// contents to create an internal representation for the build actions that must
66// be performed. This phase also performs validation of the module dependencies
67// and property values defined in the parsed Blueprints files. Finally, the
68// write phase generates the Ninja manifest text based on the generated build
69// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070070type Context struct {
Colin Cross3a8c0252019-01-23 13:21:48 -080071 context.Context
72
Jamie Gennis1bc967e2014-05-27 16:34:41 -070073 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070074 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080075 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070076 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070077 moduleInfo map[Module]*moduleInfo
78 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080079 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070080 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070081 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070082 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070083 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070084
Colin Cross3702ac72016-08-11 11:09:00 -070085 depsModified uint32 // positive if a mutator modified the dependencies
86
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 dependenciesReady bool // set to true on a successful ResolveDependencies
88 buildActionsReady bool // set to true on a successful PrepareBuildActions
89
90 // set by SetIgnoreUnknownModuleTypes
91 ignoreUnknownModuleTypes bool
92
Colin Cross036a1df2015-12-17 15:49:30 -080093 // set by SetAllowMissingDependencies
94 allowMissingDependencies bool
95
Jamie Gennis1bc967e2014-05-27 16:34:41 -070096 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080097 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080098 liveGlobals *liveTracker
Colin Cross2ce594e2020-01-29 12:58:03 -080099 globalVariables map[Variable]ninjaString
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100 globalPools map[Pool]*poolDef
101 globalRules map[Rule]*ruleDef
102
103 // set during PrepareBuildActions
Colin Cross2ce594e2020-01-29 12:58:03 -0800104 ninjaBuildDir ninjaString // The builddir special Ninja variable
105 requiredNinjaMajor int // For the ninja_required_version variable
106 requiredNinjaMinor int // For the ninja_required_version variable
107 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700108
Dan Willemsenab223a52018-07-05 21:56:59 -0700109 subninjas []string
110
Jeff Gastond70bf752017-11-10 15:12:08 -0800111 // set lazily by sortedModuleGroups
112 cachedSortedModuleGroups []*moduleGroup
Colin Crossd7b0f602016-06-02 15:30:20 -0700113
Colin Cross127d2ea2016-11-01 11:10:51 -0700114 globs map[string]GlobPath
115 globLock sync.Mutex
116
Colin Crossc5fa50e2019-12-17 13:12:35 -0800117 srcDir string
Jeff Gastonc3e28442017-08-09 15:13:12 -0700118 fs pathtools.FileSystem
119 moduleListFile string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700120}
121
Jamie Gennisd4e10182014-06-12 20:06:50 -0700122// An Error describes a problem that was encountered that is related to a
123// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700124type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700125 Err error // the error that occurred
126 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700127}
128
Colin Cross2c628442016-10-07 17:13:10 -0700129// A ModuleError describes a problem that was encountered that is related to a
130// particular module in a Blueprints file
131type ModuleError struct {
132 BlueprintError
133 module *moduleInfo
134}
135
136// A PropertyError describes a problem that was encountered that is related to a
137// particular property in a Blueprints file
138type PropertyError struct {
139 ModuleError
140 property string
141}
142
143func (e *BlueprintError) Error() string {
144 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
145}
146
147func (e *ModuleError) Error() string {
148 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
149}
150
151func (e *PropertyError) Error() string {
152 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
153}
154
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700155type localBuildActions struct {
156 variables []*localVariable
157 rules []*localRule
158 buildDefs []*buildDef
159}
160
Colin Crossf7beb892019-11-13 20:11:14 -0800161type moduleAlias struct {
Colin Cross71c4be62020-08-13 12:07:30 -0700162 variant variant
163 target *moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800164}
165
Colin Crossbbfa51a2014-12-17 16:12:41 -0800166type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700167 name string
168 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700169
Colin Crossbbfa51a2014-12-17 16:12:41 -0800170 modules []*moduleInfo
Colin Crossf7beb892019-11-13 20:11:14 -0800171 aliases []*moduleAlias
Jeff Gastond70bf752017-11-10 15:12:08 -0800172
173 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700174}
175
Colin Crossbbfa51a2014-12-17 16:12:41 -0800176type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700177 // set during Parse
178 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700179 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700180 relBlueprintsFile string
181 pos scanner.Position
182 propertyPos map[string]scanner.Position
Colin Cross322cc012019-05-20 13:55:14 -0700183 createdBy *moduleInfo
Colin Crossed342d92015-03-11 00:57:25 -0700184
Colin Cross71c4be62020-08-13 12:07:30 -0700185 variant variant
Colin Crosse7daa222015-03-11 14:35:41 -0700186
Colin Crossd2f4ac12017-07-28 14:31:03 -0700187 logicModule Module
188 group *moduleGroup
189 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800190
191 // set during ResolveDependencies
Colin Cross99bdb2a2019-03-29 16:35:02 -0700192 missingDeps []string
193 newDirectDeps []depInfo
Colin Crossc9028482014-12-18 16:28:54 -0800194
Colin Cross7addea32015-03-11 15:43:52 -0700195 // set during updateDependencies
196 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700197 forwardDeps []*moduleInfo
Colin Cross99bdb2a2019-03-29 16:35:02 -0700198 directDeps []depInfo
Colin Cross7addea32015-03-11 15:43:52 -0700199
200 // used by parallelVisitAllBottomUp
201 waitingCount int
202
Colin Crossc9028482014-12-18 16:28:54 -0800203 // set during each runMutator
Colin Cross4a693162020-08-13 12:11:52 -0700204 splitModules []*moduleInfo
205 pendingAliases []pendingAlias
Colin Crossab6d7902015-03-11 16:17:52 -0700206
207 // set during PrepareBuildActions
208 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800209}
210
Colin Cross71c4be62020-08-13 12:07:30 -0700211type variant struct {
212 name string
213 variations variationMap
214 dependencyVariations variationMap
215}
216
Colin Cross2c1f3d12016-04-11 15:47:28 -0700217type depInfo struct {
218 module *moduleInfo
219 tag DependencyTag
220}
221
Colin Cross0b7e83e2016-05-17 14:58:05 -0700222func (module *moduleInfo) Name() string {
Paul Duffin244033b2020-05-04 11:00:03 +0100223 // If this is called from a LoadHook (which is run before the module has been registered)
224 // then group will not be set and so the name is retrieved from logicModule.Name().
225 // Usually, using that method is not safe as it does not track renames (group.name does).
226 // However, when called from LoadHook it is safe as there is no way to rename a module
227 // until after the LoadHook has run and the module has been registered.
228 if module.group != nil {
229 return module.group.name
230 } else {
231 return module.logicModule.Name()
232 }
Colin Cross0b7e83e2016-05-17 14:58:05 -0700233}
234
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800235func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700236 s := fmt.Sprintf("module %q", module.Name())
Colin Cross71c4be62020-08-13 12:07:30 -0700237 if module.variant.name != "" {
238 s += fmt.Sprintf(" variant %q", module.variant.name)
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800239 }
Colin Cross322cc012019-05-20 13:55:14 -0700240 if module.createdBy != nil {
241 s += fmt.Sprintf(" (created by %s)", module.createdBy)
242 }
243
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800244 return s
245}
246
Jeff Gastond70bf752017-11-10 15:12:08 -0800247func (module *moduleInfo) namespace() Namespace {
248 return module.group.namespace
249}
250
Colin Crossf5e34b92015-03-13 16:02:36 -0700251// A Variation is a way that a variant of a module differs from other variants of the same module.
252// For example, two variants of the same module might have Variation{"arch","arm"} and
253// Variation{"arch","arm64"}
254type Variation struct {
255 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700256 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700257 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
258 // "shared" or "static" for link.
259 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700260}
261
Colin Crossf5e34b92015-03-13 16:02:36 -0700262// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
263type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700264
Colin Crossf5e34b92015-03-13 16:02:36 -0700265func (vm variationMap) clone() variationMap {
Colin Cross9403b5a2019-11-13 20:11:04 -0800266 if vm == nil {
267 return nil
268 }
Colin Crossf5e34b92015-03-13 16:02:36 -0700269 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700270 for k, v := range vm {
271 newVm[k] = v
272 }
273
274 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800275}
276
Colin Cross89486232015-05-08 11:14:54 -0700277// Compare this variationMap to another one. Returns true if the every entry in this map
278// is either the same in the other map or doesn't exist in the other map.
279func (vm variationMap) subset(other variationMap) bool {
280 for k, v1 := range vm {
281 if v2, ok := other[k]; ok && v1 != v2 {
282 return false
283 }
284 }
285 return true
286}
287
Colin Crossf5e34b92015-03-13 16:02:36 -0700288func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700289 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800290}
291
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700292type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700293 // set during RegisterSingletonType
294 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700295 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700296 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700297
298 // set during PrepareBuildActions
299 actionDefs localBuildActions
300}
301
Colin Crossc9028482014-12-18 16:28:54 -0800302type mutatorInfo struct {
303 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800304 topDownMutator TopDownMutator
305 bottomUpMutator BottomUpMutator
306 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700307 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800308}
309
Colin Crossaf4fd212017-07-28 14:32:36 -0700310func newContext() *Context {
311 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800312 Context: context.Background(),
Colin Cross5f03f112017-11-07 13:29:54 -0800313 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800314 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800315 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross5f03f112017-11-07 13:29:54 -0800316 globs: make(map[string]GlobPath),
317 fs: pathtools.OsFs,
318 ninjaBuildDir: nil,
319 requiredNinjaMajor: 1,
320 requiredNinjaMinor: 7,
321 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700322 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700323}
324
325// NewContext creates a new Context object. The created context initially has
326// no module or singleton factories registered, so the RegisterModuleFactory and
327// RegisterSingletonFactory methods must be called before it can do anything
328// useful.
329func NewContext() *Context {
330 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700331
332 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
333
334 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700335}
336
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700337// A ModuleFactory function creates a new Module object. See the
338// Context.RegisterModuleType method for details about how a registered
339// ModuleFactory is used by a Context.
340type ModuleFactory func() (m Module, propertyStructs []interface{})
341
Jamie Gennisd4e10182014-06-12 20:06:50 -0700342// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700343// Blueprints file) with a Module factory function. When the given module type
344// name is encountered in a Blueprints file during parsing, the Module factory
345// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800346// generation for the module. If a Mutator splits a module into multiple variants,
347// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700348//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700349// The module type names given here must be unique for the context. The factory
350// function should be a named function so that its package and name can be
351// included in the generated Ninja file for debugging purposes.
352//
353// The factory function returns two values. The first is the newly created
354// Module object. The second is a slice of pointers to that Module object's
355// properties structs. Each properties struct is examined when parsing a module
356// definition of this type in a Blueprints file. Exported fields of the
357// properties structs are automatically set to the property values specified in
358// the Blueprints file. The properties struct field names determine the name of
359// the Blueprints file properties that are used - the Blueprints property name
360// matches that of the properties struct field name with the first letter
361// converted to lower-case.
362//
363// The fields of the properties struct must be either []string, a string, or
364// bool. The Context will panic if a Module gets instantiated with a properties
365// struct containing a field that is not one these supported types.
366//
367// Any properties that appear in the Blueprints files that are not built-in
368// module properties (such as "name" and "deps") and do not have a corresponding
369// field in the returned module properties struct result in an error during the
370// Context's parse phase.
371//
372// As an example, the follow code:
373//
374// type myModule struct {
375// properties struct {
376// Foo string
377// Bar []string
378// }
379// }
380//
381// func NewMyModule() (blueprint.Module, []interface{}) {
382// module := new(myModule)
383// properties := &module.properties
384// return module, []interface{}{properties}
385// }
386//
387// func main() {
388// ctx := blueprint.NewContext()
389// ctx.RegisterModuleType("my_module", NewMyModule)
390// // ...
391// }
392//
393// would support parsing a module defined in a Blueprints file as follows:
394//
395// my_module {
396// name: "myName",
397// foo: "my foo string",
398// bar: ["my", "bar", "strings"],
399// }
400//
Colin Cross7ad621c2015-01-07 16:22:45 -0800401// The factory function may be called from multiple goroutines. Any accesses
402// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700403func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
404 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700405 panic(errors.New("module type name is already registered"))
406 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700407 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700408}
409
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700410// A SingletonFactory function creates a new Singleton object. See the
411// Context.RegisterSingletonType method for details about how a registered
412// SingletonFactory is used by a Context.
413type SingletonFactory func() Singleton
414
415// RegisterSingletonType registers a singleton type that will be invoked to
416// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700417// and invoked exactly once as part of the generate phase. Each registered
418// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700419//
420// The singleton type names given here must be unique for the context. The
421// factory function should be a named function so that its package and name can
422// be included in the generated Ninja file for debugging purposes.
423func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700424 for _, s := range c.singletonInfo {
425 if s.name == name {
426 panic(errors.New("singleton name is already registered"))
427 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700428 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700429
Yuchen Wub9103ef2015-08-25 17:58:17 -0700430 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700431 factory: factory,
432 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700433 name: name,
434 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700435}
436
Colin Cross5f03f112017-11-07 13:29:54 -0800437// RegisterPreSingletonType registers a presingleton type that will be invoked to
438// generate build actions before any Blueprint files have been read. Each registered
439// presingleton type is instantiated and invoked exactly once at the beginning of the
440// parse phase. Each registered presingleton is invoked in registration order.
441//
442// The presingleton type names given here must be unique for the context. The
443// factory function should be a named function so that its package and name can
444// be included in the generated Ninja file for debugging purposes.
445func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
446 for _, s := range c.preSingletonInfo {
447 if s.name == name {
448 panic(errors.New("presingleton name is already registered"))
449 }
450 }
451
452 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
453 factory: factory,
454 singleton: factory(),
455 name: name,
456 })
457}
458
Jeff Gastond70bf752017-11-10 15:12:08 -0800459func (c *Context) SetNameInterface(i NameInterface) {
460 c.nameInterface = i
461}
462
Colin Crossc5fa50e2019-12-17 13:12:35 -0800463func (c *Context) SetSrcDir(path string) {
464 c.srcDir = path
465 c.fs = pathtools.NewOsFs(path)
466}
467
468func (c *Context) SrcDir() string {
469 return c.srcDir
470}
471
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700472func singletonPkgPath(singleton Singleton) string {
473 typ := reflect.TypeOf(singleton)
474 for typ.Kind() == reflect.Ptr {
475 typ = typ.Elem()
476 }
477 return typ.PkgPath()
478}
479
480func singletonTypeName(singleton Singleton) string {
481 typ := reflect.TypeOf(singleton)
482 for typ.Kind() == reflect.Ptr {
483 typ = typ.Elem()
484 }
485 return typ.PkgPath() + "." + typ.Name()
486}
487
Colin Cross3702ac72016-08-11 11:09:00 -0700488// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
489// top-down between Modules. Each registered mutator is invoked in registration order (mixing
490// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
491// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800492//
Colin Cross65569e42015-03-10 20:08:19 -0700493// The mutator type names given here must be unique to all top down mutators in
494// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700495//
496// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
497// parallel while maintaining ordering.
498func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800499 for _, m := range c.mutatorInfo {
500 if m.name == name && m.topDownMutator != nil {
501 panic(fmt.Errorf("mutator name %s is already registered", name))
502 }
503 }
504
Colin Cross3702ac72016-08-11 11:09:00 -0700505 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800506 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800507 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700508 }
509
510 c.mutatorInfo = append(c.mutatorInfo, info)
511
512 return info
Colin Crossc9028482014-12-18 16:28:54 -0800513}
514
Colin Cross3702ac72016-08-11 11:09:00 -0700515// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
516// Each registered mutator is invoked in registration order (mixing TopDownMutators and
517// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
518// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800519//
Colin Cross65569e42015-03-10 20:08:19 -0700520// The mutator type names given here must be unique to all bottom up or early
521// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700522//
Colin Cross3702ac72016-08-11 11:09:00 -0700523// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
524// parallel while maintaining ordering.
525func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700526 for _, m := range c.variantMutatorNames {
527 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800528 panic(fmt.Errorf("mutator name %s is already registered", name))
529 }
530 }
531
Colin Cross49c279a2016-08-05 22:30:44 -0700532 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800533 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800534 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700535 }
536 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700537
538 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700539
540 return info
541}
542
Colin Cross3702ac72016-08-11 11:09:00 -0700543type MutatorHandle interface {
544 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
545 // method on the mutator context is thread-safe, but the mutator must handle synchronization
546 // for any modifications to global state or any modules outside the one it was invoked on.
547 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700548}
549
Colin Cross3702ac72016-08-11 11:09:00 -0700550func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700551 mutator.parallel = true
552 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700553}
554
555// RegisterEarlyMutator registers a mutator that will be invoked to split
556// Modules into multiple variant Modules before any dependencies have been
557// created. Each registered mutator is invoked in registration order once
558// per Module (including each variant from previous early mutators). Module
559// order is unpredictable.
560//
561// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700562// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700563//
564// The mutator type names given here must be unique to all bottom up or early
565// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700566//
567// Deprecated, use a BottomUpMutator instead. The only difference between
568// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
569// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700570func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
571 for _, m := range c.variantMutatorNames {
572 if m == name {
573 panic(fmt.Errorf("mutator name %s is already registered", name))
574 }
575 }
576
Colin Crossf8b50422016-08-10 12:56:40 -0700577 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
578 bottomUpMutator: func(mctx BottomUpMutatorContext) {
579 mutator(mctx)
580 },
581 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700582 })
583
584 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800585}
586
Jamie Gennisd4e10182014-06-12 20:06:50 -0700587// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
588// where it encounters an unknown module type while parsing Blueprints files. By
589// default, the context will report unknown module types as an error. If this
590// method is called with ignoreUnknownModuleTypes set to true then the context
591// will silently ignore unknown module types.
592//
593// This method should generally not be used. It exists to facilitate the
594// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700595func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
596 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
597}
598
Colin Cross036a1df2015-12-17 15:49:30 -0800599// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
600// unresolved dependencies. If the module's GenerateBuildActions calls
601// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
602// for missing dependencies.
603func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
604 c.allowMissingDependencies = allowMissingDependencies
605}
606
Jeff Gastonc3e28442017-08-09 15:13:12 -0700607func (c *Context) SetModuleListFile(listFile string) {
608 c.moduleListFile = listFile
609}
610
611func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
612 reader, err := c.fs.Open(c.moduleListFile)
613 if err != nil {
614 return nil, err
615 }
616 bytes, err := ioutil.ReadAll(reader)
617 if err != nil {
618 return nil, err
619 }
620 text := string(bytes)
621
622 text = strings.Trim(text, "\n")
623 lines := strings.Split(text, "\n")
624 for i := range lines {
625 lines[i] = filepath.Join(baseDir, lines[i])
626 }
627
628 return lines, nil
629}
630
Jeff Gaston656870f2017-11-29 18:37:31 -0800631// a fileParseContext tells the status of parsing a particular file
632type fileParseContext struct {
633 // name of file
634 fileName string
635
636 // scope to use when resolving variables
637 Scope *parser.Scope
638
639 // pointer to the one in the parent directory
640 parent *fileParseContext
641
642 // is closed once FileHandler has completed for this file
643 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700644}
645
Jamie Gennisd4e10182014-06-12 20:06:50 -0700646// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
647// at rootFile. When it encounters a Blueprints file with a set of subdirs
648// listed it recursively parses any Blueprints files found in those
649// subdirectories.
650//
651// If no errors are encountered while parsing the files, the list of paths on
652// which the future output will depend is returned. This list will include both
653// Blueprints file paths as well as directory paths for cases where wildcard
654// subdirs are found.
Colin Crossda70fd02019-12-30 18:40:09 -0800655func (c *Context) ParseBlueprintsFiles(rootFile string,
656 config interface{}) (deps []string, errs []error) {
657
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800658 baseDir := filepath.Dir(rootFile)
659 pathsToParse, err := c.ListModulePaths(baseDir)
660 if err != nil {
661 return nil, []error{err}
662 }
Colin Crossda70fd02019-12-30 18:40:09 -0800663 return c.ParseFileList(baseDir, pathsToParse, config)
Patrice Arrudab0a40a72019-03-08 13:42:29 -0800664}
665
Colin Crossda70fd02019-12-30 18:40:09 -0800666func (c *Context) ParseFileList(rootDir string, filePaths []string,
667 config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700668
Jeff Gastonc3e28442017-08-09 15:13:12 -0700669 if len(filePaths) < 1 {
670 return nil, []error{fmt.Errorf("no paths provided to parse")}
671 }
672
Colin Cross7ad621c2015-01-07 16:22:45 -0800673 c.dependenciesReady = false
674
Colin Crossda70fd02019-12-30 18:40:09 -0800675 type newModuleInfo struct {
676 *moduleInfo
677 added chan<- struct{}
678 }
679
680 moduleCh := make(chan newModuleInfo)
Colin Cross23d7aa12015-06-30 16:05:22 -0700681 errsCh := make(chan []error)
682 doneCh := make(chan struct{})
683 var numErrs uint32
684 var numGoroutines int32
685
686 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700687 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700688 if atomic.LoadUint32(&numErrs) > maxErrors {
689 return
690 }
691
Colin Crossda70fd02019-12-30 18:40:09 -0800692 addedCh := make(chan struct{})
693
Colin Cross9672d862019-12-30 18:38:20 -0800694 var scopedModuleFactories map[string]ModuleFactory
695
Colin Crossda70fd02019-12-30 18:40:09 -0800696 var addModule func(module *moduleInfo) []error
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100697 addModule = func(module *moduleInfo) []error {
Paul Duffin244033b2020-05-04 11:00:03 +0100698 // Run any load hooks immediately before it is sent to the moduleCh and is
699 // registered by name. This allows load hooks to set and/or modify any aspect
700 // of the module (including names) using information that is not available when
701 // the module factory is called.
702 newModules, errs := runAndRemoveLoadHooks(c, config, module, &scopedModuleFactories)
Colin Crossda70fd02019-12-30 18:40:09 -0800703 if len(errs) > 0 {
704 return errs
705 }
Paul Duffin244033b2020-05-04 11:00:03 +0100706
707 moduleCh <- newModuleInfo{module, addedCh}
708 <-addedCh
Colin Crossda70fd02019-12-30 18:40:09 -0800709 for _, n := range newModules {
710 errs = addModule(n)
711 if len(errs) > 0 {
712 return errs
713 }
714 }
715 return nil
716 }
717
Jeff Gaston656870f2017-11-29 18:37:31 -0800718 for _, def := range file.Defs {
Jeff Gaston656870f2017-11-29 18:37:31 -0800719 switch def := def.(type) {
720 case *parser.Module:
Paul Duffin2a2c58e2020-05-13 09:06:17 +0100721 module, errs := processModuleDef(def, file.Name, c.moduleFactories, scopedModuleFactories, c.ignoreUnknownModuleTypes)
Colin Crossda70fd02019-12-30 18:40:09 -0800722 if len(errs) == 0 && module != nil {
723 errs = addModule(module)
724 }
725
726 if len(errs) > 0 {
727 atomic.AddUint32(&numErrs, uint32(len(errs)))
728 errsCh <- errs
729 }
730
Jeff Gaston656870f2017-11-29 18:37:31 -0800731 case *parser.Assignment:
732 // Already handled via Scope object
733 default:
734 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700735 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800736
Jeff Gaston656870f2017-11-29 18:37:31 -0800737 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700738 }
739
740 atomic.AddInt32(&numGoroutines, 1)
741 go func() {
742 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700743 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700744 if len(errs) > 0 {
745 errsCh <- errs
746 }
747 doneCh <- struct{}{}
748 }()
749
750loop:
751 for {
752 select {
753 case newErrs := <-errsCh:
754 errs = append(errs, newErrs...)
755 case module := <-moduleCh:
Colin Crossda70fd02019-12-30 18:40:09 -0800756 newErrs := c.addModule(module.moduleInfo)
757 if module.added != nil {
758 module.added <- struct{}{}
759 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700760 if len(newErrs) > 0 {
761 errs = append(errs, newErrs...)
762 }
763 case <-doneCh:
764 n := atomic.AddInt32(&numGoroutines, -1)
765 if n == 0 {
766 break loop
767 }
768 }
769 }
770
771 return deps, errs
772}
773
774type FileHandler func(*parser.File)
775
Jeff Gastonc3e28442017-08-09 15:13:12 -0700776// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
777// calling the given file handler on each
778//
779// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
780// it recursively parses any Blueprints files found in those subdirectories.
781//
782// If any of the file paths is an ancestor directory of any other of file path, the ancestor
783// will be parsed and visited first.
784//
785// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700786//
787// If no errors are encountered while parsing the files, the list of paths on
788// which the future output will depend is returned. This list will include both
789// Blueprints file paths as well as directory paths for cases where wildcard
790// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800791//
792// visitor will be called asynchronously, and will only be called once visitor for each
793// ancestor directory has completed.
794//
795// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700796func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
797 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700798
Jeff Gastonc3e28442017-08-09 15:13:12 -0700799 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
800 descendantsMap, err := findBlueprintDescendants(filePaths)
801 if err != nil {
802 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700803 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800804 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700805
Jeff Gaston5800d042017-12-05 14:57:58 -0800806 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800807 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800808 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800809 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700810
Jeff Gaston5800d042017-12-05 14:57:58 -0800811 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800812 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700813
Colin Cross7ad621c2015-01-07 16:22:45 -0800814 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700815 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800816 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700817 tooManyErrors := false
818
819 // Limit concurrent calls to parseBlueprintFiles to 200
820 // Darwin has a default limit of 256 open files
821 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800822
Jeff Gaston656870f2017-11-29 18:37:31 -0800823 // count the number of pending calls to visitor()
824 visitorWaitGroup := sync.WaitGroup{}
825
826 startParseBlueprintsFile := func(blueprint fileParseContext) {
827 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700828 return
829 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800830 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700831 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800832 deps = append(deps, blueprint.fileName)
833 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800834 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800835 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
836 &blueprint)
837 if len(errs) > 0 {
838 errsCh <- errs
839 }
840 for _, blueprint := range blueprints {
841 blueprintsCh <- blueprint
842 }
843 for _, dep := range deps {
844 depsCh <- dep
845 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800846 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700847
Jeff Gaston656870f2017-11-29 18:37:31 -0800848 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
849 // wait for visitor() of parent to complete
850 <-blueprint.parent.doneVisiting
851 }
852
Jeff Gastona7e408a2017-12-05 15:11:55 -0800853 if len(errs) == 0 {
854 // process this file
855 visitor(file)
856 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800857 if blueprint.doneVisiting != nil {
858 close(blueprint.doneVisiting)
859 }
860 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800861 }()
862 }
863
Jeff Gaston656870f2017-11-29 18:37:31 -0800864 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700865 if activeCount >= maxActiveCount {
866 pending = append(pending, blueprint)
867 } else {
868 startParseBlueprintsFile(blueprint)
869 }
870 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800871
Jeff Gaston656870f2017-11-29 18:37:31 -0800872 startParseDescendants := func(blueprint fileParseContext) {
873 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700874 if hasDescendants {
875 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800876 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700877 }
878 }
879 }
Colin Cross4a02a302017-05-16 10:33:58 -0700880
Jeff Gastonc3e28442017-08-09 15:13:12 -0700881 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800882 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800883
884loop:
885 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700886 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800887 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700888 }
889
Colin Cross7ad621c2015-01-07 16:22:45 -0800890 select {
891 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700892 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800893 case dep := <-depsCh:
894 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800895 case blueprint := <-blueprintsCh:
896 if tooManyErrors {
897 continue
898 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700899 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800900 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700901 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700902 if !tooManyErrors {
903 startParseDescendants(blueprint)
904 }
905 if activeCount < maxActiveCount && len(pending) > 0 {
906 // start to process the next one from the queue
907 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700908 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700909 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700910 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700911 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800912 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700913 }
914 }
915 }
916
Jeff Gastonc3e28442017-08-09 15:13:12 -0700917 sort.Strings(deps)
918
Jeff Gaston656870f2017-11-29 18:37:31 -0800919 // wait for every visitor() to complete
920 visitorWaitGroup.Wait()
921
Colin Cross7ad621c2015-01-07 16:22:45 -0800922 return
923}
924
Colin Crossd7b0f602016-06-02 15:30:20 -0700925// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
926// filenames to contents stored as a byte slice.
927func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800928 // look for a module list file
929 _, ok := files[MockModuleListFile]
930 if !ok {
931 // no module list file specified; find every file named Blueprints
932 pathsToParse := []string{}
933 for candidate := range files {
934 if filepath.Base(candidate) == "Blueprints" {
935 pathsToParse = append(pathsToParse, candidate)
936 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700937 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800938 if len(pathsToParse) < 1 {
939 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
940 }
941 // put the list of Blueprints files into a list file
942 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700943 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800944 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700945
946 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800947 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700948}
949
Colin Cross8cde4252019-12-17 13:11:21 -0800950func (c *Context) SetFs(fs pathtools.FileSystem) {
951 c.fs = fs
952}
953
Jeff Gaston8fd95782017-12-05 15:03:51 -0800954// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -0800955func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -0800956 parent *fileParseContext) (file *parser.File,
957 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800958
Colin Crossd7b0f602016-06-02 15:30:20 -0700959 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800960 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700961 // couldn't open the file; see if we can provide a clearer error than "could not open file"
962 stats, statErr := c.fs.Lstat(filename)
963 if statErr == nil {
964 isSymlink := stats.Mode()&os.ModeSymlink != 0
965 if isSymlink {
966 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
967 target, readlinkErr := os.Readlink(filename)
968 if readlinkErr == nil {
969 _, targetStatsErr := c.fs.Lstat(target)
970 if targetStatsErr != nil {
971 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
972 }
973 }
974 } else {
975 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
976 }
977 }
Jeff Gaston8fd95782017-12-05 15:03:51 -0800978 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700979 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800980
Jeff Gaston8fd95782017-12-05 15:03:51 -0800981 func() {
982 defer func() {
983 err = f.Close()
984 if err != nil {
985 errs = append(errs, err)
986 }
987 }()
988 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -0700989 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700990
Colin Cross7ad621c2015-01-07 16:22:45 -0800991 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800992 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -0800993 }
994
Colin Cross1fef5362015-04-20 16:50:54 -0700995 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800996 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -0700997 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800998
Jeff Gaston8fd95782017-12-05 15:03:51 -0800999 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -07001000}
1001
Jeff Gastona12f22f2017-08-08 14:45:56 -07001002// parseOne parses a single Blueprints file from the given reader, creating Module
1003// objects for each of the module definitions encountered. If the Blueprints
1004// file contains an assignment to the "subdirs" variable, then the
1005// subdirectories listed are searched for Blueprints files returned in the
1006// subBlueprints return value. If the Blueprints file contains an assignment
1007// to the "build" variable, then the file listed are returned in the
1008// subBlueprints return value.
1009//
1010// rootDir specifies the path to the root directory of the source tree, while
1011// filename specifies the path to the Blueprints file. These paths are used for
1012// error reporting and for determining the module's directory.
1013func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -08001014 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -07001015
1016 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
1017 if err != nil {
1018 return nil, nil, []error{err}
1019 }
1020
Jeff Gastona12f22f2017-08-08 14:45:56 -07001021 scope.Remove("subdirs")
1022 scope.Remove("optional_subdirs")
1023 scope.Remove("build")
1024 file, errs = parser.ParseAndEval(filename, reader, scope)
1025 if len(errs) > 0 {
1026 for i, err := range errs {
1027 if parseErr, ok := err.(*parser.ParseError); ok {
1028 err = &BlueprintError{
1029 Err: parseErr.Err,
1030 Pos: parseErr.Pos,
1031 }
1032 errs[i] = err
1033 }
1034 }
1035
1036 // If there were any parse errors don't bother trying to interpret the
1037 // result.
1038 return nil, nil, errs
1039 }
1040 file.Name = relBlueprintsFile
1041
Jeff Gastona12f22f2017-08-08 14:45:56 -07001042 build, buildPos, err := getLocalStringListFromScope(scope, "build")
1043 if err != nil {
1044 errs = append(errs, err)
1045 }
Jeff Gastonf23e3662017-11-30 17:31:43 -08001046 for _, buildEntry := range build {
1047 if strings.Contains(buildEntry, "/") {
1048 errs = append(errs, &BlueprintError{
1049 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
1050 Pos: buildPos,
1051 })
1052 }
1053 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001054
1055 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
1056 if err != nil {
1057 errs = append(errs, err)
1058 }
1059
1060 if subBlueprintsName == "" {
1061 subBlueprintsName = "Blueprints"
1062 }
1063
1064 var blueprints []string
1065
1066 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
1067 blueprints = append(blueprints, newBlueprints...)
1068 errs = append(errs, newErrs...)
1069
Jeff Gaston656870f2017-11-29 18:37:31 -08001070 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -07001071 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -08001072 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -07001073 }
Jeff Gastona12f22f2017-08-08 14:45:56 -07001074 return file, subBlueprintsAndScope, errs
1075}
1076
Colin Cross7f507402015-12-16 13:03:41 -08001077func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -07001078 buildPos scanner.Position) ([]string, []error) {
1079
1080 var blueprints []string
1081 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001082
1083 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001084 pattern := filepath.Join(dir, file)
1085 var matches []string
1086 var err error
1087
Colin Cross08e49542016-11-14 15:23:33 -08001088 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001089
Colin Cross7f507402015-12-16 13:03:41 -08001090 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001091 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001092 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001093 Pos: buildPos,
1094 })
1095 continue
1096 }
1097
1098 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001099 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001100 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001101 Pos: buildPos,
1102 })
1103 }
1104
Colin Cross7f507402015-12-16 13:03:41 -08001105 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001106 if strings.HasSuffix(foundBlueprints, "/") {
1107 errs = append(errs, &BlueprintError{
1108 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1109 Pos: buildPos,
1110 })
1111 }
Colin Cross7f507402015-12-16 13:03:41 -08001112 blueprints = append(blueprints, foundBlueprints)
1113 }
1114 }
1115
Colin Cross127d2ea2016-11-01 11:10:51 -07001116 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001117}
1118
1119func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001120 subBlueprintsName string, optional bool) ([]string, []error) {
1121
1122 var blueprints []string
1123 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001124
1125 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001126 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1127 var matches []string
1128 var err error
1129
Colin Cross08e49542016-11-14 15:23:33 -08001130 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001131
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001132 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001133 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001134 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001135 Pos: subdirsPos,
1136 })
1137 continue
1138 }
1139
Colin Cross7f507402015-12-16 13:03:41 -08001140 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001141 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001142 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001143 Pos: subdirsPos,
1144 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001145 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001146
Colin Cross127d2ea2016-11-01 11:10:51 -07001147 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001148 if strings.HasSuffix(subBlueprints, "/") {
1149 errs = append(errs, &BlueprintError{
1150 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1151 Pos: subdirsPos,
1152 })
1153 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001154 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001155 }
1156 }
Colin Cross1fef5362015-04-20 16:50:54 -07001157
Colin Cross127d2ea2016-11-01 11:10:51 -07001158 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001159}
1160
Colin Cross6d8780f2015-07-10 17:51:55 -07001161func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1162 if assignment, local := scope.Get(v); assignment == nil || !local {
1163 return nil, scanner.Position{}, nil
1164 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001165 switch value := assignment.Value.Eval().(type) {
1166 case *parser.List:
1167 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001168
Colin Crosse32cc802016-06-07 12:28:16 -07001169 for _, listValue := range value.Values {
1170 s, ok := listValue.(*parser.String)
1171 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001172 // The parser should not produce this.
1173 panic("non-string value found in list")
1174 }
1175
Colin Crosse32cc802016-06-07 12:28:16 -07001176 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001177 }
1178
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001179 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001180 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001181 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001182 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001183 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001184 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001185 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001186 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001187 }
1188 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001189}
1190
Colin Cross29394222015-04-27 13:18:21 -07001191func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001192 if assignment, _ := scope.Get(v); assignment == nil {
1193 return "", scanner.Position{}, nil
1194 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001195 switch value := assignment.Value.Eval().(type) {
1196 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001197 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001198 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001199 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001200 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001201 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001202 }
1203 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001204 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001205 }
1206 }
Colin Cross29394222015-04-27 13:18:21 -07001207}
1208
Colin Cross910242b2016-04-11 15:41:52 -07001209// Clones a build logic module by calling the factory method for its module type, and then cloning
1210// property values. Any values stored in the module object that are not stored in properties
1211// structs will be lost.
1212func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001213 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001214
Colin Crossd2f4ac12017-07-28 14:31:03 -07001215 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001216 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001217 }
1218
1219 for i := range newProperties {
Colin Cross5d57b2d2020-01-27 16:14:31 -08001220 dst := reflect.ValueOf(newProperties[i])
1221 src := reflect.ValueOf(origModule.properties[i])
Colin Cross910242b2016-04-11 15:41:52 -07001222
1223 proptools.CopyProperties(dst, src)
1224 }
1225
1226 return newLogicModule, newProperties
1227}
1228
Colin Cross71c4be62020-08-13 12:07:30 -07001229func newVariant(module *moduleInfo, mutatorName string, variationName string,
1230 local bool) variant {
1231
1232 newVariantName := module.variant.name
1233 if variationName != "" {
1234 if newVariantName == "" {
1235 newVariantName = variationName
1236 } else {
1237 newVariantName += "_" + variationName
1238 }
1239 }
1240
1241 newVariations := module.variant.variations.clone()
1242 if newVariations == nil {
1243 newVariations = make(variationMap)
1244 }
1245 newVariations[mutatorName] = variationName
1246
1247 newDependencyVariations := module.variant.dependencyVariations.clone()
1248 if !local {
1249 if newDependencyVariations == nil {
1250 newDependencyVariations = make(variationMap)
1251 }
1252 newDependencyVariations[mutatorName] = variationName
1253 }
1254
1255 return variant{newVariantName, newVariations, newDependencyVariations}
1256}
1257
Colin Crossf5e34b92015-03-13 16:02:36 -07001258func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
Colin Cross71c4be62020-08-13 12:07:30 -07001259 defaultVariationName *string, variationNames []string, local bool) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001260
Colin Crossf4d18a62015-03-18 17:43:15 -07001261 if len(variationNames) == 0 {
1262 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001263 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001264 }
1265
Colin Crossc9028482014-12-18 16:28:54 -08001266 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001267
Colin Cross174ae052015-03-03 17:37:03 -08001268 var errs []error
1269
Colin Crossf5e34b92015-03-13 16:02:36 -07001270 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001271 var newLogicModule Module
1272 var newProperties []interface{}
1273
1274 if i == 0 {
1275 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001276 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1277 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001278 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001279 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001280 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001281 }
1282
Colin Crossed342d92015-03-11 00:57:25 -07001283 m := *origModule
1284 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001285 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001286 newModule.logicModule = newLogicModule
Colin Cross71c4be62020-08-13 12:07:30 -07001287 newModule.variant = newVariant(origModule, mutatorName, variationName, local)
Colin Crossd2f4ac12017-07-28 14:31:03 -07001288 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001289
1290 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001291
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001292 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName, defaultVariationName)
Colin Cross174ae052015-03-03 17:37:03 -08001293 if len(newErrs) > 0 {
1294 errs = append(errs, newErrs...)
1295 }
Colin Crossc9028482014-12-18 16:28:54 -08001296 }
1297
1298 // Mark original variant as invalid. Modules that depend on this module will still
1299 // depend on origModule, but we'll fix it when the mutator is called on them.
1300 origModule.logicModule = nil
1301 origModule.splitModules = newModules
1302
Colin Cross3702ac72016-08-11 11:09:00 -07001303 atomic.AddUint32(&c.depsModified, 1)
1304
Colin Cross174ae052015-03-03 17:37:03 -08001305 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001306}
1307
Colin Crossf5e34b92015-03-13 16:02:36 -07001308func (c *Context) convertDepsToVariation(module *moduleInfo,
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001309 mutatorName, variationName string, defaultVariationName *string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001310
Colin Crossc9028482014-12-18 16:28:54 -08001311 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001312 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001313 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001314 for _, m := range dep.module.splitModules {
Colin Cross71c4be62020-08-13 12:07:30 -07001315 if m.variant.variations[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001316 newDep = m
1317 break
1318 }
1319 }
Colin Cross4a693162020-08-13 12:11:52 -07001320 if newDep == nil {
1321 // check aliases against variationNam
1322 for _, a := range dep.module.pendingAliases {
1323 if a.fromVariant.variations[mutatorName] == variationName {
1324 newDep = a.target
1325 break
1326 }
1327 }
1328 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001329 if newDep == nil && defaultVariationName != nil {
1330 // give it a second chance; match with defaultVariationName
1331 for _, m := range dep.module.splitModules {
Colin Cross71c4be62020-08-13 12:07:30 -07001332 if m.variant.variations[mutatorName] == *defaultVariationName {
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001333 newDep = m
1334 break
1335 }
1336 }
Colin Cross4a693162020-08-13 12:11:52 -07001337 if newDep == nil {
1338 // check aliases against defaultVariationName
1339 for _, a := range dep.module.pendingAliases {
1340 if a.fromVariant.variations[mutatorName] == *defaultVariationName {
1341 newDep = a.target
1342 break
1343 }
1344 }
1345 }
Jiyong Park1e2e56d2019-07-29 19:59:15 +09001346 }
Colin Crossc9028482014-12-18 16:28:54 -08001347 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001348 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001349 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001350 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001351 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001352 })
1353 continue
Colin Crossc9028482014-12-18 16:28:54 -08001354 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001355 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001356 }
1357 }
Colin Cross174ae052015-03-03 17:37:03 -08001358
1359 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001360}
1361
Colin Cross71c4be62020-08-13 12:07:30 -07001362func (c *Context) prettyPrintVariant(variations variationMap) string {
1363 names := make([]string, 0, len(variations))
Colin Cross65569e42015-03-10 20:08:19 -07001364 for _, m := range c.variantMutatorNames {
Colin Cross71c4be62020-08-13 12:07:30 -07001365 if v, ok := variations[m]; ok {
Colin Cross65569e42015-03-10 20:08:19 -07001366 names = append(names, m+":"+v)
1367 }
1368 }
1369
1370 return strings.Join(names, ", ")
1371}
1372
Colin Crossd03b59d2019-11-13 20:10:12 -08001373func (c *Context) prettyPrintGroupVariants(group *moduleGroup) string {
1374 var variants []string
1375 for _, mod := range group.modules {
Colin Cross71c4be62020-08-13 12:07:30 -07001376 variants = append(variants, c.prettyPrintVariant(mod.variant.variations))
Colin Crossd03b59d2019-11-13 20:10:12 -08001377 }
Colin Crossf7beb892019-11-13 20:11:14 -08001378 for _, mod := range group.aliases {
Colin Cross71c4be62020-08-13 12:07:30 -07001379 variants = append(variants, c.prettyPrintVariant(mod.variant.variations)+
1380 "(alias to "+c.prettyPrintVariant(mod.target.variant.variations)+")")
Colin Crossf7beb892019-11-13 20:11:14 -08001381 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001382 sort.Strings(variants)
1383 return strings.Join(variants, "\n ")
1384}
1385
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001386func newModule(factory ModuleFactory) *moduleInfo {
Colin Crossaf4fd212017-07-28 14:32:36 -07001387 logicModule, properties := factory()
1388
1389 module := &moduleInfo{
1390 logicModule: logicModule,
1391 factory: factory,
1392 }
1393
1394 module.properties = properties
1395
1396 return module
1397}
1398
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001399func processModuleDef(moduleDef *parser.Module,
1400 relBlueprintsFile string, moduleFactories, scopedModuleFactories map[string]ModuleFactory, ignoreUnknownModuleTypes bool) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001401
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001402 factory, ok := moduleFactories[moduleDef.Type]
Colin Cross9672d862019-12-30 18:38:20 -08001403 if !ok && scopedModuleFactories != nil {
1404 factory, ok = scopedModuleFactories[moduleDef.Type]
1405 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001406 if !ok {
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001407 if ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001408 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001409 }
1410
Colin Cross7ad621c2015-01-07 16:22:45 -08001411 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001412 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001413 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1414 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001415 },
1416 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001417 }
1418
Paul Duffin2a2c58e2020-05-13 09:06:17 +01001419 module := newModule(factory)
Colin Crossaf4fd212017-07-28 14:32:36 -07001420 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001421
Colin Crossaf4fd212017-07-28 14:32:36 -07001422 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001423
Colin Crossf27c5e42020-01-02 09:37:49 -08001424 propertyMap, errs := proptools.UnpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001425 if len(errs) > 0 {
Colin Crossf27c5e42020-01-02 09:37:49 -08001426 for i, err := range errs {
1427 if unpackErr, ok := err.(*proptools.UnpackError); ok {
1428 err = &BlueprintError{
1429 Err: unpackErr.Err,
1430 Pos: unpackErr.Pos,
1431 }
1432 errs[i] = err
1433 }
1434 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001435 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001436 }
1437
Colin Crossc32c4792016-06-09 15:52:30 -07001438 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001439 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001440 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001441 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001442 }
1443
Colin Cross7ad621c2015-01-07 16:22:45 -08001444 return module, nil
1445}
1446
Colin Cross23d7aa12015-06-30 16:05:22 -07001447func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001448 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001449 if name == "" {
1450 return []error{
1451 &BlueprintError{
1452 Err: fmt.Errorf("property 'name' is missing from a module"),
1453 Pos: module.pos,
1454 },
1455 }
1456 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001457 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001458
Colin Cross0b7e83e2016-05-17 14:58:05 -07001459 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001460 name: name,
1461 modules: []*moduleInfo{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001462 }
1463 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001464 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001465 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001466 ModuleGroup{moduleGroup: group},
1467 module.logicModule)
1468 if len(errs) > 0 {
1469 for i := range errs {
1470 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1471 }
1472 return errs
1473 }
1474 group.namespace = namespace
1475
Colin Cross0b7e83e2016-05-17 14:58:05 -07001476 c.moduleGroups = append(c.moduleGroups, group)
1477
Colin Cross23d7aa12015-06-30 16:05:22 -07001478 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001479}
1480
Jamie Gennisd4e10182014-06-12 20:06:50 -07001481// ResolveDependencies checks that the dependencies specified by all of the
1482// modules defined in the parsed Blueprints files are valid. This means that
1483// the modules depended upon are defined and that no circular dependencies
1484// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001485func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001486 return c.resolveDependencies(c.Context, config)
1487}
Colin Cross5f03f112017-11-07 13:29:54 -08001488
Colin Cross3a8c0252019-01-23 13:21:48 -08001489func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1490 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
1491 c.liveGlobals = newLiveTracker(config)
1492
1493 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1494 if len(errs) > 0 {
1495 return
1496 }
1497
1498 errs = c.updateDependencies()
1499 if len(errs) > 0 {
1500 return
1501 }
1502
1503 var mutatorDeps []string
1504 mutatorDeps, errs = c.runMutators(ctx, config)
1505 if len(errs) > 0 {
1506 return
1507 }
1508 deps = append(deps, mutatorDeps...)
1509
1510 c.cloneModules()
1511
1512 c.dependenciesReady = true
1513 })
1514
Colin Cross5f03f112017-11-07 13:29:54 -08001515 if len(errs) > 0 {
1516 return nil, errs
1517 }
1518
Colin Cross874a3462017-07-31 17:26:06 -07001519 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001520}
1521
Colin Cross763b6f12015-10-29 15:32:56 -07001522// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001523// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001524// module names returned by its DynamicDependencies method and those added by calling
1525// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001526func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001527 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001528 func() {
1529 defer func() {
1530 if r := recover(); r != nil {
1531 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1532 }
1533 }()
1534 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001535
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001536 if ctx.Failed() {
1537 return
1538 }
Colin Cross763b6f12015-10-29 15:32:56 -07001539
Colin Cross2c1f3d12016-04-11 15:47:28 -07001540 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001541 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001542 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001543}
1544
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001545// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1546// and returns the matching module, or nil if one is not found.
Colin Crossd03b59d2019-11-13 20:10:12 -08001547func (c *Context) findMatchingVariant(module *moduleInfo, possible *moduleGroup, reverse bool) *moduleInfo {
1548 if len(possible.modules) == 1 {
1549 return possible.modules[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001550 } else {
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001551 var variantToMatch variationMap
1552 if !reverse {
1553 // For forward dependency, ignore local variants by matching against
1554 // dependencyVariant which doesn't have the local variants
Colin Cross71c4be62020-08-13 12:07:30 -07001555 variantToMatch = module.variant.dependencyVariations
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001556 } else {
1557 // For reverse dependency, use all the variants
Colin Cross71c4be62020-08-13 12:07:30 -07001558 variantToMatch = module.variant.variations
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001559 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001560 for _, m := range possible.modules {
Colin Cross71c4be62020-08-13 12:07:30 -07001561 if m.variant.variations.equal(variantToMatch) {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001562 return m
1563 }
1564 }
Colin Crossf7beb892019-11-13 20:11:14 -08001565 for _, m := range possible.aliases {
Colin Cross71c4be62020-08-13 12:07:30 -07001566 if m.variant.variations.equal(variantToMatch) {
Colin Crossf7beb892019-11-13 20:11:14 -08001567 return m.target
1568 }
1569 }
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001570 }
1571
1572 return nil
1573}
1574
Colin Cross2c1f3d12016-04-11 15:47:28 -07001575func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001576 if _, ok := tag.(BaseDependencyTag); ok {
1577 panic("BaseDependencyTag is not allowed to be used directly!")
1578 }
1579
Colin Cross0b7e83e2016-05-17 14:58:05 -07001580 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001581 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001582 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001583 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001584 }}
1585 }
1586
Colin Crossd03b59d2019-11-13 20:10:12 -08001587 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001588 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001589 return c.discoveredMissingDependencies(module, depName)
Colin Crossc9028482014-12-18 16:28:54 -08001590 }
1591
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001592 if m := c.findMatchingVariant(module, possibleDeps, false); m != nil {
Colin Cross99bdb2a2019-03-29 16:35:02 -07001593 module.newDirectDeps = append(module.newDirectDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001594 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001595 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001596 }
Colin Crossc9028482014-12-18 16:28:54 -08001597
Paul Duffinb77556b2020-03-24 19:01:20 +00001598 if c.allowMissingDependencies {
1599 // Allow missing variants.
Colin Cross71c4be62020-08-13 12:07:30 -07001600 return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(module.variant.dependencyVariations))
Paul Duffinb77556b2020-03-24 19:01:20 +00001601 }
1602
Colin Cross2c628442016-10-07 17:13:10 -07001603 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001604 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001605 depName, module.Name(),
Colin Cross71c4be62020-08-13 12:07:30 -07001606 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001607 c.prettyPrintGroupVariants(possibleDeps)),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001608 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001609 }}
1610}
1611
Colin Cross8d8a7af2015-11-03 16:41:29 -08001612func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001613 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001614 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001615 Err: fmt.Errorf("%q depends on itself", destName),
1616 Pos: module.pos,
1617 }}
1618 }
1619
Colin Crossd03b59d2019-11-13 20:10:12 -08001620 possibleDeps := c.moduleGroupFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001621 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001622 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001623 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001624 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001625 Pos: module.pos,
1626 }}
1627 }
1628
Jiyong Parkdf4ed952019-09-18 00:59:02 +09001629 if m := c.findMatchingVariant(module, possibleDeps, true); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001630 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001631 }
1632
Paul Duffinb77556b2020-03-24 19:01:20 +00001633 if c.allowMissingDependencies {
1634 // Allow missing variants.
Colin Cross71c4be62020-08-13 12:07:30 -07001635 return module, c.discoveredMissingDependencies(module, destName+c.prettyPrintVariant(module.variant.dependencyVariations))
Paul Duffinb77556b2020-03-24 19:01:20 +00001636 }
1637
Colin Cross2c628442016-10-07 17:13:10 -07001638 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001639 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001640 destName, module.Name(),
Colin Cross71c4be62020-08-13 12:07:30 -07001641 c.prettyPrintVariant(module.variant.dependencyVariations),
Colin Crossd03b59d2019-11-13 20:10:12 -08001642 c.prettyPrintGroupVariants(possibleDeps)),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001643 Pos: module.pos,
1644 }}
1645}
1646
Martin Stjernholm110018c2020-03-06 00:29:24 +00001647func (c *Context) findVariant(module *moduleInfo, possibleDeps *moduleGroup, variations []Variation, far bool, reverse bool) (*moduleInfo, variationMap) {
Colin Cross71c4be62020-08-13 12:07:30 -07001648 // We can't just append variant.Variant to module.dependencyVariant.variantName and
Colin Cross65569e42015-03-10 20:08:19 -07001649 // compare the strings because the result won't be in mutator registration order.
1650 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001651 var newVariant variationMap
1652 if !far {
Martin Stjernholm110018c2020-03-06 00:29:24 +00001653 if !reverse {
1654 // For forward dependency, ignore local variants by matching against
1655 // dependencyVariant which doesn't have the local variants
Colin Cross71c4be62020-08-13 12:07:30 -07001656 newVariant = module.variant.dependencyVariations.clone()
Martin Stjernholm110018c2020-03-06 00:29:24 +00001657 } else {
1658 // For reverse dependency, use all the variants
Colin Cross71c4be62020-08-13 12:07:30 -07001659 newVariant = module.variant.variations.clone()
Martin Stjernholm110018c2020-03-06 00:29:24 +00001660 }
Colin Cross89486232015-05-08 11:14:54 -07001661 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001662 for _, v := range variations {
Colin Cross9403b5a2019-11-13 20:11:04 -08001663 if newVariant == nil {
1664 newVariant = make(variationMap)
1665 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001666 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001667 }
1668
Colin Crossd03b59d2019-11-13 20:10:12 -08001669 check := func(variant variationMap) bool {
Colin Cross89486232015-05-08 11:14:54 -07001670 if far {
Colin Crossd03b59d2019-11-13 20:10:12 -08001671 return variant.subset(newVariant)
Colin Cross89486232015-05-08 11:14:54 -07001672 } else {
Colin Crossd03b59d2019-11-13 20:10:12 -08001673 return variant.equal(newVariant)
Colin Cross65569e42015-03-10 20:08:19 -07001674 }
1675 }
1676
Colin Crossd03b59d2019-11-13 20:10:12 -08001677 var foundDep *moduleInfo
1678 for _, m := range possibleDeps.modules {
Colin Cross71c4be62020-08-13 12:07:30 -07001679 if check(m.variant.variations) {
Colin Crossd03b59d2019-11-13 20:10:12 -08001680 foundDep = m
1681 break
1682 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001683 }
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001684
Colin Crossd03b59d2019-11-13 20:10:12 -08001685 if foundDep == nil {
Colin Crossf7beb892019-11-13 20:11:14 -08001686 for _, m := range possibleDeps.aliases {
Colin Cross71c4be62020-08-13 12:07:30 -07001687 if check(m.variant.variations) {
Colin Crossf7beb892019-11-13 20:11:14 -08001688 foundDep = m.target
1689 break
1690 }
1691 }
1692 }
1693
Martin Stjernholm110018c2020-03-06 00:29:24 +00001694 return foundDep, newVariant
1695}
1696
1697func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
1698 tag DependencyTag, depName string, far bool) []error {
1699 if _, ok := tag.(BaseDependencyTag); ok {
1700 panic("BaseDependencyTag is not allowed to be used directly!")
1701 }
1702
1703 possibleDeps := c.moduleGroupFromName(depName, module.namespace())
1704 if possibleDeps == nil {
1705 return c.discoveredMissingDependencies(module, depName)
1706 }
1707
1708 foundDep, newVariant := c.findVariant(module, possibleDeps, variations, far, false)
1709
Colin Crossf7beb892019-11-13 20:11:14 -08001710 if foundDep == nil {
Paul Duffinb77556b2020-03-24 19:01:20 +00001711 if c.allowMissingDependencies {
1712 // Allow missing variants.
1713 return c.discoveredMissingDependencies(module, depName+c.prettyPrintVariant(newVariant))
1714 }
Colin Crossd03b59d2019-11-13 20:10:12 -08001715 return []error{&BlueprintError{
1716 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
1717 depName, module.Name(),
1718 c.prettyPrintVariant(newVariant),
1719 c.prettyPrintGroupVariants(possibleDeps)),
1720 Pos: module.pos,
1721 }}
1722 }
1723
1724 if module == foundDep {
1725 return []error{&BlueprintError{
1726 Err: fmt.Errorf("%q depends on itself", depName),
1727 Pos: module.pos,
1728 }}
1729 }
1730 // AddVariationDependency allows adding a dependency on itself, but only if
1731 // that module is earlier in the module list than this one, since we always
1732 // run GenerateBuildActions in order for the variants of a module
1733 if foundDep.group == module.group && beforeInModuleList(module, foundDep, module.group.modules) {
1734 return []error{&BlueprintError{
1735 Err: fmt.Errorf("%q depends on later version of itself", depName),
1736 Pos: module.pos,
1737 }}
1738 }
1739 module.newDirectDeps = append(module.newDirectDeps, depInfo{foundDep, tag})
1740 atomic.AddUint32(&c.depsModified, 1)
1741 return nil
Colin Crossc9028482014-12-18 16:28:54 -08001742}
1743
Colin Crossf1875462016-04-11 17:33:13 -07001744func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1745 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001746 if _, ok := tag.(BaseDependencyTag); ok {
1747 panic("BaseDependencyTag is not allowed to be used directly!")
1748 }
Colin Crossf1875462016-04-11 17:33:13 -07001749
1750 var fromInfo, toInfo *moduleInfo
1751 for _, m := range origModule.splitModules {
1752 if m.logicModule == from {
1753 fromInfo = m
1754 }
1755 if m.logicModule == to {
1756 toInfo = m
1757 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001758 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001759 }
1760 }
1761 }
1762
1763 if fromInfo == nil || toInfo == nil {
1764 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001765 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001766 }
1767
Colin Cross99bdb2a2019-03-29 16:35:02 -07001768 fromInfo.newDirectDeps = append(fromInfo.newDirectDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001769 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001770}
1771
Jeff Gastonc3e28442017-08-09 15:13:12 -07001772// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1773// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1774// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1775func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1776 // make mapping from dir path to file path
1777 filesByDir := make(map[string]string, len(paths))
1778 for _, path := range paths {
1779 dir := filepath.Dir(path)
1780 _, alreadyFound := filesByDir[dir]
1781 if alreadyFound {
1782 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1783 }
1784 filesByDir[dir] = path
1785 }
1786
Jeff Gaston656870f2017-11-29 18:37:31 -08001787 findAncestor := func(childFile string) (ancestor string) {
1788 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001789 for {
1790 ancestorDir := filepath.Dir(prevAncestorDir)
1791 if ancestorDir == prevAncestorDir {
1792 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001793 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001794 }
1795
1796 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1797 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001798 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001799 }
1800 prevAncestorDir = ancestorDir
1801 }
1802 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001803 // generate the descendants map
1804 descendants = make(map[string][]string, len(filesByDir))
1805 for _, childFile := range filesByDir {
1806 ancestorFile := findAncestor(childFile)
1807 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1808 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001809 return descendants, nil
1810}
1811
Colin Cross3702ac72016-08-11 11:09:00 -07001812type visitOrderer interface {
1813 // returns the number of modules that this module needs to wait for
1814 waitCount(module *moduleInfo) int
1815 // returns the list of modules that are waiting for this module
1816 propagate(module *moduleInfo) []*moduleInfo
1817 // visit modules in order
1818 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1819}
1820
Colin Cross7e723372018-03-28 11:50:12 -07001821type unorderedVisitorImpl struct{}
1822
1823func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1824 return 0
1825}
1826
1827func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1828 return nil
1829}
1830
1831func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1832 for _, module := range modules {
1833 if visit(module) {
1834 return
1835 }
1836 }
1837}
1838
Colin Cross3702ac72016-08-11 11:09:00 -07001839type bottomUpVisitorImpl struct{}
1840
1841func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1842 return len(module.forwardDeps)
1843}
1844
1845func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1846 return module.reverseDeps
1847}
1848
1849func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1850 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001851 if visit(module) {
1852 return
1853 }
1854 }
1855}
1856
Colin Cross3702ac72016-08-11 11:09:00 -07001857type topDownVisitorImpl struct{}
1858
1859func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1860 return len(module.reverseDeps)
1861}
1862
1863func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1864 return module.forwardDeps
1865}
1866
1867func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1868 for i := 0; i < len(modules); i++ {
1869 module := modules[len(modules)-1-i]
1870 if visit(module) {
1871 return
1872 }
1873 }
1874}
1875
1876var (
1877 bottomUpVisitor bottomUpVisitorImpl
1878 topDownVisitor topDownVisitorImpl
1879)
1880
Colin Cross49c279a2016-08-05 22:30:44 -07001881// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1882// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001883func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001884 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001885 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001886 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001887 cancel := false
Colin Cross7e723372018-03-28 11:50:12 -07001888 var backlog []*moduleInfo
1889 const limit = 1000
Colin Cross691a60d2015-01-07 18:08:56 -08001890
Colin Cross7addea32015-03-11 15:43:52 -07001891 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001892 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001893 }
1894
Colin Cross7addea32015-03-11 15:43:52 -07001895 visitOne := func(module *moduleInfo) {
Colin Cross7e723372018-03-28 11:50:12 -07001896 if count < limit {
1897 count++
1898 go func() {
1899 ret := visit(module)
1900 if ret {
1901 cancelCh <- true
1902 }
1903 doneCh <- module
1904 }()
1905 } else {
1906 backlog = append(backlog, module)
1907 }
Colin Cross691a60d2015-01-07 18:08:56 -08001908 }
1909
Colin Cross7addea32015-03-11 15:43:52 -07001910 for _, module := range c.modulesSorted {
1911 if module.waitingCount == 0 {
1912 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001913 }
1914 }
1915
Colin Cross7e723372018-03-28 11:50:12 -07001916 for count > 0 || len(backlog) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001917 select {
Colin Cross7e723372018-03-28 11:50:12 -07001918 case <-cancelCh:
1919 cancel = true
1920 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07001921 case doneModule := <-doneCh:
Colin Cross7e723372018-03-28 11:50:12 -07001922 count--
Colin Cross8900e9b2015-03-02 14:03:01 -08001923 if !cancel {
Colin Cross7e723372018-03-28 11:50:12 -07001924 for count < limit && len(backlog) > 0 {
1925 toVisit := backlog[0]
1926 backlog = backlog[1:]
1927 visitOne(toVisit)
1928 }
Colin Cross3702ac72016-08-11 11:09:00 -07001929 for _, module := range order.propagate(doneModule) {
1930 module.waitingCount--
1931 if module.waitingCount == 0 {
1932 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001933 }
Colin Cross691a60d2015-01-07 18:08:56 -08001934 }
1935 }
Colin Cross691a60d2015-01-07 18:08:56 -08001936 }
1937 }
1938}
1939
1940// updateDependencies recursively walks the module dependency graph and updates
1941// additional fields based on the dependencies. It builds a sorted list of modules
1942// such that dependencies of a module always appear first, and populates reverse
1943// dependency links and counts of total dependencies. It also reports errors when
1944// it encounters dependency cycles. This should called after resolveDependencies,
1945// as well as after any mutator pass has called addDependency
1946func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001947 visited := make(map[*moduleInfo]bool) // modules that were already checked
1948 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001949
Colin Cross7addea32015-03-11 15:43:52 -07001950 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001951
Colin Cross7addea32015-03-11 15:43:52 -07001952 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001953
Colin Cross7addea32015-03-11 15:43:52 -07001954 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001955 // We are the "start" of the cycle, so we're responsible
1956 // for generating the errors. The cycle list is in
1957 // reverse order because all the 'check' calls append
1958 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001959 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001960 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001961 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001962 })
1963
1964 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001965 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001966 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001967 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001968 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001969 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001970 curModule.Name(),
1971 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001972 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001973 })
Colin Cross7addea32015-03-11 15:43:52 -07001974 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001975 }
1976 }
1977
Colin Cross7addea32015-03-11 15:43:52 -07001978 check = func(module *moduleInfo) []*moduleInfo {
1979 visited[module] = true
1980 checking[module] = true
1981 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001982
Colin Cross7addea32015-03-11 15:43:52 -07001983 deps := make(map[*moduleInfo]bool)
1984
1985 // Add an implicit dependency ordering on all earlier modules in the same module group
1986 for _, dep := range module.group.modules {
1987 if dep == module {
1988 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001989 }
Colin Cross7addea32015-03-11 15:43:52 -07001990 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001991 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001992
Colin Cross7addea32015-03-11 15:43:52 -07001993 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001994 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001995 }
1996
1997 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001998 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001999
Colin Crossbbfa51a2014-12-17 16:12:41 -08002000 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002001 if checking[dep] {
2002 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07002003 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002004 }
2005
2006 if !visited[dep] {
2007 cycle := check(dep)
2008 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002009 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002010 // We are the "start" of the cycle, so we're responsible
2011 // for generating the errors. The cycle list is in
2012 // reverse order because all the 'check' calls append
2013 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07002014 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002015
2016 // We can continue processing this module's children to
2017 // find more cycles. Since all the modules that were
2018 // part of the found cycle were marked as visited we
2019 // won't run into that cycle again.
2020 } else {
2021 // We're not the "start" of the cycle, so we just append
2022 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07002023 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002024 }
2025 }
2026 }
Colin Cross691a60d2015-01-07 18:08:56 -08002027
Colin Cross3702ac72016-08-11 11:09:00 -07002028 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07002029 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002030 }
2031
Colin Cross7addea32015-03-11 15:43:52 -07002032 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08002033
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002034 return nil
2035 }
2036
Colin Cross7addea32015-03-11 15:43:52 -07002037 for _, module := range c.moduleInfo {
2038 if !visited[module] {
2039 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002040 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07002041 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07002042 panic("inconceivable!")
2043 }
2044 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002045 }
2046 }
2047 }
2048
Colin Cross7addea32015-03-11 15:43:52 -07002049 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08002050
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002051 return
2052}
2053
Jamie Gennisd4e10182014-06-12 20:06:50 -07002054// PrepareBuildActions generates an internal representation of all the build
2055// actions that need to be performed. This process involves invoking the
2056// GenerateBuildActions method on each of the Module objects created during the
2057// parse phase and then on each of the registered Singleton objects.
2058//
2059// If the ResolveDependencies method has not already been called it is called
2060// automatically by this method.
2061//
2062// The config argument is made available to all of the Module and Singleton
2063// objects via the Config method on the ModuleContext and SingletonContext
2064// objects passed to GenerateBuildActions. It is also passed to the functions
2065// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
2066// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002067//
2068// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08002069// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
2070// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
2071// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002072func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08002073 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
2074 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002075
Colin Cross3a8c0252019-01-23 13:21:48 -08002076 if !c.dependenciesReady {
2077 var extraDeps []string
2078 extraDeps, errs = c.resolveDependencies(ctx, config)
2079 if len(errs) > 0 {
2080 return
2081 }
2082 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002083 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002084
Colin Cross3a8c0252019-01-23 13:21:48 -08002085 var depsModules []string
2086 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
2087 if len(errs) > 0 {
2088 return
2089 }
2090
2091 var depsSingletons []string
2092 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
2093 if len(errs) > 0 {
2094 return
2095 }
2096
2097 deps = append(deps, depsModules...)
2098 deps = append(deps, depsSingletons...)
2099
2100 if c.ninjaBuildDir != nil {
2101 err := c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
2102 if err != nil {
2103 errs = []error{err}
2104 return
2105 }
2106 }
2107
2108 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
2109
2110 deps = append(deps, depsPackages...)
2111
2112 // This will panic if it finds a problem since it's a programming error.
2113 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
2114
2115 c.pkgNames = pkgNames
2116 c.globalVariables = c.liveGlobals.variables
2117 c.globalPools = c.liveGlobals.pools
2118 c.globalRules = c.liveGlobals.rules
2119
2120 c.buildActionsReady = true
2121 })
2122
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002123 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002124 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002125 }
2126
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002127 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002128}
2129
Colin Cross3a8c0252019-01-23 13:21:48 -08002130func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07002131 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07002132
Colin Cross3a8c0252019-01-23 13:21:48 -08002133 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
2134 mutators = append(mutators, c.earlyMutatorInfo...)
2135 mutators = append(mutators, c.mutatorInfo...)
Colin Crossf8b50422016-08-10 12:56:40 -07002136
Colin Cross3a8c0252019-01-23 13:21:48 -08002137 for _, mutator := range mutators {
2138 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
2139 var newDeps []string
2140 if mutator.topDownMutator != nil {
2141 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
2142 } else if mutator.bottomUpMutator != nil {
2143 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
2144 } else {
2145 panic("no mutator set on " + mutator.name)
2146 }
2147 if len(errs) > 0 {
2148 return
2149 }
2150 deps = append(deps, newDeps...)
2151 })
2152 if len(errs) > 0 {
2153 return
2154 }
Colin Crossc9028482014-12-18 16:28:54 -08002155 }
Colin Cross3a8c0252019-01-23 13:21:48 -08002156 })
2157
2158 if len(errs) > 0 {
2159 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08002160 }
2161
Colin Cross874a3462017-07-31 17:26:06 -07002162 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08002163}
2164
Colin Cross3702ac72016-08-11 11:09:00 -07002165type mutatorDirection interface {
2166 run(mutator *mutatorInfo, ctx *mutatorContext)
2167 orderer() visitOrderer
2168 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08002169}
2170
Colin Cross3702ac72016-08-11 11:09:00 -07002171type bottomUpMutatorImpl struct{}
2172
2173func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2174 mutator.bottomUpMutator(ctx)
2175}
2176
2177func (bottomUpMutatorImpl) orderer() visitOrderer {
2178 return bottomUpVisitor
2179}
2180
2181func (bottomUpMutatorImpl) String() string {
2182 return "bottom up mutator"
2183}
2184
2185type topDownMutatorImpl struct{}
2186
2187func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
2188 mutator.topDownMutator(ctx)
2189}
2190
2191func (topDownMutatorImpl) orderer() visitOrderer {
2192 return topDownVisitor
2193}
2194
2195func (topDownMutatorImpl) String() string {
2196 return "top down mutator"
2197}
2198
2199var (
2200 topDownMutator topDownMutatorImpl
2201 bottomUpMutator bottomUpMutatorImpl
2202)
2203
Colin Cross49c279a2016-08-05 22:30:44 -07002204type reverseDep struct {
2205 module *moduleInfo
2206 dep depInfo
2207}
2208
Colin Cross3702ac72016-08-11 11:09:00 -07002209func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002210 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002211
2212 newModuleInfo := make(map[Module]*moduleInfo)
2213 for k, v := range c.moduleInfo {
2214 newModuleInfo[k] = v
2215 }
Colin Crossc9028482014-12-18 16:28:54 -08002216
Colin Cross0ce142c2016-12-09 10:29:05 -08002217 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002218 reverse []reverseDep
2219 rename []rename
2220 replace []replace
2221 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002222 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002223 }
2224
Colin Cross2c1f3d12016-04-11 15:47:28 -07002225 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002226 var rename []rename
2227 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002228 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002229
Colin Cross49c279a2016-08-05 22:30:44 -07002230 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002231 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07002232 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07002233 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002234
Colin Cross3702ac72016-08-11 11:09:00 -07002235 c.depsModified = 0
2236
Colin Cross49c279a2016-08-05 22:30:44 -07002237 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002238 if module.splitModules != nil {
2239 panic("split module found in sorted module list")
2240 }
2241
Colin Cross4a693162020-08-13 12:11:52 -07002242 module.pendingAliases = nil
2243
Colin Cross7addea32015-03-11 15:43:52 -07002244 mctx := &mutatorContext{
2245 baseModuleContext: baseModuleContext{
2246 context: c,
2247 config: config,
2248 module: module,
2249 },
Colin Cross49c279a2016-08-05 22:30:44 -07002250 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07002251 }
Colin Crossc9028482014-12-18 16:28:54 -08002252
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002253 func() {
2254 defer func() {
2255 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002256 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002257 if err, ok := r.(panicError); ok {
2258 err.addIn(in)
2259 mctx.error(err)
2260 } else {
2261 mctx.error(newPanicErrorf(r, in))
2262 }
2263 }
2264 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002265 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002266 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002267
Colin Cross7addea32015-03-11 15:43:52 -07002268 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002269 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002270 return true
Colin Cross7addea32015-03-11 15:43:52 -07002271 }
Colin Crossc9028482014-12-18 16:28:54 -08002272
Colin Cross5fe225f2017-07-28 15:22:46 -07002273 if len(mctx.newVariations) > 0 {
2274 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002275 }
2276
Colin Crossab0a83f2020-03-03 14:23:27 -08002277 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 -08002278 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002279 reverse: mctx.reverseDeps,
2280 replace: mctx.replace,
2281 rename: mctx.rename,
2282 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002283 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002284 }
Colin Cross49c279a2016-08-05 22:30:44 -07002285 }
2286
2287 return false
2288 }
2289
2290 // Process errs and reverseDeps in a single goroutine
2291 go func() {
2292 for {
2293 select {
2294 case newErrs := <-errsCh:
2295 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002296 case globalStateChange := <-globalStateCh:
2297 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002298 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2299 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002300 replace = append(replace, globalStateChange.replace...)
2301 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002302 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002303 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002304 case newVariations := <-newVariationsCh:
2305 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002306 newModuleInfo[m.logicModule] = m
2307 }
2308 case <-done:
2309 return
Colin Crossc9028482014-12-18 16:28:54 -08002310 }
2311 }
Colin Cross49c279a2016-08-05 22:30:44 -07002312 }()
Colin Crossc9028482014-12-18 16:28:54 -08002313
Colin Cross49c279a2016-08-05 22:30:44 -07002314 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002315 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002316 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002317 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002318 }
2319
2320 done <- true
2321
2322 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002323 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002324 }
2325
2326 c.moduleInfo = newModuleInfo
2327
2328 for _, group := range c.moduleGroups {
2329 for i := 0; i < len(group.modules); i++ {
2330 module := group.modules[i]
2331
2332 // Update module group to contain newly split variants
2333 if module.splitModules != nil {
2334 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2335 }
2336
Colin Crossf7beb892019-11-13 20:11:14 -08002337 // Create any new aliases.
Colin Cross4a693162020-08-13 12:11:52 -07002338 for _, alias := range module.pendingAliases {
Colin Crossf7beb892019-11-13 20:11:14 -08002339 group.aliases = append(group.aliases, &moduleAlias{
Colin Cross4a693162020-08-13 12:11:52 -07002340 variant: alias.fromVariant,
2341 target: alias.target,
Colin Crossf7beb892019-11-13 20:11:14 -08002342 })
2343 }
2344
Colin Cross49c279a2016-08-05 22:30:44 -07002345 // Fix up any remaining dependencies on modules that were split into variants
2346 // by replacing them with the first variant
2347 for j, dep := range module.directDeps {
2348 if dep.module.logicModule == nil {
2349 module.directDeps[j].module = dep.module.splitModules[0]
2350 }
2351 }
Colin Cross99bdb2a2019-03-29 16:35:02 -07002352
Colin Cross322cc012019-05-20 13:55:14 -07002353 if module.createdBy != nil && module.createdBy.logicModule == nil {
2354 module.createdBy = module.createdBy.splitModules[0]
2355 }
2356
Colin Cross99bdb2a2019-03-29 16:35:02 -07002357 // Add in any new direct dependencies that were added by the mutator
2358 module.directDeps = append(module.directDeps, module.newDirectDeps...)
2359 module.newDirectDeps = nil
Colin Cross7addea32015-03-11 15:43:52 -07002360 }
Colin Crossf7beb892019-11-13 20:11:14 -08002361
Colin Cross4a693162020-08-13 12:11:52 -07002362 findAliasTarget := func(variant variant) *moduleInfo {
2363 for _, alias := range group.aliases {
2364 if alias.variant.variations.equal(variant.variations) {
2365 return alias.target
2366 }
2367 }
2368 return nil
2369 }
2370
Colin Crossf7beb892019-11-13 20:11:14 -08002371 // Forward or delete any dangling aliases.
2372 for i := 0; i < len(group.aliases); i++ {
2373 alias := group.aliases[i]
2374
2375 if alias.target.logicModule == nil {
Colin Cross4a693162020-08-13 12:11:52 -07002376 newTarget := findAliasTarget(alias.target.variant)
2377 if newTarget != nil {
2378 alias.target = newTarget
Colin Crossf7beb892019-11-13 20:11:14 -08002379 } else {
2380 // The alias was left dangling, remove it.
2381 group.aliases = append(group.aliases[:i], group.aliases[i+1:]...)
2382 i--
2383 }
2384 }
2385 }
Colin Crossc9028482014-12-18 16:28:54 -08002386 }
2387
Colin Cross99bdb2a2019-03-29 16:35:02 -07002388 // Add in any new reverse dependencies that were added by the mutator
Colin Cross8d8a7af2015-11-03 16:41:29 -08002389 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002390 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002391 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002392 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002393 }
2394
Colin Crossaf4fd212017-07-28 14:32:36 -07002395 for _, module := range newModules {
2396 errs = c.addModule(module)
2397 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002398 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002399 }
2400 atomic.AddUint32(&c.depsModified, 1)
2401 }
2402
Colin Cross0ce142c2016-12-09 10:29:05 -08002403 errs = c.handleRenames(rename)
2404 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002405 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002406 }
2407
2408 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002409 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002410 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002411 }
2412
Colin Cross3702ac72016-08-11 11:09:00 -07002413 if c.depsModified > 0 {
2414 errs = c.updateDependencies()
2415 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002416 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002417 }
Colin Crossc9028482014-12-18 16:28:54 -08002418 }
2419
Colin Cross874a3462017-07-31 17:26:06 -07002420 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002421}
2422
Colin Cross910242b2016-04-11 15:41:52 -07002423// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2424// a mutator sets a non-property member variable on a module, which works until a later mutator
2425// creates variants of that module.
2426func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002427 type update struct {
2428 orig Module
2429 clone *moduleInfo
2430 }
Colin Cross7e723372018-03-28 11:50:12 -07002431 ch := make(chan update)
2432 doneCh := make(chan bool)
2433 go func() {
2434 c.parallelVisit(unorderedVisitorImpl{}, func(m *moduleInfo) bool {
Colin Crossc93490c2016-08-09 14:21:02 -07002435 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002436 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002437 ch <- update{origLogicModule, m}
Colin Cross7e723372018-03-28 11:50:12 -07002438 return false
2439 })
2440 doneCh <- true
2441 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002442
Colin Cross7e723372018-03-28 11:50:12 -07002443 done := false
2444 for !done {
2445 select {
2446 case <-doneCh:
2447 done = true
2448 case update := <-ch:
2449 delete(c.moduleInfo, update.orig)
2450 c.moduleInfo[update.clone.logicModule] = update.clone
2451 }
Colin Cross910242b2016-04-11 15:41:52 -07002452 }
2453}
2454
Colin Cross49c279a2016-08-05 22:30:44 -07002455// Removes modules[i] from the list and inserts newModules... where it was located, returning
2456// the new slice and the index of the last inserted element
2457func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002458 spliceSize := len(newModules)
2459 newLen := len(modules) + spliceSize - 1
2460 var dest []*moduleInfo
2461 if cap(modules) >= len(modules)-1+len(newModules) {
2462 // We can fit the splice in the existing capacity, do everything in place
2463 dest = modules[:newLen]
2464 } else {
2465 dest = make([]*moduleInfo, newLen)
2466 copy(dest, modules[:i])
2467 }
2468
2469 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002470 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002471
2472 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002473 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002474
Colin Cross49c279a2016-08-05 22:30:44 -07002475 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002476}
2477
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002478func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002479 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002480
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002481 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002482 var errs []error
2483
Colin Cross691a60d2015-01-07 18:08:56 -08002484 cancelCh := make(chan struct{})
2485 errsCh := make(chan []error)
2486 depsCh := make(chan []string)
2487
2488 go func() {
2489 for {
2490 select {
2491 case <-cancelCh:
2492 close(cancelCh)
2493 return
2494 case newErrs := <-errsCh:
2495 errs = append(errs, newErrs...)
2496 case newDeps := <-depsCh:
2497 deps = append(deps, newDeps...)
2498
2499 }
2500 }
2501 }()
2502
Colin Cross3702ac72016-08-11 11:09:00 -07002503 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08002504
2505 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2506 sanitizedName := toNinjaName(uniqueName)
2507
Colin Cross71c4be62020-08-13 12:07:30 -07002508 prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variant.name)
Jeff Gaston0e907592017-12-01 17:10:52 -08002509
Colin Cross7addea32015-03-11 15:43:52 -07002510 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2511 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2512 // just set it to nil.
Colin Cross7addea32015-03-11 15:43:52 -07002513 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002514
Colin Cross7addea32015-03-11 15:43:52 -07002515 mctx := &moduleContext{
2516 baseModuleContext: baseModuleContext{
2517 context: c,
2518 config: config,
2519 module: module,
2520 },
Colin Cross036a1df2015-12-17 15:49:30 -08002521 scope: scope,
2522 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002523 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002524
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002525 func() {
2526 defer func() {
2527 if r := recover(); r != nil {
2528 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2529 if err, ok := r.(panicError); ok {
2530 err.addIn(in)
2531 mctx.error(err)
2532 } else {
2533 mctx.error(newPanicErrorf(r, in))
2534 }
2535 }
2536 }()
2537 mctx.module.logicModule.GenerateBuildActions(mctx)
2538 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002539
Colin Cross7addea32015-03-11 15:43:52 -07002540 if len(mctx.errs) > 0 {
2541 errsCh <- mctx.errs
2542 return true
2543 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002544
Colin Cross036a1df2015-12-17 15:49:30 -08002545 if module.missingDeps != nil && !mctx.handledMissingDeps {
2546 var errs []error
2547 for _, depName := range module.missingDeps {
Jeff Gastond70bf752017-11-10 15:12:08 -08002548 errs = append(errs, c.missingDependencyError(module, depName))
Colin Cross036a1df2015-12-17 15:49:30 -08002549 }
2550 errsCh <- errs
2551 return true
2552 }
2553
Colin Cross7addea32015-03-11 15:43:52 -07002554 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002555
Colin Crossab6d7902015-03-11 16:17:52 -07002556 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002557 &mctx.actionDefs, liveGlobals)
2558 if len(newErrs) > 0 {
2559 errsCh <- newErrs
2560 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002561 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002562 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002563 })
2564
2565 cancelCh <- struct{}{}
2566 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002567
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002568 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002569}
2570
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002571func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002572 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002573
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002574 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002575 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002576
Colin Cross5f03f112017-11-07 13:29:54 -08002577 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002578 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2579 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2580 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002581 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002582
2583 sctx := &singletonContext{
Colin Cross9226d6c2019-02-25 18:07:44 -08002584 name: info.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002585 context: c,
2586 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002587 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002588 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002589 }
2590
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002591 func() {
2592 defer func() {
2593 if r := recover(); r != nil {
2594 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2595 if err, ok := r.(panicError); ok {
2596 err.addIn(in)
2597 sctx.error(err)
2598 } else {
2599 sctx.error(newPanicErrorf(r, in))
2600 }
2601 }
2602 }()
2603 info.singleton.GenerateBuildActions(sctx)
2604 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002605
2606 if len(sctx.errs) > 0 {
2607 errs = append(errs, sctx.errs...)
2608 if len(errs) > maxErrors {
2609 break
2610 }
2611 continue
2612 }
2613
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002614 deps = append(deps, sctx.ninjaFileDeps...)
2615
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002616 newErrs := c.processLocalBuildActions(&info.actionDefs,
2617 &sctx.actionDefs, liveGlobals)
2618 errs = append(errs, newErrs...)
2619 if len(errs) > maxErrors {
2620 break
2621 }
2622 }
2623
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002624 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002625}
2626
2627func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2628 liveGlobals *liveTracker) []error {
2629
2630 var errs []error
2631
2632 // First we go through and add everything referenced by the module's
2633 // buildDefs to the live globals set. This will end up adding the live
2634 // locals to the set as well, but we'll take them out after.
2635 for _, def := range in.buildDefs {
2636 err := liveGlobals.AddBuildDefDeps(def)
2637 if err != nil {
2638 errs = append(errs, err)
2639 }
2640 }
2641
2642 if len(errs) > 0 {
2643 return errs
2644 }
2645
Colin Crossc9028482014-12-18 16:28:54 -08002646 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002647
2648 // We use the now-incorrect set of live "globals" to determine which local
2649 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002650 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002651 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002652 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002653 if isLive {
2654 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002655 }
2656 }
2657
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002658 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002659 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002660 if isLive {
2661 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002662 }
2663 }
2664
2665 return nil
2666}
2667
Colin Cross9607a9f2018-06-20 11:16:37 -07002668func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07002669 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002670
2671 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002672 var visiting *moduleInfo
2673
2674 defer func() {
2675 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002676 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2677 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002678 }
2679 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002680
2681 var walk func(module *moduleInfo)
2682 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002683 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07002684 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002685 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002686 recurse := true
2687 if visitDown != nil {
2688 recurse = visitDown(dep, module)
2689 }
Colin Cross526e02f2018-06-21 13:31:53 -07002690 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002691 walk(dep.module)
Paul Duffin72bab172020-04-02 10:51:33 +01002692 visited[dep.module] = true
Yuchen Wu222e2452015-10-06 14:03:27 -07002693 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002694 if visitUp != nil {
2695 visitUp(dep, module)
2696 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002697 }
2698 }
2699 }
2700
2701 walk(topModule)
2702}
2703
Colin Cross9cfd1982016-10-11 09:58:53 -07002704type replace struct {
Paul Duffinc191e602020-06-30 12:15:26 +01002705 from, to *moduleInfo
2706 predicate ReplaceDependencyPredicate
Colin Cross9cfd1982016-10-11 09:58:53 -07002707}
2708
Colin Crossc4e5b812016-10-12 10:45:05 -07002709type rename struct {
2710 group *moduleGroup
2711 name string
2712}
2713
Colin Cross0ce142c2016-12-09 10:29:05 -08002714func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Crossd03b59d2019-11-13 20:10:12 -08002715 group := c.moduleGroupFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07002716
Colin Crossd03b59d2019-11-13 20:10:12 -08002717 if group == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002718 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002719 }
2720
Colin Crossd03b59d2019-11-13 20:10:12 -08002721 for _, m := range group.modules {
Colin Cross71c4be62020-08-13 12:07:30 -07002722 if module.variant.name == m.variant.name {
Colin Cross0ce142c2016-12-09 10:29:05 -08002723 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002724 }
2725 }
2726
Colin Crossf7beb892019-11-13 20:11:14 -08002727 for _, m := range group.aliases {
Colin Cross71c4be62020-08-13 12:07:30 -07002728 if module.variant.name == m.variant.name {
Colin Crossf7beb892019-11-13 20:11:14 -08002729 return m.target
2730 }
2731 }
2732
Colin Cross0ce142c2016-12-09 10:29:05 -08002733 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002734}
2735
Colin Cross0ce142c2016-12-09 10:29:05 -08002736func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002737 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002738 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002739 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08002740 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07002741 continue
2742 }
2743
Jeff Gastond70bf752017-11-10 15:12:08 -08002744 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07002745 }
2746
Colin Cross0ce142c2016-12-09 10:29:05 -08002747 return errs
2748}
2749
2750func (c *Context) handleReplacements(replacements []replace) []error {
2751 var errs []error
Paul Duffinc191e602020-06-30 12:15:26 +01002752 changedDeps := false
Colin Cross0ce142c2016-12-09 10:29:05 -08002753 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002754 for _, m := range replace.from.reverseDeps {
2755 for i, d := range m.directDeps {
2756 if d.module == replace.from {
Paul Duffinc191e602020-06-30 12:15:26 +01002757 // If the replacement has a predicate then check it.
2758 if replace.predicate == nil || replace.predicate(m.logicModule, d.tag, d.module.logicModule) {
2759 m.directDeps[i].module = replace.to
2760 changedDeps = true
2761 }
Colin Cross9cfd1982016-10-11 09:58:53 -07002762 }
2763 }
2764 }
2765
Colin Cross9cfd1982016-10-11 09:58:53 -07002766 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002767
Paul Duffinc191e602020-06-30 12:15:26 +01002768 if changedDeps {
2769 atomic.AddUint32(&c.depsModified, 1)
2770 }
Colin Crossc4e5b812016-10-12 10:45:05 -07002771 return errs
2772}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002773
Jeff Gastond70bf752017-11-10 15:12:08 -08002774func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
2775 if c.allowMissingDependencies {
2776 module.missingDeps = append(module.missingDeps, depName)
2777 return nil
2778 }
2779 return []error{c.missingDependencyError(module, depName)}
2780}
2781
2782func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
2783 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
2784
2785 return &BlueprintError{
2786 Err: err,
2787 Pos: module.pos,
2788 }
2789}
2790
Colin Crossd03b59d2019-11-13 20:10:12 -08002791func (c *Context) moduleGroupFromName(name string, namespace Namespace) *moduleGroup {
Jeff Gastond70bf752017-11-10 15:12:08 -08002792 group, exists := c.nameInterface.ModuleFromName(name, namespace)
2793 if exists {
Colin Crossd03b59d2019-11-13 20:10:12 -08002794 return group.moduleGroup
Colin Cross0b7e83e2016-05-17 14:58:05 -07002795 }
2796 return nil
2797}
2798
Jeff Gastond70bf752017-11-10 15:12:08 -08002799func (c *Context) sortedModuleGroups() []*moduleGroup {
2800 if c.cachedSortedModuleGroups == nil {
2801 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
2802 result := make([]*moduleGroup, 0, len(wrappers))
2803 for _, group := range wrappers {
2804 result = append(result, group.moduleGroup)
2805 }
2806 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07002807 }
Jeff Gastond70bf752017-11-10 15:12:08 -08002808
2809 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Jamie Gennisc15544d2014-09-24 20:26:52 -07002810 }
2811
Jeff Gastond70bf752017-11-10 15:12:08 -08002812 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07002813}
2814
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002815func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002816 var module *moduleInfo
2817
2818 defer func() {
2819 if r := recover(); r != nil {
2820 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2821 funcName(visit), module))
2822 }
2823 }()
2824
Jeff Gastond70bf752017-11-10 15:12:08 -08002825 for _, moduleGroup := range c.sortedModuleGroups() {
2826 for _, module = range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002827 visit(module.logicModule)
2828 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002829 }
2830}
2831
2832func (c *Context) visitAllModulesIf(pred func(Module) bool,
2833 visit func(Module)) {
2834
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002835 var module *moduleInfo
2836
2837 defer func() {
2838 if r := recover(); r != nil {
2839 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2840 funcName(pred), funcName(visit), module))
2841 }
2842 }()
2843
Jeff Gastond70bf752017-11-10 15:12:08 -08002844 for _, moduleGroup := range c.sortedModuleGroups() {
2845 for _, module := range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002846 if pred(module.logicModule) {
2847 visit(module.logicModule)
2848 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002849 }
2850 }
2851}
2852
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002853func (c *Context) visitAllModuleVariants(module *moduleInfo,
2854 visit func(Module)) {
2855
2856 var variant *moduleInfo
2857
2858 defer func() {
2859 if r := recover(); r != nil {
2860 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2861 module, funcName(visit), variant))
2862 }
2863 }()
2864
2865 for _, variant = range module.group.modules {
2866 visit(variant.logicModule)
2867 }
2868}
2869
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002870func (c *Context) requireNinjaVersion(major, minor, micro int) {
2871 if major != 1 {
2872 panic("ninja version with major version != 1 not supported")
2873 }
2874 if c.requiredNinjaMinor < minor {
2875 c.requiredNinjaMinor = minor
2876 c.requiredNinjaMicro = micro
2877 }
2878 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2879 c.requiredNinjaMicro = micro
2880 }
2881}
2882
Colin Cross2ce594e2020-01-29 12:58:03 -08002883func (c *Context) setNinjaBuildDir(value ninjaString) {
Colin Crossa2599452015-11-18 16:01:01 -08002884 if c.ninjaBuildDir == nil {
2885 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002886 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002887}
2888
2889func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002890 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002891
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002892 pkgs := make(map[string]*packageContext)
2893 pkgNames := make(map[*packageContext]string)
2894 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002895
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002896 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002897 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002898 // This is a built-in rule and has no package.
2899 return
2900 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002901 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002902 // We've already processed this package.
2903 return
2904 }
2905
Jamie Gennis2fb20952014-10-03 02:49:58 -07002906 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002907 if present {
2908 // Short name collision. Both this package and the one that's
2909 // already there need to use their full names. We leave the short
2910 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002911 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002912 longPkgNames[otherPkg] = true
2913 } else {
2914 // No collision so far. Tentatively set the package's name to be
2915 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002916 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002917 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002918 }
2919 }
2920
2921 // We try to give all packages their short name, but when we get collisions
2922 // we need to use the full unique package name.
2923 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002924 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002925 }
2926 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002927 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002928 }
2929 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002930 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002931 }
2932
2933 // Add the packages that had collisions using their full unique names. This
2934 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002935 for pctx := range longPkgNames {
2936 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002937 }
2938
Dan Willemsena481ae22015-12-18 15:18:03 -08002939 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2940 deps := []string{}
2941 for _, pkg := range pkgs {
2942 deps = append(deps, pkg.ninjaFileDeps...)
2943 }
2944
2945 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002946}
2947
2948func (c *Context) checkForVariableReferenceCycles(
Colin Cross2ce594e2020-01-29 12:58:03 -08002949 variables map[Variable]ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002950
2951 visited := make(map[Variable]bool) // variables that were already checked
2952 checking := make(map[Variable]bool) // variables actively being checked
2953
2954 var check func(v Variable) []Variable
2955
2956 check = func(v Variable) []Variable {
2957 visited[v] = true
2958 checking[v] = true
2959 defer delete(checking, v)
2960
2961 value := variables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08002962 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002963 if checking[dep] {
2964 // This is a cycle.
2965 return []Variable{dep, v}
2966 }
2967
2968 if !visited[dep] {
2969 cycle := check(dep)
2970 if cycle != nil {
2971 if cycle[0] == v {
2972 // We are the "start" of the cycle, so we're responsible
2973 // for generating the errors. The cycle list is in
2974 // reverse order because all the 'check' calls append
2975 // their own module to the list.
2976 msgs := []string{"detected variable reference cycle:"}
2977
2978 // Iterate backwards through the cycle list.
2979 curName := v.fullName(pkgNames)
2980 curValue := value.Value(pkgNames)
2981 for i := len(cycle) - 1; i >= 0; i-- {
2982 next := cycle[i]
2983 nextName := next.fullName(pkgNames)
2984 nextValue := variables[next].Value(pkgNames)
2985
2986 msgs = append(msgs, fmt.Sprintf(
2987 " %q depends on %q", curName, nextName))
2988 msgs = append(msgs, fmt.Sprintf(
2989 " [%s = %s]", curName, curValue))
2990
2991 curName = nextName
2992 curValue = nextValue
2993 }
2994
2995 // Variable reference cycles are a programming error,
2996 // not the fault of the Blueprint file authors.
2997 panic(strings.Join(msgs, "\n"))
2998 } else {
2999 // We're not the "start" of the cycle, so we just append
3000 // our module to the list and return it.
3001 return append(cycle, v)
3002 }
3003 }
3004 }
3005 }
3006
3007 return nil
3008 }
3009
3010 for v := range variables {
3011 if !visited[v] {
3012 cycle := check(v)
3013 if cycle != nil {
3014 panic("inconceivable!")
3015 }
3016 }
3017 }
3018}
3019
Jamie Gennisaf435562014-10-27 22:34:56 -07003020// AllTargets returns a map all the build target names to the rule used to build
3021// them. This is the same information that is output by running 'ninja -t
3022// targets all'. If this is called before PrepareBuildActions successfully
3023// completes then ErrbuildActionsNotReady is returned.
3024func (c *Context) AllTargets() (map[string]string, error) {
3025 if !c.buildActionsReady {
3026 return nil, ErrBuildActionsNotReady
3027 }
3028
3029 targets := map[string]string{}
3030
3031 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07003032 for _, module := range c.moduleInfo {
3033 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07003034 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003035 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003036 outputValue, err := output.Eval(c.globalVariables)
3037 if err != nil {
3038 return nil, err
3039 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003040 targets[outputValue] = ruleName
3041 }
3042 }
3043 }
3044
3045 // Collect all the singleton build targets.
3046 for _, info := range c.singletonInfo {
3047 for _, buildDef := range info.actionDefs.buildDefs {
3048 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07003049 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08003050 outputValue, err := output.Eval(c.globalVariables)
3051 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08003052 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08003053 }
Jamie Gennisaf435562014-10-27 22:34:56 -07003054 targets[outputValue] = ruleName
3055 }
3056 }
3057 }
3058
3059 return targets, nil
3060}
3061
Colin Crossa2599452015-11-18 16:01:01 -08003062func (c *Context) NinjaBuildDir() (string, error) {
3063 if c.ninjaBuildDir != nil {
3064 return c.ninjaBuildDir.Eval(c.globalVariables)
3065 } else {
3066 return "", nil
3067 }
3068}
3069
Colin Cross4572edd2015-05-13 14:36:24 -07003070// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
3071// property structs returned by the factory for that module type.
3072func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
3073 ret := make(map[string][]interface{})
3074 for moduleType, factory := range c.moduleFactories {
3075 _, ret[moduleType] = factory()
3076 }
3077
3078 return ret
3079}
3080
Jaewoong Jung781f6b22019-02-06 16:20:17 -08003081func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
3082 ret := make(map[string]ModuleFactory)
3083 for k, v := range c.moduleFactories {
3084 ret[k] = v
3085 }
3086 return ret
3087}
3088
Colin Cross4572edd2015-05-13 14:36:24 -07003089func (c *Context) ModuleName(logicModule Module) string {
3090 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07003091 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07003092}
3093
Jeff Gaston3c8c3342017-11-30 17:30:42 -08003094func (c *Context) ModulePath(logicModule Module) string {
Colin Cross4572edd2015-05-13 14:36:24 -07003095 module := c.moduleInfo[logicModule]
Jeff Gaston3c8c3342017-11-30 17:30:42 -08003096 return module.relBlueprintsFile
3097}
3098
3099func (c *Context) ModuleDir(logicModule Module) string {
3100 return filepath.Dir(c.ModulePath(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07003101}
3102
Colin Cross8c602f72015-12-17 18:02:11 -08003103func (c *Context) ModuleSubDir(logicModule Module) string {
3104 module := c.moduleInfo[logicModule]
Colin Cross71c4be62020-08-13 12:07:30 -07003105 return module.variant.name
Colin Cross8c602f72015-12-17 18:02:11 -08003106}
3107
Dan Willemsenc98e55b2016-07-25 15:51:50 -07003108func (c *Context) ModuleType(logicModule Module) string {
3109 module := c.moduleInfo[logicModule]
3110 return module.typeName
3111}
3112
Colin Cross4572edd2015-05-13 14:36:24 -07003113func (c *Context) BlueprintFile(logicModule Module) string {
3114 module := c.moduleInfo[logicModule]
3115 return module.relBlueprintsFile
3116}
3117
3118func (c *Context) ModuleErrorf(logicModule Module, format string,
3119 args ...interface{}) error {
3120
3121 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07003122 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07003123 Err: fmt.Errorf(format, args...),
3124 Pos: module.pos,
3125 }
3126}
3127
3128func (c *Context) VisitAllModules(visit func(Module)) {
3129 c.visitAllModules(visit)
3130}
3131
3132func (c *Context) VisitAllModulesIf(pred func(Module) bool,
3133 visit func(Module)) {
3134
3135 c.visitAllModulesIf(pred, visit)
3136}
3137
Colin Cross080c1332017-03-17 13:09:05 -07003138func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
3139 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07003140
Colin Cross080c1332017-03-17 13:09:05 -07003141 var visiting *moduleInfo
3142
3143 defer func() {
3144 if r := recover(); r != nil {
3145 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
3146 topModule, funcName(visit), visiting))
3147 }
3148 }()
3149
3150 for _, dep := range topModule.directDeps {
3151 visiting = dep.module
3152 visit(dep.module.logicModule)
3153 }
3154}
3155
3156func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
3157 topModule := c.moduleInfo[module]
3158
3159 var visiting *moduleInfo
3160
3161 defer func() {
3162 if r := recover(); r != nil {
3163 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
3164 topModule, funcName(pred), funcName(visit), visiting))
3165 }
3166 }()
3167
3168 for _, dep := range topModule.directDeps {
3169 visiting = dep.module
3170 if pred(dep.module.logicModule) {
3171 visit(dep.module.logicModule)
3172 }
3173 }
3174}
3175
3176func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003177 topModule := c.moduleInfo[module]
3178
3179 var visiting *moduleInfo
3180
3181 defer func() {
3182 if r := recover(); r != nil {
3183 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
3184 topModule, funcName(visit), visiting))
3185 }
3186 }()
3187
Colin Cross9607a9f2018-06-20 11:16:37 -07003188 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003189 visiting = dep.module
3190 visit(dep.module.logicModule)
3191 })
Colin Cross4572edd2015-05-13 14:36:24 -07003192}
3193
Colin Cross080c1332017-03-17 13:09:05 -07003194func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003195 topModule := c.moduleInfo[module]
3196
3197 var visiting *moduleInfo
3198
3199 defer func() {
3200 if r := recover(); r != nil {
3201 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
3202 topModule, funcName(pred), funcName(visit), visiting))
3203 }
3204 }()
3205
Colin Cross9607a9f2018-06-20 11:16:37 -07003206 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07003207 if pred(dep.module.logicModule) {
3208 visiting = dep.module
3209 visit(dep.module.logicModule)
3210 }
3211 })
Colin Cross4572edd2015-05-13 14:36:24 -07003212}
3213
Colin Cross24ad5872015-11-17 16:22:29 -08003214func (c *Context) PrimaryModule(module Module) Module {
3215 return c.moduleInfo[module].group.modules[0].logicModule
3216}
3217
3218func (c *Context) FinalModule(module Module) Module {
3219 modules := c.moduleInfo[module].group.modules
3220 return modules[len(modules)-1].logicModule
3221}
3222
3223func (c *Context) VisitAllModuleVariants(module Module,
3224 visit func(Module)) {
3225
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003226 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08003227}
3228
Colin Cross9226d6c2019-02-25 18:07:44 -08003229// Singletons returns a list of all registered Singletons.
3230func (c *Context) Singletons() []Singleton {
3231 var ret []Singleton
3232 for _, s := range c.singletonInfo {
3233 ret = append(ret, s.singleton)
3234 }
3235 return ret
3236}
3237
3238// SingletonName returns the name that the given singleton was registered with.
3239func (c *Context) SingletonName(singleton Singleton) string {
3240 for _, s := range c.singletonInfo {
3241 if s.singleton == singleton {
3242 return s.name
3243 }
3244 }
3245 return ""
3246}
3247
Jamie Gennisd4e10182014-06-12 20:06:50 -07003248// WriteBuildFile writes the Ninja manifeset text for the generated build
3249// actions to w. If this is called before PrepareBuildActions successfully
3250// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003251func (c *Context) WriteBuildFile(w io.Writer) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08003252 var err error
3253 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
3254 if !c.buildActionsReady {
3255 err = ErrBuildActionsNotReady
3256 return
3257 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003258
Colin Cross3a8c0252019-01-23 13:21:48 -08003259 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003260
Colin Cross3a8c0252019-01-23 13:21:48 -08003261 err = c.writeBuildFileHeader(nw)
3262 if err != nil {
3263 return
3264 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003265
Colin Cross3a8c0252019-01-23 13:21:48 -08003266 err = c.writeNinjaRequiredVersion(nw)
3267 if err != nil {
3268 return
3269 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003270
Colin Cross3a8c0252019-01-23 13:21:48 -08003271 err = c.writeSubninjas(nw)
3272 if err != nil {
3273 return
3274 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003275
Colin Cross3a8c0252019-01-23 13:21:48 -08003276 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003277
Colin Cross3a8c0252019-01-23 13:21:48 -08003278 err = c.writeGlobalVariables(nw)
3279 if err != nil {
3280 return
3281 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003282
Colin Cross3a8c0252019-01-23 13:21:48 -08003283 err = c.writeGlobalPools(nw)
3284 if err != nil {
3285 return
3286 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003287
Colin Cross3a8c0252019-01-23 13:21:48 -08003288 err = c.writeBuildDir(nw)
3289 if err != nil {
3290 return
3291 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003292
Colin Cross3a8c0252019-01-23 13:21:48 -08003293 err = c.writeGlobalRules(nw)
3294 if err != nil {
3295 return
3296 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003297
Colin Cross3a8c0252019-01-23 13:21:48 -08003298 err = c.writeAllModuleActions(nw)
3299 if err != nil {
3300 return
3301 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003302
Colin Cross3a8c0252019-01-23 13:21:48 -08003303 err = c.writeAllSingletonActions(nw)
3304 if err != nil {
3305 return
3306 }
3307 })
3308
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003309 if err != nil {
3310 return err
3311 }
3312
3313 return nil
3314}
3315
Jamie Gennisc15544d2014-09-24 20:26:52 -07003316type pkgAssociation struct {
3317 PkgName string
3318 PkgPath string
3319}
3320
3321type pkgAssociationSorter struct {
3322 pkgs []pkgAssociation
3323}
3324
3325func (s *pkgAssociationSorter) Len() int {
3326 return len(s.pkgs)
3327}
3328
3329func (s *pkgAssociationSorter) Less(i, j int) bool {
3330 iName := s.pkgs[i].PkgName
3331 jName := s.pkgs[j].PkgName
3332 return iName < jName
3333}
3334
3335func (s *pkgAssociationSorter) Swap(i, j int) {
3336 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3337}
3338
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003339func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3340 headerTemplate := template.New("fileHeader")
3341 _, err := headerTemplate.Parse(fileHeaderTemplate)
3342 if err != nil {
3343 // This is a programming error.
3344 panic(err)
3345 }
3346
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003347 var pkgs []pkgAssociation
3348 maxNameLen := 0
3349 for pkg, name := range c.pkgNames {
3350 pkgs = append(pkgs, pkgAssociation{
3351 PkgName: name,
3352 PkgPath: pkg.pkgPath,
3353 })
3354 if len(name) > maxNameLen {
3355 maxNameLen = len(name)
3356 }
3357 }
3358
3359 for i := range pkgs {
3360 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3361 }
3362
Jamie Gennisc15544d2014-09-24 20:26:52 -07003363 sort.Sort(&pkgAssociationSorter{pkgs})
3364
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003365 params := map[string]interface{}{
3366 "Pkgs": pkgs,
3367 }
3368
3369 buf := bytes.NewBuffer(nil)
3370 err = headerTemplate.Execute(buf, params)
3371 if err != nil {
3372 return err
3373 }
3374
3375 return nw.Comment(buf.String())
3376}
3377
3378func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3379 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3380 c.requiredNinjaMicro)
3381
3382 err := nw.Assign("ninja_required_version", value)
3383 if err != nil {
3384 return err
3385 }
3386
3387 return nw.BlankLine()
3388}
3389
Dan Willemsenab223a52018-07-05 21:56:59 -07003390func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3391 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003392 err := nw.Subninja(subninja)
3393 if err != nil {
3394 return err
3395 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003396 }
3397 return nw.BlankLine()
3398}
3399
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003400func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08003401 if c.ninjaBuildDir != nil {
3402 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003403 if err != nil {
3404 return err
3405 }
3406
3407 err = nw.BlankLine()
3408 if err != nil {
3409 return err
3410 }
3411 }
3412 return nil
3413}
3414
Jamie Gennisc15544d2014-09-24 20:26:52 -07003415type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003416 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003417}
3418
Jamie Gennisc15544d2014-09-24 20:26:52 -07003419type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003420 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003421 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003422}
3423
Jamie Gennisc15544d2014-09-24 20:26:52 -07003424func (s *globalEntitySorter) Len() int {
3425 return len(s.entities)
3426}
3427
3428func (s *globalEntitySorter) Less(i, j int) bool {
3429 iName := s.entities[i].fullName(s.pkgNames)
3430 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003431 return iName < jName
3432}
3433
Jamie Gennisc15544d2014-09-24 20:26:52 -07003434func (s *globalEntitySorter) Swap(i, j int) {
3435 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003436}
3437
3438func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3439 visited := make(map[Variable]bool)
3440
3441 var walk func(v Variable) error
3442 walk = func(v Variable) error {
3443 visited[v] = true
3444
3445 // First visit variables on which this variable depends.
3446 value := c.globalVariables[v]
Colin Cross2ce594e2020-01-29 12:58:03 -08003447 for _, dep := range value.Variables() {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003448 if !visited[dep] {
3449 err := walk(dep)
3450 if err != nil {
3451 return err
3452 }
3453 }
3454 }
3455
3456 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3457 if err != nil {
3458 return err
3459 }
3460
3461 err = nw.BlankLine()
3462 if err != nil {
3463 return err
3464 }
3465
3466 return nil
3467 }
3468
Jamie Gennisc15544d2014-09-24 20:26:52 -07003469 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3470 for variable := range c.globalVariables {
3471 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003472 }
3473
Jamie Gennisc15544d2014-09-24 20:26:52 -07003474 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003475
Jamie Gennisc15544d2014-09-24 20:26:52 -07003476 for _, entity := range globalVariables {
3477 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003478 if !visited[v] {
3479 err := walk(v)
3480 if err != nil {
3481 return nil
3482 }
3483 }
3484 }
3485
3486 return nil
3487}
3488
3489func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003490 globalPools := make([]globalEntity, 0, len(c.globalPools))
3491 for pool := range c.globalPools {
3492 globalPools = append(globalPools, pool)
3493 }
3494
3495 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3496
3497 for _, entity := range globalPools {
3498 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003499 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003500 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003501 err := def.WriteTo(nw, name)
3502 if err != nil {
3503 return err
3504 }
3505
3506 err = nw.BlankLine()
3507 if err != nil {
3508 return err
3509 }
3510 }
3511
3512 return nil
3513}
3514
3515func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003516 globalRules := make([]globalEntity, 0, len(c.globalRules))
3517 for rule := range c.globalRules {
3518 globalRules = append(globalRules, rule)
3519 }
3520
3521 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3522
3523 for _, entity := range globalRules {
3524 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003525 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003526 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003527 err := def.WriteTo(nw, name, c.pkgNames)
3528 if err != nil {
3529 return err
3530 }
3531
3532 err = nw.BlankLine()
3533 if err != nil {
3534 return err
3535 }
3536 }
3537
3538 return nil
3539}
3540
Colin Cross2c1f3d12016-04-11 15:47:28 -07003541type depSorter []depInfo
3542
3543func (s depSorter) Len() int {
3544 return len(s)
3545}
3546
3547func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003548 iName := s[i].module.Name()
3549 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003550 if iName == jName {
Colin Cross71c4be62020-08-13 12:07:30 -07003551 iName = s[i].module.variant.name
3552 jName = s[j].module.variant.name
Colin Cross2c1f3d12016-04-11 15:47:28 -07003553 }
3554 return iName < jName
3555}
3556
3557func (s depSorter) Swap(i, j int) {
3558 s[i], s[j] = s[j], s[i]
3559}
3560
Jeff Gaston0e907592017-12-01 17:10:52 -08003561type moduleSorter struct {
3562 modules []*moduleInfo
3563 nameInterface NameInterface
3564}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003565
Colin Crossab6d7902015-03-11 16:17:52 -07003566func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003567 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003568}
3569
Colin Crossab6d7902015-03-11 16:17:52 -07003570func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003571 iMod := s.modules[i]
3572 jMod := s.modules[j]
3573 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3574 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003575 if iName == jName {
Colin Cross4a693162020-08-13 12:11:52 -07003576 iVariantName := s.modules[i].variant.name
3577 jVariantName := s.modules[j].variant.name
3578 if iVariantName == jVariantName {
3579 panic(fmt.Sprintf("duplicate module name: %s %s: %#v and %#v\n",
3580 iName, iVariantName, iMod.variant.variations, jMod.variant.variations))
3581 } else {
3582 return iVariantName < jVariantName
3583 }
3584 } else {
3585 return iName < jName
Jeff Gaston0e907592017-12-01 17:10:52 -08003586 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003587}
3588
Colin Crossab6d7902015-03-11 16:17:52 -07003589func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003590 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003591}
3592
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003593func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3594 headerTemplate := template.New("moduleHeader")
3595 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3596 if err != nil {
3597 // This is a programming error.
3598 panic(err)
3599 }
3600
Colin Crossab6d7902015-03-11 16:17:52 -07003601 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3602 for _, module := range c.moduleInfo {
3603 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003604 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003605 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003606
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003607 buf := bytes.NewBuffer(nil)
3608
Colin Crossab6d7902015-03-11 16:17:52 -07003609 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003610 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3611 continue
3612 }
3613
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003614 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003615
3616 // In order to make the bootstrap build manifest independent of the
3617 // build dir we need to output the Blueprints file locations in the
3618 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003619 relPos := module.pos
3620 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003621
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003622 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003623 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003624 factoryName := factoryFunc.Name()
3625
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003626 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003627 "name": module.Name(),
3628 "typeName": module.typeName,
3629 "goFactory": factoryName,
3630 "pos": relPos,
Colin Cross71c4be62020-08-13 12:07:30 -07003631 "variant": module.variant.name,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003632 }
3633 err = headerTemplate.Execute(buf, infoMap)
3634 if err != nil {
3635 return err
3636 }
3637
3638 err = nw.Comment(buf.String())
3639 if err != nil {
3640 return err
3641 }
3642
3643 err = nw.BlankLine()
3644 if err != nil {
3645 return err
3646 }
3647
Colin Crossab6d7902015-03-11 16:17:52 -07003648 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003649 if err != nil {
3650 return err
3651 }
3652
3653 err = nw.BlankLine()
3654 if err != nil {
3655 return err
3656 }
3657 }
3658
3659 return nil
3660}
3661
3662func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3663 headerTemplate := template.New("singletonHeader")
3664 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3665 if err != nil {
3666 // This is a programming error.
3667 panic(err)
3668 }
3669
3670 buf := bytes.NewBuffer(nil)
3671
Yuchen Wub9103ef2015-08-25 17:58:17 -07003672 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003673 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3674 continue
3675 }
3676
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003677 // Get the name of the factory function for the module.
3678 factory := info.factory
3679 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3680 factoryName := factoryFunc.Name()
3681
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003682 buf.Reset()
3683 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003684 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003685 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003686 }
3687 err = headerTemplate.Execute(buf, infoMap)
3688 if err != nil {
3689 return err
3690 }
3691
3692 err = nw.Comment(buf.String())
3693 if err != nil {
3694 return err
3695 }
3696
3697 err = nw.BlankLine()
3698 if err != nil {
3699 return err
3700 }
3701
3702 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3703 if err != nil {
3704 return err
3705 }
3706
3707 err = nw.BlankLine()
3708 if err != nil {
3709 return err
3710 }
3711 }
3712
3713 return nil
3714}
3715
3716func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3717 defs *localBuildActions) error {
3718
3719 // Write the local variable assignments.
3720 for _, v := range defs.variables {
3721 // A localVariable doesn't need the package names or config to
3722 // determine its name or value.
3723 name := v.fullName(nil)
3724 value, err := v.value(nil)
3725 if err != nil {
3726 panic(err)
3727 }
3728 err = nw.Assign(name, value.Value(c.pkgNames))
3729 if err != nil {
3730 return err
3731 }
3732 }
3733
3734 if len(defs.variables) > 0 {
3735 err := nw.BlankLine()
3736 if err != nil {
3737 return err
3738 }
3739 }
3740
3741 // Write the local rules.
3742 for _, r := range defs.rules {
3743 // A localRule doesn't need the package names or config to determine
3744 // its name or definition.
3745 name := r.fullName(nil)
3746 def, err := r.def(nil)
3747 if err != nil {
3748 panic(err)
3749 }
3750
3751 err = def.WriteTo(nw, name, c.pkgNames)
3752 if err != nil {
3753 return err
3754 }
3755
3756 err = nw.BlankLine()
3757 if err != nil {
3758 return err
3759 }
3760 }
3761
3762 // Write the build definitions.
3763 for _, buildDef := range defs.buildDefs {
3764 err := buildDef.WriteTo(nw, c.pkgNames)
3765 if err != nil {
3766 return err
3767 }
3768
3769 if len(buildDef.Args) > 0 {
3770 err = nw.BlankLine()
3771 if err != nil {
3772 return err
3773 }
3774 }
3775 }
3776
3777 return nil
3778}
3779
Colin Cross65569e42015-03-10 20:08:19 -07003780func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3781 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003782 if a == b {
3783 return false
3784 }
Colin Cross65569e42015-03-10 20:08:19 -07003785 for _, l := range list {
3786 if l == a {
3787 found = true
3788 } else if l == b {
3789 return found
3790 }
3791 }
3792
3793 missing := a
3794 if found {
3795 missing = b
3796 }
3797 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3798}
3799
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003800type panicError struct {
3801 panic interface{}
3802 stack []byte
3803 in string
3804}
3805
3806func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3807 buf := make([]byte, 4096)
3808 count := runtime.Stack(buf, false)
3809 return panicError{
3810 panic: panic,
3811 in: fmt.Sprintf(in, a...),
3812 stack: buf[:count],
3813 }
3814}
3815
3816func (p panicError) Error() string {
3817 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3818}
3819
3820func (p *panicError) addIn(in string) {
3821 p.in += " in " + in
3822}
3823
3824func funcName(f interface{}) string {
3825 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3826}
3827
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003828var fileHeaderTemplate = `******************************************************************************
3829*** This file is generated and should not be edited ***
3830******************************************************************************
3831{{if .Pkgs}}
3832This file contains variables, rules, and pools with name prefixes indicating
3833they were generated by the following Go packages:
3834{{range .Pkgs}}
3835 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3836
3837`
3838
3839var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003840Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003841Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003842Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003843Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003844Defined: {{.pos}}
3845`
3846
3847var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3848Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003849Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003850`