blob: 5a7e558c9d7ef99f52765efd4c0ab40311d4a63d [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"
19 "errors"
20 "fmt"
21 "io"
Jeff Gastonc3e28442017-08-09 15:13:12 -070022 "io/ioutil"
Jeff Gastonaca42202017-08-23 17:30:05 -070023 "os"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070024 "path/filepath"
25 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070026 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070027 "sort"
Colin Cross6134a5c2015-02-10 11:26:26 -080028 "strconv"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 "strings"
Colin Cross127d2ea2016-11-01 11:10:51 -070030 "sync"
Colin Cross23d7aa12015-06-30 16:05:22 -070031 "sync/atomic"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070032 "text/scanner"
33 "text/template"
Colin Cross1fef5362015-04-20 16:50:54 -070034
35 "github.com/google/blueprint/parser"
Colin Crossb519a7e2017-02-01 13:21:35 -080036 "github.com/google/blueprint/pathtools"
Colin Cross1fef5362015-04-20 16:50:54 -070037 "github.com/google/blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070038)
39
40var ErrBuildActionsNotReady = errors.New("build actions are not ready")
41
42const maxErrors = 10
Jeff Gaston9f630902017-11-15 14:49:48 -080043const MockModuleListFile = "bplist"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070044
Jamie Gennisd4e10182014-06-12 20:06:50 -070045// A Context contains all the state needed to parse a set of Blueprints files
46// and generate a Ninja file. The process of generating a Ninja file proceeds
47// through a series of four phases. Each phase corresponds with a some methods
48// on the Context object
49//
50// Phase Methods
51// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070052// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070053//
54// 2. Parse ParseBlueprintsFiles, Parse
55//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070056// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070057//
58// 4. Write WriteBuildFile
59//
60// The registration phase prepares the context to process Blueprints files
61// containing various types of modules. The parse phase reads in one or more
62// Blueprints files and validates their contents against the module types that
63// have been registered. The generate phase then analyzes the parsed Blueprints
64// contents to create an internal representation for the build actions that must
65// be performed. This phase also performs validation of the module dependencies
66// and property values defined in the parsed Blueprints files. Finally, the
67// write phase generates the Ninja manifest text based on the generated build
68// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070069type Context struct {
70 // set at instantiation
Colin Cross65569e42015-03-10 20:08:19 -070071 moduleFactories map[string]ModuleFactory
Jeff Gastond70bf752017-11-10 15:12:08 -080072 nameInterface NameInterface
Colin Cross0b7e83e2016-05-17 14:58:05 -070073 moduleGroups []*moduleGroup
Colin Cross65569e42015-03-10 20:08:19 -070074 moduleInfo map[Module]*moduleInfo
75 modulesSorted []*moduleInfo
Colin Cross5f03f112017-11-07 13:29:54 -080076 preSingletonInfo []*singletonInfo
Yuchen Wub9103ef2015-08-25 17:58:17 -070077 singletonInfo []*singletonInfo
Colin Cross65569e42015-03-10 20:08:19 -070078 mutatorInfo []*mutatorInfo
Colin Crossf8b50422016-08-10 12:56:40 -070079 earlyMutatorInfo []*mutatorInfo
Colin Cross65569e42015-03-10 20:08:19 -070080 variantMutatorNames []string
81 moduleNinjaNames map[string]*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -070082
Colin Cross3702ac72016-08-11 11:09:00 -070083 depsModified uint32 // positive if a mutator modified the dependencies
84
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085 dependenciesReady bool // set to true on a successful ResolveDependencies
86 buildActionsReady bool // set to true on a successful PrepareBuildActions
87
88 // set by SetIgnoreUnknownModuleTypes
89 ignoreUnknownModuleTypes bool
90
Colin Cross036a1df2015-12-17 15:49:30 -080091 // set by SetAllowMissingDependencies
92 allowMissingDependencies bool
93
Jamie Gennis1bc967e2014-05-27 16:34:41 -070094 // set during PrepareBuildActions
Dan Willemsenaeffbf72015-11-25 15:29:32 -080095 pkgNames map[*packageContext]string
Colin Cross5f03f112017-11-07 13:29:54 -080096 liveGlobals *liveTracker
Jamie Gennis1bc967e2014-05-27 16:34:41 -070097 globalVariables map[Variable]*ninjaString
98 globalPools map[Pool]*poolDef
99 globalRules map[Rule]*ruleDef
100
101 // set during PrepareBuildActions
Colin Crossa2599452015-11-18 16:01:01 -0800102 ninjaBuildDir *ninjaString // The builddir special Ninja variable
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700103 requiredNinjaMajor int // For the ninja_required_version variable
104 requiredNinjaMinor int // For the ninja_required_version variable
105 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -0700106
Jeff Gastond70bf752017-11-10 15:12:08 -0800107 // set lazily by sortedModuleGroups
108 cachedSortedModuleGroups []*moduleGroup
Colin Crossd7b0f602016-06-02 15:30:20 -0700109
Colin Cross127d2ea2016-11-01 11:10:51 -0700110 globs map[string]GlobPath
111 globLock sync.Mutex
112
Jeff Gastonc3e28442017-08-09 15:13:12 -0700113 fs pathtools.FileSystem
114 moduleListFile string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115}
116
Jamie Gennisd4e10182014-06-12 20:06:50 -0700117// An Error describes a problem that was encountered that is related to a
118// particular location in a Blueprints file.
Colin Cross2c628442016-10-07 17:13:10 -0700119type BlueprintError struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -0700120 Err error // the error that occurred
121 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700122}
123
Colin Cross2c628442016-10-07 17:13:10 -0700124// A ModuleError describes a problem that was encountered that is related to a
125// particular module in a Blueprints file
126type ModuleError struct {
127 BlueprintError
128 module *moduleInfo
129}
130
131// A PropertyError describes a problem that was encountered that is related to a
132// particular property in a Blueprints file
133type PropertyError struct {
134 ModuleError
135 property string
136}
137
138func (e *BlueprintError) Error() string {
139 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
140}
141
142func (e *ModuleError) Error() string {
143 return fmt.Sprintf("%s: %s: %s", e.Pos, e.module, e.Err)
144}
145
146func (e *PropertyError) Error() string {
147 return fmt.Sprintf("%s: %s: %s: %s", e.Pos, e.module, e.property, e.Err)
148}
149
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700150type localBuildActions struct {
151 variables []*localVariable
152 rules []*localRule
153 buildDefs []*buildDef
154}
155
Colin Crossbbfa51a2014-12-17 16:12:41 -0800156type moduleGroup struct {
Colin Crossed342d92015-03-11 00:57:25 -0700157 name string
158 ninjaName string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700159
Colin Crossbbfa51a2014-12-17 16:12:41 -0800160 modules []*moduleInfo
Jeff Gastond70bf752017-11-10 15:12:08 -0800161
162 namespace Namespace
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700163}
164
Colin Crossbbfa51a2014-12-17 16:12:41 -0800165type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700166 // set during Parse
167 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700168 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700169 relBlueprintsFile string
170 pos scanner.Position
171 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700172
Colin Crossf5e34b92015-03-13 16:02:36 -0700173 variantName string
174 variant variationMap
175 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700176
Colin Crossd2f4ac12017-07-28 14:31:03 -0700177 logicModule Module
178 group *moduleGroup
179 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800180
181 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700182 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800183 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800184
Colin Cross7addea32015-03-11 15:43:52 -0700185 // set during updateDependencies
186 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700187 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700188
189 // used by parallelVisitAllBottomUp
190 waitingCount int
191
Colin Crossc9028482014-12-18 16:28:54 -0800192 // set during each runMutator
193 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700194
195 // set during PrepareBuildActions
196 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800197}
198
Colin Cross2c1f3d12016-04-11 15:47:28 -0700199type depInfo struct {
200 module *moduleInfo
201 tag DependencyTag
202}
203
Colin Cross0b7e83e2016-05-17 14:58:05 -0700204func (module *moduleInfo) Name() string {
205 return module.group.name
206}
207
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800208func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700209 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800210 if module.variantName != "" {
211 s += fmt.Sprintf(" variant %q", module.variantName)
212 }
213 return s
214}
215
Jeff Gastond70bf752017-11-10 15:12:08 -0800216func (module *moduleInfo) namespace() Namespace {
217 return module.group.namespace
218}
219
Colin Crossf5e34b92015-03-13 16:02:36 -0700220// A Variation is a way that a variant of a module differs from other variants of the same module.
221// For example, two variants of the same module might have Variation{"arch","arm"} and
222// Variation{"arch","arm64"}
223type Variation struct {
224 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700225 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700226 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
227 // "shared" or "static" for link.
228 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700229}
230
Colin Crossf5e34b92015-03-13 16:02:36 -0700231// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
232type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700233
Colin Crossf5e34b92015-03-13 16:02:36 -0700234func (vm variationMap) clone() variationMap {
235 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700236 for k, v := range vm {
237 newVm[k] = v
238 }
239
240 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800241}
242
Colin Cross89486232015-05-08 11:14:54 -0700243// Compare this variationMap to another one. Returns true if the every entry in this map
244// is either the same in the other map or doesn't exist in the other map.
245func (vm variationMap) subset(other variationMap) bool {
246 for k, v1 := range vm {
247 if v2, ok := other[k]; ok && v1 != v2 {
248 return false
249 }
250 }
251 return true
252}
253
Colin Crossf5e34b92015-03-13 16:02:36 -0700254func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700255 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800256}
257
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700258type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700259 // set during RegisterSingletonType
260 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700261 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700262 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700263
264 // set during PrepareBuildActions
265 actionDefs localBuildActions
266}
267
Colin Crossc9028482014-12-18 16:28:54 -0800268type mutatorInfo struct {
269 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800270 topDownMutator TopDownMutator
271 bottomUpMutator BottomUpMutator
272 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700273 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800274}
275
Colin Crossaf4fd212017-07-28 14:32:36 -0700276func newContext() *Context {
277 return &Context{
Colin Cross5f03f112017-11-07 13:29:54 -0800278 moduleFactories: make(map[string]ModuleFactory),
Jeff Gastond70bf752017-11-10 15:12:08 -0800279 nameInterface: NewSimpleNameInterface(),
Colin Cross5f03f112017-11-07 13:29:54 -0800280 moduleInfo: make(map[Module]*moduleInfo),
281 moduleNinjaNames: make(map[string]*moduleGroup),
282 globs: make(map[string]GlobPath),
283 fs: pathtools.OsFs,
284 ninjaBuildDir: nil,
285 requiredNinjaMajor: 1,
286 requiredNinjaMinor: 7,
287 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700288 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700289}
290
291// NewContext creates a new Context object. The created context initially has
292// no module or singleton factories registered, so the RegisterModuleFactory and
293// RegisterSingletonFactory methods must be called before it can do anything
294// useful.
295func NewContext() *Context {
296 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700297
298 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
299
300 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700301}
302
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700303// A ModuleFactory function creates a new Module object. See the
304// Context.RegisterModuleType method for details about how a registered
305// ModuleFactory is used by a Context.
306type ModuleFactory func() (m Module, propertyStructs []interface{})
307
Jamie Gennisd4e10182014-06-12 20:06:50 -0700308// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700309// Blueprints file) with a Module factory function. When the given module type
310// name is encountered in a Blueprints file during parsing, the Module factory
311// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800312// generation for the module. If a Mutator splits a module into multiple variants,
313// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700314//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700315// The module type names given here must be unique for the context. The factory
316// function should be a named function so that its package and name can be
317// included in the generated Ninja file for debugging purposes.
318//
319// The factory function returns two values. The first is the newly created
320// Module object. The second is a slice of pointers to that Module object's
321// properties structs. Each properties struct is examined when parsing a module
322// definition of this type in a Blueprints file. Exported fields of the
323// properties structs are automatically set to the property values specified in
324// the Blueprints file. The properties struct field names determine the name of
325// the Blueprints file properties that are used - the Blueprints property name
326// matches that of the properties struct field name with the first letter
327// converted to lower-case.
328//
329// The fields of the properties struct must be either []string, a string, or
330// bool. The Context will panic if a Module gets instantiated with a properties
331// struct containing a field that is not one these supported types.
332//
333// Any properties that appear in the Blueprints files that are not built-in
334// module properties (such as "name" and "deps") and do not have a corresponding
335// field in the returned module properties struct result in an error during the
336// Context's parse phase.
337//
338// As an example, the follow code:
339//
340// type myModule struct {
341// properties struct {
342// Foo string
343// Bar []string
344// }
345// }
346//
347// func NewMyModule() (blueprint.Module, []interface{}) {
348// module := new(myModule)
349// properties := &module.properties
350// return module, []interface{}{properties}
351// }
352//
353// func main() {
354// ctx := blueprint.NewContext()
355// ctx.RegisterModuleType("my_module", NewMyModule)
356// // ...
357// }
358//
359// would support parsing a module defined in a Blueprints file as follows:
360//
361// my_module {
362// name: "myName",
363// foo: "my foo string",
364// bar: ["my", "bar", "strings"],
365// }
366//
Colin Cross7ad621c2015-01-07 16:22:45 -0800367// The factory function may be called from multiple goroutines. Any accesses
368// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700369func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
370 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700371 panic(errors.New("module type name is already registered"))
372 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700373 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700374}
375
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700376// A SingletonFactory function creates a new Singleton object. See the
377// Context.RegisterSingletonType method for details about how a registered
378// SingletonFactory is used by a Context.
379type SingletonFactory func() Singleton
380
381// RegisterSingletonType registers a singleton type that will be invoked to
382// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700383// and invoked exactly once as part of the generate phase. Each registered
384// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700385//
386// The singleton type names given here must be unique for the context. The
387// factory function should be a named function so that its package and name can
388// be included in the generated Ninja file for debugging purposes.
389func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700390 for _, s := range c.singletonInfo {
391 if s.name == name {
392 panic(errors.New("singleton name is already registered"))
393 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700394 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700395
Yuchen Wub9103ef2015-08-25 17:58:17 -0700396 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700397 factory: factory,
398 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700399 name: name,
400 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700401}
402
Colin Cross5f03f112017-11-07 13:29:54 -0800403// RegisterPreSingletonType registers a presingleton type that will be invoked to
404// generate build actions before any Blueprint files have been read. Each registered
405// presingleton type is instantiated and invoked exactly once at the beginning of the
406// parse phase. Each registered presingleton is invoked in registration order.
407//
408// The presingleton type names given here must be unique for the context. The
409// factory function should be a named function so that its package and name can
410// be included in the generated Ninja file for debugging purposes.
411func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
412 for _, s := range c.preSingletonInfo {
413 if s.name == name {
414 panic(errors.New("presingleton name is already registered"))
415 }
416 }
417
418 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
419 factory: factory,
420 singleton: factory(),
421 name: name,
422 })
423}
424
Jeff Gastond70bf752017-11-10 15:12:08 -0800425func (c *Context) SetNameInterface(i NameInterface) {
426 c.nameInterface = i
427}
428
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700429func singletonPkgPath(singleton Singleton) string {
430 typ := reflect.TypeOf(singleton)
431 for typ.Kind() == reflect.Ptr {
432 typ = typ.Elem()
433 }
434 return typ.PkgPath()
435}
436
437func singletonTypeName(singleton Singleton) string {
438 typ := reflect.TypeOf(singleton)
439 for typ.Kind() == reflect.Ptr {
440 typ = typ.Elem()
441 }
442 return typ.PkgPath() + "." + typ.Name()
443}
444
Colin Cross3702ac72016-08-11 11:09:00 -0700445// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
446// top-down between Modules. Each registered mutator is invoked in registration order (mixing
447// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
448// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800449//
Colin Cross65569e42015-03-10 20:08:19 -0700450// The mutator type names given here must be unique to all top down mutators in
451// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700452//
453// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
454// parallel while maintaining ordering.
455func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800456 for _, m := range c.mutatorInfo {
457 if m.name == name && m.topDownMutator != nil {
458 panic(fmt.Errorf("mutator name %s is already registered", name))
459 }
460 }
461
Colin Cross3702ac72016-08-11 11:09:00 -0700462 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800463 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800464 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700465 }
466
467 c.mutatorInfo = append(c.mutatorInfo, info)
468
469 return info
Colin Crossc9028482014-12-18 16:28:54 -0800470}
471
Colin Cross3702ac72016-08-11 11:09:00 -0700472// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
473// Each registered mutator is invoked in registration order (mixing TopDownMutators and
474// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
475// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800476//
Colin Cross65569e42015-03-10 20:08:19 -0700477// The mutator type names given here must be unique to all bottom up or early
478// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700479//
Colin Cross3702ac72016-08-11 11:09:00 -0700480// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
481// parallel while maintaining ordering.
482func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700483 for _, m := range c.variantMutatorNames {
484 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800485 panic(fmt.Errorf("mutator name %s is already registered", name))
486 }
487 }
488
Colin Cross49c279a2016-08-05 22:30:44 -0700489 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800490 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800491 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700492 }
493 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700494
495 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700496
497 return info
498}
499
Colin Cross3702ac72016-08-11 11:09:00 -0700500type MutatorHandle interface {
501 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
502 // method on the mutator context is thread-safe, but the mutator must handle synchronization
503 // for any modifications to global state or any modules outside the one it was invoked on.
504 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700505}
506
Colin Cross3702ac72016-08-11 11:09:00 -0700507func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700508 mutator.parallel = true
509 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700510}
511
512// RegisterEarlyMutator registers a mutator that will be invoked to split
513// Modules into multiple variant Modules before any dependencies have been
514// created. Each registered mutator is invoked in registration order once
515// per Module (including each variant from previous early mutators). Module
516// order is unpredictable.
517//
518// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700519// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700520//
521// The mutator type names given here must be unique to all bottom up or early
522// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700523//
524// Deprecated, use a BottomUpMutator instead. The only difference between
525// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
526// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700527func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
528 for _, m := range c.variantMutatorNames {
529 if m == name {
530 panic(fmt.Errorf("mutator name %s is already registered", name))
531 }
532 }
533
Colin Crossf8b50422016-08-10 12:56:40 -0700534 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
535 bottomUpMutator: func(mctx BottomUpMutatorContext) {
536 mutator(mctx)
537 },
538 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700539 })
540
541 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800542}
543
Jamie Gennisd4e10182014-06-12 20:06:50 -0700544// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
545// where it encounters an unknown module type while parsing Blueprints files. By
546// default, the context will report unknown module types as an error. If this
547// method is called with ignoreUnknownModuleTypes set to true then the context
548// will silently ignore unknown module types.
549//
550// This method should generally not be used. It exists to facilitate the
551// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700552func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
553 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
554}
555
Colin Cross036a1df2015-12-17 15:49:30 -0800556// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
557// unresolved dependencies. If the module's GenerateBuildActions calls
558// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
559// for missing dependencies.
560func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
561 c.allowMissingDependencies = allowMissingDependencies
562}
563
Jeff Gastonc3e28442017-08-09 15:13:12 -0700564func (c *Context) SetModuleListFile(listFile string) {
565 c.moduleListFile = listFile
566}
567
568func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
569 reader, err := c.fs.Open(c.moduleListFile)
570 if err != nil {
571 return nil, err
572 }
573 bytes, err := ioutil.ReadAll(reader)
574 if err != nil {
575 return nil, err
576 }
577 text := string(bytes)
578
579 text = strings.Trim(text, "\n")
580 lines := strings.Split(text, "\n")
581 for i := range lines {
582 lines[i] = filepath.Join(baseDir, lines[i])
583 }
584
585 return lines, nil
586}
587
Jeff Gaston656870f2017-11-29 18:37:31 -0800588// a fileParseContext tells the status of parsing a particular file
589type fileParseContext struct {
590 // name of file
591 fileName string
592
593 // scope to use when resolving variables
594 Scope *parser.Scope
595
596 // pointer to the one in the parent directory
597 parent *fileParseContext
598
599 // is closed once FileHandler has completed for this file
600 doneVisiting chan struct{}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700601}
602
Jeff Gastonc3e28442017-08-09 15:13:12 -0700603func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
604 baseDir := filepath.Dir(rootFile)
605 pathsToParse, err := c.ListModulePaths(baseDir)
606 if err != nil {
607 return nil, []error{err}
608 }
609 return c.ParseFileList(baseDir, pathsToParse)
610}
611
Jamie Gennisd4e10182014-06-12 20:06:50 -0700612// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
613// at rootFile. When it encounters a Blueprints file with a set of subdirs
614// listed it recursively parses any Blueprints files found in those
615// subdirectories.
616//
617// If no errors are encountered while parsing the files, the list of paths on
618// which the future output will depend is returned. This list will include both
619// Blueprints file paths as well as directory paths for cases where wildcard
620// subdirs are found.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700621func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700622 errs []error) {
623
Jeff Gastonc3e28442017-08-09 15:13:12 -0700624 if len(filePaths) < 1 {
625 return nil, []error{fmt.Errorf("no paths provided to parse")}
626 }
627
Colin Cross7ad621c2015-01-07 16:22:45 -0800628 c.dependenciesReady = false
629
Colin Cross23d7aa12015-06-30 16:05:22 -0700630 moduleCh := make(chan *moduleInfo)
631 errsCh := make(chan []error)
632 doneCh := make(chan struct{})
633 var numErrs uint32
634 var numGoroutines int32
635
636 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700637 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700638 if atomic.LoadUint32(&numErrs) > maxErrors {
639 return
640 }
641
Jeff Gaston656870f2017-11-29 18:37:31 -0800642 for _, def := range file.Defs {
643 var module *moduleInfo
644 var errs []error
645 switch def := def.(type) {
646 case *parser.Module:
647 module, errs = c.processModuleDef(def, file.Name)
648 case *parser.Assignment:
649 // Already handled via Scope object
650 default:
651 panic("unknown definition type")
Colin Cross23d7aa12015-06-30 16:05:22 -0700652 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800653
654 if len(errs) > 0 {
655 atomic.AddUint32(&numErrs, uint32(len(errs)))
656 errsCh <- errs
657 } else if module != nil {
658 moduleCh <- module
659 }
660 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700661 }
662
663 atomic.AddInt32(&numGoroutines, 1)
664 go func() {
665 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700666 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700667 if len(errs) > 0 {
668 errsCh <- errs
669 }
670 doneCh <- struct{}{}
671 }()
672
673loop:
674 for {
675 select {
676 case newErrs := <-errsCh:
677 errs = append(errs, newErrs...)
678 case module := <-moduleCh:
679 newErrs := c.addModule(module)
680 if len(newErrs) > 0 {
681 errs = append(errs, newErrs...)
682 }
683 case <-doneCh:
684 n := atomic.AddInt32(&numGoroutines, -1)
685 if n == 0 {
686 break loop
687 }
688 }
689 }
690
691 return deps, errs
692}
693
694type FileHandler func(*parser.File)
695
Jeff Gastonc3e28442017-08-09 15:13:12 -0700696// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
697// calling the given file handler on each
698//
699// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
700// it recursively parses any Blueprints files found in those subdirectories.
701//
702// If any of the file paths is an ancestor directory of any other of file path, the ancestor
703// will be parsed and visited first.
704//
705// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700706//
707// If no errors are encountered while parsing the files, the list of paths on
708// which the future output will depend is returned. This list will include both
709// Blueprints file paths as well as directory paths for cases where wildcard
710// subdirs are found.
Jeff Gaston656870f2017-11-29 18:37:31 -0800711//
712// visitor will be called asynchronously, and will only be called once visitor for each
713// ancestor directory has completed.
714//
715// WalkBlueprintsFiles will not return until all calls to visitor have returned.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700716func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
717 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700718
Jeff Gastonc3e28442017-08-09 15:13:12 -0700719 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
720 descendantsMap, err := findBlueprintDescendants(filePaths)
721 if err != nil {
722 panic(err.Error())
723 return nil, []error{err}
724 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800725 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700726
Jeff Gaston5f763d02017-08-08 14:43:58 -0700727 // Channels to receive data back from parseOneAsync goroutines
Jeff Gaston656870f2017-11-29 18:37:31 -0800728 blueprintsCh := make(chan fileParseContext)
Colin Cross7ad621c2015-01-07 16:22:45 -0800729 errsCh := make(chan []error)
Colin Cross7ad621c2015-01-07 16:22:45 -0800730 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700731
Jeff Gaston5f763d02017-08-08 14:43:58 -0700732 // Channel to notify main loop that a parseOneAsync goroutine has finished
Jeff Gaston656870f2017-11-29 18:37:31 -0800733 doneParsingCh := make(chan fileParseContext)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700734
Colin Cross7ad621c2015-01-07 16:22:45 -0800735 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700736 activeCount := 0
Jeff Gaston656870f2017-11-29 18:37:31 -0800737 var pending []fileParseContext
Jeff Gastonc3e28442017-08-09 15:13:12 -0700738 tooManyErrors := false
739
740 // Limit concurrent calls to parseBlueprintFiles to 200
741 // Darwin has a default limit of 256 open files
742 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800743
Jeff Gaston656870f2017-11-29 18:37:31 -0800744 // count the number of pending calls to visitor()
745 visitorWaitGroup := sync.WaitGroup{}
746
747 startParseBlueprintsFile := func(blueprint fileParseContext) {
748 if blueprintsSet[blueprint.fileName] {
Colin Cross4a02a302017-05-16 10:33:58 -0700749 return
750 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800751 blueprintsSet[blueprint.fileName] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700752 activeCount++
Jeff Gaston656870f2017-11-29 18:37:31 -0800753 deps = append(deps, blueprint.fileName)
754 visitorWaitGroup.Add(1)
Colin Cross7ad621c2015-01-07 16:22:45 -0800755 go func() {
Jeff Gaston656870f2017-11-29 18:37:31 -0800756 file := c.parseOneAsync(blueprint.fileName, blueprint.Scope, rootDir,
757 errsCh, blueprintsCh, depsCh, &blueprint)
758 doneParsingCh <- blueprint
Jeff Gaston5f763d02017-08-08 14:43:58 -0700759
Jeff Gaston656870f2017-11-29 18:37:31 -0800760 if blueprint.parent != nil && blueprint.parent.doneVisiting != nil {
761 // wait for visitor() of parent to complete
762 <-blueprint.parent.doneVisiting
763 }
764
765 // process this file
766 visitor(file)
767 if blueprint.doneVisiting != nil {
768 close(blueprint.doneVisiting)
769 }
770 visitorWaitGroup.Done()
Colin Cross7ad621c2015-01-07 16:22:45 -0800771 }()
772 }
773
Jeff Gaston656870f2017-11-29 18:37:31 -0800774 foundParseableBlueprint := func(blueprint fileParseContext) {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700775 if activeCount >= maxActiveCount {
776 pending = append(pending, blueprint)
777 } else {
778 startParseBlueprintsFile(blueprint)
779 }
780 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800781
Jeff Gaston656870f2017-11-29 18:37:31 -0800782 startParseDescendants := func(blueprint fileParseContext) {
783 descendants, hasDescendants := descendantsMap[blueprint.fileName]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700784 if hasDescendants {
785 for _, descendant := range descendants {
Jeff Gaston656870f2017-11-29 18:37:31 -0800786 foundParseableBlueprint(fileParseContext{descendant, parser.NewScope(blueprint.Scope), &blueprint, make(chan struct{})})
Jeff Gastonc3e28442017-08-09 15:13:12 -0700787 }
788 }
789 }
Colin Cross4a02a302017-05-16 10:33:58 -0700790
Jeff Gastonc3e28442017-08-09 15:13:12 -0700791 // begin parsing any files that have no ancestors
Jeff Gaston656870f2017-11-29 18:37:31 -0800792 startParseDescendants(fileParseContext{"", parser.NewScope(nil), nil, nil})
Colin Cross7ad621c2015-01-07 16:22:45 -0800793
794loop:
795 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700796 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800797 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700798 }
799
Colin Cross7ad621c2015-01-07 16:22:45 -0800800 select {
801 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700802 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800803 case dep := <-depsCh:
804 deps = append(deps, dep)
Colin Cross7ad621c2015-01-07 16:22:45 -0800805 case blueprint := <-blueprintsCh:
806 if tooManyErrors {
807 continue
808 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700809 foundParseableBlueprint(blueprint)
Jeff Gaston656870f2017-11-29 18:37:31 -0800810 case blueprint := <-doneParsingCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700811 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700812 if !tooManyErrors {
813 startParseDescendants(blueprint)
814 }
815 if activeCount < maxActiveCount && len(pending) > 0 {
816 // start to process the next one from the queue
817 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700818 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700819 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700820 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700821 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800822 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700823 }
824 }
825 }
826
Jeff Gastonc3e28442017-08-09 15:13:12 -0700827 sort.Strings(deps)
828
Jeff Gaston656870f2017-11-29 18:37:31 -0800829 // wait for every visitor() to complete
830 visitorWaitGroup.Wait()
831
Colin Cross7ad621c2015-01-07 16:22:45 -0800832 return
833}
834
Colin Crossd7b0f602016-06-02 15:30:20 -0700835// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
836// filenames to contents stored as a byte slice.
837func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800838 // look for a module list file
839 _, ok := files[MockModuleListFile]
840 if !ok {
841 // no module list file specified; find every file named Blueprints
842 pathsToParse := []string{}
843 for candidate := range files {
844 if filepath.Base(candidate) == "Blueprints" {
845 pathsToParse = append(pathsToParse, candidate)
846 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700847 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800848 if len(pathsToParse) < 1 {
849 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
850 }
851 // put the list of Blueprints files into a list file
852 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700853 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800854 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700855
856 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800857 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700858}
859
Jeff Gaston5f763d02017-08-08 14:43:58 -0700860// parseOneAsync parses a single Blueprints file, and sends results through the provided channels
861//
862// Errors are returned through errsCh.
863// Any defined modules are returned through modulesCh.
864// Any sub-Blueprints files are returned through blueprintsCh.
865// Any dependencies on Blueprints files or directories are returned through depsCh.
Jeff Gaston5f763d02017-08-08 14:43:58 -0700866func (c *Context) parseOneAsync(filename string, scope *parser.Scope, rootDir string,
Jeff Gaston656870f2017-11-29 18:37:31 -0800867 errsCh chan<- []error, blueprintsCh chan<- fileParseContext,
868 depsCh chan<- string, parent *fileParseContext) (file *parser.File) {
Colin Cross7ad621c2015-01-07 16:22:45 -0800869
Colin Crossd7b0f602016-06-02 15:30:20 -0700870 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800871 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700872 // couldn't open the file; see if we can provide a clearer error than "could not open file"
873 stats, statErr := c.fs.Lstat(filename)
874 if statErr == nil {
875 isSymlink := stats.Mode()&os.ModeSymlink != 0
876 if isSymlink {
877 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
878 target, readlinkErr := os.Readlink(filename)
879 if readlinkErr == nil {
880 _, targetStatsErr := c.fs.Lstat(target)
881 if targetStatsErr != nil {
882 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
883 }
884 }
885 } else {
886 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
887 }
888 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800889 errsCh <- []error{err}
Jeff Gaston656870f2017-11-29 18:37:31 -0800890 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700891 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800892
Colin Cross23d7aa12015-06-30 16:05:22 -0700893 defer func() {
894 err = f.Close()
895 if err != nil {
896 errsCh <- []error{err}
897 }
898 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700899
Jeff Gaston656870f2017-11-29 18:37:31 -0800900 file, subBlueprints, errs := c.parseOne(rootDir, filename, f, scope, parent)
Colin Cross7ad621c2015-01-07 16:22:45 -0800901 if len(errs) > 0 {
902 errsCh <- errs
903 }
904
Colin Cross1fef5362015-04-20 16:50:54 -0700905 for _, b := range subBlueprints {
906 blueprintsCh <- b
Jeff Gaston656870f2017-11-29 18:37:31 -0800907 depsCh <- b.fileName
Colin Cross1fef5362015-04-20 16:50:54 -0700908 }
Jeff Gaston656870f2017-11-29 18:37:31 -0800909
910 return file
Colin Cross1fef5362015-04-20 16:50:54 -0700911}
912
Jeff Gastona12f22f2017-08-08 14:45:56 -0700913// parseOne parses a single Blueprints file from the given reader, creating Module
914// objects for each of the module definitions encountered. If the Blueprints
915// file contains an assignment to the "subdirs" variable, then the
916// subdirectories listed are searched for Blueprints files returned in the
917// subBlueprints return value. If the Blueprints file contains an assignment
918// to the "build" variable, then the file listed are returned in the
919// subBlueprints return value.
920//
921// rootDir specifies the path to the root directory of the source tree, while
922// filename specifies the path to the Blueprints file. These paths are used for
923// error reporting and for determining the module's directory.
924func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
Jeff Gaston656870f2017-11-29 18:37:31 -0800925 scope *parser.Scope, parent *fileParseContext) (file *parser.File, subBlueprints []fileParseContext, errs []error) {
Jeff Gastona12f22f2017-08-08 14:45:56 -0700926
927 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
928 if err != nil {
929 return nil, nil, []error{err}
930 }
931
Jeff Gastona12f22f2017-08-08 14:45:56 -0700932 scope.Remove("subdirs")
933 scope.Remove("optional_subdirs")
934 scope.Remove("build")
935 file, errs = parser.ParseAndEval(filename, reader, scope)
936 if len(errs) > 0 {
937 for i, err := range errs {
938 if parseErr, ok := err.(*parser.ParseError); ok {
939 err = &BlueprintError{
940 Err: parseErr.Err,
941 Pos: parseErr.Pos,
942 }
943 errs[i] = err
944 }
945 }
946
947 // If there were any parse errors don't bother trying to interpret the
948 // result.
949 return nil, nil, errs
950 }
951 file.Name = relBlueprintsFile
952
Jeff Gastona12f22f2017-08-08 14:45:56 -0700953 build, buildPos, err := getLocalStringListFromScope(scope, "build")
954 if err != nil {
955 errs = append(errs, err)
956 }
Jeff Gastonf23e3662017-11-30 17:31:43 -0800957 for _, buildEntry := range build {
958 if strings.Contains(buildEntry, "/") {
959 errs = append(errs, &BlueprintError{
960 Err: fmt.Errorf("illegal value %v. The '/' character is not permitted", buildEntry),
961 Pos: buildPos,
962 })
963 }
964 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700965
966 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
967 if err != nil {
968 errs = append(errs, err)
969 }
970
971 if subBlueprintsName == "" {
972 subBlueprintsName = "Blueprints"
973 }
974
975 var blueprints []string
976
977 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
978 blueprints = append(blueprints, newBlueprints...)
979 errs = append(errs, newErrs...)
980
Jeff Gaston656870f2017-11-29 18:37:31 -0800981 subBlueprintsAndScope := make([]fileParseContext, len(blueprints))
Jeff Gastona12f22f2017-08-08 14:45:56 -0700982 for i, b := range blueprints {
Jeff Gaston656870f2017-11-29 18:37:31 -0800983 subBlueprintsAndScope[i] = fileParseContext{b, parser.NewScope(scope), parent, make(chan struct{})}
Jeff Gastona12f22f2017-08-08 14:45:56 -0700984 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700985 return file, subBlueprintsAndScope, errs
986}
987
Colin Cross7f507402015-12-16 13:03:41 -0800988func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -0700989 buildPos scanner.Position) ([]string, []error) {
990
991 var blueprints []string
992 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -0800993
994 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -0700995 pattern := filepath.Join(dir, file)
996 var matches []string
997 var err error
998
Colin Cross08e49542016-11-14 15:23:33 -0800999 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001000
Colin Cross7f507402015-12-16 13:03:41 -08001001 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001002 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001003 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -08001004 Pos: buildPos,
1005 })
1006 continue
1007 }
1008
1009 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -07001010 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001011 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -08001012 Pos: buildPos,
1013 })
1014 }
1015
Colin Cross7f507402015-12-16 13:03:41 -08001016 for _, foundBlueprints := range matches {
Colin Cross7f507402015-12-16 13:03:41 -08001017 blueprints = append(blueprints, foundBlueprints)
1018 }
1019 }
1020
Colin Cross127d2ea2016-11-01 11:10:51 -07001021 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -08001022}
1023
1024func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -07001025 subBlueprintsName string, optional bool) ([]string, []error) {
1026
1027 var blueprints []string
1028 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -08001029
1030 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -07001031 pattern := filepath.Join(dir, subdir, subBlueprintsName)
1032 var matches []string
1033 var err error
1034
Colin Cross08e49542016-11-14 15:23:33 -08001035 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -07001036
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001037 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -07001038 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001039 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -07001040 Pos: subdirsPos,
1041 })
1042 continue
1043 }
1044
Colin Cross7f507402015-12-16 13:03:41 -08001045 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001046 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001047 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001048 Pos: subdirsPos,
1049 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001050 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001051
Colin Cross127d2ea2016-11-01 11:10:51 -07001052 for _, subBlueprints := range matches {
1053 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001054 }
1055 }
Colin Cross1fef5362015-04-20 16:50:54 -07001056
Colin Cross127d2ea2016-11-01 11:10:51 -07001057 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001058}
1059
Colin Cross6d8780f2015-07-10 17:51:55 -07001060func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1061 if assignment, local := scope.Get(v); assignment == nil || !local {
1062 return nil, scanner.Position{}, nil
1063 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001064 switch value := assignment.Value.Eval().(type) {
1065 case *parser.List:
1066 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001067
Colin Crosse32cc802016-06-07 12:28:16 -07001068 for _, listValue := range value.Values {
1069 s, ok := listValue.(*parser.String)
1070 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001071 // The parser should not produce this.
1072 panic("non-string value found in list")
1073 }
1074
Colin Crosse32cc802016-06-07 12:28:16 -07001075 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001076 }
1077
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001078 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001079 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001080 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001081 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001082 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001083 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001084 default:
1085 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
1086 }
1087 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001088}
1089
Colin Cross29394222015-04-27 13:18:21 -07001090func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001091 if assignment, _ := scope.Get(v); assignment == nil {
1092 return "", scanner.Position{}, nil
1093 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001094 switch value := assignment.Value.Eval().(type) {
1095 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001096 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001097 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001098 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001099 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001100 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001101 }
1102 default:
1103 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
1104 }
1105 }
Colin Cross29394222015-04-27 13:18:21 -07001106}
1107
Colin Cross910242b2016-04-11 15:41:52 -07001108// Clones a build logic module by calling the factory method for its module type, and then cloning
1109// property values. Any values stored in the module object that are not stored in properties
1110// structs will be lost.
1111func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001112 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001113
Colin Crossd2f4ac12017-07-28 14:31:03 -07001114 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001115 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001116 }
1117
1118 for i := range newProperties {
1119 dst := reflect.ValueOf(newProperties[i]).Elem()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001120 src := reflect.ValueOf(origModule.properties[i]).Elem()
Colin Cross910242b2016-04-11 15:41:52 -07001121
1122 proptools.CopyProperties(dst, src)
1123 }
1124
1125 return newLogicModule, newProperties
1126}
1127
Colin Crossf5e34b92015-03-13 16:02:36 -07001128func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
1129 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001130
Colin Crossf4d18a62015-03-18 17:43:15 -07001131 if len(variationNames) == 0 {
1132 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001133 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001134 }
1135
Colin Crossc9028482014-12-18 16:28:54 -08001136 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001137
Colin Cross174ae052015-03-03 17:37:03 -08001138 var errs []error
1139
Colin Crossf5e34b92015-03-13 16:02:36 -07001140 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001141 var newLogicModule Module
1142 var newProperties []interface{}
1143
1144 if i == 0 {
1145 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001146 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1147 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001148 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001149 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001150 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001151 }
1152
Colin Crossf5e34b92015-03-13 16:02:36 -07001153 newVariant := origModule.variant.clone()
1154 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001155
Colin Crossed342d92015-03-11 00:57:25 -07001156 m := *origModule
1157 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001158 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001159 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001160 newModule.variant = newVariant
1161 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001162 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001163
Colin Crossbadc8812016-08-11 17:01:46 -07001164 if variationName != "" {
1165 if newModule.variantName == "" {
1166 newModule.variantName = variationName
1167 } else {
1168 newModule.variantName += "_" + variationName
1169 }
Colin Crosse7daa222015-03-11 14:35:41 -07001170 }
1171
Colin Crossc9028482014-12-18 16:28:54 -08001172 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001173
Colin Crossf5e34b92015-03-13 16:02:36 -07001174 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001175 if len(newErrs) > 0 {
1176 errs = append(errs, newErrs...)
1177 }
Colin Crossc9028482014-12-18 16:28:54 -08001178 }
1179
1180 // Mark original variant as invalid. Modules that depend on this module will still
1181 // depend on origModule, but we'll fix it when the mutator is called on them.
1182 origModule.logicModule = nil
1183 origModule.splitModules = newModules
1184
Colin Cross3702ac72016-08-11 11:09:00 -07001185 atomic.AddUint32(&c.depsModified, 1)
1186
Colin Cross174ae052015-03-03 17:37:03 -08001187 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001188}
1189
Colin Crossf5e34b92015-03-13 16:02:36 -07001190func (c *Context) convertDepsToVariation(module *moduleInfo,
1191 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001192
Colin Crossc9028482014-12-18 16:28:54 -08001193 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001194 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001195 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001196 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001197 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001198 newDep = m
1199 break
1200 }
1201 }
1202 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001203 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001204 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001205 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001206 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001207 })
1208 continue
Colin Crossc9028482014-12-18 16:28:54 -08001209 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001210 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001211 }
1212 }
Colin Cross174ae052015-03-03 17:37:03 -08001213
1214 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001215}
1216
Colin Crossf5e34b92015-03-13 16:02:36 -07001217func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001218 names := make([]string, 0, len(variant))
1219 for _, m := range c.variantMutatorNames {
1220 if v, ok := variant[m]; ok {
1221 names = append(names, m+":"+v)
1222 }
1223 }
1224
1225 return strings.Join(names, ", ")
1226}
1227
Colin Crossaf4fd212017-07-28 14:32:36 -07001228func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
1229 logicModule, properties := factory()
1230
1231 module := &moduleInfo{
1232 logicModule: logicModule,
1233 factory: factory,
1234 }
1235
1236 module.properties = properties
1237
1238 return module
1239}
1240
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001241func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001242 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001243
Colin Crossc32c4792016-06-09 15:52:30 -07001244 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001245 if !ok {
1246 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001247 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001248 }
1249
Colin Cross7ad621c2015-01-07 16:22:45 -08001250 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001251 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001252 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1253 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001254 },
1255 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001256 }
1257
Colin Crossaf4fd212017-07-28 14:32:36 -07001258 module := c.newModule(factory)
1259 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001260
Colin Crossaf4fd212017-07-28 14:32:36 -07001261 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001262
Colin Crossaf4fd212017-07-28 14:32:36 -07001263 propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001264 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001265 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001266 }
1267
Colin Crossc32c4792016-06-09 15:52:30 -07001268 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001269 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001270 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001271 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001272 }
1273
Colin Cross7ad621c2015-01-07 16:22:45 -08001274 return module, nil
1275}
1276
Colin Cross23d7aa12015-06-30 16:05:22 -07001277func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001278 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001279 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001280
Colin Cross0b7e83e2016-05-17 14:58:05 -07001281 ninjaName := toNinjaName(name)
Colin Cross0b7e83e2016-05-17 14:58:05 -07001282 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1283 // already exists
1284 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1285 ninjaName = toNinjaName(name) + strconv.Itoa(i)
1286 }
1287
1288 group := &moduleGroup{
1289 name: name,
1290 ninjaName: ninjaName,
1291 modules: []*moduleInfo{module},
1292 }
1293 module.group = group
Jeff Gastond70bf752017-11-10 15:12:08 -08001294 namespace, errs := c.nameInterface.NewModule(
Jeff Gaston3c8c3342017-11-30 17:30:42 -08001295 &namespaceContextImpl{c.ModulePath(module.logicModule)},
Jeff Gastond70bf752017-11-10 15:12:08 -08001296 ModuleGroup{moduleGroup: group},
1297 module.logicModule)
1298 if len(errs) > 0 {
1299 for i := range errs {
1300 errs[i] = &BlueprintError{Err: errs[i], Pos: module.pos}
1301 }
1302 return errs
1303 }
1304 group.namespace = namespace
1305
Colin Cross0b7e83e2016-05-17 14:58:05 -07001306 c.moduleNinjaNames[ninjaName] = group
1307 c.moduleGroups = append(c.moduleGroups, group)
1308
Colin Cross23d7aa12015-06-30 16:05:22 -07001309 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001310}
1311
Jamie Gennisd4e10182014-06-12 20:06:50 -07001312// ResolveDependencies checks that the dependencies specified by all of the
1313// modules defined in the parsed Blueprints files are valid. This means that
1314// the modules depended upon are defined and that no circular dependencies
1315// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001316func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross5f03f112017-11-07 13:29:54 -08001317 c.liveGlobals = newLiveTracker(config)
1318
1319 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1320 if len(errs) > 0 {
1321 return nil, errs
1322 }
1323
Colin Cross874a3462017-07-31 17:26:06 -07001324 errs = c.updateDependencies()
Colin Crossf8b50422016-08-10 12:56:40 -07001325 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001326 return nil, errs
Colin Crossf8b50422016-08-10 12:56:40 -07001327 }
1328
Colin Cross5f03f112017-11-07 13:29:54 -08001329 mutatorDeps, errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001330 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001331 return nil, errs
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001332 }
Colin Cross5f03f112017-11-07 13:29:54 -08001333 deps = append(deps, mutatorDeps...)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001334
Colin Cross910242b2016-04-11 15:41:52 -07001335 c.cloneModules()
1336
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001337 c.dependenciesReady = true
Colin Cross874a3462017-07-31 17:26:06 -07001338 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001339}
1340
Colin Cross763b6f12015-10-29 15:32:56 -07001341// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001342// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001343// module names returned by its DynamicDependencies method and those added by calling
1344// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001345func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001346 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001347 func() {
1348 defer func() {
1349 if r := recover(); r != nil {
1350 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1351 }
1352 }()
1353 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001354
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001355 if ctx.Failed() {
1356 return
1357 }
Colin Cross763b6f12015-10-29 15:32:56 -07001358
Colin Cross2c1f3d12016-04-11 15:47:28 -07001359 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001360 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001361 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001362}
1363
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001364// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1365// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001366func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1367 if len(possible) == 1 {
1368 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001369 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001370 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001371 if m.variant.equal(module.dependencyVariant) {
1372 return m
1373 }
1374 }
1375 }
1376
1377 return nil
1378}
1379
Colin Cross2c1f3d12016-04-11 15:47:28 -07001380func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001381 if _, ok := tag.(BaseDependencyTag); ok {
1382 panic("BaseDependencyTag is not allowed to be used directly!")
1383 }
1384
Colin Cross0b7e83e2016-05-17 14:58:05 -07001385 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001386 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001387 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001388 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001389 }}
1390 }
1391
Jeff Gastond70bf752017-11-10 15:12:08 -08001392 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001393 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001394 return c.discoveredMissingDependencies(module, depName)
Colin Crossc9028482014-12-18 16:28:54 -08001395 }
1396
Colin Cross0b7e83e2016-05-17 14:58:05 -07001397 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001398 for _, dep := range module.directDeps {
1399 if m == dep.module {
1400 // TODO(ccross): what if adding a dependency with a different tag?
1401 return nil
1402 }
Colin Cross65569e42015-03-10 20:08:19 -07001403 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001404 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001405 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001406 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001407 }
Colin Crossc9028482014-12-18 16:28:54 -08001408
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001409 variants := make([]string, len(possibleDeps))
1410 for i, mod := range possibleDeps {
1411 variants[i] = c.prettyPrintVariant(mod.variant)
1412 }
1413 sort.Strings(variants)
1414
Colin Cross2c628442016-10-07 17:13:10 -07001415 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001416 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001417 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001418 c.prettyPrintVariant(module.dependencyVariant),
1419 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001420 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001421 }}
1422}
1423
Colin Cross8d8a7af2015-11-03 16:41:29 -08001424func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001425 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001426 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001427 Err: fmt.Errorf("%q depends on itself", destName),
1428 Pos: module.pos,
1429 }}
1430 }
1431
Jeff Gastond70bf752017-11-10 15:12:08 -08001432 possibleDeps := c.modulesFromName(destName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001433 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001434 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001435 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001436 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001437 Pos: module.pos,
1438 }}
1439 }
1440
Colin Cross0b7e83e2016-05-17 14:58:05 -07001441 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001442 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001443 }
1444
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001445 variants := make([]string, len(possibleDeps))
1446 for i, mod := range possibleDeps {
1447 variants[i] = c.prettyPrintVariant(mod.variant)
1448 }
1449 sort.Strings(variants)
1450
Colin Cross2c628442016-10-07 17:13:10 -07001451 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001452 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001453 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001454 c.prettyPrintVariant(module.dependencyVariant),
1455 strings.Join(variants, "\n ")),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001456 Pos: module.pos,
1457 }}
1458}
1459
Colin Crossf5e34b92015-03-13 16:02:36 -07001460func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001461 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001462 if _, ok := tag.(BaseDependencyTag); ok {
1463 panic("BaseDependencyTag is not allowed to be used directly!")
1464 }
Colin Cross65569e42015-03-10 20:08:19 -07001465
Jeff Gastond70bf752017-11-10 15:12:08 -08001466 possibleDeps := c.modulesFromName(depName, module.namespace())
Colin Cross0b7e83e2016-05-17 14:58:05 -07001467 if possibleDeps == nil {
Jeff Gastond70bf752017-11-10 15:12:08 -08001468 return c.discoveredMissingDependencies(module, depName)
Colin Cross65569e42015-03-10 20:08:19 -07001469 }
1470
1471 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1472 // compare the strings because the result won't be in mutator registration order.
1473 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001474 var newVariant variationMap
1475 if !far {
1476 newVariant = module.dependencyVariant.clone()
1477 } else {
1478 newVariant = make(variationMap)
1479 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001480 for _, v := range variations {
1481 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001482 }
1483
Colin Cross0b7e83e2016-05-17 14:58:05 -07001484 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001485 var found bool
1486 if far {
1487 found = m.variant.subset(newVariant)
1488 } else {
1489 found = m.variant.equal(newVariant)
1490 }
1491 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001492 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001493 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001494 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001495 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001496 }}
1497 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001498 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001499 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001500 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001501 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001502 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001503 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001504 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001505 }}
1506 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001507 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001508 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001509 return nil
1510 }
1511 }
1512
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001513 variants := make([]string, len(possibleDeps))
1514 for i, mod := range possibleDeps {
1515 variants[i] = c.prettyPrintVariant(mod.variant)
1516 }
1517 sort.Strings(variants)
1518
Colin Cross2c628442016-10-07 17:13:10 -07001519 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001520 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001521 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001522 c.prettyPrintVariant(newVariant),
1523 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001524 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001525 }}
Colin Crossc9028482014-12-18 16:28:54 -08001526}
1527
Colin Crossf1875462016-04-11 17:33:13 -07001528func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1529 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001530 if _, ok := tag.(BaseDependencyTag); ok {
1531 panic("BaseDependencyTag is not allowed to be used directly!")
1532 }
Colin Crossf1875462016-04-11 17:33:13 -07001533
1534 var fromInfo, toInfo *moduleInfo
1535 for _, m := range origModule.splitModules {
1536 if m.logicModule == from {
1537 fromInfo = m
1538 }
1539 if m.logicModule == to {
1540 toInfo = m
1541 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001542 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001543 }
1544 }
1545 }
1546
1547 if fromInfo == nil || toInfo == nil {
1548 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001549 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001550 }
1551
1552 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001553 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001554}
1555
Jeff Gastonc3e28442017-08-09 15:13:12 -07001556// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1557// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1558// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1559func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1560 // make mapping from dir path to file path
1561 filesByDir := make(map[string]string, len(paths))
1562 for _, path := range paths {
1563 dir := filepath.Dir(path)
1564 _, alreadyFound := filesByDir[dir]
1565 if alreadyFound {
1566 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1567 }
1568 filesByDir[dir] = path
1569 }
1570
Jeff Gaston656870f2017-11-29 18:37:31 -08001571 findAncestor := func(childFile string) (ancestor string) {
1572 prevAncestorDir := filepath.Dir(childFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -07001573 for {
1574 ancestorDir := filepath.Dir(prevAncestorDir)
1575 if ancestorDir == prevAncestorDir {
1576 // reached the root dir without any matches; assign this as a descendant of ""
Jeff Gaston656870f2017-11-29 18:37:31 -08001577 return ""
Jeff Gastonc3e28442017-08-09 15:13:12 -07001578 }
1579
1580 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1581 if ancestorExists {
Jeff Gaston656870f2017-11-29 18:37:31 -08001582 return ancestorFile
Jeff Gastonc3e28442017-08-09 15:13:12 -07001583 }
1584 prevAncestorDir = ancestorDir
1585 }
1586 }
Jeff Gaston656870f2017-11-29 18:37:31 -08001587 // generate the descendants map
1588 descendants = make(map[string][]string, len(filesByDir))
1589 for _, childFile := range filesByDir {
1590 ancestorFile := findAncestor(childFile)
1591 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1592 }
Jeff Gastonc3e28442017-08-09 15:13:12 -07001593 return descendants, nil
1594}
1595
Colin Cross3702ac72016-08-11 11:09:00 -07001596type visitOrderer interface {
1597 // returns the number of modules that this module needs to wait for
1598 waitCount(module *moduleInfo) int
1599 // returns the list of modules that are waiting for this module
1600 propagate(module *moduleInfo) []*moduleInfo
1601 // visit modules in order
1602 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1603}
1604
1605type bottomUpVisitorImpl struct{}
1606
1607func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1608 return len(module.forwardDeps)
1609}
1610
1611func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1612 return module.reverseDeps
1613}
1614
1615func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1616 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001617 if visit(module) {
1618 return
1619 }
1620 }
1621}
1622
Colin Cross3702ac72016-08-11 11:09:00 -07001623type topDownVisitorImpl struct{}
1624
1625func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1626 return len(module.reverseDeps)
1627}
1628
1629func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1630 return module.forwardDeps
1631}
1632
1633func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1634 for i := 0; i < len(modules); i++ {
1635 module := modules[len(modules)-1-i]
1636 if visit(module) {
1637 return
1638 }
1639 }
1640}
1641
1642var (
1643 bottomUpVisitor bottomUpVisitorImpl
1644 topDownVisitor topDownVisitorImpl
1645)
1646
Colin Cross49c279a2016-08-05 22:30:44 -07001647// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1648// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001649func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001650 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001651 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001652 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001653 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001654
Colin Cross7addea32015-03-11 15:43:52 -07001655 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001656 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001657 }
1658
Colin Cross7addea32015-03-11 15:43:52 -07001659 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001660 count++
1661 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001662 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001663 if ret {
Colin Cross0fff7422016-08-11 15:37:45 -07001664 cancelCh <- true
Colin Cross8900e9b2015-03-02 14:03:01 -08001665 }
Colin Cross7addea32015-03-11 15:43:52 -07001666 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001667 }()
1668 }
1669
Colin Cross7addea32015-03-11 15:43:52 -07001670 for _, module := range c.modulesSorted {
1671 if module.waitingCount == 0 {
1672 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001673 }
1674 }
1675
Colin Cross11e3b0d2015-02-04 10:41:00 -08001676 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001677 select {
Colin Cross0fff7422016-08-11 15:37:45 -07001678 case cancel = <-cancelCh:
Colin Cross7addea32015-03-11 15:43:52 -07001679 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001680 if !cancel {
Colin Cross3702ac72016-08-11 11:09:00 -07001681 for _, module := range order.propagate(doneModule) {
1682 module.waitingCount--
1683 if module.waitingCount == 0 {
1684 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001685 }
Colin Cross691a60d2015-01-07 18:08:56 -08001686 }
1687 }
1688 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001689 }
1690 }
1691}
1692
1693// updateDependencies recursively walks the module dependency graph and updates
1694// additional fields based on the dependencies. It builds a sorted list of modules
1695// such that dependencies of a module always appear first, and populates reverse
1696// dependency links and counts of total dependencies. It also reports errors when
1697// it encounters dependency cycles. This should called after resolveDependencies,
1698// as well as after any mutator pass has called addDependency
1699func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001700 visited := make(map[*moduleInfo]bool) // modules that were already checked
1701 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001702
Colin Cross7addea32015-03-11 15:43:52 -07001703 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001704
Colin Cross7addea32015-03-11 15:43:52 -07001705 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001706
Colin Cross7addea32015-03-11 15:43:52 -07001707 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001708 // We are the "start" of the cycle, so we're responsible
1709 // for generating the errors. The cycle list is in
1710 // reverse order because all the 'check' calls append
1711 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001712 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001713 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001714 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001715 })
1716
1717 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001718 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001719 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001720 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001721 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001722 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001723 curModule.Name(),
1724 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001725 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001726 })
Colin Cross7addea32015-03-11 15:43:52 -07001727 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001728 }
1729 }
1730
Colin Cross7addea32015-03-11 15:43:52 -07001731 check = func(module *moduleInfo) []*moduleInfo {
1732 visited[module] = true
1733 checking[module] = true
1734 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001735
Colin Cross7addea32015-03-11 15:43:52 -07001736 deps := make(map[*moduleInfo]bool)
1737
1738 // Add an implicit dependency ordering on all earlier modules in the same module group
1739 for _, dep := range module.group.modules {
1740 if dep == module {
1741 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001742 }
Colin Cross7addea32015-03-11 15:43:52 -07001743 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001744 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001745
Colin Cross7addea32015-03-11 15:43:52 -07001746 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001747 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001748 }
1749
1750 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001751 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001752
Colin Crossbbfa51a2014-12-17 16:12:41 -08001753 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001754 if checking[dep] {
1755 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001756 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001757 }
1758
1759 if !visited[dep] {
1760 cycle := check(dep)
1761 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001762 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001763 // We are the "start" of the cycle, so we're responsible
1764 // for generating the errors. The cycle list is in
1765 // reverse order because all the 'check' calls append
1766 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001767 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001768
1769 // We can continue processing this module's children to
1770 // find more cycles. Since all the modules that were
1771 // part of the found cycle were marked as visited we
1772 // won't run into that cycle again.
1773 } else {
1774 // We're not the "start" of the cycle, so we just append
1775 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001776 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001777 }
1778 }
1779 }
Colin Cross691a60d2015-01-07 18:08:56 -08001780
Colin Cross3702ac72016-08-11 11:09:00 -07001781 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001782 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001783 }
1784
Colin Cross7addea32015-03-11 15:43:52 -07001785 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001786
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001787 return nil
1788 }
1789
Colin Cross7addea32015-03-11 15:43:52 -07001790 for _, module := range c.moduleInfo {
1791 if !visited[module] {
1792 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001793 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001794 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001795 panic("inconceivable!")
1796 }
1797 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 }
1799 }
1800 }
1801
Colin Cross7addea32015-03-11 15:43:52 -07001802 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001803
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001804 return
1805}
1806
Jamie Gennisd4e10182014-06-12 20:06:50 -07001807// PrepareBuildActions generates an internal representation of all the build
1808// actions that need to be performed. This process involves invoking the
1809// GenerateBuildActions method on each of the Module objects created during the
1810// parse phase and then on each of the registered Singleton objects.
1811//
1812// If the ResolveDependencies method has not already been called it is called
1813// automatically by this method.
1814//
1815// The config argument is made available to all of the Module and Singleton
1816// objects via the Config method on the ModuleContext and SingletonContext
1817// objects passed to GenerateBuildActions. It is also passed to the functions
1818// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1819// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001820//
1821// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001822// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1823// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1824// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001825func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001826 c.buildActionsReady = false
1827
1828 if !c.dependenciesReady {
Colin Cross874a3462017-07-31 17:26:06 -07001829 extraDeps, errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001830 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001831 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001832 }
Colin Cross874a3462017-07-31 17:26:06 -07001833 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001834 }
1835
Colin Cross5f03f112017-11-07 13:29:54 -08001836 depsModules, errs := c.generateModuleBuildActions(config, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001837 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001838 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001839 }
1840
Colin Cross5f03f112017-11-07 13:29:54 -08001841 depsSingletons, errs := c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001842 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001843 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001844 }
1845
Colin Cross874a3462017-07-31 17:26:06 -07001846 deps = append(deps, depsModules...)
1847 deps = append(deps, depsSingletons...)
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001848
Colin Crossa2599452015-11-18 16:01:01 -08001849 if c.ninjaBuildDir != nil {
Colin Cross5f03f112017-11-07 13:29:54 -08001850 c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001851 }
1852
Colin Cross5f03f112017-11-07 13:29:54 -08001853 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
Dan Willemsena481ae22015-12-18 15:18:03 -08001854
1855 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001856
1857 // This will panic if it finds a problem since it's a programming error.
Colin Cross5f03f112017-11-07 13:29:54 -08001858 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001859
1860 c.pkgNames = pkgNames
Colin Cross5f03f112017-11-07 13:29:54 -08001861 c.globalVariables = c.liveGlobals.variables
1862 c.globalPools = c.liveGlobals.pools
1863 c.globalRules = c.liveGlobals.rules
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001864
1865 c.buildActionsReady = true
1866
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001867 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001868}
1869
Colin Cross874a3462017-07-31 17:26:06 -07001870func (c *Context) runMutators(config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001871 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001872
Colin Crossf8b50422016-08-10 12:56:40 -07001873 mutators = append(mutators, c.earlyMutatorInfo...)
1874 mutators = append(mutators, c.mutatorInfo...)
1875
1876 for _, mutator := range mutators {
Colin Cross874a3462017-07-31 17:26:06 -07001877 var newDeps []string
Colin Crossc9028482014-12-18 16:28:54 -08001878 if mutator.topDownMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001879 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001880 } else if mutator.bottomUpMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001881 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001882 } else {
1883 panic("no mutator set on " + mutator.name)
1884 }
1885 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001886 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08001887 }
Colin Cross874a3462017-07-31 17:26:06 -07001888 deps = append(deps, newDeps...)
Colin Crossc9028482014-12-18 16:28:54 -08001889 }
1890
Colin Cross874a3462017-07-31 17:26:06 -07001891 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08001892}
1893
Colin Cross3702ac72016-08-11 11:09:00 -07001894type mutatorDirection interface {
1895 run(mutator *mutatorInfo, ctx *mutatorContext)
1896 orderer() visitOrderer
1897 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001898}
1899
Colin Cross3702ac72016-08-11 11:09:00 -07001900type bottomUpMutatorImpl struct{}
1901
1902func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1903 mutator.bottomUpMutator(ctx)
1904}
1905
1906func (bottomUpMutatorImpl) orderer() visitOrderer {
1907 return bottomUpVisitor
1908}
1909
1910func (bottomUpMutatorImpl) String() string {
1911 return "bottom up mutator"
1912}
1913
1914type topDownMutatorImpl struct{}
1915
1916func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1917 mutator.topDownMutator(ctx)
1918}
1919
1920func (topDownMutatorImpl) orderer() visitOrderer {
1921 return topDownVisitor
1922}
1923
1924func (topDownMutatorImpl) String() string {
1925 return "top down mutator"
1926}
1927
1928var (
1929 topDownMutator topDownMutatorImpl
1930 bottomUpMutator bottomUpMutatorImpl
1931)
1932
Colin Cross49c279a2016-08-05 22:30:44 -07001933type reverseDep struct {
1934 module *moduleInfo
1935 dep depInfo
1936}
1937
Colin Cross3702ac72016-08-11 11:09:00 -07001938func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07001939 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001940
1941 newModuleInfo := make(map[Module]*moduleInfo)
1942 for k, v := range c.moduleInfo {
1943 newModuleInfo[k] = v
1944 }
Colin Crossc9028482014-12-18 16:28:54 -08001945
Colin Cross0ce142c2016-12-09 10:29:05 -08001946 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07001947 reverse []reverseDep
1948 rename []rename
1949 replace []replace
1950 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07001951 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08001952 }
1953
Colin Cross2c1f3d12016-04-11 15:47:28 -07001954 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08001955 var rename []rename
1956 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07001957 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08001958
Colin Cross49c279a2016-08-05 22:30:44 -07001959 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08001960 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07001961 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07001962 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001963
Colin Cross3702ac72016-08-11 11:09:00 -07001964 c.depsModified = 0
1965
Colin Cross49c279a2016-08-05 22:30:44 -07001966 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001967 if module.splitModules != nil {
1968 panic("split module found in sorted module list")
1969 }
1970
Colin Cross7addea32015-03-11 15:43:52 -07001971 mctx := &mutatorContext{
1972 baseModuleContext: baseModuleContext{
1973 context: c,
1974 config: config,
1975 module: module,
1976 },
Colin Cross49c279a2016-08-05 22:30:44 -07001977 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001978 }
Colin Crossc9028482014-12-18 16:28:54 -08001979
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001980 func() {
1981 defer func() {
1982 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001983 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001984 if err, ok := r.(panicError); ok {
1985 err.addIn(in)
1986 mctx.error(err)
1987 } else {
1988 mctx.error(newPanicErrorf(r, in))
1989 }
1990 }
1991 }()
Colin Cross3702ac72016-08-11 11:09:00 -07001992 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001993 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001994
Colin Cross7addea32015-03-11 15:43:52 -07001995 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07001996 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07001997 return true
Colin Cross7addea32015-03-11 15:43:52 -07001998 }
Colin Crossc9028482014-12-18 16:28:54 -08001999
Colin Cross5fe225f2017-07-28 15:22:46 -07002000 if len(mctx.newVariations) > 0 {
2001 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07002002 }
2003
Colin Crossaf4fd212017-07-28 14:32:36 -07002004 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08002005 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07002006 reverse: mctx.reverseDeps,
2007 replace: mctx.replace,
2008 rename: mctx.rename,
2009 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07002010 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08002011 }
Colin Cross49c279a2016-08-05 22:30:44 -07002012 }
2013
2014 return false
2015 }
2016
2017 // Process errs and reverseDeps in a single goroutine
2018 go func() {
2019 for {
2020 select {
2021 case newErrs := <-errsCh:
2022 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08002023 case globalStateChange := <-globalStateCh:
2024 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07002025 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
2026 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002027 replace = append(replace, globalStateChange.replace...)
2028 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002029 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002030 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002031 case newVariations := <-newVariationsCh:
2032 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002033 newModuleInfo[m.logicModule] = m
2034 }
2035 case <-done:
2036 return
Colin Crossc9028482014-12-18 16:28:54 -08002037 }
2038 }
Colin Cross49c279a2016-08-05 22:30:44 -07002039 }()
Colin Crossc9028482014-12-18 16:28:54 -08002040
Colin Cross49c279a2016-08-05 22:30:44 -07002041 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002042 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002043 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002044 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002045 }
2046
2047 done <- true
2048
2049 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002050 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002051 }
2052
2053 c.moduleInfo = newModuleInfo
2054
2055 for _, group := range c.moduleGroups {
2056 for i := 0; i < len(group.modules); i++ {
2057 module := group.modules[i]
2058
2059 // Update module group to contain newly split variants
2060 if module.splitModules != nil {
2061 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2062 }
2063
2064 // Fix up any remaining dependencies on modules that were split into variants
2065 // by replacing them with the first variant
2066 for j, dep := range module.directDeps {
2067 if dep.module.logicModule == nil {
2068 module.directDeps[j].module = dep.module.splitModules[0]
2069 }
2070 }
Colin Cross7addea32015-03-11 15:43:52 -07002071 }
Colin Crossc9028482014-12-18 16:28:54 -08002072 }
2073
Colin Cross8d8a7af2015-11-03 16:41:29 -08002074 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002075 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002076 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002077 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002078 }
2079
Colin Crossaf4fd212017-07-28 14:32:36 -07002080 for _, module := range newModules {
2081 errs = c.addModule(module)
2082 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002083 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002084 }
2085 atomic.AddUint32(&c.depsModified, 1)
2086 }
2087
Colin Cross0ce142c2016-12-09 10:29:05 -08002088 errs = c.handleRenames(rename)
2089 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002090 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002091 }
2092
2093 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002094 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002095 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002096 }
2097
Colin Cross3702ac72016-08-11 11:09:00 -07002098 if c.depsModified > 0 {
2099 errs = c.updateDependencies()
2100 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002101 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002102 }
Colin Crossc9028482014-12-18 16:28:54 -08002103 }
2104
Colin Cross874a3462017-07-31 17:26:06 -07002105 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002106}
2107
Colin Cross910242b2016-04-11 15:41:52 -07002108// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2109// a mutator sets a non-property member variable on a module, which works until a later mutator
2110// creates variants of that module.
2111func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002112 type update struct {
2113 orig Module
2114 clone *moduleInfo
2115 }
2116 ch := make(chan update, 100)
2117
Colin Cross910242b2016-04-11 15:41:52 -07002118 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07002119 go func(m *moduleInfo) {
2120 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002121 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002122 ch <- update{origLogicModule, m}
2123 }(m)
2124 }
2125
2126 for i := 0; i < len(c.modulesSorted); i++ {
2127 update := <-ch
2128 delete(c.moduleInfo, update.orig)
2129 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07002130 }
2131}
2132
Colin Cross49c279a2016-08-05 22:30:44 -07002133// Removes modules[i] from the list and inserts newModules... where it was located, returning
2134// the new slice and the index of the last inserted element
2135func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002136 spliceSize := len(newModules)
2137 newLen := len(modules) + spliceSize - 1
2138 var dest []*moduleInfo
2139 if cap(modules) >= len(modules)-1+len(newModules) {
2140 // We can fit the splice in the existing capacity, do everything in place
2141 dest = modules[:newLen]
2142 } else {
2143 dest = make([]*moduleInfo, newLen)
2144 copy(dest, modules[:i])
2145 }
2146
2147 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002148 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002149
2150 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002151 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002152
Colin Cross49c279a2016-08-05 22:30:44 -07002153 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002154}
2155
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002156func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002157 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002158
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002159 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002160 var errs []error
2161
Colin Cross691a60d2015-01-07 18:08:56 -08002162 cancelCh := make(chan struct{})
2163 errsCh := make(chan []error)
2164 depsCh := make(chan []string)
2165
2166 go func() {
2167 for {
2168 select {
2169 case <-cancelCh:
2170 close(cancelCh)
2171 return
2172 case newErrs := <-errsCh:
2173 errs = append(errs, newErrs...)
2174 case newDeps := <-depsCh:
2175 deps = append(deps, newDeps...)
2176
2177 }
2178 }
2179 }()
2180
Colin Cross3702ac72016-08-11 11:09:00 -07002181 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Colin Cross7addea32015-03-11 15:43:52 -07002182 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2183 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2184 // just set it to nil.
2185 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
2186 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002187
Colin Cross7addea32015-03-11 15:43:52 -07002188 mctx := &moduleContext{
2189 baseModuleContext: baseModuleContext{
2190 context: c,
2191 config: config,
2192 module: module,
2193 },
Colin Cross036a1df2015-12-17 15:49:30 -08002194 scope: scope,
2195 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002196 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002197
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002198 func() {
2199 defer func() {
2200 if r := recover(); r != nil {
2201 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2202 if err, ok := r.(panicError); ok {
2203 err.addIn(in)
2204 mctx.error(err)
2205 } else {
2206 mctx.error(newPanicErrorf(r, in))
2207 }
2208 }
2209 }()
2210 mctx.module.logicModule.GenerateBuildActions(mctx)
2211 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002212
Colin Cross7addea32015-03-11 15:43:52 -07002213 if len(mctx.errs) > 0 {
2214 errsCh <- mctx.errs
2215 return true
2216 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002217
Colin Cross036a1df2015-12-17 15:49:30 -08002218 if module.missingDeps != nil && !mctx.handledMissingDeps {
2219 var errs []error
2220 for _, depName := range module.missingDeps {
Jeff Gastond70bf752017-11-10 15:12:08 -08002221 errs = append(errs, c.missingDependencyError(module, depName))
Colin Cross036a1df2015-12-17 15:49:30 -08002222 }
2223 errsCh <- errs
2224 return true
2225 }
2226
Colin Cross7addea32015-03-11 15:43:52 -07002227 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002228
Colin Crossab6d7902015-03-11 16:17:52 -07002229 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002230 &mctx.actionDefs, liveGlobals)
2231 if len(newErrs) > 0 {
2232 errsCh <- newErrs
2233 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002234 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002235 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002236 })
2237
2238 cancelCh <- struct{}{}
2239 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002240
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002241 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002242}
2243
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002244func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002245 singletons []*singletonInfo, 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
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002249
Colin Cross5f03f112017-11-07 13:29:54 -08002250 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002251 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2252 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2253 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002254 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002255
2256 sctx := &singletonContext{
2257 context: c,
2258 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002259 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002260 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002261 }
2262
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002263 func() {
2264 defer func() {
2265 if r := recover(); r != nil {
2266 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2267 if err, ok := r.(panicError); ok {
2268 err.addIn(in)
2269 sctx.error(err)
2270 } else {
2271 sctx.error(newPanicErrorf(r, in))
2272 }
2273 }
2274 }()
2275 info.singleton.GenerateBuildActions(sctx)
2276 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002277
2278 if len(sctx.errs) > 0 {
2279 errs = append(errs, sctx.errs...)
2280 if len(errs) > maxErrors {
2281 break
2282 }
2283 continue
2284 }
2285
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002286 deps = append(deps, sctx.ninjaFileDeps...)
2287
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002288 newErrs := c.processLocalBuildActions(&info.actionDefs,
2289 &sctx.actionDefs, liveGlobals)
2290 errs = append(errs, newErrs...)
2291 if len(errs) > maxErrors {
2292 break
2293 }
2294 }
2295
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002296 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002297}
2298
2299func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2300 liveGlobals *liveTracker) []error {
2301
2302 var errs []error
2303
2304 // First we go through and add everything referenced by the module's
2305 // buildDefs to the live globals set. This will end up adding the live
2306 // locals to the set as well, but we'll take them out after.
2307 for _, def := range in.buildDefs {
2308 err := liveGlobals.AddBuildDefDeps(def)
2309 if err != nil {
2310 errs = append(errs, err)
2311 }
2312 }
2313
2314 if len(errs) > 0 {
2315 return errs
2316 }
2317
Colin Crossc9028482014-12-18 16:28:54 -08002318 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002319
2320 // We use the now-incorrect set of live "globals" to determine which local
2321 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002322 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002323 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002324 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002325 if isLive {
2326 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002327 }
2328 }
2329
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002330 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002331 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002332 if isLive {
2333 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002334 }
2335 }
2336
2337 return nil
2338}
2339
Yuchen Wu222e2452015-10-06 14:03:27 -07002340func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002341 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002342
2343 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002344 var visiting *moduleInfo
2345
2346 defer func() {
2347 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002348 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2349 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002350 }
2351 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002352
2353 var walk func(module *moduleInfo)
2354 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002355 for _, dep := range module.directDeps {
2356 if !visited[dep.module] {
2357 visited[dep.module] = true
2358 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002359 recurse := true
2360 if visitDown != nil {
2361 recurse = visitDown(dep, module)
2362 }
2363 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002364 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002365 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002366 if visitUp != nil {
2367 visitUp(dep, module)
2368 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002369 }
2370 }
2371 }
2372
2373 walk(topModule)
2374}
2375
Colin Cross9cfd1982016-10-11 09:58:53 -07002376type replace struct {
2377 from, to *moduleInfo
2378}
2379
Colin Crossc4e5b812016-10-12 10:45:05 -07002380type rename struct {
2381 group *moduleGroup
2382 name string
2383}
2384
Colin Cross0ce142c2016-12-09 10:29:05 -08002385func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Jeff Gastond70bf752017-11-10 15:12:08 -08002386 targets := c.modulesFromName(name, module.namespace())
Colin Cross9cfd1982016-10-11 09:58:53 -07002387
2388 if targets == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002389 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002390 }
2391
Colin Cross9cfd1982016-10-11 09:58:53 -07002392 for _, m := range targets {
2393 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002394 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002395 }
2396 }
2397
Colin Cross0ce142c2016-12-09 10:29:05 -08002398 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002399}
2400
Colin Cross0ce142c2016-12-09 10:29:05 -08002401func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002402 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002403 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002404 group, name := rename.group, rename.name
Jeff Gastond70bf752017-11-10 15:12:08 -08002405 if name == group.name || len(group.modules) < 1 {
Colin Crossc4e5b812016-10-12 10:45:05 -07002406 continue
2407 }
2408
Jeff Gastond70bf752017-11-10 15:12:08 -08002409 errs = append(errs, c.nameInterface.Rename(group.name, rename.name, group.namespace)...)
Colin Crossc4e5b812016-10-12 10:45:05 -07002410 }
2411
Colin Cross0ce142c2016-12-09 10:29:05 -08002412 return errs
2413}
2414
2415func (c *Context) handleReplacements(replacements []replace) []error {
2416 var errs []error
2417 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002418 for _, m := range replace.from.reverseDeps {
2419 for i, d := range m.directDeps {
2420 if d.module == replace.from {
2421 m.directDeps[i].module = replace.to
2422 }
2423 }
2424 }
2425
2426 atomic.AddUint32(&c.depsModified, 1)
2427 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002428
Colin Crossc4e5b812016-10-12 10:45:05 -07002429 return errs
2430}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002431
Jeff Gastond70bf752017-11-10 15:12:08 -08002432func (c *Context) discoveredMissingDependencies(module *moduleInfo, depName string) (errs []error) {
2433 if c.allowMissingDependencies {
2434 module.missingDeps = append(module.missingDeps, depName)
2435 return nil
2436 }
2437 return []error{c.missingDependencyError(module, depName)}
2438}
2439
2440func (c *Context) missingDependencyError(module *moduleInfo, depName string) (errs error) {
2441 err := c.nameInterface.MissingDependencyError(module.Name(), module.namespace(), depName)
2442
2443 return &BlueprintError{
2444 Err: err,
2445 Pos: module.pos,
2446 }
2447}
2448
2449func (c *Context) modulesFromName(name string, namespace Namespace) []*moduleInfo {
2450 group, exists := c.nameInterface.ModuleFromName(name, namespace)
2451 if exists {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002452 return group.modules
2453 }
2454 return nil
2455}
2456
Jeff Gastond70bf752017-11-10 15:12:08 -08002457func (c *Context) sortedModuleGroups() []*moduleGroup {
2458 if c.cachedSortedModuleGroups == nil {
2459 unwrap := func(wrappers []ModuleGroup) []*moduleGroup {
2460 result := make([]*moduleGroup, 0, len(wrappers))
2461 for _, group := range wrappers {
2462 result = append(result, group.moduleGroup)
2463 }
2464 return result
Jamie Gennisc15544d2014-09-24 20:26:52 -07002465 }
Jeff Gastond70bf752017-11-10 15:12:08 -08002466
2467 c.cachedSortedModuleGroups = unwrap(c.nameInterface.AllModules())
Jamie Gennisc15544d2014-09-24 20:26:52 -07002468 }
2469
Jeff Gastond70bf752017-11-10 15:12:08 -08002470 return c.cachedSortedModuleGroups
Jamie Gennisc15544d2014-09-24 20:26:52 -07002471}
2472
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002473func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002474 var module *moduleInfo
2475
2476 defer func() {
2477 if r := recover(); r != nil {
2478 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2479 funcName(visit), module))
2480 }
2481 }()
2482
Jeff Gastond70bf752017-11-10 15:12:08 -08002483 for _, moduleGroup := range c.sortedModuleGroups() {
2484 for _, module = range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002485 visit(module.logicModule)
2486 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002487 }
2488}
2489
2490func (c *Context) visitAllModulesIf(pred func(Module) bool,
2491 visit func(Module)) {
2492
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002493 var module *moduleInfo
2494
2495 defer func() {
2496 if r := recover(); r != nil {
2497 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2498 funcName(pred), funcName(visit), module))
2499 }
2500 }()
2501
Jeff Gastond70bf752017-11-10 15:12:08 -08002502 for _, moduleGroup := range c.sortedModuleGroups() {
2503 for _, module := range moduleGroup.modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002504 if pred(module.logicModule) {
2505 visit(module.logicModule)
2506 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002507 }
2508 }
2509}
2510
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002511func (c *Context) visitAllModuleVariants(module *moduleInfo,
2512 visit func(Module)) {
2513
2514 var variant *moduleInfo
2515
2516 defer func() {
2517 if r := recover(); r != nil {
2518 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2519 module, funcName(visit), variant))
2520 }
2521 }()
2522
2523 for _, variant = range module.group.modules {
2524 visit(variant.logicModule)
2525 }
2526}
2527
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002528func (c *Context) requireNinjaVersion(major, minor, micro int) {
2529 if major != 1 {
2530 panic("ninja version with major version != 1 not supported")
2531 }
2532 if c.requiredNinjaMinor < minor {
2533 c.requiredNinjaMinor = minor
2534 c.requiredNinjaMicro = micro
2535 }
2536 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2537 c.requiredNinjaMicro = micro
2538 }
2539}
2540
Colin Crossa2599452015-11-18 16:01:01 -08002541func (c *Context) setNinjaBuildDir(value *ninjaString) {
2542 if c.ninjaBuildDir == nil {
2543 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002544 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002545}
2546
2547func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002548 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002549
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002550 pkgs := make(map[string]*packageContext)
2551 pkgNames := make(map[*packageContext]string)
2552 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002553
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002554 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002555 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002556 // This is a built-in rule and has no package.
2557 return
2558 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002559 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002560 // We've already processed this package.
2561 return
2562 }
2563
Jamie Gennis2fb20952014-10-03 02:49:58 -07002564 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002565 if present {
2566 // Short name collision. Both this package and the one that's
2567 // already there need to use their full names. We leave the short
2568 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002569 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002570 longPkgNames[otherPkg] = true
2571 } else {
2572 // No collision so far. Tentatively set the package's name to be
2573 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002574 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002575 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002576 }
2577 }
2578
2579 // We try to give all packages their short name, but when we get collisions
2580 // we need to use the full unique package name.
2581 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002582 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002583 }
2584 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002585 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002586 }
2587 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002588 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002589 }
2590
2591 // Add the packages that had collisions using their full unique names. This
2592 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002593 for pctx := range longPkgNames {
2594 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002595 }
2596
Dan Willemsena481ae22015-12-18 15:18:03 -08002597 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2598 deps := []string{}
2599 for _, pkg := range pkgs {
2600 deps = append(deps, pkg.ninjaFileDeps...)
2601 }
2602
2603 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002604}
2605
2606func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002607 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002608
2609 visited := make(map[Variable]bool) // variables that were already checked
2610 checking := make(map[Variable]bool) // variables actively being checked
2611
2612 var check func(v Variable) []Variable
2613
2614 check = func(v Variable) []Variable {
2615 visited[v] = true
2616 checking[v] = true
2617 defer delete(checking, v)
2618
2619 value := variables[v]
2620 for _, dep := range value.variables {
2621 if checking[dep] {
2622 // This is a cycle.
2623 return []Variable{dep, v}
2624 }
2625
2626 if !visited[dep] {
2627 cycle := check(dep)
2628 if cycle != nil {
2629 if cycle[0] == v {
2630 // We are the "start" of the cycle, so we're responsible
2631 // for generating the errors. The cycle list is in
2632 // reverse order because all the 'check' calls append
2633 // their own module to the list.
2634 msgs := []string{"detected variable reference cycle:"}
2635
2636 // Iterate backwards through the cycle list.
2637 curName := v.fullName(pkgNames)
2638 curValue := value.Value(pkgNames)
2639 for i := len(cycle) - 1; i >= 0; i-- {
2640 next := cycle[i]
2641 nextName := next.fullName(pkgNames)
2642 nextValue := variables[next].Value(pkgNames)
2643
2644 msgs = append(msgs, fmt.Sprintf(
2645 " %q depends on %q", curName, nextName))
2646 msgs = append(msgs, fmt.Sprintf(
2647 " [%s = %s]", curName, curValue))
2648
2649 curName = nextName
2650 curValue = nextValue
2651 }
2652
2653 // Variable reference cycles are a programming error,
2654 // not the fault of the Blueprint file authors.
2655 panic(strings.Join(msgs, "\n"))
2656 } else {
2657 // We're not the "start" of the cycle, so we just append
2658 // our module to the list and return it.
2659 return append(cycle, v)
2660 }
2661 }
2662 }
2663 }
2664
2665 return nil
2666 }
2667
2668 for v := range variables {
2669 if !visited[v] {
2670 cycle := check(v)
2671 if cycle != nil {
2672 panic("inconceivable!")
2673 }
2674 }
2675 }
2676}
2677
Jamie Gennisaf435562014-10-27 22:34:56 -07002678// AllTargets returns a map all the build target names to the rule used to build
2679// them. This is the same information that is output by running 'ninja -t
2680// targets all'. If this is called before PrepareBuildActions successfully
2681// completes then ErrbuildActionsNotReady is returned.
2682func (c *Context) AllTargets() (map[string]string, error) {
2683 if !c.buildActionsReady {
2684 return nil, ErrBuildActionsNotReady
2685 }
2686
2687 targets := map[string]string{}
2688
2689 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002690 for _, module := range c.moduleInfo {
2691 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002692 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002693 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002694 outputValue, err := output.Eval(c.globalVariables)
2695 if err != nil {
2696 return nil, err
2697 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002698 targets[outputValue] = ruleName
2699 }
2700 }
2701 }
2702
2703 // Collect all the singleton build targets.
2704 for _, info := range c.singletonInfo {
2705 for _, buildDef := range info.actionDefs.buildDefs {
2706 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002707 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002708 outputValue, err := output.Eval(c.globalVariables)
2709 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002710 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002711 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002712 targets[outputValue] = ruleName
2713 }
2714 }
2715 }
2716
2717 return targets, nil
2718}
2719
Colin Crossa2599452015-11-18 16:01:01 -08002720func (c *Context) NinjaBuildDir() (string, error) {
2721 if c.ninjaBuildDir != nil {
2722 return c.ninjaBuildDir.Eval(c.globalVariables)
2723 } else {
2724 return "", nil
2725 }
2726}
2727
Colin Cross4572edd2015-05-13 14:36:24 -07002728// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2729// property structs returned by the factory for that module type.
2730func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2731 ret := make(map[string][]interface{})
2732 for moduleType, factory := range c.moduleFactories {
2733 _, ret[moduleType] = factory()
2734 }
2735
2736 return ret
2737}
2738
2739func (c *Context) ModuleName(logicModule Module) string {
2740 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002741 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002742}
2743
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002744func (c *Context) ModulePath(logicModule Module) string {
Colin Cross4572edd2015-05-13 14:36:24 -07002745 module := c.moduleInfo[logicModule]
Jeff Gaston3c8c3342017-11-30 17:30:42 -08002746 return module.relBlueprintsFile
2747}
2748
2749func (c *Context) ModuleDir(logicModule Module) string {
2750 return filepath.Dir(c.ModulePath(logicModule))
Colin Cross4572edd2015-05-13 14:36:24 -07002751}
2752
Colin Cross8c602f72015-12-17 18:02:11 -08002753func (c *Context) ModuleSubDir(logicModule Module) string {
2754 module := c.moduleInfo[logicModule]
2755 return module.variantName
2756}
2757
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002758func (c *Context) ModuleType(logicModule Module) string {
2759 module := c.moduleInfo[logicModule]
2760 return module.typeName
2761}
2762
Colin Cross4572edd2015-05-13 14:36:24 -07002763func (c *Context) BlueprintFile(logicModule Module) string {
2764 module := c.moduleInfo[logicModule]
2765 return module.relBlueprintsFile
2766}
2767
2768func (c *Context) ModuleErrorf(logicModule Module, format string,
2769 args ...interface{}) error {
2770
2771 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002772 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002773 Err: fmt.Errorf(format, args...),
2774 Pos: module.pos,
2775 }
2776}
2777
2778func (c *Context) VisitAllModules(visit func(Module)) {
2779 c.visitAllModules(visit)
2780}
2781
2782func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2783 visit func(Module)) {
2784
2785 c.visitAllModulesIf(pred, visit)
2786}
2787
Colin Cross080c1332017-03-17 13:09:05 -07002788func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
2789 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07002790
Colin Cross080c1332017-03-17 13:09:05 -07002791 var visiting *moduleInfo
2792
2793 defer func() {
2794 if r := recover(); r != nil {
2795 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
2796 topModule, funcName(visit), visiting))
2797 }
2798 }()
2799
2800 for _, dep := range topModule.directDeps {
2801 visiting = dep.module
2802 visit(dep.module.logicModule)
2803 }
2804}
2805
2806func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
2807 topModule := c.moduleInfo[module]
2808
2809 var visiting *moduleInfo
2810
2811 defer func() {
2812 if r := recover(); r != nil {
2813 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
2814 topModule, funcName(pred), funcName(visit), visiting))
2815 }
2816 }()
2817
2818 for _, dep := range topModule.directDeps {
2819 visiting = dep.module
2820 if pred(dep.module.logicModule) {
2821 visit(dep.module.logicModule)
2822 }
2823 }
2824}
2825
2826func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002827 topModule := c.moduleInfo[module]
2828
2829 var visiting *moduleInfo
2830
2831 defer func() {
2832 if r := recover(); r != nil {
2833 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2834 topModule, funcName(visit), visiting))
2835 }
2836 }()
2837
2838 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2839 visiting = dep.module
2840 visit(dep.module.logicModule)
2841 })
Colin Cross4572edd2015-05-13 14:36:24 -07002842}
2843
Colin Cross080c1332017-03-17 13:09:05 -07002844func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002845 topModule := c.moduleInfo[module]
2846
2847 var visiting *moduleInfo
2848
2849 defer func() {
2850 if r := recover(); r != nil {
2851 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2852 topModule, funcName(pred), funcName(visit), visiting))
2853 }
2854 }()
2855
2856 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2857 if pred(dep.module.logicModule) {
2858 visiting = dep.module
2859 visit(dep.module.logicModule)
2860 }
2861 })
Colin Cross4572edd2015-05-13 14:36:24 -07002862}
2863
Colin Cross24ad5872015-11-17 16:22:29 -08002864func (c *Context) PrimaryModule(module Module) Module {
2865 return c.moduleInfo[module].group.modules[0].logicModule
2866}
2867
2868func (c *Context) FinalModule(module Module) Module {
2869 modules := c.moduleInfo[module].group.modules
2870 return modules[len(modules)-1].logicModule
2871}
2872
2873func (c *Context) VisitAllModuleVariants(module Module,
2874 visit func(Module)) {
2875
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002876 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002877}
2878
Jamie Gennisd4e10182014-06-12 20:06:50 -07002879// WriteBuildFile writes the Ninja manifeset text for the generated build
2880// actions to w. If this is called before PrepareBuildActions successfully
2881// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002882func (c *Context) WriteBuildFile(w io.Writer) error {
2883 if !c.buildActionsReady {
2884 return ErrBuildActionsNotReady
2885 }
2886
2887 nw := newNinjaWriter(w)
2888
2889 err := c.writeBuildFileHeader(nw)
2890 if err != nil {
2891 return err
2892 }
2893
2894 err = c.writeNinjaRequiredVersion(nw)
2895 if err != nil {
2896 return err
2897 }
2898
2899 // TODO: Group the globals by package.
2900
2901 err = c.writeGlobalVariables(nw)
2902 if err != nil {
2903 return err
2904 }
2905
2906 err = c.writeGlobalPools(nw)
2907 if err != nil {
2908 return err
2909 }
2910
2911 err = c.writeBuildDir(nw)
2912 if err != nil {
2913 return err
2914 }
2915
2916 err = c.writeGlobalRules(nw)
2917 if err != nil {
2918 return err
2919 }
2920
2921 err = c.writeAllModuleActions(nw)
2922 if err != nil {
2923 return err
2924 }
2925
2926 err = c.writeAllSingletonActions(nw)
2927 if err != nil {
2928 return err
2929 }
2930
2931 return nil
2932}
2933
Jamie Gennisc15544d2014-09-24 20:26:52 -07002934type pkgAssociation struct {
2935 PkgName string
2936 PkgPath string
2937}
2938
2939type pkgAssociationSorter struct {
2940 pkgs []pkgAssociation
2941}
2942
2943func (s *pkgAssociationSorter) Len() int {
2944 return len(s.pkgs)
2945}
2946
2947func (s *pkgAssociationSorter) Less(i, j int) bool {
2948 iName := s.pkgs[i].PkgName
2949 jName := s.pkgs[j].PkgName
2950 return iName < jName
2951}
2952
2953func (s *pkgAssociationSorter) Swap(i, j int) {
2954 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2955}
2956
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002957func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2958 headerTemplate := template.New("fileHeader")
2959 _, err := headerTemplate.Parse(fileHeaderTemplate)
2960 if err != nil {
2961 // This is a programming error.
2962 panic(err)
2963 }
2964
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002965 var pkgs []pkgAssociation
2966 maxNameLen := 0
2967 for pkg, name := range c.pkgNames {
2968 pkgs = append(pkgs, pkgAssociation{
2969 PkgName: name,
2970 PkgPath: pkg.pkgPath,
2971 })
2972 if len(name) > maxNameLen {
2973 maxNameLen = len(name)
2974 }
2975 }
2976
2977 for i := range pkgs {
2978 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2979 }
2980
Jamie Gennisc15544d2014-09-24 20:26:52 -07002981 sort.Sort(&pkgAssociationSorter{pkgs})
2982
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002983 params := map[string]interface{}{
2984 "Pkgs": pkgs,
2985 }
2986
2987 buf := bytes.NewBuffer(nil)
2988 err = headerTemplate.Execute(buf, params)
2989 if err != nil {
2990 return err
2991 }
2992
2993 return nw.Comment(buf.String())
2994}
2995
2996func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2997 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2998 c.requiredNinjaMicro)
2999
3000 err := nw.Assign("ninja_required_version", value)
3001 if err != nil {
3002 return err
3003 }
3004
3005 return nw.BlankLine()
3006}
3007
3008func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08003009 if c.ninjaBuildDir != nil {
3010 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003011 if err != nil {
3012 return err
3013 }
3014
3015 err = nw.BlankLine()
3016 if err != nil {
3017 return err
3018 }
3019 }
3020 return nil
3021}
3022
Jamie Gennisc15544d2014-09-24 20:26:52 -07003023type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003024 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003025}
3026
Jamie Gennisc15544d2014-09-24 20:26:52 -07003027type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08003028 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003029 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003030}
3031
Jamie Gennisc15544d2014-09-24 20:26:52 -07003032func (s *globalEntitySorter) Len() int {
3033 return len(s.entities)
3034}
3035
3036func (s *globalEntitySorter) Less(i, j int) bool {
3037 iName := s.entities[i].fullName(s.pkgNames)
3038 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003039 return iName < jName
3040}
3041
Jamie Gennisc15544d2014-09-24 20:26:52 -07003042func (s *globalEntitySorter) Swap(i, j int) {
3043 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003044}
3045
3046func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3047 visited := make(map[Variable]bool)
3048
3049 var walk func(v Variable) error
3050 walk = func(v Variable) error {
3051 visited[v] = true
3052
3053 // First visit variables on which this variable depends.
3054 value := c.globalVariables[v]
3055 for _, dep := range value.variables {
3056 if !visited[dep] {
3057 err := walk(dep)
3058 if err != nil {
3059 return err
3060 }
3061 }
3062 }
3063
3064 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3065 if err != nil {
3066 return err
3067 }
3068
3069 err = nw.BlankLine()
3070 if err != nil {
3071 return err
3072 }
3073
3074 return nil
3075 }
3076
Jamie Gennisc15544d2014-09-24 20:26:52 -07003077 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3078 for variable := range c.globalVariables {
3079 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003080 }
3081
Jamie Gennisc15544d2014-09-24 20:26:52 -07003082 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003083
Jamie Gennisc15544d2014-09-24 20:26:52 -07003084 for _, entity := range globalVariables {
3085 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003086 if !visited[v] {
3087 err := walk(v)
3088 if err != nil {
3089 return nil
3090 }
3091 }
3092 }
3093
3094 return nil
3095}
3096
3097func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003098 globalPools := make([]globalEntity, 0, len(c.globalPools))
3099 for pool := range c.globalPools {
3100 globalPools = append(globalPools, pool)
3101 }
3102
3103 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3104
3105 for _, entity := range globalPools {
3106 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003107 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003108 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003109 err := def.WriteTo(nw, name)
3110 if err != nil {
3111 return err
3112 }
3113
3114 err = nw.BlankLine()
3115 if err != nil {
3116 return err
3117 }
3118 }
3119
3120 return nil
3121}
3122
3123func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003124 globalRules := make([]globalEntity, 0, len(c.globalRules))
3125 for rule := range c.globalRules {
3126 globalRules = append(globalRules, rule)
3127 }
3128
3129 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3130
3131 for _, entity := range globalRules {
3132 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003133 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003134 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003135 err := def.WriteTo(nw, name, c.pkgNames)
3136 if err != nil {
3137 return err
3138 }
3139
3140 err = nw.BlankLine()
3141 if err != nil {
3142 return err
3143 }
3144 }
3145
3146 return nil
3147}
3148
Colin Cross2c1f3d12016-04-11 15:47:28 -07003149type depSorter []depInfo
3150
3151func (s depSorter) Len() int {
3152 return len(s)
3153}
3154
3155func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003156 iName := s[i].module.Name()
3157 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003158 if iName == jName {
3159 iName = s[i].module.variantName
3160 jName = s[j].module.variantName
3161 }
3162 return iName < jName
3163}
3164
3165func (s depSorter) Swap(i, j int) {
3166 s[i], s[j] = s[j], s[i]
3167}
3168
Colin Crossab6d7902015-03-11 16:17:52 -07003169type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07003170
Colin Crossab6d7902015-03-11 16:17:52 -07003171func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07003172 return len(s)
3173}
3174
Colin Crossab6d7902015-03-11 16:17:52 -07003175func (s moduleSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003176 iName := s[i].Name()
3177 jName := s[j].Name()
Colin Crossab6d7902015-03-11 16:17:52 -07003178 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07003179 iName = s[i].variantName
3180 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07003181 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003182 return iName < jName
3183}
3184
Colin Crossab6d7902015-03-11 16:17:52 -07003185func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07003186 s[i], s[j] = s[j], s[i]
3187}
3188
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003189func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3190 headerTemplate := template.New("moduleHeader")
3191 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3192 if err != nil {
3193 // This is a programming error.
3194 panic(err)
3195 }
3196
Colin Crossab6d7902015-03-11 16:17:52 -07003197 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3198 for _, module := range c.moduleInfo {
3199 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003200 }
Colin Crossab6d7902015-03-11 16:17:52 -07003201 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07003202
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003203 buf := bytes.NewBuffer(nil)
3204
Colin Crossab6d7902015-03-11 16:17:52 -07003205 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003206 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3207 continue
3208 }
3209
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003210 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003211
3212 // In order to make the bootstrap build manifest independent of the
3213 // build dir we need to output the Blueprints file locations in the
3214 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003215 relPos := module.pos
3216 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003217
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003218 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003219 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003220 factoryName := factoryFunc.Name()
3221
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003222 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003223 "name": module.Name(),
3224 "typeName": module.typeName,
3225 "goFactory": factoryName,
3226 "pos": relPos,
3227 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003228 }
3229 err = headerTemplate.Execute(buf, infoMap)
3230 if err != nil {
3231 return err
3232 }
3233
3234 err = nw.Comment(buf.String())
3235 if err != nil {
3236 return err
3237 }
3238
3239 err = nw.BlankLine()
3240 if err != nil {
3241 return err
3242 }
3243
Colin Crossab6d7902015-03-11 16:17:52 -07003244 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003245 if err != nil {
3246 return err
3247 }
3248
3249 err = nw.BlankLine()
3250 if err != nil {
3251 return err
3252 }
3253 }
3254
3255 return nil
3256}
3257
3258func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3259 headerTemplate := template.New("singletonHeader")
3260 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3261 if err != nil {
3262 // This is a programming error.
3263 panic(err)
3264 }
3265
3266 buf := bytes.NewBuffer(nil)
3267
Yuchen Wub9103ef2015-08-25 17:58:17 -07003268 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003269 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3270 continue
3271 }
3272
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003273 // Get the name of the factory function for the module.
3274 factory := info.factory
3275 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3276 factoryName := factoryFunc.Name()
3277
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003278 buf.Reset()
3279 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003280 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003281 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003282 }
3283 err = headerTemplate.Execute(buf, infoMap)
3284 if err != nil {
3285 return err
3286 }
3287
3288 err = nw.Comment(buf.String())
3289 if err != nil {
3290 return err
3291 }
3292
3293 err = nw.BlankLine()
3294 if err != nil {
3295 return err
3296 }
3297
3298 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3299 if err != nil {
3300 return err
3301 }
3302
3303 err = nw.BlankLine()
3304 if err != nil {
3305 return err
3306 }
3307 }
3308
3309 return nil
3310}
3311
3312func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3313 defs *localBuildActions) error {
3314
3315 // Write the local variable assignments.
3316 for _, v := range defs.variables {
3317 // A localVariable doesn't need the package names or config to
3318 // determine its name or value.
3319 name := v.fullName(nil)
3320 value, err := v.value(nil)
3321 if err != nil {
3322 panic(err)
3323 }
3324 err = nw.Assign(name, value.Value(c.pkgNames))
3325 if err != nil {
3326 return err
3327 }
3328 }
3329
3330 if len(defs.variables) > 0 {
3331 err := nw.BlankLine()
3332 if err != nil {
3333 return err
3334 }
3335 }
3336
3337 // Write the local rules.
3338 for _, r := range defs.rules {
3339 // A localRule doesn't need the package names or config to determine
3340 // its name or definition.
3341 name := r.fullName(nil)
3342 def, err := r.def(nil)
3343 if err != nil {
3344 panic(err)
3345 }
3346
3347 err = def.WriteTo(nw, name, c.pkgNames)
3348 if err != nil {
3349 return err
3350 }
3351
3352 err = nw.BlankLine()
3353 if err != nil {
3354 return err
3355 }
3356 }
3357
3358 // Write the build definitions.
3359 for _, buildDef := range defs.buildDefs {
3360 err := buildDef.WriteTo(nw, c.pkgNames)
3361 if err != nil {
3362 return err
3363 }
3364
3365 if len(buildDef.Args) > 0 {
3366 err = nw.BlankLine()
3367 if err != nil {
3368 return err
3369 }
3370 }
3371 }
3372
3373 return nil
3374}
3375
Colin Cross65569e42015-03-10 20:08:19 -07003376func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3377 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003378 if a == b {
3379 return false
3380 }
Colin Cross65569e42015-03-10 20:08:19 -07003381 for _, l := range list {
3382 if l == a {
3383 found = true
3384 } else if l == b {
3385 return found
3386 }
3387 }
3388
3389 missing := a
3390 if found {
3391 missing = b
3392 }
3393 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3394}
3395
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003396type panicError struct {
3397 panic interface{}
3398 stack []byte
3399 in string
3400}
3401
3402func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3403 buf := make([]byte, 4096)
3404 count := runtime.Stack(buf, false)
3405 return panicError{
3406 panic: panic,
3407 in: fmt.Sprintf(in, a...),
3408 stack: buf[:count],
3409 }
3410}
3411
3412func (p panicError) Error() string {
3413 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3414}
3415
3416func (p *panicError) addIn(in string) {
3417 p.in += " in " + in
3418}
3419
3420func funcName(f interface{}) string {
3421 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3422}
3423
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003424var fileHeaderTemplate = `******************************************************************************
3425*** This file is generated and should not be edited ***
3426******************************************************************************
3427{{if .Pkgs}}
3428This file contains variables, rules, and pools with name prefixes indicating
3429they were generated by the following Go packages:
3430{{range .Pkgs}}
3431 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3432
3433`
3434
3435var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003436Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003437Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003438Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003439Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003440Defined: {{.pos}}
3441`
3442
3443var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3444Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003445Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003446`