blob: 8d43c6c5dd3e1e6efa64845a3588f5a804807c81 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
Jamie Gennis1bc967e2014-05-27 16:34:41 -070018 "bytes"
Colin Cross3a8c0252019-01-23 13:21:48 -080019 "context"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "errors"
21 "fmt"
22 "io"
Jeff Gastonc3e28442017-08-09 15:13:12 -070023 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070024 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070025 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Colin Cross3a8c0252019-01-23 13:21:48 -080028 "runtime/pprof"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "sort"
30 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070031 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070032 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070033 "text/scanner"
34 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070035
36 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080037 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070038 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070039)
40
41var ErrBuildActionsNotReady = errors.New("build actions are not ready")
42
43const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080044const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070045
Jamie Gennisd4e10182014-06-12 20:06:50 -070046// A Context contains all the state needed to parse a set of Blueprints files
47// and generate a Ninja file. The process of generating a Ninja file proceeds
48// through a series of four phases. Each phase corresponds with a some methods
49// on the Context object
50//
51// Phase Methods
52// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070053// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070054//
55// 2. Parse ParseBlueprintsFiles, Parse
56//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070057// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070058//
59// 4. Write WriteBuildFile
60//
61// The registration phase prepares the context to process Blueprints files
62// containing various types of modules. The parse phase reads in one or more
63// Blueprints files and validates their contents against the module types that
64// have been registered. The generate phase then analyzes the parsed Blueprints
65// contents to create an internal representation for the build actions that must
66// be performed. This phase also performs validation of the module dependencies
67// and property values defined in the parsed Blueprints files. Finally, the
68// write phase generates the Ninja manifest text based on the generated build
69// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070070type Context struct {
Colin Cross3a8c0252019-01-23 13:21:48 -080071 context.Context
72
Jamie Gennis1bc967e2014-05-27 16:34:41 -070073 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070074 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080075 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070076 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070077 moduleInfo map[Module]*moduleInfo
78 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080079 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070080 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070081 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070082 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070083 variantMutatorNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070084
Colin Cross3702ac72016-08-11 11:09:00 -070085 depsModified uint32 // positive if a mutator modified the dependencies
86
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087 dependenciesReady bool // set to true on a successful ResolveDependencies
88 buildActionsReady bool // set to true on a successful PrepareBuildActions
89
90 // set by SetIgnoreUnknownModuleTypes
91 ignoreUnknownModuleTypes bool
92
Colin Cross036a1df2015-12-17 15:49:30 -080093 // set by SetAllowMissingDependencies
94 allowMissingDependencies bool
95
Jamie Gennis1bc967e2014-05-27 16:34:41 -070096 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080097 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080098 liveGlobals *liveTracker
Jamie Gennis1bc967e2014-05-27 16:34:41 -070099 globalVariables map[Variable]*ninjaString
100 globalPools map[Pool]*poolDef
101 globalRules map[Rule]*ruleDef
102
103 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -0800104 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700105 requiredNinjaMajor int // For the ninja_required_version variable
106 requiredNinjaMinor int // For the ninja_required_version variable
107 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700108
Dan Willemsenab223a52018-07-05 21:56:59 -0700109 subninjas []string
110
Jeff Gastond70bf752017-11-10 15:12:08 -0800111 // set lazily by sortedModuleGroups
112 cachedSortedModuleGroups []*moduleGroup
Colin Crossd7b0f602016-06-02 15:30:20 -0700113
Colin Cross127d2ea2016-11-01 11:10:51 -0700114 globs map[string]GlobPath
115 globLock sync.Mutex
116
Jeff Gastonc3e28442017-08-09 15:13:12 -0700117 fs pathtools.FileSystem
118 moduleListFile string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700119}
120
Jamie Gennisd4e10182014-06-12 20:06:50 -0700121// An Error describes a problem that was encountered that is related to a
122// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700123type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700124 Err error // the error that occurred
125 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700126}
127
Colin Cross2c628442016-10-07 17:13:10 -0700128// A ModuleError describes a problem that was encountered that is related to a
129// particular module in a Blueprints file
130type ModuleError struct {
131 BlueprintError
132 module *moduleInfo
133}
134
135// A PropertyError describes a problem that was encountered that is related to a
136// particular property in a Blueprints file
137type PropertyError struct {
138 ModuleError
139 property string
140}
141
142func (e *BlueprintError) Error() string {
143 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
144}
145
146func (e *ModuleError) Error() string {
147 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
148}
149
150func (e *PropertyError) Error() string {
151 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
152}
153
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700154type localBuildActions struct {
155 variables []*localVariable
156 rules []*localRule
157 buildDefs []*buildDef
158}
159
Colin Crossbbfa51a2014-12-17 16:12:41 -0800160type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700161 name string
162 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700163
Colin Crossbbfa51a2014-12-17 16:12:41 -0800164 modules []*moduleInfo
Jeff Gastond70bf752017-11-10 15:12:08 -0800165
166 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700167}
168
Colin Crossbbfa51a2014-12-17 16:12:41 -0800169type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700170 // set during Parse
171 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700172 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700173 relBlueprintsFile string
174 pos scanner.Position
175 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700176
Colin Crossf5e34b92015-03-13 16:02:36 -0700177 variantName string
178 variant variationMap
179 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700180
Colin Crossd2f4ac12017-07-28 14:31:03 -0700181 logicModule Module
182 group *moduleGroup
183 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800184
185 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700186 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800187 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800188
Colin Cross7addea32015-03-11 15:43:52 -0700189 // set during updateDependencies
190 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700191 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700192
193 // used by parallelVisitAllBottomUp
194 waitingCount int
195
Colin Crossc9028482014-12-18 16:28:54 -0800196 // set during each runMutator
197 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700198
199 // set during PrepareBuildActions
200 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800201}
202
Colin Cross2c1f3d12016-04-11 15:47:28 -0700203type depInfo struct {
204 module *moduleInfo
205 tag DependencyTag
206}
207
Colin Cross0b7e83e2016-05-17 14:58:05 -0700208func (module *moduleInfo) Name() string {
209 return module.group.name
210}
211
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800212func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700213 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800214 if module.variantName != "" {
215 s += fmt.Sprintf(" variant %q", module.variantName)
216 }
217 return s
218}
219
Jeff Gastond70bf752017-11-10 15:12:08 -0800220func (module *moduleInfo) namespace() Namespace {
221 return module.group.namespace
222}
223
Colin Crossf5e34b92015-03-13 16:02:36 -0700224// A Variation is a way that a variant of a module differs from other variants of the same module.
225// For example, two variants of the same module might have Variation{"arch","arm"} and
226// Variation{"arch","arm64"}
227type Variation struct {
228 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700229 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700230 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
231 // "shared" or "static" for link.
232 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700233}
234
Colin Crossf5e34b92015-03-13 16:02:36 -0700235// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
236type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700237
Colin Crossf5e34b92015-03-13 16:02:36 -0700238func (vm variationMap) clone() variationMap {
239 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700240 for k, v := range vm {
241 newVm[k] = v
242 }
243
244 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800245}
246
Colin Cross89486232015-05-08 11:14:54 -0700247// Compare this variationMap to another one. Returns true if the every entry in this map
248// is either the same in the other map or doesn't exist in the other map.
249func (vm variationMap) subset(other variationMap) bool {
250 for k, v1 := range vm {
251 if v2, ok := other[k]; ok && v1 != v2 {
252 return false
253 }
254 }
255 return true
256}
257
Colin Crossf5e34b92015-03-13 16:02:36 -0700258func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700259 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800260}
261
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700262type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700263 // set during RegisterSingletonType
264 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700265 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700266 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700267
268 // set during PrepareBuildActions
269 actionDefs localBuildActions
270}
271
Colin Crossc9028482014-12-18 16:28:54 -0800272type mutatorInfo struct {
273 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800274 topDownMutator TopDownMutator
275 bottomUpMutator BottomUpMutator
276 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700277 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800278}
279
Colin Crossaf4fd212017-07-28 14:32:36 -0700280func newContext() *Context {
281 return &Context{
Colin Cross3a8c0252019-01-23 13:21:48 -0800282 Context: context.Background(),
Colin Cross5f03f112017-11-07 13:29:54 -0800283 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800284 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800285 moduleInfo: make(map[Module]*moduleInfo),
Colin Cross5f03f112017-11-07 13:29:54 -0800286 globs: make(map[string]GlobPath),
287 fs: pathtools.OsFs,
288 ninjaBuildDir: nil,
289 requiredNinjaMajor: 1,
290 requiredNinjaMinor: 7,
291 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700292 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700293}
294
295// NewContext creates a new Context object. The created context initially has
296// no module or singleton factories registered, so the RegisterModuleFactory and
297// RegisterSingletonFactory methods must be called before it can do anything
298// useful.
299func NewContext() *Context {
300 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700301
302 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
303
304 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700305}
306
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700307// A ModuleFactory function creates a new Module object. See the
308// Context.RegisterModuleType method for details about how a registered
309// ModuleFactory is used by a Context.
310type ModuleFactory func() (m Module, propertyStructs []interface{})
311
Jamie Gennisd4e10182014-06-12 20:06:50 -0700312// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700313// Blueprints file) with a Module factory function. When the given module type
314// name is encountered in a Blueprints file during parsing, the Module factory
315// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800316// generation for the module. If a Mutator splits a module into multiple variants,
317// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700318//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700319// The module type names given here must be unique for the context. The factory
320// function should be a named function so that its package and name can be
321// included in the generated Ninja file for debugging purposes.
322//
323// The factory function returns two values. The first is the newly created
324// Module object. The second is a slice of pointers to that Module object's
325// properties structs. Each properties struct is examined when parsing a module
326// definition of this type in a Blueprints file. Exported fields of the
327// properties structs are automatically set to the property values specified in
328// the Blueprints file. The properties struct field names determine the name of
329// the Blueprints file properties that are used - the Blueprints property name
330// matches that of the properties struct field name with the first letter
331// converted to lower-case.
332//
333// The fields of the properties struct must be either []string, a string, or
334// bool. The Context will panic if a Module gets instantiated with a properties
335// struct containing a field that is not one these supported types.
336//
337// Any properties that appear in the Blueprints files that are not built-in
338// module properties (such as "name" and "deps") and do not have a corresponding
339// field in the returned module properties struct result in an error during the
340// Context's parse phase.
341//
342// As an example, the follow code:
343//
344// type myModule struct {
345// properties struct {
346// Foo string
347// Bar []string
348// }
349// }
350//
351// func NewMyModule() (blueprint.Module, []interface{}) {
352// module := new(myModule)
353// properties := &module.properties
354// return module, []interface{}{properties}
355// }
356//
357// func main() {
358// ctx := blueprint.NewContext()
359// ctx.RegisterModuleType("my_module", NewMyModule)
360// // ...
361// }
362//
363// would support parsing a module defined in a Blueprints file as follows:
364//
365// my_module {
366// name: "myName",
367// foo: "my foo string",
368// bar: ["my", "bar", "strings"],
369// }
370//
Colin Cross7ad621c2015-01-07 16:22:45 -0800371// The factory function may be called from multiple goroutines. Any accesses
372// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700373func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
374 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700375 panic(errors.New("module type name is already registered"))
376 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700377 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700378}
379
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700380// A SingletonFactory function creates a new Singleton object. See the
381// Context.RegisterSingletonType method for details about how a registered
382// SingletonFactory is used by a Context.
383type SingletonFactory func() Singleton
384
385// RegisterSingletonType registers a singleton type that will be invoked to
386// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700387// and invoked exactly once as part of the generate phase. Each registered
388// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700389//
390// The singleton type names given here must be unique for the context. The
391// factory function should be a named function so that its package and name can
392// be included in the generated Ninja file for debugging purposes.
393func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700394 for _, s := range c.singletonInfo {
395 if s.name == name {
396 panic(errors.New("singleton name is already registered"))
397 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700399
Yuchen Wub9103ef2015-08-25 17:58:17 -0700400 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700401 factory: factory,
402 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700403 name: name,
404 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700405}
406
Colin Cross5f03f112017-11-07 13:29:54 -0800407// RegisterPreSingletonType registers a presingleton type that will be invoked to
408// generate build actions before any Blueprint files have been read. Each registered
409// presingleton type is instantiated and invoked exactly once at the beginning of the
410// parse phase. Each registered presingleton is invoked in registration order.
411//
412// The presingleton type names given here must be unique for the context. The
413// factory function should be a named function so that its package and name can
414// be included in the generated Ninja file for debugging purposes.
415func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
416 for _, s := range c.preSingletonInfo {
417 if s.name == name {
418 panic(errors.New("presingleton name is already registered"))
419 }
420 }
421
422 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
423 factory: factory,
424 singleton: factory(),
425 name: name,
426 })
427}
428
Jeff Gastond70bf752017-11-10 15:12:08 -0800429func (c *Context) SetNameInterface(i NameInterface) {
430 c.nameInterface = i
431}
432
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700433func singletonPkgPath(singleton Singleton) string {
434 typ := reflect.TypeOf(singleton)
435 for typ.Kind() == reflect.Ptr {
436 typ = typ.Elem()
437 }
438 return typ.PkgPath()
439}
440
441func singletonTypeName(singleton Singleton) string {
442 typ := reflect.TypeOf(singleton)
443 for typ.Kind() == reflect.Ptr {
444 typ = typ.Elem()
445 }
446 return typ.PkgPath() + "." + typ.Name()
447}
448
Colin Cross3702ac72016-08-11 11:09:00 -0700449// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
450// top-down between Modules. Each registered mutator is invoked in registration order (mixing
451// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
452// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800453//
Colin Cross65569e42015-03-10 20:08:19 -0700454// The mutator type names given here must be unique to all top down mutators in
455// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700456//
457// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
458// parallel while maintaining ordering.
459func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800460 for _, m := range c.mutatorInfo {
461 if m.name == name && m.topDownMutator != nil {
462 panic(fmt.Errorf("mutator name %s is already registered", name))
463 }
464 }
465
Colin Cross3702ac72016-08-11 11:09:00 -0700466 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800467 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800468 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700469 }
470
471 c.mutatorInfo = append(c.mutatorInfo, info)
472
473 return info
Colin Crossc9028482014-12-18 16:28:54 -0800474}
475
Colin Cross3702ac72016-08-11 11:09:00 -0700476// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
477// Each registered mutator is invoked in registration order (mixing TopDownMutators and
478// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
479// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800480//
Colin Cross65569e42015-03-10 20:08:19 -0700481// The mutator type names given here must be unique to all bottom up or early
482// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700483//
Colin Cross3702ac72016-08-11 11:09:00 -0700484// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
485// parallel while maintaining ordering.
486func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700487 for _, m := range c.variantMutatorNames {
488 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800489 panic(fmt.Errorf("mutator name %s is already registered", name))
490 }
491 }
492
Colin Cross49c279a2016-08-05 22:30:44 -0700493 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800494 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800495 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700496 }
497 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700498
499 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700500
501 return info
502}
503
Colin Cross3702ac72016-08-11 11:09:00 -0700504type MutatorHandle interface {
505 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
506 // method on the mutator context is thread-safe, but the mutator must handle synchronization
507 // for any modifications to global state or any modules outside the one it was invoked on.
508 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700509}
510
Colin Cross3702ac72016-08-11 11:09:00 -0700511func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700512 mutator.parallel = true
513 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700514}
515
516// RegisterEarlyMutator registers a mutator that will be invoked to split
517// Modules into multiple variant Modules before any dependencies have been
518// created. Each registered mutator is invoked in registration order once
519// per Module (including each variant from previous early mutators). Module
520// order is unpredictable.
521//
522// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700523// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700524//
525// The mutator type names given here must be unique to all bottom up or early
526// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700527//
528// Deprecated, use a BottomUpMutator instead. The only difference between
529// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
530// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700531func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
532 for _, m := range c.variantMutatorNames {
533 if m == name {
534 panic(fmt.Errorf("mutator name %s is already registered", name))
535 }
536 }
537
Colin Crossf8b50422016-08-10 12:56:40 -0700538 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
539 bottomUpMutator: func(mctx BottomUpMutatorContext) {
540 mutator(mctx)
541 },
542 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700543 })
544
545 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800546}
547
Jamie Gennisd4e10182014-06-12 20:06:50 -0700548// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
549// where it encounters an unknown module type while parsing Blueprints files. By
550// default, the context will report unknown module types as an error. If this
551// method is called with ignoreUnknownModuleTypes set to true then the context
552// will silently ignore unknown module types.
553//
554// This method should generally not be used. It exists to facilitate the
555// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700556func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
557 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
558}
559
Colin Cross036a1df2015-12-17 15:49:30 -0800560// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
561// unresolved dependencies. If the module's GenerateBuildActions calls
562// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
563// for missing dependencies.
564func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
565 c.allowMissingDependencies = allowMissingDependencies
566}
567
Jeff Gastonc3e28442017-08-09 15:13:12 -0700568func (c *Context) SetModuleListFile(listFile string) {
569 c.moduleListFile = listFile
570}
571
572func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
573 reader, err := c.fs.Open(c.moduleListFile)
574 if err != nil {
575 return nil, err
576 }
577 bytes, err := ioutil.ReadAll(reader)
578 if err != nil {
579 return nil, err
580 }
581 text := string(bytes)
582
583 text = strings.Trim(text, "\n")
584 lines := strings.Split(text, "\n")
585 for i := range lines {
586 lines[i] = filepath.Join(baseDir, lines[i])
587 }
588
589 return lines, nil
590}
591
Jeff Gaston656870f2017-11-29 18:37:31 -0800592// a fileParseContext tells the status of parsing a particular file
593type fileParseContext struct {
594 // name of file
595 fileName string
596
597 // scope to use when resolving variables
598 Scope *parser.Scope
599
600 // pointer to the one in the parent directory
601 parent *fileParseContext
602
603 // is closed once FileHandler has completed for this file
604 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700605}
606
Jeff Gastonc3e28442017-08-09 15:13:12 -0700607func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
608 baseDir := filepath.Dir(rootFile)
609 pathsToParse, err := c.ListModulePaths(baseDir)
610 if err != nil {
611 return nil, []error{err}
612 }
613 return c.ParseFileList(baseDir, pathsToParse)
614}
615
Jamie Gennisd4e10182014-06-12 20:06:50 -0700616// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
617// at rootFile. When it encounters a Blueprints file with a set of subdirs
618// listed it recursively parses any Blueprints files found in those
619// subdirectories.
620//
621// If no errors are encountered while parsing the files, the list of paths on
622// which the future output will depend is returned. This list will include both
623// Blueprints file paths as well as directory paths for cases where wildcard
624// subdirs are found.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700625func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700626 errs []error) {
627
Jeff Gastonc3e28442017-08-09 15:13:12 -0700628 if len(filePaths) < 1 {
629 return nil, []error{fmt.Errorf("no paths provided to parse")}
630 }
631
Colin Cross7ad621c2015-01-07 16:22:45 -0800632 c.dependenciesReady = false
633
Colin Cross23d7aa12015-06-30 16:05:22 -0700634 moduleCh := make(chan *moduleInfo)
635 errsCh := make(chan []error)
636 doneCh := make(chan struct{})
637 var numErrs uint32
638 var numGoroutines int32
639
640 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700641 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700642 if atomic.LoadUint32(&numErrs) > maxErrors {
643 return
644 }
645
Jeff Gaston656870f2017-11-29 18:37:31 -0800646 for _, def := range file.Defs {
647 var module *moduleInfo
648 var errs []error
649 switch def := def.(type) {
650 case *parser.Module:
651 module, errs = c.processModuleDef(def, file.Name)
652 case *parser.Assignment:
653 // Already handled via Scope object
654 default:
655 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700656 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800657
658 if len(errs) > 0 {
659 atomic.AddUint32(&numErrs, uint32(len(errs)))
660 errsCh <- errs
661 } else if module != nil {
662 moduleCh <- module
663 }
664 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700665 }
666
667 atomic.AddInt32(&numGoroutines, 1)
668 go func() {
669 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700670 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700671 if len(errs) > 0 {
672 errsCh <- errs
673 }
674 doneCh <- struct{}{}
675 }()
676
677loop:
678 for {
679 select {
680 case newErrs := <-errsCh:
681 errs = append(errs, newErrs...)
682 case module := <-moduleCh:
683 newErrs := c.addModule(module)
684 if len(newErrs) > 0 {
685 errs = append(errs, newErrs...)
686 }
687 case <-doneCh:
688 n := atomic.AddInt32(&numGoroutines, -1)
689 if n == 0 {
690 break loop
691 }
692 }
693 }
694
695 return deps, errs
696}
697
698type FileHandler func(*parser.File)
699
Jeff Gastonc3e28442017-08-09 15:13:12 -0700700// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
701// calling the given file handler on each
702//
703// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
704// it recursively parses any Blueprints files found in those subdirectories.
705//
706// If any of the file paths is an ancestor directory of any other of file path, the ancestor
707// will be parsed and visited first.
708//
709// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700710//
711// If no errors are encountered while parsing the files, the list of paths on
712// which the future output will depend is returned. This list will include both
713// Blueprints file paths as well as directory paths for cases where wildcard
714// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800715//
716// visitor will be called asynchronously, and will only be called once visitor for each
717// ancestor directory has completed.
718//
719// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700720func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
721 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700722
Jeff Gastonc3e28442017-08-09 15:13:12 -0700723 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
724 descendantsMap, err := findBlueprintDescendants(filePaths)
725 if err != nil {
726 panic(err.Error())
Jeff Gastonc3e28442017-08-09 15:13:12 -0700727 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800728 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700729
Jeff Gaston5800d042017-12-05 14:57:58 -0800730 // Channels to receive data back from openAndParse goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800731 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800732 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800733 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700734
Jeff Gaston5800d042017-12-05 14:57:58 -0800735 // Channel to notify main loop that a openAndParse goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800736 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700737
Colin Cross7ad621c2015-01-07 16:22:45 -0800738 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700739 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800740 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700741 tooManyErrors := false
742
743 // Limit concurrent calls to parseBlueprintFiles to 200
744 // Darwin has a default limit of 256 open files
745 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800746
Jeff Gaston656870f2017-11-29 18:37:31 -0800747 // count the number of pending calls to visitor()
748 visitorWaitGroup := sync.WaitGroup{}
749
750 startParseBlueprintsFile := func(blueprint fileParseContext) {
751 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700752 return
753 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800754 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700755 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800756 deps = append(deps, blueprint.fileName)
757 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800758 go func() {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800759 file, blueprints, deps, errs := c.openAndParse(blueprint.fileName, blueprint.Scope, rootDir,
760 &blueprint)
761 if len(errs) > 0 {
762 errsCh <- errs
763 }
764 for _, blueprint := range blueprints {
765 blueprintsCh <- blueprint
766 }
767 for _, dep := range deps {
768 depsCh <- dep
769 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800770 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700771
Jeff Gaston656870f2017-11-29 18:37:31 -0800772 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
773 // wait for visitor() of parent to complete
774 <-blueprint.parent.doneVisiting
775 }
776
Jeff Gastona7e408a2017-12-05 15:11:55 -0800777 if len(errs) == 0 {
778 // process this file
779 visitor(file)
780 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800781 if blueprint.doneVisiting != nil {
782 close(blueprint.doneVisiting)
783 }
784 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800785 }()
786 }
787
Jeff Gaston656870f2017-11-29 18:37:31 -0800788 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700789 if activeCount >= maxActiveCount {
790 pending = append(pending, blueprint)
791 } else {
792 startParseBlueprintsFile(blueprint)
793 }
794 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800795
Jeff Gaston656870f2017-11-29 18:37:31 -0800796 startParseDescendants := func(blueprint fileParseContext) {
797 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700798 if hasDescendants {
799 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800800 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700801 }
802 }
803 }
Colin Cross4a02a302017-05-16 10:33:58 -0700804
Jeff Gastonc3e28442017-08-09 15:13:12 -0700805 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800806 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800807
808loop:
809 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700810 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800811 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700812 }
813
Colin Cross7ad621c2015-01-07 16:22:45 -0800814 select {
815 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700816 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800817 case dep := <-depsCh:
818 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800819 case blueprint := <-blueprintsCh:
820 if tooManyErrors {
821 continue
822 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700823 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800824 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700825 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700826 if !tooManyErrors {
827 startParseDescendants(blueprint)
828 }
829 if activeCount < maxActiveCount && len(pending) > 0 {
830 // start to process the next one from the queue
831 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700832 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700833 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700834 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700835 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800836 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700837 }
838 }
839 }
840
Jeff Gastonc3e28442017-08-09 15:13:12 -0700841 sort.Strings(deps)
842
Jeff Gaston656870f2017-11-29 18:37:31 -0800843 // wait for every visitor() to complete
844 visitorWaitGroup.Wait()
845
Colin Cross7ad621c2015-01-07 16:22:45 -0800846 return
847}
848
Colin Crossd7b0f602016-06-02 15:30:20 -0700849// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
850// filenames to contents stored as a byte slice.
851func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800852 // look for a module list file
853 _, ok := files[MockModuleListFile]
854 if !ok {
855 // no module list file specified; find every file named Blueprints
856 pathsToParse := []string{}
857 for candidate := range files {
858 if filepath.Base(candidate) == "Blueprints" {
859 pathsToParse = append(pathsToParse, candidate)
860 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700861 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800862 if len(pathsToParse) < 1 {
863 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
864 }
865 // put the list of Blueprints files into a list file
866 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700867 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800868 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700869
870 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800871 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700872}
873
Jeff Gaston8fd95782017-12-05 15:03:51 -0800874// openAndParse opens and parses a single Blueprints file, and returns the results
Jeff Gaston5800d042017-12-05 14:57:58 -0800875func (c *Context) openAndParse(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston8fd95782017-12-05 15:03:51 -0800876 parent *fileParseContext) (file *parser.File,
877 subBlueprints []fileParseContext, deps []string, errs []error) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800878
Colin Crossd7b0f602016-06-02 15:30:20 -0700879 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800880 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700881 // couldn't open the file; see if we can provide a clearer error than "could not open file"
882 stats, statErr := c.fs.Lstat(filename)
883 if statErr == nil {
884 isSymlink := stats.Mode()&os.ModeSymlink != 0
885 if isSymlink {
886 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
887 target, readlinkErr := os.Readlink(filename)
888 if readlinkErr == nil {
889 _, targetStatsErr := c.fs.Lstat(target)
890 if targetStatsErr != nil {
891 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
892 }
893 }
894 } else {
895 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
896 }
897 }
Jeff Gaston8fd95782017-12-05 15:03:51 -0800898 return nil, nil, nil, []error{err}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700899 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800900
Jeff Gaston8fd95782017-12-05 15:03:51 -0800901 func() {
902 defer func() {
903 err = f.Close()
904 if err != nil {
905 errs = append(errs, err)
906 }
907 }()
908 file, subBlueprints, errs = c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross23d7aa12015-06-30 16:05:22 -0700909 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700910
Colin Cross7ad621c2015-01-07 16:22:45 -0800911 if len(errs) > 0 {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800912 return nil, nil, nil, errs
Colin Cross7ad621c2015-01-07 16:22:45 -0800913 }
914
Colin Cross1fef5362015-04-20 16:50:54 -0700915 for _, b := range subBlueprints {
Jeff Gaston8fd95782017-12-05 15:03:51 -0800916 deps = append(deps, b.fileName)
Colin Cross1fef5362015-04-20 16:50:54 -0700917 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800918
Jeff Gaston8fd95782017-12-05 15:03:51 -0800919 return file, subBlueprints, deps, nil
Colin Cross1fef5362015-04-20 16:50:54 -0700920}
921
Jeff Gastona12f22f2017-08-08 14:45:56 -0700922// parseOne parses a single Blueprints file from the given reader, creating Module
923// objects for each of the module definitions encountered. If the Blueprints
924// file contains an assignment to the "subdirs" variable, then the
925// subdirectories listed are searched for Blueprints files returned in the
926// subBlueprints return value. If the Blueprints file contains an assignment
927// to the "build" variable, then the file listed are returned in the
928// subBlueprints return value.
929//
930// rootDir specifies the path to the root directory of the source tree, while
931// filename specifies the path to the Blueprints file. These paths are used for
932// error reporting and for determining the module's directory.
933func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -0800934 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -0700935
936 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
937 if err != nil {
938 return nil, nil, []error{err}
939 }
940
Jeff Gastona12f22f2017-08-08 14:45:56 -0700941 scope.Remove("subdirs")
942 scope.Remove("optional_subdirs")
943 scope.Remove("build")
944 file, errs = parser.ParseAndEval(filename, reader, scope)
945 if len(errs) > 0 {
946 for i, err := range errs {
947 if parseErr, ok := err.(*parser.ParseError); ok {
948 err = &BlueprintError{
949 Err: parseErr.Err,
950 Pos: parseErr.Pos,
951 }
952 errs[i] = err
953 }
954 }
955
956 // If there were any parse errors don't bother trying to interpret the
957 // result.
958 return nil, nil, errs
959 }
960 file.Name = relBlueprintsFile
961
Jeff Gastona12f22f2017-08-08 14:45:56 -0700962 build, buildPos, err := getLocalStringListFromScope(scope, "build")
963 if err != nil {
964 errs = append(errs, err)
965 }
Jeff Gastonf23e3662017-11-30 17:31:43 -0800966 for _, buildEntry := range build {
967 if strings.Contains(buildEntry, "/") {
968 errs = append(errs, &BlueprintError{
969 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
970 Pos: buildPos,
971 })
972 }
973 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700974
975 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
976 if err != nil {
977 errs = append(errs, err)
978 }
979
980 if subBlueprintsName == "" {
981 subBlueprintsName = "Blueprints"
982 }
983
984 var blueprints []string
985
986 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
987 blueprints = append(blueprints, newBlueprints...)
988 errs = append(errs, newErrs...)
989
Jeff Gaston656870f2017-11-29 18:37:31 -0800990 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -0700991 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -0800992 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -0700993 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700994 return file, subBlueprintsAndScope, errs
995}
996
Colin Cross7f507402015-12-16 13:03:41 -0800997func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -0700998 buildPos scanner.Position) ([]string, []error) {
999
1000 var blueprints []string
1001 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -08001002
1003 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -07001004 pattern := filepath.Join(dir, file)
1005 var matches []string
1006 var err error
1007
Colin Cross08e49542016-11-14 15:23:33 -08001008 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001009
Colin Cross7f507402015-12-16 13:03:41 -08001010 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001011 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001012 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001013 Pos: buildPos,
1014 })
1015 continue
1016 }
1017
1018 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001019 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001020 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001021 Pos: buildPos,
1022 })
1023 }
1024
Colin Cross7f507402015-12-16 13:03:41 -08001025 for _, foundBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001026 if strings.HasSuffix(foundBlueprints, "/") {
1027 errs = append(errs, &BlueprintError{
1028 Err: fmt.Errorf("%q: is a directory", foundBlueprints),
1029 Pos: buildPos,
1030 })
1031 }
Colin Cross7f507402015-12-16 13:03:41 -08001032 blueprints = append(blueprints, foundBlueprints)
1033 }
1034 }
1035
Colin Cross127d2ea2016-11-01 11:10:51 -07001036 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001037}
1038
1039func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001040 subBlueprintsName string, optional bool) ([]string, []error) {
1041
1042 var blueprints []string
1043 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001044
1045 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001046 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1047 var matches []string
1048 var err error
1049
Colin Cross08e49542016-11-14 15:23:33 -08001050 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001051
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001052 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001053 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001054 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001055 Pos: subdirsPos,
1056 })
1057 continue
1058 }
1059
Colin Cross7f507402015-12-16 13:03:41 -08001060 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001061 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001062 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001063 Pos: subdirsPos,
1064 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001065 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001066
Colin Cross127d2ea2016-11-01 11:10:51 -07001067 for _, subBlueprints := range matches {
Dan Willemsenb6c90232018-02-23 14:49:45 -08001068 if strings.HasSuffix(subBlueprints, "/") {
1069 errs = append(errs, &BlueprintError{
1070 Err: fmt.Errorf("%q: is a directory", subBlueprints),
1071 Pos: subdirsPos,
1072 })
1073 }
Colin Cross127d2ea2016-11-01 11:10:51 -07001074 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001075 }
1076 }
Colin Cross1fef5362015-04-20 16:50:54 -07001077
Colin Cross127d2ea2016-11-01 11:10:51 -07001078 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001079}
1080
Colin Cross6d8780f2015-07-10 17:51:55 -07001081func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1082 if assignment, local := scope.Get(v); assignment == nil || !local {
1083 return nil, scanner.Position{}, nil
1084 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001085 switch value := assignment.Value.Eval().(type) {
1086 case *parser.List:
1087 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001088
Colin Crosse32cc802016-06-07 12:28:16 -07001089 for _, listValue := range value.Values {
1090 s, ok := listValue.(*parser.String)
1091 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001092 // The parser should not produce this.
1093 panic("non-string value found in list")
1094 }
1095
Colin Crosse32cc802016-06-07 12:28:16 -07001096 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001097 }
1098
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001099 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001100 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001101 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001102 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001103 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001104 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001105 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001106 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001107 }
1108 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001109}
1110
Colin Cross29394222015-04-27 13:18:21 -07001111func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001112 if assignment, _ := scope.Get(v); assignment == nil {
1113 return "", scanner.Position{}, nil
1114 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001115 switch value := assignment.Value.Eval().(type) {
1116 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001117 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001118 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001119 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001120 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001121 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001122 }
1123 default:
Dan Willemsene6d45fe2018-02-27 01:38:08 -08001124 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type()))
Colin Cross29394222015-04-27 13:18:21 -07001125 }
1126 }
Colin Cross29394222015-04-27 13:18:21 -07001127}
1128
Colin Cross910242b2016-04-11 15:41:52 -07001129// Clones a build logic module by calling the factory method for its module type, and then cloning
1130// property values. Any values stored in the module object that are not stored in properties
1131// structs will be lost.
1132func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001133 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001134
Colin Crossd2f4ac12017-07-28 14:31:03 -07001135 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001136 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001137 }
1138
1139 for i := range newProperties {
1140 dst := reflect.ValueOf(newProperties[i]).Elem()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001141 src := reflect.ValueOf(origModule.properties[i]).Elem()
Colin Cross910242b2016-04-11 15:41:52 -07001142
1143 proptools.CopyProperties(dst, src)
1144 }
1145
1146 return newLogicModule, newProperties
1147}
1148
Colin Crossf5e34b92015-03-13 16:02:36 -07001149func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
1150 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001151
Colin Crossf4d18a62015-03-18 17:43:15 -07001152 if len(variationNames) == 0 {
1153 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001154 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001155 }
1156
Colin Crossc9028482014-12-18 16:28:54 -08001157 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001158
Colin Cross174ae052015-03-03 17:37:03 -08001159 var errs []error
1160
Colin Crossf5e34b92015-03-13 16:02:36 -07001161 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001162 var newLogicModule Module
1163 var newProperties []interface{}
1164
1165 if i == 0 {
1166 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001167 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1168 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001169 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001170 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001171 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001172 }
1173
Colin Crossf5e34b92015-03-13 16:02:36 -07001174 newVariant := origModule.variant.clone()
1175 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001176
Colin Crossed342d92015-03-11 00:57:25 -07001177 m := *origModule
1178 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001179 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001180 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001181 newModule.variant = newVariant
1182 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001183 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001184
Colin Crossbadc8812016-08-11 17:01:46 -07001185 if variationName != "" {
1186 if newModule.variantName == "" {
1187 newModule.variantName = variationName
1188 } else {
1189 newModule.variantName += "_" + variationName
1190 }
Colin Crosse7daa222015-03-11 14:35:41 -07001191 }
1192
Colin Crossc9028482014-12-18 16:28:54 -08001193 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001194
Colin Crossf5e34b92015-03-13 16:02:36 -07001195 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001196 if len(newErrs) > 0 {
1197 errs = append(errs, newErrs...)
1198 }
Colin Crossc9028482014-12-18 16:28:54 -08001199 }
1200
1201 // Mark original variant as invalid. Modules that depend on this module will still
1202 // depend on origModule, but we'll fix it when the mutator is called on them.
1203 origModule.logicModule = nil
1204 origModule.splitModules = newModules
1205
Colin Cross3702ac72016-08-11 11:09:00 -07001206 atomic.AddUint32(&c.depsModified, 1)
1207
Colin Cross174ae052015-03-03 17:37:03 -08001208 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001209}
1210
Colin Crossf5e34b92015-03-13 16:02:36 -07001211func (c *Context) convertDepsToVariation(module *moduleInfo,
1212 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001213
Colin Crossc9028482014-12-18 16:28:54 -08001214 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001215 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001216 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001217 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001218 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001219 newDep = m
1220 break
1221 }
1222 }
1223 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001224 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001225 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001226 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001227 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001228 })
1229 continue
Colin Crossc9028482014-12-18 16:28:54 -08001230 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001231 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001232 }
1233 }
Colin Cross174ae052015-03-03 17:37:03 -08001234
1235 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001236}
1237
Colin Crossf5e34b92015-03-13 16:02:36 -07001238func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001239 names := make([]string, 0, len(variant))
1240 for _, m := range c.variantMutatorNames {
1241 if v, ok := variant[m]; ok {
1242 names = append(names, m+":"+v)
1243 }
1244 }
1245
1246 return strings.Join(names, ", ")
1247}
1248
Colin Crossaf4fd212017-07-28 14:32:36 -07001249func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
1250 logicModule, properties := factory()
1251
1252 module := &moduleInfo{
1253 logicModule: logicModule,
1254 factory: factory,
1255 }
1256
1257 module.properties = properties
1258
1259 return module
1260}
1261
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001262func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001263 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001264
Colin Crossc32c4792016-06-09 15:52:30 -07001265 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001266 if !ok {
1267 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001268 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001269 }
1270
Colin Cross7ad621c2015-01-07 16:22:45 -08001271 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001272 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001273 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1274 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001275 },
1276 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001277 }
1278
Colin Crossaf4fd212017-07-28 14:32:36 -07001279 module := c.newModule(factory)
1280 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001281
Colin Crossaf4fd212017-07-28 14:32:36 -07001282 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001283
Colin Crossaf4fd212017-07-28 14:32:36 -07001284 propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001285 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001286 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001287 }
1288
Colin Crossc32c4792016-06-09 15:52:30 -07001289 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001290 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001291 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001292 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001293 }
1294
Colin Cross7ad621c2015-01-07 16:22:45 -08001295 return module, nil
1296}
1297
Colin Cross23d7aa12015-06-30 16:05:22 -07001298func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001299 name := module.logicModule.Name()
Jaewoong Jungccc34942018-10-11 13:01:05 -07001300 if name == "" {
1301 return []error{
1302 &BlueprintError{
1303 Err: fmt.Errorf("property 'name' is missing from a module"),
1304 Pos: module.pos,
1305 },
1306 }
1307 }
Colin Cross23d7aa12015-06-30 16:05:22 -07001308 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001309
Colin Cross0b7e83e2016-05-17 14:58:05 -07001310 group := &moduleGroup{
Jeff Gaston0e907592017-12-01 17:10:52 -08001311 name: name,
1312 modules: []*moduleInfo{module},
Colin Cross0b7e83e2016-05-17 14:58:05 -07001313 }
1314 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001315 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston0e907592017-12-01 17:10:52 -08001316 newNamespaceContext(module),
Jeff Gastond70bf752017-11-10 15:12:08 -08001317 ModuleGroup{moduleGroup: group},
1318 module.logicModule)
1319 if len(errs) > 0 {
1320 for i := range errs {
1321 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1322 }
1323 return errs
1324 }
1325 group.namespace = namespace
1326
Colin Cross0b7e83e2016-05-17 14:58:05 -07001327 c.moduleGroups = append(c.moduleGroups, group)
1328
Colin Cross23d7aa12015-06-30 16:05:22 -07001329 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001330}
1331
Jamie Gennisd4e10182014-06-12 20:06:50 -07001332// ResolveDependencies checks that the dependencies specified by all of the
1333// modules defined in the parsed Blueprints files are valid. This means that
1334// the modules depended upon are defined and that no circular dependencies
1335// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001336func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001337 return c.resolveDependencies(c.Context, config)
1338}
Colin Cross5f03f112017-11-07 13:29:54 -08001339
Colin Cross3a8c0252019-01-23 13:21:48 -08001340func (c *Context) resolveDependencies(ctx context.Context, config interface{}) (deps []string, errs []error) {
1341 pprof.Do(ctx, pprof.Labels("blueprint", "ResolveDependencies"), func(ctx context.Context) {
1342 c.liveGlobals = newLiveTracker(config)
1343
1344 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1345 if len(errs) > 0 {
1346 return
1347 }
1348
1349 errs = c.updateDependencies()
1350 if len(errs) > 0 {
1351 return
1352 }
1353
1354 var mutatorDeps []string
1355 mutatorDeps, errs = c.runMutators(ctx, config)
1356 if len(errs) > 0 {
1357 return
1358 }
1359 deps = append(deps, mutatorDeps...)
1360
1361 c.cloneModules()
1362
1363 c.dependenciesReady = true
1364 })
1365
Colin Cross5f03f112017-11-07 13:29:54 -08001366 if len(errs) > 0 {
1367 return nil, errs
1368 }
1369
Colin Cross874a3462017-07-31 17:26:06 -07001370 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001371}
1372
Colin Cross763b6f12015-10-29 15:32:56 -07001373// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001374// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001375// module names returned by its DynamicDependencies method and those added by calling
1376// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001377func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001378 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001379 func() {
1380 defer func() {
1381 if r := recover(); r != nil {
1382 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1383 }
1384 }()
1385 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001386
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001387 if ctx.Failed() {
1388 return
1389 }
Colin Cross763b6f12015-10-29 15:32:56 -07001390
Colin Cross2c1f3d12016-04-11 15:47:28 -07001391 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001392 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001393 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001394}
1395
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001396// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1397// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001398func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1399 if len(possible) == 1 {
1400 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001401 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001402 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001403 if m.variant.equal(module.dependencyVariant) {
1404 return m
1405 }
1406 }
1407 }
1408
1409 return nil
1410}
1411
Colin Cross2c1f3d12016-04-11 15:47:28 -07001412func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001413 if _, ok := tag.(BaseDependencyTag); ok {
1414 panic("BaseDependencyTag is not allowed to be used directly!")
1415 }
1416
Colin Cross0b7e83e2016-05-17 14:58:05 -07001417 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001418 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001419 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001420 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001421 }}
1422 }
1423
Jeff Gastond70bf752017-11-10 15:12:08 -08001424 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001425 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001426 return c.discoveredMissingDependencies(module, depName)
Colin Crossc9028482014-12-18 16:28:54 -08001427 }
1428
Colin Cross0b7e83e2016-05-17 14:58:05 -07001429 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001430 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001431 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001432 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001433 }
Colin Crossc9028482014-12-18 16:28:54 -08001434
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001435 variants := make([]string, len(possibleDeps))
1436 for i, mod := range possibleDeps {
1437 variants[i] = c.prettyPrintVariant(mod.variant)
1438 }
1439 sort.Strings(variants)
1440
Colin Cross2c628442016-10-07 17:13:10 -07001441 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001442 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001443 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001444 c.prettyPrintVariant(module.dependencyVariant),
1445 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001446 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001447 }}
1448}
1449
Colin Cross8d8a7af2015-11-03 16:41:29 -08001450func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001451 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001452 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001453 Err: fmt.Errorf("%q depends on itself", destName),
1454 Pos: module.pos,
1455 }}
1456 }
1457
Jeff Gastond70bf752017-11-10 15:12:08 -08001458 possibleDeps := c.modulesFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001459 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001460 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001461 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001462 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001463 Pos: module.pos,
1464 }}
1465 }
1466
Colin Cross0b7e83e2016-05-17 14:58:05 -07001467 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001468 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001469 }
1470
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001471 variants := make([]string, len(possibleDeps))
1472 for i, mod := range possibleDeps {
1473 variants[i] = c.prettyPrintVariant(mod.variant)
1474 }
1475 sort.Strings(variants)
1476
Colin Cross2c628442016-10-07 17:13:10 -07001477 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001478 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001479 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001480 c.prettyPrintVariant(module.dependencyVariant),
1481 strings.Join(variants, "\n ")),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001482 Pos: module.pos,
1483 }}
1484}
1485
Colin Crossf5e34b92015-03-13 16:02:36 -07001486func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001487 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001488 if _, ok := tag.(BaseDependencyTag); ok {
1489 panic("BaseDependencyTag is not allowed to be used directly!")
1490 }
Colin Cross65569e42015-03-10 20:08:19 -07001491
Jeff Gastond70bf752017-11-10 15:12:08 -08001492 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001493 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001494 return c.discoveredMissingDependencies(module, depName)
Colin Cross65569e42015-03-10 20:08:19 -07001495 }
1496
1497 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1498 // compare the strings because the result won't be in mutator registration order.
1499 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001500 var newVariant variationMap
1501 if !far {
1502 newVariant = module.dependencyVariant.clone()
1503 } else {
1504 newVariant = make(variationMap)
1505 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001506 for _, v := range variations {
1507 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001508 }
1509
Colin Cross0b7e83e2016-05-17 14:58:05 -07001510 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001511 var found bool
1512 if far {
1513 found = m.variant.subset(newVariant)
1514 } else {
1515 found = m.variant.equal(newVariant)
1516 }
1517 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001518 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001519 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001520 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001521 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001522 }}
1523 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001524 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001525 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001526 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001527 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001528 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001529 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001530 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001531 }}
1532 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001533 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001534 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001535 return nil
1536 }
1537 }
1538
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001539 variants := make([]string, len(possibleDeps))
1540 for i, mod := range possibleDeps {
1541 variants[i] = c.prettyPrintVariant(mod.variant)
1542 }
1543 sort.Strings(variants)
1544
Colin Cross2c628442016-10-07 17:13:10 -07001545 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001546 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001547 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001548 c.prettyPrintVariant(newVariant),
1549 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001550 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001551 }}
Colin Crossc9028482014-12-18 16:28:54 -08001552}
1553
Colin Crossf1875462016-04-11 17:33:13 -07001554func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1555 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001556 if _, ok := tag.(BaseDependencyTag); ok {
1557 panic("BaseDependencyTag is not allowed to be used directly!")
1558 }
Colin Crossf1875462016-04-11 17:33:13 -07001559
1560 var fromInfo, toInfo *moduleInfo
1561 for _, m := range origModule.splitModules {
1562 if m.logicModule == from {
1563 fromInfo = m
1564 }
1565 if m.logicModule == to {
1566 toInfo = m
1567 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001568 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001569 }
1570 }
1571 }
1572
1573 if fromInfo == nil || toInfo == nil {
1574 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001575 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001576 }
1577
1578 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001579 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001580}
1581
Jeff Gastonc3e28442017-08-09 15:13:12 -07001582// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1583// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1584// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1585func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1586 // make mapping from dir path to file path
1587 filesByDir := make(map[string]string, len(paths))
1588 for _, path := range paths {
1589 dir := filepath.Dir(path)
1590 _, alreadyFound := filesByDir[dir]
1591 if alreadyFound {
1592 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1593 }
1594 filesByDir[dir] = path
1595 }
1596
Jeff Gaston656870f2017-11-29 18:37:31 -08001597 findAncestor := func(childFile string) (ancestor string) {
1598 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001599 for {
1600 ancestorDir := filepath.Dir(prevAncestorDir)
1601 if ancestorDir == prevAncestorDir {
1602 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001603 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001604 }
1605
1606 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1607 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001608 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001609 }
1610 prevAncestorDir = ancestorDir
1611 }
1612 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001613 // generate the descendants map
1614 descendants = make(map[string][]string, len(filesByDir))
1615 for _, childFile := range filesByDir {
1616 ancestorFile := findAncestor(childFile)
1617 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1618 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001619 return descendants, nil
1620}
1621
Colin Cross3702ac72016-08-11 11:09:00 -07001622type visitOrderer interface {
1623 // returns the number of modules that this module needs to wait for
1624 waitCount(module *moduleInfo) int
1625 // returns the list of modules that are waiting for this module
1626 propagate(module *moduleInfo) []*moduleInfo
1627 // visit modules in order
1628 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1629}
1630
Colin Cross7e723372018-03-28 11:50:12 -07001631type unorderedVisitorImpl struct{}
1632
1633func (unorderedVisitorImpl) waitCount(module *moduleInfo) int {
1634 return 0
1635}
1636
1637func (unorderedVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1638 return nil
1639}
1640
1641func (unorderedVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1642 for _, module := range modules {
1643 if visit(module) {
1644 return
1645 }
1646 }
1647}
1648
Colin Cross3702ac72016-08-11 11:09:00 -07001649type bottomUpVisitorImpl struct{}
1650
1651func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1652 return len(module.forwardDeps)
1653}
1654
1655func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1656 return module.reverseDeps
1657}
1658
1659func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1660 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001661 if visit(module) {
1662 return
1663 }
1664 }
1665}
1666
Colin Cross3702ac72016-08-11 11:09:00 -07001667type topDownVisitorImpl struct{}
1668
1669func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1670 return len(module.reverseDeps)
1671}
1672
1673func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1674 return module.forwardDeps
1675}
1676
1677func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1678 for i := 0; i < len(modules); i++ {
1679 module := modules[len(modules)-1-i]
1680 if visit(module) {
1681 return
1682 }
1683 }
1684}
1685
1686var (
1687 bottomUpVisitor bottomUpVisitorImpl
1688 topDownVisitor topDownVisitorImpl
1689)
1690
Colin Cross49c279a2016-08-05 22:30:44 -07001691// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1692// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001693func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001694 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001695 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001696 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001697 cancel := false
Colin Cross7e723372018-03-28 11:50:12 -07001698 var backlog []*moduleInfo
1699 const limit = 1000
Colin Cross691a60d2015-01-07 18:08:56 -08001700
Colin Cross7addea32015-03-11 15:43:52 -07001701 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001702 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001703 }
1704
Colin Cross7addea32015-03-11 15:43:52 -07001705 visitOne := func(module *moduleInfo) {
Colin Cross7e723372018-03-28 11:50:12 -07001706 if count < limit {
1707 count++
1708 go func() {
1709 ret := visit(module)
1710 if ret {
1711 cancelCh <- true
1712 }
1713 doneCh <- module
1714 }()
1715 } else {
1716 backlog = append(backlog, module)
1717 }
Colin Cross691a60d2015-01-07 18:08:56 -08001718 }
1719
Colin Cross7addea32015-03-11 15:43:52 -07001720 for _, module := range c.modulesSorted {
1721 if module.waitingCount == 0 {
1722 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001723 }
1724 }
1725
Colin Cross7e723372018-03-28 11:50:12 -07001726 for count > 0 || len(backlog) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001727 select {
Colin Cross7e723372018-03-28 11:50:12 -07001728 case <-cancelCh:
1729 cancel = true
1730 backlog = nil
Colin Cross7addea32015-03-11 15:43:52 -07001731 case doneModule := <-doneCh:
Colin Cross7e723372018-03-28 11:50:12 -07001732 count--
Colin Cross8900e9b2015-03-02 14:03:01 -08001733 if !cancel {
Colin Cross7e723372018-03-28 11:50:12 -07001734 for count < limit && len(backlog) > 0 {
1735 toVisit := backlog[0]
1736 backlog = backlog[1:]
1737 visitOne(toVisit)
1738 }
Colin Cross3702ac72016-08-11 11:09:00 -07001739 for _, module := range order.propagate(doneModule) {
1740 module.waitingCount--
1741 if module.waitingCount == 0 {
1742 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001743 }
Colin Cross691a60d2015-01-07 18:08:56 -08001744 }
1745 }
Colin Cross691a60d2015-01-07 18:08:56 -08001746 }
1747 }
1748}
1749
1750// updateDependencies recursively walks the module dependency graph and updates
1751// additional fields based on the dependencies. It builds a sorted list of modules
1752// such that dependencies of a module always appear first, and populates reverse
1753// dependency links and counts of total dependencies. It also reports errors when
1754// it encounters dependency cycles. This should called after resolveDependencies,
1755// as well as after any mutator pass has called addDependency
1756func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001757 visited := make(map[*moduleInfo]bool) // modules that were already checked
1758 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001759
Colin Cross7addea32015-03-11 15:43:52 -07001760 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001761
Colin Cross7addea32015-03-11 15:43:52 -07001762 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001763
Colin Cross7addea32015-03-11 15:43:52 -07001764 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001765 // We are the "start" of the cycle, so we're responsible
1766 // for generating the errors. The cycle list is in
1767 // reverse order because all the 'check' calls append
1768 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001769 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001770 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001771 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001772 })
1773
1774 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001775 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001776 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001777 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001778 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001779 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001780 curModule.Name(),
1781 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001782 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001783 })
Colin Cross7addea32015-03-11 15:43:52 -07001784 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001785 }
1786 }
1787
Colin Cross7addea32015-03-11 15:43:52 -07001788 check = func(module *moduleInfo) []*moduleInfo {
1789 visited[module] = true
1790 checking[module] = true
1791 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001792
Colin Cross7addea32015-03-11 15:43:52 -07001793 deps := make(map[*moduleInfo]bool)
1794
1795 // Add an implicit dependency ordering on all earlier modules in the same module group
1796 for _, dep := range module.group.modules {
1797 if dep == module {
1798 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001799 }
Colin Cross7addea32015-03-11 15:43:52 -07001800 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001801 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001802
Colin Cross7addea32015-03-11 15:43:52 -07001803 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001804 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001805 }
1806
1807 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001808 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001809
Colin Crossbbfa51a2014-12-17 16:12:41 -08001810 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001811 if checking[dep] {
1812 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001813 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001814 }
1815
1816 if !visited[dep] {
1817 cycle := check(dep)
1818 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001819 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001820 // We are the "start" of the cycle, so we're responsible
1821 // for generating the errors. The cycle list is in
1822 // reverse order because all the 'check' calls append
1823 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001824 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001825
1826 // We can continue processing this module's children to
1827 // find more cycles. Since all the modules that were
1828 // part of the found cycle were marked as visited we
1829 // won't run into that cycle again.
1830 } else {
1831 // We're not the "start" of the cycle, so we just append
1832 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001833 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001834 }
1835 }
1836 }
Colin Cross691a60d2015-01-07 18:08:56 -08001837
Colin Cross3702ac72016-08-11 11:09:00 -07001838 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001839 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001840 }
1841
Colin Cross7addea32015-03-11 15:43:52 -07001842 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001843
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844 return nil
1845 }
1846
Colin Cross7addea32015-03-11 15:43:52 -07001847 for _, module := range c.moduleInfo {
1848 if !visited[module] {
1849 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001850 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001851 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001852 panic("inconceivable!")
1853 }
1854 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001855 }
1856 }
1857 }
1858
Colin Cross7addea32015-03-11 15:43:52 -07001859 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001860
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001861 return
1862}
1863
Jamie Gennisd4e10182014-06-12 20:06:50 -07001864// PrepareBuildActions generates an internal representation of all the build
1865// actions that need to be performed. This process involves invoking the
1866// GenerateBuildActions method on each of the Module objects created during the
1867// parse phase and then on each of the registered Singleton objects.
1868//
1869// If the ResolveDependencies method has not already been called it is called
1870// automatically by this method.
1871//
1872// The config argument is made available to all of the Module and Singleton
1873// objects via the Config method on the ModuleContext and SingletonContext
1874// objects passed to GenerateBuildActions. It is also passed to the functions
1875// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1876// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001877//
1878// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001879// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1880// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1881// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001882func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Colin Cross3a8c0252019-01-23 13:21:48 -08001883 pprof.Do(c.Context, pprof.Labels("blueprint", "PrepareBuildActions"), func(ctx context.Context) {
1884 c.buildActionsReady = false
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001885
Colin Cross3a8c0252019-01-23 13:21:48 -08001886 if !c.dependenciesReady {
1887 var extraDeps []string
1888 extraDeps, errs = c.resolveDependencies(ctx, config)
1889 if len(errs) > 0 {
1890 return
1891 }
1892 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001893 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001894
Colin Cross3a8c0252019-01-23 13:21:48 -08001895 var depsModules []string
1896 depsModules, errs = c.generateModuleBuildActions(config, c.liveGlobals)
1897 if len(errs) > 0 {
1898 return
1899 }
1900
1901 var depsSingletons []string
1902 depsSingletons, errs = c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
1903 if len(errs) > 0 {
1904 return
1905 }
1906
1907 deps = append(deps, depsModules...)
1908 deps = append(deps, depsSingletons...)
1909
1910 if c.ninjaBuildDir != nil {
1911 err := c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
1912 if err != nil {
1913 errs = []error{err}
1914 return
1915 }
1916 }
1917
1918 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
1919
1920 deps = append(deps, depsPackages...)
1921
1922 // This will panic if it finds a problem since it's a programming error.
1923 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
1924
1925 c.pkgNames = pkgNames
1926 c.globalVariables = c.liveGlobals.variables
1927 c.globalPools = c.liveGlobals.pools
1928 c.globalRules = c.liveGlobals.rules
1929
1930 c.buildActionsReady = true
1931 })
1932
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001933 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001934 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001935 }
1936
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001937 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001938}
1939
Colin Cross3a8c0252019-01-23 13:21:48 -08001940func (c *Context) runMutators(ctx context.Context, config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001941 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001942
Colin Cross3a8c0252019-01-23 13:21:48 -08001943 pprof.Do(ctx, pprof.Labels("blueprint", "runMutators"), func(ctx context.Context) {
1944 mutators = append(mutators, c.earlyMutatorInfo...)
1945 mutators = append(mutators, c.mutatorInfo...)
Colin Crossf8b50422016-08-10 12:56:40 -07001946
Colin Cross3a8c0252019-01-23 13:21:48 -08001947 for _, mutator := range mutators {
1948 pprof.Do(ctx, pprof.Labels("mutator", mutator.name), func(context.Context) {
1949 var newDeps []string
1950 if mutator.topDownMutator != nil {
1951 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
1952 } else if mutator.bottomUpMutator != nil {
1953 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
1954 } else {
1955 panic("no mutator set on " + mutator.name)
1956 }
1957 if len(errs) > 0 {
1958 return
1959 }
1960 deps = append(deps, newDeps...)
1961 })
1962 if len(errs) > 0 {
1963 return
1964 }
Colin Crossc9028482014-12-18 16:28:54 -08001965 }
Colin Cross3a8c0252019-01-23 13:21:48 -08001966 })
1967
1968 if len(errs) > 0 {
1969 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08001970 }
1971
Colin Cross874a3462017-07-31 17:26:06 -07001972 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08001973}
1974
Colin Cross3702ac72016-08-11 11:09:00 -07001975type mutatorDirection interface {
1976 run(mutator *mutatorInfo, ctx *mutatorContext)
1977 orderer() visitOrderer
1978 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001979}
1980
Colin Cross3702ac72016-08-11 11:09:00 -07001981type bottomUpMutatorImpl struct{}
1982
1983func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1984 mutator.bottomUpMutator(ctx)
1985}
1986
1987func (bottomUpMutatorImpl) orderer() visitOrderer {
1988 return bottomUpVisitor
1989}
1990
1991func (bottomUpMutatorImpl) String() string {
1992 return "bottom up mutator"
1993}
1994
1995type topDownMutatorImpl struct{}
1996
1997func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1998 mutator.topDownMutator(ctx)
1999}
2000
2001func (topDownMutatorImpl) orderer() visitOrderer {
2002 return topDownVisitor
2003}
2004
2005func (topDownMutatorImpl) String() string {
2006 return "top down mutator"
2007}
2008
2009var (
2010 topDownMutator topDownMutatorImpl
2011 bottomUpMutator bottomUpMutatorImpl
2012)
2013
Colin Cross49c279a2016-08-05 22:30:44 -07002014type reverseDep struct {
2015 module *moduleInfo
2016 dep depInfo
2017}
2018
Colin Cross3702ac72016-08-11 11:09:00 -07002019func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07002020 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07002021
2022 newModuleInfo := make(map[Module]*moduleInfo)
2023 for k, v := range c.moduleInfo {
2024 newModuleInfo[k] = v
2025 }
Colin Crossc9028482014-12-18 16:28:54 -08002026
Colin Cross0ce142c2016-12-09 10:29:05 -08002027 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07002028 reverse []reverseDep
2029 rename []rename
2030 replace []replace
2031 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07002032 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08002033 }
2034
Colin Cross2c1f3d12016-04-11 15:47:28 -07002035 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08002036 var rename []rename
2037 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07002038 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08002039
Colin Cross49c279a2016-08-05 22:30:44 -07002040 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08002041 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07002042 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07002043 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08002044
Colin Cross3702ac72016-08-11 11:09:00 -07002045 c.depsModified = 0
2046
Colin Cross49c279a2016-08-05 22:30:44 -07002047 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04002048 if module.splitModules != nil {
2049 panic("split module found in sorted module list")
2050 }
2051
Colin Cross7addea32015-03-11 15:43:52 -07002052 mctx := &mutatorContext{
2053 baseModuleContext: baseModuleContext{
2054 context: c,
2055 config: config,
2056 module: module,
2057 },
Colin Cross49c279a2016-08-05 22:30:44 -07002058 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07002059 }
Colin Crossc9028482014-12-18 16:28:54 -08002060
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002061 func() {
2062 defer func() {
2063 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07002064 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002065 if err, ok := r.(panicError); ok {
2066 err.addIn(in)
2067 mctx.error(err)
2068 } else {
2069 mctx.error(newPanicErrorf(r, in))
2070 }
2071 }
2072 }()
Colin Cross3702ac72016-08-11 11:09:00 -07002073 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002074 }()
Colin Cross49c279a2016-08-05 22:30:44 -07002075
Colin Cross7addea32015-03-11 15:43:52 -07002076 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07002077 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07002078 return true
Colin Cross7addea32015-03-11 15:43:52 -07002079 }
Colin Crossc9028482014-12-18 16:28:54 -08002080
Colin Cross5fe225f2017-07-28 15:22:46 -07002081 if len(mctx.newVariations) > 0 {
2082 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002083 }
2084
Colin Crossaf4fd212017-07-28 14:32:36 -07002085 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08002086 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002087 reverse: mctx.reverseDeps,
2088 replace: mctx.replace,
2089 rename: mctx.rename,
2090 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002091 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002092 }
Colin Cross49c279a2016-08-05 22:30:44 -07002093 }
2094
2095 return false
2096 }
2097
2098 // Process errs and reverseDeps in a single goroutine
2099 go func() {
2100 for {
2101 select {
2102 case newErrs := <-errsCh:
2103 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002104 case globalStateChange := <-globalStateCh:
2105 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002106 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2107 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002108 replace = append(replace, globalStateChange.replace...)
2109 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002110 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002111 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002112 case newVariations := <-newVariationsCh:
2113 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002114 newModuleInfo[m.logicModule] = m
2115 }
2116 case <-done:
2117 return
Colin Crossc9028482014-12-18 16:28:54 -08002118 }
2119 }
Colin Cross49c279a2016-08-05 22:30:44 -07002120 }()
Colin Crossc9028482014-12-18 16:28:54 -08002121
Colin Cross49c279a2016-08-05 22:30:44 -07002122 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002123 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002124 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002125 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002126 }
2127
2128 done <- true
2129
2130 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002131 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002132 }
2133
2134 c.moduleInfo = newModuleInfo
2135
2136 for _, group := range c.moduleGroups {
2137 for i := 0; i < len(group.modules); i++ {
2138 module := group.modules[i]
2139
2140 // Update module group to contain newly split variants
2141 if module.splitModules != nil {
2142 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2143 }
2144
2145 // Fix up any remaining dependencies on modules that were split into variants
2146 // by replacing them with the first variant
2147 for j, dep := range module.directDeps {
2148 if dep.module.logicModule == nil {
2149 module.directDeps[j].module = dep.module.splitModules[0]
2150 }
2151 }
Colin Cross7addea32015-03-11 15:43:52 -07002152 }
Colin Crossc9028482014-12-18 16:28:54 -08002153 }
2154
Colin Cross8d8a7af2015-11-03 16:41:29 -08002155 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002156 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002157 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002158 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002159 }
2160
Colin Crossaf4fd212017-07-28 14:32:36 -07002161 for _, module := range newModules {
2162 errs = c.addModule(module)
2163 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002164 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002165 }
2166 atomic.AddUint32(&c.depsModified, 1)
2167 }
2168
Colin Cross0ce142c2016-12-09 10:29:05 -08002169 errs = c.handleRenames(rename)
2170 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002171 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002172 }
2173
2174 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002175 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002176 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002177 }
2178
Colin Cross3702ac72016-08-11 11:09:00 -07002179 if c.depsModified > 0 {
2180 errs = c.updateDependencies()
2181 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002182 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002183 }
Colin Crossc9028482014-12-18 16:28:54 -08002184 }
2185
Colin Cross874a3462017-07-31 17:26:06 -07002186 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002187}
2188
Colin Cross910242b2016-04-11 15:41:52 -07002189// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2190// a mutator sets a non-property member variable on a module, which works until a later mutator
2191// creates variants of that module.
2192func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002193 type update struct {
2194 orig Module
2195 clone *moduleInfo
2196 }
Colin Cross7e723372018-03-28 11:50:12 -07002197 ch := make(chan update)
2198 doneCh := make(chan bool)
2199 go func() {
2200 c.parallelVisit(unorderedVisitorImpl{}, func(m *moduleInfo) bool {
Colin Crossc93490c2016-08-09 14:21:02 -07002201 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002202 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002203 ch <- update{origLogicModule, m}
Colin Cross7e723372018-03-28 11:50:12 -07002204 return false
2205 })
2206 doneCh <- true
2207 }()
Colin Crossc93490c2016-08-09 14:21:02 -07002208
Colin Cross7e723372018-03-28 11:50:12 -07002209 done := false
2210 for !done {
2211 select {
2212 case <-doneCh:
2213 done = true
2214 case update := <-ch:
2215 delete(c.moduleInfo, update.orig)
2216 c.moduleInfo[update.clone.logicModule] = update.clone
2217 }
Colin Cross910242b2016-04-11 15:41:52 -07002218 }
2219}
2220
Colin Cross49c279a2016-08-05 22:30:44 -07002221// Removes modules[i] from the list and inserts newModules... where it was located, returning
2222// the new slice and the index of the last inserted element
2223func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002224 spliceSize := len(newModules)
2225 newLen := len(modules) + spliceSize - 1
2226 var dest []*moduleInfo
2227 if cap(modules) >= len(modules)-1+len(newModules) {
2228 // We can fit the splice in the existing capacity, do everything in place
2229 dest = modules[:newLen]
2230 } else {
2231 dest = make([]*moduleInfo, newLen)
2232 copy(dest, modules[:i])
2233 }
2234
2235 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002236 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002237
2238 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002239 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002240
Colin Cross49c279a2016-08-05 22:30:44 -07002241 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002242}
2243
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002244func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002245 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002246
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002247 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002248 var errs []error
2249
Colin Cross691a60d2015-01-07 18:08:56 -08002250 cancelCh := make(chan struct{})
2251 errsCh := make(chan []error)
2252 depsCh := make(chan []string)
2253
2254 go func() {
2255 for {
2256 select {
2257 case <-cancelCh:
2258 close(cancelCh)
2259 return
2260 case newErrs := <-errsCh:
2261 errs = append(errs, newErrs...)
2262 case newDeps := <-depsCh:
2263 deps = append(deps, newDeps...)
2264
2265 }
2266 }
2267 }()
2268
Colin Cross3702ac72016-08-11 11:09:00 -07002269 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08002270
2271 uniqueName := c.nameInterface.UniqueName(newNamespaceContext(module), module.group.name)
2272 sanitizedName := toNinjaName(uniqueName)
2273
2274 prefix := moduleNamespacePrefix(sanitizedName + "_" + module.variantName)
2275
Colin Cross7addea32015-03-11 15:43:52 -07002276 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2277 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2278 // just set it to nil.
Colin Cross7addea32015-03-11 15:43:52 -07002279 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002280
Colin Cross7addea32015-03-11 15:43:52 -07002281 mctx := &moduleContext{
2282 baseModuleContext: baseModuleContext{
2283 context: c,
2284 config: config,
2285 module: module,
2286 },
Colin Cross036a1df2015-12-17 15:49:30 -08002287 scope: scope,
2288 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002289 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002290
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002291 func() {
2292 defer func() {
2293 if r := recover(); r != nil {
2294 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2295 if err, ok := r.(panicError); ok {
2296 err.addIn(in)
2297 mctx.error(err)
2298 } else {
2299 mctx.error(newPanicErrorf(r, in))
2300 }
2301 }
2302 }()
2303 mctx.module.logicModule.GenerateBuildActions(mctx)
2304 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002305
Colin Cross7addea32015-03-11 15:43:52 -07002306 if len(mctx.errs) > 0 {
2307 errsCh <- mctx.errs
2308 return true
2309 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002310
Colin Cross036a1df2015-12-17 15:49:30 -08002311 if module.missingDeps != nil && !mctx.handledMissingDeps {
2312 var errs []error
2313 for _, depName := range module.missingDeps {
Jeff Gastond70bf752017-11-10 15:12:08 -08002314 errs = append(errs, c.missingDependencyError(module, depName))
Colin Cross036a1df2015-12-17 15:49:30 -08002315 }
2316 errsCh <- errs
2317 return true
2318 }
2319
Colin Cross7addea32015-03-11 15:43:52 -07002320 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002321
Colin Crossab6d7902015-03-11 16:17:52 -07002322 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002323 &mctx.actionDefs, liveGlobals)
2324 if len(newErrs) > 0 {
2325 errsCh <- newErrs
2326 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002327 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002328 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002329 })
2330
2331 cancelCh <- struct{}{}
2332 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002333
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002334 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002335}
2336
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002337func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002338 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002339
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002340 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002341 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002342
Colin Cross5f03f112017-11-07 13:29:54 -08002343 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002344 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2345 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2346 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002347 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002348
2349 sctx := &singletonContext{
2350 context: c,
2351 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002352 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002353 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002354 }
2355
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002356 func() {
2357 defer func() {
2358 if r := recover(); r != nil {
2359 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2360 if err, ok := r.(panicError); ok {
2361 err.addIn(in)
2362 sctx.error(err)
2363 } else {
2364 sctx.error(newPanicErrorf(r, in))
2365 }
2366 }
2367 }()
2368 info.singleton.GenerateBuildActions(sctx)
2369 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002370
2371 if len(sctx.errs) > 0 {
2372 errs = append(errs, sctx.errs...)
2373 if len(errs) > maxErrors {
2374 break
2375 }
2376 continue
2377 }
2378
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002379 deps = append(deps, sctx.ninjaFileDeps...)
2380
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002381 newErrs := c.processLocalBuildActions(&info.actionDefs,
2382 &sctx.actionDefs, liveGlobals)
2383 errs = append(errs, newErrs...)
2384 if len(errs) > maxErrors {
2385 break
2386 }
2387 }
2388
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002389 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002390}
2391
2392func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2393 liveGlobals *liveTracker) []error {
2394
2395 var errs []error
2396
2397 // First we go through and add everything referenced by the module's
2398 // buildDefs to the live globals set. This will end up adding the live
2399 // locals to the set as well, but we'll take them out after.
2400 for _, def := range in.buildDefs {
2401 err := liveGlobals.AddBuildDefDeps(def)
2402 if err != nil {
2403 errs = append(errs, err)
2404 }
2405 }
2406
2407 if len(errs) > 0 {
2408 return errs
2409 }
2410
Colin Crossc9028482014-12-18 16:28:54 -08002411 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002412
2413 // We use the now-incorrect set of live "globals" to determine which local
2414 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002415 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002416 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002417 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002418 if isLive {
2419 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002420 }
2421 }
2422
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002423 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002424 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002425 if isLive {
2426 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002427 }
2428 }
2429
2430 return nil
2431}
2432
Colin Cross9607a9f2018-06-20 11:16:37 -07002433func (c *Context) walkDeps(topModule *moduleInfo, allowDuplicates bool,
Colin Crossbafd5f52016-08-06 22:52:01 -07002434 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002435
2436 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002437 var visiting *moduleInfo
2438
2439 defer func() {
2440 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002441 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2442 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002443 }
2444 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002445
2446 var walk func(module *moduleInfo)
2447 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002448 for _, dep := range module.directDeps {
Colin Cross9607a9f2018-06-20 11:16:37 -07002449 if allowDuplicates || !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002450 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002451 recurse := true
2452 if visitDown != nil {
2453 recurse = visitDown(dep, module)
2454 }
Colin Cross526e02f2018-06-21 13:31:53 -07002455 if recurse && !visited[dep.module] {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002456 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002457 }
Colin Cross526e02f2018-06-21 13:31:53 -07002458 visited[dep.module] = true
Colin Crossbafd5f52016-08-06 22:52:01 -07002459 if visitUp != nil {
2460 visitUp(dep, module)
2461 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002462 }
2463 }
2464 }
2465
2466 walk(topModule)
2467}
2468
Colin Cross9cfd1982016-10-11 09:58:53 -07002469type replace struct {
2470 from, to *moduleInfo
2471}
2472
Colin Crossc4e5b812016-10-12 10:45:05 -07002473type rename struct {
2474 group *moduleGroup
2475 name string
2476}
2477
Colin Cross0ce142c2016-12-09 10:29:05 -08002478func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Jeff Gastond70bf752017-11-10 15:12:08 -08002479 targets := c.modulesFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07002480
2481 if targets == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002482 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002483 }
2484
Colin Cross9cfd1982016-10-11 09:58:53 -07002485 for _, m := range targets {
2486 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002487 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002488 }
2489 }
2490
Colin Cross0ce142c2016-12-09 10:29:05 -08002491 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002492}
2493
Colin Cross0ce142c2016-12-09 10:29:05 -08002494func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002495 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002496 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002497 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08002498 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07002499 continue
2500 }
2501
Jeff Gastond70bf752017-11-10 15:12:08 -08002502 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07002503 }
2504
Colin Cross0ce142c2016-12-09 10:29:05 -08002505 return errs
2506}
2507
2508func (c *Context) handleReplacements(replacements []replace) []error {
2509 var errs []error
2510 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002511 for _, m := range replace.from.reverseDeps {
2512 for i, d := range m.directDeps {
2513 if d.module == replace.from {
2514 m.directDeps[i].module = replace.to
2515 }
2516 }
2517 }
2518
2519 atomic.AddUint32(&c.depsModified, 1)
2520 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002521
Colin Crossc4e5b812016-10-12 10:45:05 -07002522 return errs
2523}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002524
Jeff Gastond70bf752017-11-10 15:12:08 -08002525func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
2526 if c.allowMissingDependencies {
2527 module.missingDeps = append(module.missingDeps, depName)
2528 return nil
2529 }
2530 return []error{c.missingDependencyError(module, depName)}
2531}
2532
2533func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
2534 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
2535
2536 return &BlueprintError{
2537 Err: err,
2538 Pos: module.pos,
2539 }
2540}
2541
2542func (c *Context) modulesFromName(name string, namespace Namespace) []*moduleInfo {
2543 group, exists := c.nameInterface.ModuleFromName(name, namespace)
2544 if exists {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002545 return group.modules
2546 }
2547 return nil
2548}
2549
Jeff Gastond70bf752017-11-10 15:12:08 -08002550func (c *Context) sortedModuleGroups() []*moduleGroup {
2551 if c.cachedSortedModuleGroups == nil {
2552 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
2553 result := make([]*moduleGroup, 0, len(wrappers))
2554 for _, group := range wrappers {
2555 result = append(result, group.moduleGroup)
2556 }
2557 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07002558 }
Jeff Gastond70bf752017-11-10 15:12:08 -08002559
2560 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Jamie Gennisc15544d2014-09-24 20:26:52 -07002561 }
2562
Jeff Gastond70bf752017-11-10 15:12:08 -08002563 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07002564}
2565
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002566func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002567 var module *moduleInfo
2568
2569 defer func() {
2570 if r := recover(); r != nil {
2571 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2572 funcName(visit), module))
2573 }
2574 }()
2575
Jeff Gastond70bf752017-11-10 15:12:08 -08002576 for _, moduleGroup := range c.sortedModuleGroups() {
2577 for _, module = range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002578 visit(module.logicModule)
2579 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002580 }
2581}
2582
2583func (c *Context) visitAllModulesIf(pred func(Module) bool,
2584 visit func(Module)) {
2585
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002586 var module *moduleInfo
2587
2588 defer func() {
2589 if r := recover(); r != nil {
2590 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2591 funcName(pred), funcName(visit), module))
2592 }
2593 }()
2594
Jeff Gastond70bf752017-11-10 15:12:08 -08002595 for _, moduleGroup := range c.sortedModuleGroups() {
2596 for _, module := range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002597 if pred(module.logicModule) {
2598 visit(module.logicModule)
2599 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002600 }
2601 }
2602}
2603
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002604func (c *Context) visitAllModuleVariants(module *moduleInfo,
2605 visit func(Module)) {
2606
2607 var variant *moduleInfo
2608
2609 defer func() {
2610 if r := recover(); r != nil {
2611 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2612 module, funcName(visit), variant))
2613 }
2614 }()
2615
2616 for _, variant = range module.group.modules {
2617 visit(variant.logicModule)
2618 }
2619}
2620
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002621func (c *Context) requireNinjaVersion(major, minor, micro int) {
2622 if major != 1 {
2623 panic("ninja version with major version != 1 not supported")
2624 }
2625 if c.requiredNinjaMinor < minor {
2626 c.requiredNinjaMinor = minor
2627 c.requiredNinjaMicro = micro
2628 }
2629 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2630 c.requiredNinjaMicro = micro
2631 }
2632}
2633
Colin Crossa2599452015-11-18 16:01:01 -08002634func (c *Context) setNinjaBuildDir(value *ninjaString) {
2635 if c.ninjaBuildDir == nil {
2636 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002637 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002638}
2639
2640func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002641 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002642
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002643 pkgs := make(map[string]*packageContext)
2644 pkgNames := make(map[*packageContext]string)
2645 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002646
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002647 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002648 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002649 // This is a built-in rule and has no package.
2650 return
2651 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002652 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002653 // We've already processed this package.
2654 return
2655 }
2656
Jamie Gennis2fb20952014-10-03 02:49:58 -07002657 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002658 if present {
2659 // Short name collision. Both this package and the one that's
2660 // already there need to use their full names. We leave the short
2661 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002662 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002663 longPkgNames[otherPkg] = true
2664 } else {
2665 // No collision so far. Tentatively set the package's name to be
2666 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002667 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002668 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002669 }
2670 }
2671
2672 // We try to give all packages their short name, but when we get collisions
2673 // we need to use the full unique package name.
2674 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002675 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002676 }
2677 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002678 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002679 }
2680 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002681 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002682 }
2683
2684 // Add the packages that had collisions using their full unique names. This
2685 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002686 for pctx := range longPkgNames {
2687 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002688 }
2689
Dan Willemsena481ae22015-12-18 15:18:03 -08002690 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2691 deps := []string{}
2692 for _, pkg := range pkgs {
2693 deps = append(deps, pkg.ninjaFileDeps...)
2694 }
2695
2696 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002697}
2698
2699func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002700 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002701
2702 visited := make(map[Variable]bool) // variables that were already checked
2703 checking := make(map[Variable]bool) // variables actively being checked
2704
2705 var check func(v Variable) []Variable
2706
2707 check = func(v Variable) []Variable {
2708 visited[v] = true
2709 checking[v] = true
2710 defer delete(checking, v)
2711
2712 value := variables[v]
2713 for _, dep := range value.variables {
2714 if checking[dep] {
2715 // This is a cycle.
2716 return []Variable{dep, v}
2717 }
2718
2719 if !visited[dep] {
2720 cycle := check(dep)
2721 if cycle != nil {
2722 if cycle[0] == v {
2723 // We are the "start" of the cycle, so we're responsible
2724 // for generating the errors. The cycle list is in
2725 // reverse order because all the 'check' calls append
2726 // their own module to the list.
2727 msgs := []string{"detected variable reference cycle:"}
2728
2729 // Iterate backwards through the cycle list.
2730 curName := v.fullName(pkgNames)
2731 curValue := value.Value(pkgNames)
2732 for i := len(cycle) - 1; i >= 0; i-- {
2733 next := cycle[i]
2734 nextName := next.fullName(pkgNames)
2735 nextValue := variables[next].Value(pkgNames)
2736
2737 msgs = append(msgs, fmt.Sprintf(
2738 " %q depends on %q", curName, nextName))
2739 msgs = append(msgs, fmt.Sprintf(
2740 " [%s = %s]", curName, curValue))
2741
2742 curName = nextName
2743 curValue = nextValue
2744 }
2745
2746 // Variable reference cycles are a programming error,
2747 // not the fault of the Blueprint file authors.
2748 panic(strings.Join(msgs, "\n"))
2749 } else {
2750 // We're not the "start" of the cycle, so we just append
2751 // our module to the list and return it.
2752 return append(cycle, v)
2753 }
2754 }
2755 }
2756 }
2757
2758 return nil
2759 }
2760
2761 for v := range variables {
2762 if !visited[v] {
2763 cycle := check(v)
2764 if cycle != nil {
2765 panic("inconceivable!")
2766 }
2767 }
2768 }
2769}
2770
Jamie Gennisaf435562014-10-27 22:34:56 -07002771// AllTargets returns a map all the build target names to the rule used to build
2772// them. This is the same information that is output by running 'ninja -t
2773// targets all'. If this is called before PrepareBuildActions successfully
2774// completes then ErrbuildActionsNotReady is returned.
2775func (c *Context) AllTargets() (map[string]string, error) {
2776 if !c.buildActionsReady {
2777 return nil, ErrBuildActionsNotReady
2778 }
2779
2780 targets := map[string]string{}
2781
2782 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002783 for _, module := range c.moduleInfo {
2784 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002785 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002786 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002787 outputValue, err := output.Eval(c.globalVariables)
2788 if err != nil {
2789 return nil, err
2790 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002791 targets[outputValue] = ruleName
2792 }
2793 }
2794 }
2795
2796 // Collect all the singleton build targets.
2797 for _, info := range c.singletonInfo {
2798 for _, buildDef := range info.actionDefs.buildDefs {
2799 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002800 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002801 outputValue, err := output.Eval(c.globalVariables)
2802 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002803 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002804 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002805 targets[outputValue] = ruleName
2806 }
2807 }
2808 }
2809
2810 return targets, nil
2811}
2812
Colin Crossa2599452015-11-18 16:01:01 -08002813func (c *Context) NinjaBuildDir() (string, error) {
2814 if c.ninjaBuildDir != nil {
2815 return c.ninjaBuildDir.Eval(c.globalVariables)
2816 } else {
2817 return "", nil
2818 }
2819}
2820
Colin Cross4572edd2015-05-13 14:36:24 -07002821// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2822// property structs returned by the factory for that module type.
2823func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2824 ret := make(map[string][]interface{})
2825 for moduleType, factory := range c.moduleFactories {
2826 _, ret[moduleType] = factory()
2827 }
2828
2829 return ret
2830}
2831
Jaewoong Jung781f6b22019-02-06 16:20:17 -08002832func (c *Context) ModuleTypeFactories() map[string]ModuleFactory {
2833 ret := make(map[string]ModuleFactory)
2834 for k, v := range c.moduleFactories {
2835 ret[k] = v
2836 }
2837 return ret
2838}
2839
Colin Cross4572edd2015-05-13 14:36:24 -07002840func (c *Context) ModuleName(logicModule Module) string {
2841 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002842 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002843}
2844
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002845func (c *Context) ModulePath(logicModule Module) string {
Colin Cross4572edd2015-05-13 14:36:24 -07002846 module := c.moduleInfo[logicModule]
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002847 return module.relBlueprintsFile
2848}
2849
2850func (c *Context) ModuleDir(logicModule Module) string {
2851 return filepath.Dir(c.ModulePath(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07002852}
2853
Colin Cross8c602f72015-12-17 18:02:11 -08002854func (c *Context) ModuleSubDir(logicModule Module) string {
2855 module := c.moduleInfo[logicModule]
2856 return module.variantName
2857}
2858
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002859func (c *Context) ModuleType(logicModule Module) string {
2860 module := c.moduleInfo[logicModule]
2861 return module.typeName
2862}
2863
Colin Cross4572edd2015-05-13 14:36:24 -07002864func (c *Context) BlueprintFile(logicModule Module) string {
2865 module := c.moduleInfo[logicModule]
2866 return module.relBlueprintsFile
2867}
2868
2869func (c *Context) ModuleErrorf(logicModule Module, format string,
2870 args ...interface{}) error {
2871
2872 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002873 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002874 Err: fmt.Errorf(format, args...),
2875 Pos: module.pos,
2876 }
2877}
2878
2879func (c *Context) VisitAllModules(visit func(Module)) {
2880 c.visitAllModules(visit)
2881}
2882
2883func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2884 visit func(Module)) {
2885
2886 c.visitAllModulesIf(pred, visit)
2887}
2888
Colin Cross080c1332017-03-17 13:09:05 -07002889func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
2890 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07002891
Colin Cross080c1332017-03-17 13:09:05 -07002892 var visiting *moduleInfo
2893
2894 defer func() {
2895 if r := recover(); r != nil {
2896 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
2897 topModule, funcName(visit), visiting))
2898 }
2899 }()
2900
2901 for _, dep := range topModule.directDeps {
2902 visiting = dep.module
2903 visit(dep.module.logicModule)
2904 }
2905}
2906
2907func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
2908 topModule := c.moduleInfo[module]
2909
2910 var visiting *moduleInfo
2911
2912 defer func() {
2913 if r := recover(); r != nil {
2914 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
2915 topModule, funcName(pred), funcName(visit), visiting))
2916 }
2917 }()
2918
2919 for _, dep := range topModule.directDeps {
2920 visiting = dep.module
2921 if pred(dep.module.logicModule) {
2922 visit(dep.module.logicModule)
2923 }
2924 }
2925}
2926
2927func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002928 topModule := c.moduleInfo[module]
2929
2930 var visiting *moduleInfo
2931
2932 defer func() {
2933 if r := recover(); r != nil {
2934 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2935 topModule, funcName(visit), visiting))
2936 }
2937 }()
2938
Colin Cross9607a9f2018-06-20 11:16:37 -07002939 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002940 visiting = dep.module
2941 visit(dep.module.logicModule)
2942 })
Colin Cross4572edd2015-05-13 14:36:24 -07002943}
2944
Colin Cross080c1332017-03-17 13:09:05 -07002945func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002946 topModule := c.moduleInfo[module]
2947
2948 var visiting *moduleInfo
2949
2950 defer func() {
2951 if r := recover(); r != nil {
2952 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2953 topModule, funcName(pred), funcName(visit), visiting))
2954 }
2955 }()
2956
Colin Cross9607a9f2018-06-20 11:16:37 -07002957 c.walkDeps(topModule, false, nil, func(dep depInfo, parent *moduleInfo) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002958 if pred(dep.module.logicModule) {
2959 visiting = dep.module
2960 visit(dep.module.logicModule)
2961 }
2962 })
Colin Cross4572edd2015-05-13 14:36:24 -07002963}
2964
Colin Cross24ad5872015-11-17 16:22:29 -08002965func (c *Context) PrimaryModule(module Module) Module {
2966 return c.moduleInfo[module].group.modules[0].logicModule
2967}
2968
2969func (c *Context) FinalModule(module Module) Module {
2970 modules := c.moduleInfo[module].group.modules
2971 return modules[len(modules)-1].logicModule
2972}
2973
2974func (c *Context) VisitAllModuleVariants(module Module,
2975 visit func(Module)) {
2976
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002977 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002978}
2979
Jamie Gennisd4e10182014-06-12 20:06:50 -07002980// WriteBuildFile writes the Ninja manifeset text for the generated build
2981// actions to w. If this is called before PrepareBuildActions successfully
2982// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002983func (c *Context) WriteBuildFile(w io.Writer) error {
Colin Cross3a8c0252019-01-23 13:21:48 -08002984 var err error
2985 pprof.Do(c.Context, pprof.Labels("blueprint", "WriteBuildFile"), func(ctx context.Context) {
2986 if !c.buildActionsReady {
2987 err = ErrBuildActionsNotReady
2988 return
2989 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002990
Colin Cross3a8c0252019-01-23 13:21:48 -08002991 nw := newNinjaWriter(w)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002992
Colin Cross3a8c0252019-01-23 13:21:48 -08002993 err = c.writeBuildFileHeader(nw)
2994 if err != nil {
2995 return
2996 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002997
Colin Cross3a8c0252019-01-23 13:21:48 -08002998 err = c.writeNinjaRequiredVersion(nw)
2999 if err != nil {
3000 return
3001 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003002
Colin Cross3a8c0252019-01-23 13:21:48 -08003003 err = c.writeSubninjas(nw)
3004 if err != nil {
3005 return
3006 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003007
Colin Cross3a8c0252019-01-23 13:21:48 -08003008 // TODO: Group the globals by package.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003009
Colin Cross3a8c0252019-01-23 13:21:48 -08003010 err = c.writeGlobalVariables(nw)
3011 if err != nil {
3012 return
3013 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003014
Colin Cross3a8c0252019-01-23 13:21:48 -08003015 err = c.writeGlobalPools(nw)
3016 if err != nil {
3017 return
3018 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003019
Colin Cross3a8c0252019-01-23 13:21:48 -08003020 err = c.writeBuildDir(nw)
3021 if err != nil {
3022 return
3023 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003024
Colin Cross3a8c0252019-01-23 13:21:48 -08003025 err = c.writeGlobalRules(nw)
3026 if err != nil {
3027 return
3028 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003029
Colin Cross3a8c0252019-01-23 13:21:48 -08003030 err = c.writeAllModuleActions(nw)
3031 if err != nil {
3032 return
3033 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003034
Colin Cross3a8c0252019-01-23 13:21:48 -08003035 err = c.writeAllSingletonActions(nw)
3036 if err != nil {
3037 return
3038 }
3039 })
3040
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003041 if err != nil {
3042 return err
3043 }
3044
3045 return nil
3046}
3047
Jamie Gennisc15544d2014-09-24 20:26:52 -07003048type pkgAssociation struct {
3049 PkgName string
3050 PkgPath string
3051}
3052
3053type pkgAssociationSorter struct {
3054 pkgs []pkgAssociation
3055}
3056
3057func (s *pkgAssociationSorter) Len() int {
3058 return len(s.pkgs)
3059}
3060
3061func (s *pkgAssociationSorter) Less(i, j int) bool {
3062 iName := s.pkgs[i].PkgName
3063 jName := s.pkgs[j].PkgName
3064 return iName < jName
3065}
3066
3067func (s *pkgAssociationSorter) Swap(i, j int) {
3068 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
3069}
3070
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003071func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
3072 headerTemplate := template.New("fileHeader")
3073 _, err := headerTemplate.Parse(fileHeaderTemplate)
3074 if err != nil {
3075 // This is a programming error.
3076 panic(err)
3077 }
3078
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003079 var pkgs []pkgAssociation
3080 maxNameLen := 0
3081 for pkg, name := range c.pkgNames {
3082 pkgs = append(pkgs, pkgAssociation{
3083 PkgName: name,
3084 PkgPath: pkg.pkgPath,
3085 })
3086 if len(name) > maxNameLen {
3087 maxNameLen = len(name)
3088 }
3089 }
3090
3091 for i := range pkgs {
3092 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
3093 }
3094
Jamie Gennisc15544d2014-09-24 20:26:52 -07003095 sort.Sort(&pkgAssociationSorter{pkgs})
3096
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003097 params := map[string]interface{}{
3098 "Pkgs": pkgs,
3099 }
3100
3101 buf := bytes.NewBuffer(nil)
3102 err = headerTemplate.Execute(buf, params)
3103 if err != nil {
3104 return err
3105 }
3106
3107 return nw.Comment(buf.String())
3108}
3109
3110func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
3111 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
3112 c.requiredNinjaMicro)
3113
3114 err := nw.Assign("ninja_required_version", value)
3115 if err != nil {
3116 return err
3117 }
3118
3119 return nw.BlankLine()
3120}
3121
Dan Willemsenab223a52018-07-05 21:56:59 -07003122func (c *Context) writeSubninjas(nw *ninjaWriter) error {
3123 for _, subninja := range c.subninjas {
Colin Crossde7afaa2019-01-23 13:23:00 -08003124 err := nw.Subninja(subninja)
3125 if err != nil {
3126 return err
3127 }
Dan Willemsenab223a52018-07-05 21:56:59 -07003128 }
3129 return nw.BlankLine()
3130}
3131
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003132func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08003133 if c.ninjaBuildDir != nil {
3134 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003135 if err != nil {
3136 return err
3137 }
3138
3139 err = nw.BlankLine()
3140 if err != nil {
3141 return err
3142 }
3143 }
3144 return nil
3145}
3146
Jamie Gennisc15544d2014-09-24 20:26:52 -07003147type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003148 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003149}
3150
Jamie Gennisc15544d2014-09-24 20:26:52 -07003151type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003152 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003153 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003154}
3155
Jamie Gennisc15544d2014-09-24 20:26:52 -07003156func (s *globalEntitySorter) Len() int {
3157 return len(s.entities)
3158}
3159
3160func (s *globalEntitySorter) Less(i, j int) bool {
3161 iName := s.entities[i].fullName(s.pkgNames)
3162 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003163 return iName < jName
3164}
3165
Jamie Gennisc15544d2014-09-24 20:26:52 -07003166func (s *globalEntitySorter) Swap(i, j int) {
3167 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003168}
3169
3170func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3171 visited := make(map[Variable]bool)
3172
3173 var walk func(v Variable) error
3174 walk = func(v Variable) error {
3175 visited[v] = true
3176
3177 // First visit variables on which this variable depends.
3178 value := c.globalVariables[v]
3179 for _, dep := range value.variables {
3180 if !visited[dep] {
3181 err := walk(dep)
3182 if err != nil {
3183 return err
3184 }
3185 }
3186 }
3187
3188 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3189 if err != nil {
3190 return err
3191 }
3192
3193 err = nw.BlankLine()
3194 if err != nil {
3195 return err
3196 }
3197
3198 return nil
3199 }
3200
Jamie Gennisc15544d2014-09-24 20:26:52 -07003201 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3202 for variable := range c.globalVariables {
3203 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003204 }
3205
Jamie Gennisc15544d2014-09-24 20:26:52 -07003206 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003207
Jamie Gennisc15544d2014-09-24 20:26:52 -07003208 for _, entity := range globalVariables {
3209 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003210 if !visited[v] {
3211 err := walk(v)
3212 if err != nil {
3213 return nil
3214 }
3215 }
3216 }
3217
3218 return nil
3219}
3220
3221func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003222 globalPools := make([]globalEntity, 0, len(c.globalPools))
3223 for pool := range c.globalPools {
3224 globalPools = append(globalPools, pool)
3225 }
3226
3227 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3228
3229 for _, entity := range globalPools {
3230 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003231 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003232 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003233 err := def.WriteTo(nw, name)
3234 if err != nil {
3235 return err
3236 }
3237
3238 err = nw.BlankLine()
3239 if err != nil {
3240 return err
3241 }
3242 }
3243
3244 return nil
3245}
3246
3247func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003248 globalRules := make([]globalEntity, 0, len(c.globalRules))
3249 for rule := range c.globalRules {
3250 globalRules = append(globalRules, rule)
3251 }
3252
3253 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3254
3255 for _, entity := range globalRules {
3256 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003257 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003258 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003259 err := def.WriteTo(nw, name, c.pkgNames)
3260 if err != nil {
3261 return err
3262 }
3263
3264 err = nw.BlankLine()
3265 if err != nil {
3266 return err
3267 }
3268 }
3269
3270 return nil
3271}
3272
Colin Cross2c1f3d12016-04-11 15:47:28 -07003273type depSorter []depInfo
3274
3275func (s depSorter) Len() int {
3276 return len(s)
3277}
3278
3279func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003280 iName := s[i].module.Name()
3281 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003282 if iName == jName {
3283 iName = s[i].module.variantName
3284 jName = s[j].module.variantName
3285 }
3286 return iName < jName
3287}
3288
3289func (s depSorter) Swap(i, j int) {
3290 s[i], s[j] = s[j], s[i]
3291}
3292
Jeff Gaston0e907592017-12-01 17:10:52 -08003293type moduleSorter struct {
3294 modules []*moduleInfo
3295 nameInterface NameInterface
3296}
Jamie Gennis86179fe2014-06-11 16:27:16 -07003297
Colin Crossab6d7902015-03-11 16:17:52 -07003298func (s moduleSorter) Len() int {
Jeff Gaston0e907592017-12-01 17:10:52 -08003299 return len(s.modules)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003300}
3301
Colin Crossab6d7902015-03-11 16:17:52 -07003302func (s moduleSorter) Less(i, j int) bool {
Jeff Gaston0e907592017-12-01 17:10:52 -08003303 iMod := s.modules[i]
3304 jMod := s.modules[j]
3305 iName := s.nameInterface.UniqueName(newNamespaceContext(iMod), iMod.group.name)
3306 jName := s.nameInterface.UniqueName(newNamespaceContext(jMod), jMod.group.name)
Colin Crossab6d7902015-03-11 16:17:52 -07003307 if iName == jName {
Jeff Gaston0e907592017-12-01 17:10:52 -08003308 iName = s.modules[i].variantName
3309 jName = s.modules[j].variantName
3310 }
3311
3312 if iName == jName {
3313 panic(fmt.Sprintf("duplicate module name: %s: %#v and %#v\n", iName, iMod, jMod))
Colin Crossab6d7902015-03-11 16:17:52 -07003314 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003315 return iName < jName
3316}
3317
Colin Crossab6d7902015-03-11 16:17:52 -07003318func (s moduleSorter) Swap(i, j int) {
Jeff Gaston0e907592017-12-01 17:10:52 -08003319 s.modules[i], s.modules[j] = s.modules[j], s.modules[i]
Jamie Gennis86179fe2014-06-11 16:27:16 -07003320}
3321
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003322func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3323 headerTemplate := template.New("moduleHeader")
3324 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3325 if err != nil {
3326 // This is a programming error.
3327 panic(err)
3328 }
3329
Colin Crossab6d7902015-03-11 16:17:52 -07003330 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3331 for _, module := range c.moduleInfo {
3332 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003333 }
Jeff Gaston0e907592017-12-01 17:10:52 -08003334 sort.Sort(moduleSorter{modules, c.nameInterface})
Jamie Gennis86179fe2014-06-11 16:27:16 -07003335
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003336 buf := bytes.NewBuffer(nil)
3337
Colin Crossab6d7902015-03-11 16:17:52 -07003338 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003339 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3340 continue
3341 }
3342
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003343 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003344
3345 // In order to make the bootstrap build manifest independent of the
3346 // build dir we need to output the Blueprints file locations in the
3347 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003348 relPos := module.pos
3349 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003350
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003351 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003352 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003353 factoryName := factoryFunc.Name()
3354
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003355 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003356 "name": module.Name(),
3357 "typeName": module.typeName,
3358 "goFactory": factoryName,
3359 "pos": relPos,
3360 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003361 }
3362 err = headerTemplate.Execute(buf, infoMap)
3363 if err != nil {
3364 return err
3365 }
3366
3367 err = nw.Comment(buf.String())
3368 if err != nil {
3369 return err
3370 }
3371
3372 err = nw.BlankLine()
3373 if err != nil {
3374 return err
3375 }
3376
Colin Crossab6d7902015-03-11 16:17:52 -07003377 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003378 if err != nil {
3379 return err
3380 }
3381
3382 err = nw.BlankLine()
3383 if err != nil {
3384 return err
3385 }
3386 }
3387
3388 return nil
3389}
3390
3391func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3392 headerTemplate := template.New("singletonHeader")
3393 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3394 if err != nil {
3395 // This is a programming error.
3396 panic(err)
3397 }
3398
3399 buf := bytes.NewBuffer(nil)
3400
Yuchen Wub9103ef2015-08-25 17:58:17 -07003401 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003402 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3403 continue
3404 }
3405
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003406 // Get the name of the factory function for the module.
3407 factory := info.factory
3408 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3409 factoryName := factoryFunc.Name()
3410
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003411 buf.Reset()
3412 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003413 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003414 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003415 }
3416 err = headerTemplate.Execute(buf, infoMap)
3417 if err != nil {
3418 return err
3419 }
3420
3421 err = nw.Comment(buf.String())
3422 if err != nil {
3423 return err
3424 }
3425
3426 err = nw.BlankLine()
3427 if err != nil {
3428 return err
3429 }
3430
3431 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3432 if err != nil {
3433 return err
3434 }
3435
3436 err = nw.BlankLine()
3437 if err != nil {
3438 return err
3439 }
3440 }
3441
3442 return nil
3443}
3444
3445func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3446 defs *localBuildActions) error {
3447
3448 // Write the local variable assignments.
3449 for _, v := range defs.variables {
3450 // A localVariable doesn't need the package names or config to
3451 // determine its name or value.
3452 name := v.fullName(nil)
3453 value, err := v.value(nil)
3454 if err != nil {
3455 panic(err)
3456 }
3457 err = nw.Assign(name, value.Value(c.pkgNames))
3458 if err != nil {
3459 return err
3460 }
3461 }
3462
3463 if len(defs.variables) > 0 {
3464 err := nw.BlankLine()
3465 if err != nil {
3466 return err
3467 }
3468 }
3469
3470 // Write the local rules.
3471 for _, r := range defs.rules {
3472 // A localRule doesn't need the package names or config to determine
3473 // its name or definition.
3474 name := r.fullName(nil)
3475 def, err := r.def(nil)
3476 if err != nil {
3477 panic(err)
3478 }
3479
3480 err = def.WriteTo(nw, name, c.pkgNames)
3481 if err != nil {
3482 return err
3483 }
3484
3485 err = nw.BlankLine()
3486 if err != nil {
3487 return err
3488 }
3489 }
3490
3491 // Write the build definitions.
3492 for _, buildDef := range defs.buildDefs {
3493 err := buildDef.WriteTo(nw, c.pkgNames)
3494 if err != nil {
3495 return err
3496 }
3497
3498 if len(buildDef.Args) > 0 {
3499 err = nw.BlankLine()
3500 if err != nil {
3501 return err
3502 }
3503 }
3504 }
3505
3506 return nil
3507}
3508
Colin Cross65569e42015-03-10 20:08:19 -07003509func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3510 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003511 if a == b {
3512 return false
3513 }
Colin Cross65569e42015-03-10 20:08:19 -07003514 for _, l := range list {
3515 if l == a {
3516 found = true
3517 } else if l == b {
3518 return found
3519 }
3520 }
3521
3522 missing := a
3523 if found {
3524 missing = b
3525 }
3526 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3527}
3528
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003529type panicError struct {
3530 panic interface{}
3531 stack []byte
3532 in string
3533}
3534
3535func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3536 buf := make([]byte, 4096)
3537 count := runtime.Stack(buf, false)
3538 return panicError{
3539 panic: panic,
3540 in: fmt.Sprintf(in, a...),
3541 stack: buf[:count],
3542 }
3543}
3544
3545func (p panicError) Error() string {
3546 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3547}
3548
3549func (p *panicError) addIn(in string) {
3550 p.in += " in " + in
3551}
3552
3553func funcName(f interface{}) string {
3554 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3555}
3556
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003557var fileHeaderTemplate = `******************************************************************************
3558*** This file is generated and should not be edited ***
3559******************************************************************************
3560{{if .Pkgs}}
3561This file contains variables, rules, and pools with name prefixes indicating
3562they were generated by the following Go packages:
3563{{range .Pkgs}}
3564 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3565
3566`
3567
3568var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003569Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003570Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003571Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003572Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003573Defined: {{.pos}}
3574`
3575
3576var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3577Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003578Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003579`