blob: ab5efee30b8b65498c336336446da5f79079ecdf [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
Colin Cross0b7e83e2016-05-17 14:58:05 -070072 moduleNames map[string]*moduleGroup
73 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
107 // set lazily by sortedModuleNames
108 cachedSortedModuleNames []string
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
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700161}
162
Colin Crossbbfa51a2014-12-17 16:12:41 -0800163type moduleInfo struct {
Colin Crossed342d92015-03-11 00:57:25 -0700164 // set during Parse
165 typeName string
Colin Crossaf4fd212017-07-28 14:32:36 -0700166 factory ModuleFactory
Colin Crossed342d92015-03-11 00:57:25 -0700167 relBlueprintsFile string
168 pos scanner.Position
169 propertyPos map[string]scanner.Position
Colin Crossed342d92015-03-11 00:57:25 -0700170
Colin Crossf5e34b92015-03-13 16:02:36 -0700171 variantName string
172 variant variationMap
173 dependencyVariant variationMap
Colin Crosse7daa222015-03-11 14:35:41 -0700174
Colin Crossd2f4ac12017-07-28 14:31:03 -0700175 logicModule Module
176 group *moduleGroup
177 properties []interface{}
Colin Crossc9028482014-12-18 16:28:54 -0800178
179 // set during ResolveDependencies
Colin Cross2c1f3d12016-04-11 15:47:28 -0700180 directDeps []depInfo
Colin Cross036a1df2015-12-17 15:49:30 -0800181 missingDeps []string
Colin Crossc9028482014-12-18 16:28:54 -0800182
Colin Cross7addea32015-03-11 15:43:52 -0700183 // set during updateDependencies
184 reverseDeps []*moduleInfo
Colin Cross3702ac72016-08-11 11:09:00 -0700185 forwardDeps []*moduleInfo
Colin Cross7addea32015-03-11 15:43:52 -0700186
187 // used by parallelVisitAllBottomUp
188 waitingCount int
189
Colin Crossc9028482014-12-18 16:28:54 -0800190 // set during each runMutator
191 splitModules []*moduleInfo
Colin Crossab6d7902015-03-11 16:17:52 -0700192
193 // set during PrepareBuildActions
194 actionDefs localBuildActions
Colin Crossc9028482014-12-18 16:28:54 -0800195}
196
Colin Cross2c1f3d12016-04-11 15:47:28 -0700197type depInfo struct {
198 module *moduleInfo
199 tag DependencyTag
200}
201
Colin Cross0b7e83e2016-05-17 14:58:05 -0700202func (module *moduleInfo) Name() string {
203 return module.group.name
204}
205
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800206func (module *moduleInfo) String() string {
Colin Cross0b7e83e2016-05-17 14:58:05 -0700207 s := fmt.Sprintf("module %q", module.Name())
Colin Cross0aa6a5f2016-01-07 13:43:09 -0800208 if module.variantName != "" {
209 s += fmt.Sprintf(" variant %q", module.variantName)
210 }
211 return s
212}
213
Colin Crossf5e34b92015-03-13 16:02:36 -0700214// A Variation is a way that a variant of a module differs from other variants of the same module.
215// For example, two variants of the same module might have Variation{"arch","arm"} and
216// Variation{"arch","arm64"}
217type Variation struct {
218 // Mutator is the axis on which this variation applies, i.e. "arch" or "link"
Colin Cross65569e42015-03-10 20:08:19 -0700219 Mutator string
Colin Crossf5e34b92015-03-13 16:02:36 -0700220 // Variation is the name of the variation on the axis, i.e. "arm" or "arm64" for arch, or
221 // "shared" or "static" for link.
222 Variation string
Colin Cross65569e42015-03-10 20:08:19 -0700223}
224
Colin Crossf5e34b92015-03-13 16:02:36 -0700225// A variationMap stores a map of Mutator to Variation to specify a variant of a module.
226type variationMap map[string]string
Colin Crosse7daa222015-03-11 14:35:41 -0700227
Colin Crossf5e34b92015-03-13 16:02:36 -0700228func (vm variationMap) clone() variationMap {
229 newVm := make(variationMap)
Colin Crosse7daa222015-03-11 14:35:41 -0700230 for k, v := range vm {
231 newVm[k] = v
232 }
233
234 return newVm
Colin Crossc9028482014-12-18 16:28:54 -0800235}
236
Colin Cross89486232015-05-08 11:14:54 -0700237// Compare this variationMap to another one. Returns true if the every entry in this map
238// is either the same in the other map or doesn't exist in the other map.
239func (vm variationMap) subset(other variationMap) bool {
240 for k, v1 := range vm {
241 if v2, ok := other[k]; ok && v1 != v2 {
242 return false
243 }
244 }
245 return true
246}
247
Colin Crossf5e34b92015-03-13 16:02:36 -0700248func (vm variationMap) equal(other variationMap) bool {
Colin Crosse7daa222015-03-11 14:35:41 -0700249 return reflect.DeepEqual(vm, other)
Colin Crossbbfa51a2014-12-17 16:12:41 -0800250}
251
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700252type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700253 // set during RegisterSingletonType
254 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700255 singleton Singleton
Yuchen Wub9103ef2015-08-25 17:58:17 -0700256 name string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700257
258 // set during PrepareBuildActions
259 actionDefs localBuildActions
260}
261
Colin Crossc9028482014-12-18 16:28:54 -0800262type mutatorInfo struct {
263 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800264 topDownMutator TopDownMutator
265 bottomUpMutator BottomUpMutator
266 name string
Colin Cross49c279a2016-08-05 22:30:44 -0700267 parallel bool
Colin Crossc9028482014-12-18 16:28:54 -0800268}
269
Colin Crossaf4fd212017-07-28 14:32:36 -0700270func newContext() *Context {
271 return &Context{
Colin Cross5f03f112017-11-07 13:29:54 -0800272 moduleFactories: make(map[string]ModuleFactory),
273 moduleNames: make(map[string]*moduleGroup),
274 moduleInfo: make(map[Module]*moduleInfo),
275 moduleNinjaNames: make(map[string]*moduleGroup),
276 globs: make(map[string]GlobPath),
277 fs: pathtools.OsFs,
278 ninjaBuildDir: nil,
279 requiredNinjaMajor: 1,
280 requiredNinjaMinor: 7,
281 requiredNinjaMicro: 0,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700282 }
Colin Crossaf4fd212017-07-28 14:32:36 -0700283}
284
285// NewContext creates a new Context object. The created context initially has
286// no module or singleton factories registered, so the RegisterModuleFactory and
287// RegisterSingletonFactory methods must be called before it can do anything
288// useful.
289func NewContext() *Context {
290 ctx := newContext()
Colin Cross763b6f12015-10-29 15:32:56 -0700291
292 ctx.RegisterBottomUpMutator("blueprint_deps", blueprintDepsMutator)
293
294 return ctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700295}
296
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700297// A ModuleFactory function creates a new Module object. See the
298// Context.RegisterModuleType method for details about how a registered
299// ModuleFactory is used by a Context.
300type ModuleFactory func() (m Module, propertyStructs []interface{})
301
Jamie Gennisd4e10182014-06-12 20:06:50 -0700302// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700303// Blueprints file) with a Module factory function. When the given module type
304// name is encountered in a Blueprints file during parsing, the Module factory
305// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800306// generation for the module. If a Mutator splits a module into multiple variants,
307// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700308//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700309// The module type names given here must be unique for the context. The factory
310// function should be a named function so that its package and name can be
311// included in the generated Ninja file for debugging purposes.
312//
313// The factory function returns two values. The first is the newly created
314// Module object. The second is a slice of pointers to that Module object's
315// properties structs. Each properties struct is examined when parsing a module
316// definition of this type in a Blueprints file. Exported fields of the
317// properties structs are automatically set to the property values specified in
318// the Blueprints file. The properties struct field names determine the name of
319// the Blueprints file properties that are used - the Blueprints property name
320// matches that of the properties struct field name with the first letter
321// converted to lower-case.
322//
323// The fields of the properties struct must be either []string, a string, or
324// bool. The Context will panic if a Module gets instantiated with a properties
325// struct containing a field that is not one these supported types.
326//
327// Any properties that appear in the Blueprints files that are not built-in
328// module properties (such as "name" and "deps") and do not have a corresponding
329// field in the returned module properties struct result in an error during the
330// Context's parse phase.
331//
332// As an example, the follow code:
333//
334// type myModule struct {
335// properties struct {
336// Foo string
337// Bar []string
338// }
339// }
340//
341// func NewMyModule() (blueprint.Module, []interface{}) {
342// module := new(myModule)
343// properties := &module.properties
344// return module, []interface{}{properties}
345// }
346//
347// func main() {
348// ctx := blueprint.NewContext()
349// ctx.RegisterModuleType("my_module", NewMyModule)
350// // ...
351// }
352//
353// would support parsing a module defined in a Blueprints file as follows:
354//
355// my_module {
356// name: "myName",
357// foo: "my foo string",
358// bar: ["my", "bar", "strings"],
359// }
360//
Colin Cross7ad621c2015-01-07 16:22:45 -0800361// The factory function may be called from multiple goroutines. Any accesses
362// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700363func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
364 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700365 panic(errors.New("module type name is already registered"))
366 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700367 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700368}
369
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700370// A SingletonFactory function creates a new Singleton object. See the
371// Context.RegisterSingletonType method for details about how a registered
372// SingletonFactory is used by a Context.
373type SingletonFactory func() Singleton
374
375// RegisterSingletonType registers a singleton type that will be invoked to
376// generate build actions. Each registered singleton type is instantiated and
Yuchen Wub9103ef2015-08-25 17:58:17 -0700377// and invoked exactly once as part of the generate phase. Each registered
378// singleton is invoked in registration order.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700379//
380// The singleton type names given here must be unique for the context. The
381// factory function should be a named function so that its package and name can
382// be included in the generated Ninja file for debugging purposes.
383func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Yuchen Wub9103ef2015-08-25 17:58:17 -0700384 for _, s := range c.singletonInfo {
385 if s.name == name {
386 panic(errors.New("singleton name is already registered"))
387 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700388 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700389
Yuchen Wub9103ef2015-08-25 17:58:17 -0700390 c.singletonInfo = append(c.singletonInfo, &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700391 factory: factory,
392 singleton: factory(),
Yuchen Wub9103ef2015-08-25 17:58:17 -0700393 name: name,
394 })
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700395}
396
Colin Cross5f03f112017-11-07 13:29:54 -0800397// RegisterPreSingletonType registers a presingleton type that will be invoked to
398// generate build actions before any Blueprint files have been read. Each registered
399// presingleton type is instantiated and invoked exactly once at the beginning of the
400// parse phase. Each registered presingleton is invoked in registration order.
401//
402// The presingleton type names given here must be unique for the context. The
403// factory function should be a named function so that its package and name can
404// be included in the generated Ninja file for debugging purposes.
405func (c *Context) RegisterPreSingletonType(name string, factory SingletonFactory) {
406 for _, s := range c.preSingletonInfo {
407 if s.name == name {
408 panic(errors.New("presingleton name is already registered"))
409 }
410 }
411
412 c.preSingletonInfo = append(c.preSingletonInfo, &singletonInfo{
413 factory: factory,
414 singleton: factory(),
415 name: name,
416 })
417}
418
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700419func singletonPkgPath(singleton Singleton) string {
420 typ := reflect.TypeOf(singleton)
421 for typ.Kind() == reflect.Ptr {
422 typ = typ.Elem()
423 }
424 return typ.PkgPath()
425}
426
427func singletonTypeName(singleton Singleton) string {
428 typ := reflect.TypeOf(singleton)
429 for typ.Kind() == reflect.Ptr {
430 typ = typ.Elem()
431 }
432 return typ.PkgPath() + "." + typ.Name()
433}
434
Colin Cross3702ac72016-08-11 11:09:00 -0700435// RegisterTopDownMutator registers a mutator that will be invoked to propagate dependency info
436// top-down between Modules. Each registered mutator is invoked in registration order (mixing
437// TopDownMutators and BottomUpMutators) once per Module, and the invocation on any module will
438// have returned before it is in invoked on any of its dependencies.
Colin Crossc9028482014-12-18 16:28:54 -0800439//
Colin Cross65569e42015-03-10 20:08:19 -0700440// The mutator type names given here must be unique to all top down mutators in
441// the Context.
Colin Cross3702ac72016-08-11 11:09:00 -0700442//
443// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
444// parallel while maintaining ordering.
445func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) MutatorHandle {
Colin Crossc9028482014-12-18 16:28:54 -0800446 for _, m := range c.mutatorInfo {
447 if m.name == name && m.topDownMutator != nil {
448 panic(fmt.Errorf("mutator name %s is already registered", name))
449 }
450 }
451
Colin Cross3702ac72016-08-11 11:09:00 -0700452 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800453 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800454 name: name,
Colin Cross3702ac72016-08-11 11:09:00 -0700455 }
456
457 c.mutatorInfo = append(c.mutatorInfo, info)
458
459 return info
Colin Crossc9028482014-12-18 16:28:54 -0800460}
461
Colin Cross3702ac72016-08-11 11:09:00 -0700462// RegisterBottomUpMutator registers a mutator that will be invoked to split Modules into variants.
463// Each registered mutator is invoked in registration order (mixing TopDownMutators and
464// BottomUpMutators) once per Module, will not be invoked on a module until the invocations on all
465// of the modules dependencies have returned.
Colin Crossc9028482014-12-18 16:28:54 -0800466//
Colin Cross65569e42015-03-10 20:08:19 -0700467// The mutator type names given here must be unique to all bottom up or early
468// mutators in the Context.
Colin Cross49c279a2016-08-05 22:30:44 -0700469//
Colin Cross3702ac72016-08-11 11:09:00 -0700470// Returns a MutatorHandle, on which Parallel can be called to set the mutator to visit modules in
471// parallel while maintaining ordering.
472func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) MutatorHandle {
Colin Cross65569e42015-03-10 20:08:19 -0700473 for _, m := range c.variantMutatorNames {
474 if m == name {
Colin Crossc9028482014-12-18 16:28:54 -0800475 panic(fmt.Errorf("mutator name %s is already registered", name))
476 }
477 }
478
Colin Cross49c279a2016-08-05 22:30:44 -0700479 info := &mutatorInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800480 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800481 name: name,
Colin Cross49c279a2016-08-05 22:30:44 -0700482 }
483 c.mutatorInfo = append(c.mutatorInfo, info)
Colin Cross65569e42015-03-10 20:08:19 -0700484
485 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Cross49c279a2016-08-05 22:30:44 -0700486
487 return info
488}
489
Colin Cross3702ac72016-08-11 11:09:00 -0700490type MutatorHandle interface {
491 // Set the mutator to visit modules in parallel while maintaining ordering. Calling any
492 // method on the mutator context is thread-safe, but the mutator must handle synchronization
493 // for any modifications to global state or any modules outside the one it was invoked on.
494 Parallel() MutatorHandle
Colin Cross49c279a2016-08-05 22:30:44 -0700495}
496
Colin Cross3702ac72016-08-11 11:09:00 -0700497func (mutator *mutatorInfo) Parallel() MutatorHandle {
Colin Cross49c279a2016-08-05 22:30:44 -0700498 mutator.parallel = true
499 return mutator
Colin Cross65569e42015-03-10 20:08:19 -0700500}
501
502// RegisterEarlyMutator registers a mutator that will be invoked to split
503// Modules into multiple variant Modules before any dependencies have been
504// created. Each registered mutator is invoked in registration order once
505// per Module (including each variant from previous early mutators). Module
506// order is unpredictable.
507//
508// In order for dependencies to be satisifed in a later pass, all dependencies
Colin Crossf5e34b92015-03-13 16:02:36 -0700509// of a module either must have an identical variant or must have no variations.
Colin Cross65569e42015-03-10 20:08:19 -0700510//
511// The mutator type names given here must be unique to all bottom up or early
512// mutators in the Context.
Colin Cross763b6f12015-10-29 15:32:56 -0700513//
514// Deprecated, use a BottomUpMutator instead. The only difference between
515// EarlyMutator and BottomUpMutator is that EarlyMutator runs before the
516// deprecated DynamicDependencies.
Colin Cross65569e42015-03-10 20:08:19 -0700517func (c *Context) RegisterEarlyMutator(name string, mutator EarlyMutator) {
518 for _, m := range c.variantMutatorNames {
519 if m == name {
520 panic(fmt.Errorf("mutator name %s is already registered", name))
521 }
522 }
523
Colin Crossf8b50422016-08-10 12:56:40 -0700524 c.earlyMutatorInfo = append(c.earlyMutatorInfo, &mutatorInfo{
525 bottomUpMutator: func(mctx BottomUpMutatorContext) {
526 mutator(mctx)
527 },
528 name: name,
Colin Cross65569e42015-03-10 20:08:19 -0700529 })
530
531 c.variantMutatorNames = append(c.variantMutatorNames, name)
Colin Crossc9028482014-12-18 16:28:54 -0800532}
533
Jamie Gennisd4e10182014-06-12 20:06:50 -0700534// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
535// where it encounters an unknown module type while parsing Blueprints files. By
536// default, the context will report unknown module types as an error. If this
537// method is called with ignoreUnknownModuleTypes set to true then the context
538// will silently ignore unknown module types.
539//
540// This method should generally not be used. It exists to facilitate the
541// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700542func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
543 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
544}
545
Colin Cross036a1df2015-12-17 15:49:30 -0800546// SetAllowMissingDependencies changes the behavior of Blueprint to ignore
547// unresolved dependencies. If the module's GenerateBuildActions calls
548// ModuleContext.GetMissingDependencies Blueprint will not emit any errors
549// for missing dependencies.
550func (c *Context) SetAllowMissingDependencies(allowMissingDependencies bool) {
551 c.allowMissingDependencies = allowMissingDependencies
552}
553
Jeff Gastonc3e28442017-08-09 15:13:12 -0700554func (c *Context) SetModuleListFile(listFile string) {
555 c.moduleListFile = listFile
556}
557
558func (c *Context) ListModulePaths(baseDir string) (paths []string, err error) {
559 reader, err := c.fs.Open(c.moduleListFile)
560 if err != nil {
561 return nil, err
562 }
563 bytes, err := ioutil.ReadAll(reader)
564 if err != nil {
565 return nil, err
566 }
567 text := string(bytes)
568
569 text = strings.Trim(text, "\n")
570 lines := strings.Split(text, "\n")
571 for i := range lines {
572 lines[i] = filepath.Join(baseDir, lines[i])
573 }
574
575 return lines, nil
576}
577
Colin Cross7ad621c2015-01-07 16:22:45 -0800578type stringAndScope struct {
579 string
580 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700581}
582
Jeff Gastonc3e28442017-08-09 15:13:12 -0700583func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string, errs []error) {
584 baseDir := filepath.Dir(rootFile)
585 pathsToParse, err := c.ListModulePaths(baseDir)
586 if err != nil {
587 return nil, []error{err}
588 }
589 return c.ParseFileList(baseDir, pathsToParse)
590}
591
Jamie Gennisd4e10182014-06-12 20:06:50 -0700592// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
593// at rootFile. When it encounters a Blueprints file with a set of subdirs
594// listed it recursively parses any Blueprints files found in those
595// subdirectories.
596//
597// If no errors are encountered while parsing the files, the list of paths on
598// which the future output will depend is returned. This list will include both
599// Blueprints file paths as well as directory paths for cases where wildcard
600// subdirs are found.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700601func (c *Context) ParseFileList(rootDir string, filePaths []string) (deps []string,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700602 errs []error) {
603
Jeff Gastonc3e28442017-08-09 15:13:12 -0700604 if len(filePaths) < 1 {
605 return nil, []error{fmt.Errorf("no paths provided to parse")}
606 }
607
Colin Cross7ad621c2015-01-07 16:22:45 -0800608 c.dependenciesReady = false
609
Colin Cross23d7aa12015-06-30 16:05:22 -0700610 moduleCh := make(chan *moduleInfo)
611 errsCh := make(chan []error)
612 doneCh := make(chan struct{})
613 var numErrs uint32
614 var numGoroutines int32
615
616 // handler must be reentrant
Jeff Gaston5f763d02017-08-08 14:43:58 -0700617 handleOneFile := func(file *parser.File) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700618 if atomic.LoadUint32(&numErrs) > maxErrors {
619 return
620 }
621
622 atomic.AddInt32(&numGoroutines, 1)
623 go func() {
624 for _, def := range file.Defs {
625 var module *moduleInfo
626 var errs []error
627 switch def := def.(type) {
628 case *parser.Module:
629 module, errs = c.processModuleDef(def, file.Name)
630 case *parser.Assignment:
631 // Already handled via Scope object
632 default:
633 panic("unknown definition type")
634 }
635
636 if len(errs) > 0 {
637 atomic.AddUint32(&numErrs, uint32(len(errs)))
638 errsCh <- errs
639 } else if module != nil {
640 moduleCh <- module
641 }
642 }
643 doneCh <- struct{}{}
644 }()
645 }
646
647 atomic.AddInt32(&numGoroutines, 1)
648 go func() {
649 var errs []error
Jeff Gastonc3e28442017-08-09 15:13:12 -0700650 deps, errs = c.WalkBlueprintsFiles(rootDir, filePaths, handleOneFile)
Colin Cross23d7aa12015-06-30 16:05:22 -0700651 if len(errs) > 0 {
652 errsCh <- errs
653 }
654 doneCh <- struct{}{}
655 }()
656
657loop:
658 for {
659 select {
660 case newErrs := <-errsCh:
661 errs = append(errs, newErrs...)
662 case module := <-moduleCh:
663 newErrs := c.addModule(module)
664 if len(newErrs) > 0 {
665 errs = append(errs, newErrs...)
666 }
667 case <-doneCh:
668 n := atomic.AddInt32(&numGoroutines, -1)
669 if n == 0 {
670 break loop
671 }
672 }
673 }
674
675 return deps, errs
676}
677
678type FileHandler func(*parser.File)
679
Jeff Gastonc3e28442017-08-09 15:13:12 -0700680// WalkBlueprintsFiles walks a set of Blueprints files starting with the given filepaths,
681// calling the given file handler on each
682//
683// When WalkBlueprintsFiles encounters a Blueprints file with a set of subdirs listed,
684// it recursively parses any Blueprints files found in those subdirectories.
685//
686// If any of the file paths is an ancestor directory of any other of file path, the ancestor
687// will be parsed and visited first.
688//
689// the file handler will be called from a goroutine, so it must be reentrant.
Colin Cross23d7aa12015-06-30 16:05:22 -0700690//
691// If no errors are encountered while parsing the files, the list of paths on
692// which the future output will depend is returned. This list will include both
693// Blueprints file paths as well as directory paths for cases where wildcard
694// subdirs are found.
Jeff Gastonc3e28442017-08-09 15:13:12 -0700695func (c *Context) WalkBlueprintsFiles(rootDir string, filePaths []string,
696 visitor FileHandler) (deps []string, errs []error) {
Colin Cross23d7aa12015-06-30 16:05:22 -0700697
Jeff Gastonc3e28442017-08-09 15:13:12 -0700698 // make a mapping from ancestors to their descendants to facilitate parsing ancestors first
699 descendantsMap, err := findBlueprintDescendants(filePaths)
700 if err != nil {
701 panic(err.Error())
702 return nil, []error{err}
703 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800704 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700705
Jeff Gaston5f763d02017-08-08 14:43:58 -0700706 // Channels to receive data back from parseOneAsync goroutines
Colin Cross7ad621c2015-01-07 16:22:45 -0800707 blueprintsCh := make(chan stringAndScope)
708 errsCh := make(chan []error)
Colin Cross23d7aa12015-06-30 16:05:22 -0700709 fileCh := make(chan *parser.File)
Colin Cross7ad621c2015-01-07 16:22:45 -0800710 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700711
Jeff Gaston5f763d02017-08-08 14:43:58 -0700712 // Channel to notify main loop that a parseOneAsync goroutine has finished
Jeff Gastonc3e28442017-08-09 15:13:12 -0700713 doneCh := make(chan stringAndScope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700714
Colin Cross7ad621c2015-01-07 16:22:45 -0800715 // Number of outstanding goroutines to wait for
Jeff Gaston5f763d02017-08-08 14:43:58 -0700716 activeCount := 0
Jeff Gastonc3e28442017-08-09 15:13:12 -0700717 var pending []stringAndScope
718 tooManyErrors := false
719
720 // Limit concurrent calls to parseBlueprintFiles to 200
721 // Darwin has a default limit of 256 open files
722 maxActiveCount := 200
Colin Cross7ad621c2015-01-07 16:22:45 -0800723
Colin Cross4a02a302017-05-16 10:33:58 -0700724 startParseBlueprintsFile := func(blueprint stringAndScope) {
725 if blueprintsSet[blueprint.string] {
726 return
727 }
728 blueprintsSet[blueprint.string] = true
Jeff Gaston5f763d02017-08-08 14:43:58 -0700729 activeCount++
Jeff Gastonc3e28442017-08-09 15:13:12 -0700730 deps = append(deps, blueprint.string)
Colin Cross7ad621c2015-01-07 16:22:45 -0800731 go func() {
Jeff Gaston5f763d02017-08-08 14:43:58 -0700732 c.parseOneAsync(blueprint.string, blueprint.Scope, rootDir,
Colin Cross23d7aa12015-06-30 16:05:22 -0700733 errsCh, fileCh, blueprintsCh, depsCh)
Jeff Gaston5f763d02017-08-08 14:43:58 -0700734
Jeff Gastonc3e28442017-08-09 15:13:12 -0700735 doneCh <- blueprint
Colin Cross7ad621c2015-01-07 16:22:45 -0800736 }()
737 }
738
Jeff Gastonc3e28442017-08-09 15:13:12 -0700739 foundParseableBlueprint := func(blueprint stringAndScope) {
740 if activeCount >= maxActiveCount {
741 pending = append(pending, blueprint)
742 } else {
743 startParseBlueprintsFile(blueprint)
744 }
745 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800746
Jeff Gastonc3e28442017-08-09 15:13:12 -0700747 startParseDescendants := func(blueprint stringAndScope) {
748 descendants, hasDescendants := descendantsMap[blueprint.string]
749 if hasDescendants {
750 for _, descendant := range descendants {
751 foundParseableBlueprint(stringAndScope{descendant, parser.NewScope(blueprint.Scope)})
752 }
753 }
754 }
Colin Cross4a02a302017-05-16 10:33:58 -0700755
Jeff Gastonc3e28442017-08-09 15:13:12 -0700756 // begin parsing any files that have no ancestors
757 startParseDescendants(stringAndScope{"", parser.NewScope(nil)})
Colin Cross7ad621c2015-01-07 16:22:45 -0800758
759loop:
760 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700761 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800762 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700763 }
764
Colin Cross7ad621c2015-01-07 16:22:45 -0800765 select {
766 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700767 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800768 case dep := <-depsCh:
769 deps = append(deps, dep)
Colin Cross23d7aa12015-06-30 16:05:22 -0700770 case file := <-fileCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700771 visitor(file)
Colin Cross7ad621c2015-01-07 16:22:45 -0800772 case blueprint := <-blueprintsCh:
773 if tooManyErrors {
774 continue
775 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700776 foundParseableBlueprint(blueprint)
777 case blueprint := <-doneCh:
Jeff Gaston5f763d02017-08-08 14:43:58 -0700778 activeCount--
Jeff Gastonc3e28442017-08-09 15:13:12 -0700779 if !tooManyErrors {
780 startParseDescendants(blueprint)
781 }
782 if activeCount < maxActiveCount && len(pending) > 0 {
783 // start to process the next one from the queue
784 next := pending[len(pending)-1]
Colin Cross4a02a302017-05-16 10:33:58 -0700785 pending = pending[:len(pending)-1]
Jeff Gastonc3e28442017-08-09 15:13:12 -0700786 startParseBlueprintsFile(next)
Colin Cross4a02a302017-05-16 10:33:58 -0700787 }
Jeff Gaston5f763d02017-08-08 14:43:58 -0700788 if activeCount == 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800789 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700790 }
791 }
792 }
793
Jeff Gastonc3e28442017-08-09 15:13:12 -0700794 sort.Strings(deps)
795
Colin Cross7ad621c2015-01-07 16:22:45 -0800796 return
797}
798
Colin Crossd7b0f602016-06-02 15:30:20 -0700799// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
800// filenames to contents stored as a byte slice.
801func (c *Context) MockFileSystem(files map[string][]byte) {
Jeff Gaston9f630902017-11-15 14:49:48 -0800802 // look for a module list file
803 _, ok := files[MockModuleListFile]
804 if !ok {
805 // no module list file specified; find every file named Blueprints
806 pathsToParse := []string{}
807 for candidate := range files {
808 if filepath.Base(candidate) == "Blueprints" {
809 pathsToParse = append(pathsToParse, candidate)
810 }
Jeff Gastonc3e28442017-08-09 15:13:12 -0700811 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800812 if len(pathsToParse) < 1 {
813 panic(fmt.Sprintf("No Blueprints files found in mock filesystem: %v\n", files))
814 }
815 // put the list of Blueprints files into a list file
816 files[MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
Jeff Gastonc3e28442017-08-09 15:13:12 -0700817 }
Jeff Gaston9f630902017-11-15 14:49:48 -0800818 c.SetModuleListFile(MockModuleListFile)
Jeff Gastonc3e28442017-08-09 15:13:12 -0700819
820 // mock the filesystem
Colin Crossb519a7e2017-02-01 13:21:35 -0800821 c.fs = pathtools.MockFs(files)
Colin Crossd7b0f602016-06-02 15:30:20 -0700822}
823
Jeff Gaston5f763d02017-08-08 14:43:58 -0700824// parseOneAsync parses a single Blueprints file, and sends results through the provided channels
825//
826// Errors are returned through errsCh.
827// Any defined modules are returned through modulesCh.
828// Any sub-Blueprints files are returned through blueprintsCh.
829// Any dependencies on Blueprints files or directories are returned through depsCh.
Jeff Gaston5f763d02017-08-08 14:43:58 -0700830func (c *Context) parseOneAsync(filename string, scope *parser.Scope, rootDir string,
Colin Cross23d7aa12015-06-30 16:05:22 -0700831 errsCh chan<- []error, fileCh chan<- *parser.File, blueprintsCh chan<- stringAndScope,
Colin Cross7ad621c2015-01-07 16:22:45 -0800832 depsCh chan<- string) {
833
Colin Crossd7b0f602016-06-02 15:30:20 -0700834 f, err := c.fs.Open(filename)
Colin Cross7ad621c2015-01-07 16:22:45 -0800835 if err != nil {
Jeff Gastonaca42202017-08-23 17:30:05 -0700836 // couldn't open the file; see if we can provide a clearer error than "could not open file"
837 stats, statErr := c.fs.Lstat(filename)
838 if statErr == nil {
839 isSymlink := stats.Mode()&os.ModeSymlink != 0
840 if isSymlink {
841 err = fmt.Errorf("could not open symlink %v : %v", filename, err)
842 target, readlinkErr := os.Readlink(filename)
843 if readlinkErr == nil {
844 _, targetStatsErr := c.fs.Lstat(target)
845 if targetStatsErr != nil {
846 err = fmt.Errorf("could not open symlink %v; its target (%v) cannot be opened", filename, target)
847 }
848 }
849 } else {
850 err = fmt.Errorf("%v exists but could not be opened: %v", filename, err)
851 }
852 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800853 errsCh <- []error{err}
854 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700855 }
Colin Cross23d7aa12015-06-30 16:05:22 -0700856 defer func() {
857 err = f.Close()
858 if err != nil {
859 errsCh <- []error{err}
860 }
861 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700862
Jeff Gaston5f763d02017-08-08 14:43:58 -0700863 file, subBlueprints, errs := c.parseOne(rootDir, filename, f, scope)
Colin Cross7ad621c2015-01-07 16:22:45 -0800864 if len(errs) > 0 {
865 errsCh <- errs
Colin Cross23d7aa12015-06-30 16:05:22 -0700866 } else {
867 fileCh <- file
Colin Cross7ad621c2015-01-07 16:22:45 -0800868 }
869
Colin Cross1fef5362015-04-20 16:50:54 -0700870 for _, b := range subBlueprints {
871 blueprintsCh <- b
Colin Cross127d2ea2016-11-01 11:10:51 -0700872 depsCh <- b.string
Colin Cross1fef5362015-04-20 16:50:54 -0700873 }
Colin Cross1fef5362015-04-20 16:50:54 -0700874}
875
Jeff Gastona12f22f2017-08-08 14:45:56 -0700876// parseOne parses a single Blueprints file from the given reader, creating Module
877// objects for each of the module definitions encountered. If the Blueprints
878// file contains an assignment to the "subdirs" variable, then the
879// subdirectories listed are searched for Blueprints files returned in the
880// subBlueprints return value. If the Blueprints file contains an assignment
881// to the "build" variable, then the file listed are returned in the
882// subBlueprints return value.
883//
884// rootDir specifies the path to the root directory of the source tree, while
885// filename specifies the path to the Blueprints file. These paths are used for
886// error reporting and for determining the module's directory.
887func (c *Context) parseOne(rootDir, filename string, reader io.Reader,
888 scope *parser.Scope) (file *parser.File, subBlueprints []stringAndScope, errs []error) {
889
890 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
891 if err != nil {
892 return nil, nil, []error{err}
893 }
894
Jeff Gastona12f22f2017-08-08 14:45:56 -0700895 scope.Remove("subdirs")
896 scope.Remove("optional_subdirs")
897 scope.Remove("build")
898 file, errs = parser.ParseAndEval(filename, reader, scope)
899 if len(errs) > 0 {
900 for i, err := range errs {
901 if parseErr, ok := err.(*parser.ParseError); ok {
902 err = &BlueprintError{
903 Err: parseErr.Err,
904 Pos: parseErr.Pos,
905 }
906 errs[i] = err
907 }
908 }
909
910 // If there were any parse errors don't bother trying to interpret the
911 // result.
912 return nil, nil, errs
913 }
914 file.Name = relBlueprintsFile
915
Jeff Gastona12f22f2017-08-08 14:45:56 -0700916 build, buildPos, err := getLocalStringListFromScope(scope, "build")
917 if err != nil {
918 errs = append(errs, err)
919 }
920
921 subBlueprintsName, _, err := getStringFromScope(scope, "subname")
922 if err != nil {
923 errs = append(errs, err)
924 }
925
926 if subBlueprintsName == "" {
927 subBlueprintsName = "Blueprints"
928 }
929
930 var blueprints []string
931
932 newBlueprints, newErrs := c.findBuildBlueprints(filepath.Dir(filename), build, buildPos)
933 blueprints = append(blueprints, newBlueprints...)
934 errs = append(errs, newErrs...)
935
Jeff Gastona12f22f2017-08-08 14:45:56 -0700936 subBlueprintsAndScope := make([]stringAndScope, len(blueprints))
937 for i, b := range blueprints {
Jeff Gastonc3e28442017-08-09 15:13:12 -0700938 subBlueprintsAndScope[i] = stringAndScope{b, parser.NewScope(scope)}
Jeff Gastona12f22f2017-08-08 14:45:56 -0700939 }
Jeff Gastona12f22f2017-08-08 14:45:56 -0700940 return file, subBlueprintsAndScope, errs
941}
942
Colin Cross7f507402015-12-16 13:03:41 -0800943func (c *Context) findBuildBlueprints(dir string, build []string,
Colin Cross127d2ea2016-11-01 11:10:51 -0700944 buildPos scanner.Position) ([]string, []error) {
945
946 var blueprints []string
947 var errs []error
Colin Cross7f507402015-12-16 13:03:41 -0800948
949 for _, file := range build {
Colin Cross127d2ea2016-11-01 11:10:51 -0700950 pattern := filepath.Join(dir, file)
951 var matches []string
952 var err error
953
Colin Cross08e49542016-11-14 15:23:33 -0800954 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -0700955
Colin Cross7f507402015-12-16 13:03:41 -0800956 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700957 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700958 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross7f507402015-12-16 13:03:41 -0800959 Pos: buildPos,
960 })
961 continue
962 }
963
964 if len(matches) == 0 {
Colin Cross2c628442016-10-07 17:13:10 -0700965 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700966 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross7f507402015-12-16 13:03:41 -0800967 Pos: buildPos,
968 })
969 }
970
Colin Cross7f507402015-12-16 13:03:41 -0800971 for _, foundBlueprints := range matches {
Colin Cross7f507402015-12-16 13:03:41 -0800972 blueprints = append(blueprints, foundBlueprints)
973 }
974 }
975
Colin Cross127d2ea2016-11-01 11:10:51 -0700976 return blueprints, errs
Colin Cross7f507402015-12-16 13:03:41 -0800977}
978
979func (c *Context) findSubdirBlueprints(dir string, subdirs []string, subdirsPos scanner.Position,
Colin Cross127d2ea2016-11-01 11:10:51 -0700980 subBlueprintsName string, optional bool) ([]string, []error) {
981
982 var blueprints []string
983 var errs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800984
985 for _, subdir := range subdirs {
Colin Cross127d2ea2016-11-01 11:10:51 -0700986 pattern := filepath.Join(dir, subdir, subBlueprintsName)
987 var matches []string
988 var err error
989
Colin Cross08e49542016-11-14 15:23:33 -0800990 matches, err = c.glob(pattern, nil)
Colin Cross127d2ea2016-11-01 11:10:51 -0700991
Michael Beardsworth1ec44532015-03-31 20:39:02 -0700992 if err != nil {
Colin Cross2c628442016-10-07 17:13:10 -0700993 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -0700994 Err: fmt.Errorf("%q: %s", pattern, err.Error()),
Colin Cross1fef5362015-04-20 16:50:54 -0700995 Pos: subdirsPos,
996 })
997 continue
998 }
999
Colin Cross7f507402015-12-16 13:03:41 -08001000 if len(matches) == 0 && !optional {
Colin Cross2c628442016-10-07 17:13:10 -07001001 errs = append(errs, &BlueprintError{
Colin Cross127d2ea2016-11-01 11:10:51 -07001002 Err: fmt.Errorf("%q: not found", pattern),
Colin Cross1fef5362015-04-20 16:50:54 -07001003 Pos: subdirsPos,
1004 })
Michael Beardsworth1ec44532015-03-31 20:39:02 -07001005 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001006
Colin Cross127d2ea2016-11-01 11:10:51 -07001007 for _, subBlueprints := range matches {
1008 blueprints = append(blueprints, subBlueprints)
Colin Cross7ad621c2015-01-07 16:22:45 -08001009 }
1010 }
Colin Cross1fef5362015-04-20 16:50:54 -07001011
Colin Cross127d2ea2016-11-01 11:10:51 -07001012 return blueprints, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001013}
1014
Colin Cross6d8780f2015-07-10 17:51:55 -07001015func getLocalStringListFromScope(scope *parser.Scope, v string) ([]string, scanner.Position, error) {
1016 if assignment, local := scope.Get(v); assignment == nil || !local {
1017 return nil, scanner.Position{}, nil
1018 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001019 switch value := assignment.Value.Eval().(type) {
1020 case *parser.List:
1021 ret := make([]string, 0, len(value.Values))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001022
Colin Crosse32cc802016-06-07 12:28:16 -07001023 for _, listValue := range value.Values {
1024 s, ok := listValue.(*parser.String)
1025 if !ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001026 // The parser should not produce this.
1027 panic("non-string value found in list")
1028 }
1029
Colin Crosse32cc802016-06-07 12:28:16 -07001030 ret = append(ret, s.Value)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001031 }
1032
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001033 return ret, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001034 case *parser.Bool, *parser.String:
Colin Cross2c628442016-10-07 17:13:10 -07001035 return nil, scanner.Position{}, &BlueprintError{
Colin Cross1fef5362015-04-20 16:50:54 -07001036 Err: fmt.Errorf("%q must be a list of strings", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001037 Pos: assignment.EqualsPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001038 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001039 default:
1040 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
1041 }
1042 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001043}
1044
Colin Cross29394222015-04-27 13:18:21 -07001045func getStringFromScope(scope *parser.Scope, v string) (string, scanner.Position, error) {
Colin Cross6d8780f2015-07-10 17:51:55 -07001046 if assignment, _ := scope.Get(v); assignment == nil {
1047 return "", scanner.Position{}, nil
1048 } else {
Colin Crosse32cc802016-06-07 12:28:16 -07001049 switch value := assignment.Value.Eval().(type) {
1050 case *parser.String:
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001051 return value.Value, assignment.EqualsPos, nil
Colin Crosse32cc802016-06-07 12:28:16 -07001052 case *parser.Bool, *parser.List:
Colin Cross2c628442016-10-07 17:13:10 -07001053 return "", scanner.Position{}, &BlueprintError{
Colin Cross29394222015-04-27 13:18:21 -07001054 Err: fmt.Errorf("%q must be a string", v),
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001055 Pos: assignment.EqualsPos,
Colin Cross29394222015-04-27 13:18:21 -07001056 }
1057 default:
1058 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
1059 }
1060 }
Colin Cross29394222015-04-27 13:18:21 -07001061}
1062
Colin Cross910242b2016-04-11 15:41:52 -07001063// Clones a build logic module by calling the factory method for its module type, and then cloning
1064// property values. Any values stored in the module object that are not stored in properties
1065// structs will be lost.
1066func (c *Context) cloneLogicModule(origModule *moduleInfo) (Module, []interface{}) {
Colin Crossaf4fd212017-07-28 14:32:36 -07001067 newLogicModule, newProperties := origModule.factory()
Colin Cross910242b2016-04-11 15:41:52 -07001068
Colin Crossd2f4ac12017-07-28 14:31:03 -07001069 if len(newProperties) != len(origModule.properties) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001070 panic("mismatched properties array length in " + origModule.Name())
Colin Cross910242b2016-04-11 15:41:52 -07001071 }
1072
1073 for i := range newProperties {
1074 dst := reflect.ValueOf(newProperties[i]).Elem()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001075 src := reflect.ValueOf(origModule.properties[i]).Elem()
Colin Cross910242b2016-04-11 15:41:52 -07001076
1077 proptools.CopyProperties(dst, src)
1078 }
1079
1080 return newLogicModule, newProperties
1081}
1082
Colin Crossf5e34b92015-03-13 16:02:36 -07001083func (c *Context) createVariations(origModule *moduleInfo, mutatorName string,
1084 variationNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -08001085
Colin Crossf4d18a62015-03-18 17:43:15 -07001086 if len(variationNames) == 0 {
1087 panic(fmt.Errorf("mutator %q passed zero-length variation list for module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001088 mutatorName, origModule.Name()))
Colin Crossf4d18a62015-03-18 17:43:15 -07001089 }
1090
Colin Crossc9028482014-12-18 16:28:54 -08001091 newModules := []*moduleInfo{}
Colin Crossc9028482014-12-18 16:28:54 -08001092
Colin Cross174ae052015-03-03 17:37:03 -08001093 var errs []error
1094
Colin Crossf5e34b92015-03-13 16:02:36 -07001095 for i, variationName := range variationNames {
Colin Crossc9028482014-12-18 16:28:54 -08001096 var newLogicModule Module
1097 var newProperties []interface{}
1098
1099 if i == 0 {
1100 // Reuse the existing module for the first new variant
Colin Cross21e078a2015-03-16 10:57:54 -07001101 // This both saves creating a new module, and causes the insertion in c.moduleInfo below
1102 // with logicModule as the key to replace the original entry in c.moduleInfo
Colin Crossd2f4ac12017-07-28 14:31:03 -07001103 newLogicModule, newProperties = origModule.logicModule, origModule.properties
Colin Crossc9028482014-12-18 16:28:54 -08001104 } else {
Colin Cross910242b2016-04-11 15:41:52 -07001105 newLogicModule, newProperties = c.cloneLogicModule(origModule)
Colin Crossc9028482014-12-18 16:28:54 -08001106 }
1107
Colin Crossf5e34b92015-03-13 16:02:36 -07001108 newVariant := origModule.variant.clone()
1109 newVariant[mutatorName] = variationName
Colin Crossc9028482014-12-18 16:28:54 -08001110
Colin Crossed342d92015-03-11 00:57:25 -07001111 m := *origModule
1112 newModule := &m
Colin Cross2c1f3d12016-04-11 15:47:28 -07001113 newModule.directDeps = append([]depInfo{}, origModule.directDeps...)
Colin Crossed342d92015-03-11 00:57:25 -07001114 newModule.logicModule = newLogicModule
Colin Crossf5e34b92015-03-13 16:02:36 -07001115 newModule.variant = newVariant
1116 newModule.dependencyVariant = origModule.dependencyVariant.clone()
Colin Crossd2f4ac12017-07-28 14:31:03 -07001117 newModule.properties = newProperties
Colin Crossc9028482014-12-18 16:28:54 -08001118
Colin Crossbadc8812016-08-11 17:01:46 -07001119 if variationName != "" {
1120 if newModule.variantName == "" {
1121 newModule.variantName = variationName
1122 } else {
1123 newModule.variantName += "_" + variationName
1124 }
Colin Crosse7daa222015-03-11 14:35:41 -07001125 }
1126
Colin Crossc9028482014-12-18 16:28:54 -08001127 newModules = append(newModules, newModule)
Colin Cross21e078a2015-03-16 10:57:54 -07001128
Colin Crossf5e34b92015-03-13 16:02:36 -07001129 newErrs := c.convertDepsToVariation(newModule, mutatorName, variationName)
Colin Cross174ae052015-03-03 17:37:03 -08001130 if len(newErrs) > 0 {
1131 errs = append(errs, newErrs...)
1132 }
Colin Crossc9028482014-12-18 16:28:54 -08001133 }
1134
1135 // Mark original variant as invalid. Modules that depend on this module will still
1136 // depend on origModule, but we'll fix it when the mutator is called on them.
1137 origModule.logicModule = nil
1138 origModule.splitModules = newModules
1139
Colin Cross3702ac72016-08-11 11:09:00 -07001140 atomic.AddUint32(&c.depsModified, 1)
1141
Colin Cross174ae052015-03-03 17:37:03 -08001142 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -08001143}
1144
Colin Crossf5e34b92015-03-13 16:02:36 -07001145func (c *Context) convertDepsToVariation(module *moduleInfo,
1146 mutatorName, variationName string) (errs []error) {
Colin Cross174ae052015-03-03 17:37:03 -08001147
Colin Crossc9028482014-12-18 16:28:54 -08001148 for i, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001149 if dep.module.logicModule == nil {
Colin Crossc9028482014-12-18 16:28:54 -08001150 var newDep *moduleInfo
Colin Cross2c1f3d12016-04-11 15:47:28 -07001151 for _, m := range dep.module.splitModules {
Colin Crossf5e34b92015-03-13 16:02:36 -07001152 if m.variant[mutatorName] == variationName {
Colin Crossc9028482014-12-18 16:28:54 -08001153 newDep = m
1154 break
1155 }
1156 }
1157 if newDep == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001158 errs = append(errs, &BlueprintError{
Colin Crossf5e34b92015-03-13 16:02:36 -07001159 Err: fmt.Errorf("failed to find variation %q for module %q needed by %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001160 variationName, dep.module.Name(), module.Name()),
Colin Crossed342d92015-03-11 00:57:25 -07001161 Pos: module.pos,
Colin Cross174ae052015-03-03 17:37:03 -08001162 })
1163 continue
Colin Crossc9028482014-12-18 16:28:54 -08001164 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001165 module.directDeps[i].module = newDep
Colin Crossc9028482014-12-18 16:28:54 -08001166 }
1167 }
Colin Cross174ae052015-03-03 17:37:03 -08001168
1169 return errs
Colin Crossc9028482014-12-18 16:28:54 -08001170}
1171
Colin Crossf5e34b92015-03-13 16:02:36 -07001172func (c *Context) prettyPrintVariant(variant variationMap) string {
Colin Cross65569e42015-03-10 20:08:19 -07001173 names := make([]string, 0, len(variant))
1174 for _, m := range c.variantMutatorNames {
1175 if v, ok := variant[m]; ok {
1176 names = append(names, m+":"+v)
1177 }
1178 }
1179
1180 return strings.Join(names, ", ")
1181}
1182
Colin Crossaf4fd212017-07-28 14:32:36 -07001183func (c *Context) newModule(factory ModuleFactory) *moduleInfo {
1184 logicModule, properties := factory()
1185
1186 module := &moduleInfo{
1187 logicModule: logicModule,
1188 factory: factory,
1189 }
1190
1191 module.properties = properties
1192
1193 return module
1194}
1195
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001196func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -08001197 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001198
Colin Crossc32c4792016-06-09 15:52:30 -07001199 factory, ok := c.moduleFactories[moduleDef.Type]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001200 if !ok {
1201 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -08001202 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001203 }
1204
Colin Cross7ad621c2015-01-07 16:22:45 -08001205 return nil, []error{
Colin Cross2c628442016-10-07 17:13:10 -07001206 &BlueprintError{
Colin Crossc32c4792016-06-09 15:52:30 -07001207 Err: fmt.Errorf("unrecognized module type %q", moduleDef.Type),
1208 Pos: moduleDef.TypePos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -07001209 },
1210 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001211 }
1212
Colin Crossaf4fd212017-07-28 14:32:36 -07001213 module := c.newModule(factory)
1214 module.typeName = moduleDef.Type
Colin Crossed342d92015-03-11 00:57:25 -07001215
Colin Crossaf4fd212017-07-28 14:32:36 -07001216 module.relBlueprintsFile = relBlueprintsFile
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001217
Colin Crossaf4fd212017-07-28 14:32:36 -07001218 propertyMap, errs := unpackProperties(moduleDef.Properties, module.properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001219 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -08001220 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001221 }
1222
Colin Crossc32c4792016-06-09 15:52:30 -07001223 module.pos = moduleDef.TypePos
Colin Crossed342d92015-03-11 00:57:25 -07001224 module.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -07001225 for name, propertyDef := range propertyMap {
Colin Crossb3d0b8d2016-06-09 17:03:57 -07001226 module.propertyPos[name] = propertyDef.ColonPos
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001227 }
1228
Colin Cross7ad621c2015-01-07 16:22:45 -08001229 return module, nil
1230}
1231
Colin Cross23d7aa12015-06-30 16:05:22 -07001232func (c *Context) addModule(module *moduleInfo) []error {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001233 name := module.logicModule.Name()
Colin Cross23d7aa12015-06-30 16:05:22 -07001234 c.moduleInfo[module.logicModule] = module
Colin Crossed342d92015-03-11 00:57:25 -07001235
Colin Cross0b7e83e2016-05-17 14:58:05 -07001236 if group, present := c.moduleNames[name]; present {
Colin Cross23d7aa12015-06-30 16:05:22 -07001237 return []error{
Colin Cross2c628442016-10-07 17:13:10 -07001238 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001239 Err: fmt.Errorf("module %q already defined", name),
1240 Pos: module.pos,
1241 },
Colin Cross2c628442016-10-07 17:13:10 -07001242 &BlueprintError{
Colin Cross23d7aa12015-06-30 16:05:22 -07001243 Err: fmt.Errorf("<-- previous definition here"),
1244 Pos: group.modules[0].pos,
1245 },
Colin Crossed342d92015-03-11 00:57:25 -07001246 }
Colin Cross7ad621c2015-01-07 16:22:45 -08001247 }
1248
Colin Cross0b7e83e2016-05-17 14:58:05 -07001249 ninjaName := toNinjaName(name)
1250
1251 // The sanitizing in toNinjaName can result in collisions, uniquify the name if it
1252 // already exists
1253 for i := 0; c.moduleNinjaNames[ninjaName] != nil; i++ {
1254 ninjaName = toNinjaName(name) + strconv.Itoa(i)
1255 }
1256
1257 group := &moduleGroup{
1258 name: name,
1259 ninjaName: ninjaName,
1260 modules: []*moduleInfo{module},
1261 }
1262 module.group = group
1263 c.moduleNames[name] = group
1264 c.moduleNinjaNames[ninjaName] = group
1265 c.moduleGroups = append(c.moduleGroups, group)
1266
Colin Cross23d7aa12015-06-30 16:05:22 -07001267 return nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001268}
1269
Jamie Gennisd4e10182014-06-12 20:06:50 -07001270// ResolveDependencies checks that the dependencies specified by all of the
1271// modules defined in the parsed Blueprints files are valid. This means that
1272// the modules depended upon are defined and that no circular dependencies
1273// exist.
Colin Cross874a3462017-07-31 17:26:06 -07001274func (c *Context) ResolveDependencies(config interface{}) (deps []string, errs []error) {
Colin Cross5f03f112017-11-07 13:29:54 -08001275 c.liveGlobals = newLiveTracker(config)
1276
1277 deps, errs = c.generateSingletonBuildActions(config, c.preSingletonInfo, c.liveGlobals)
1278 if len(errs) > 0 {
1279 return nil, errs
1280 }
1281
Colin Cross874a3462017-07-31 17:26:06 -07001282 errs = c.updateDependencies()
Colin Crossf8b50422016-08-10 12:56:40 -07001283 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001284 return nil, errs
Colin Crossf8b50422016-08-10 12:56:40 -07001285 }
1286
Colin Cross5f03f112017-11-07 13:29:54 -08001287 mutatorDeps, errs := c.runMutators(config)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001288 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001289 return nil, errs
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001290 }
Colin Cross5f03f112017-11-07 13:29:54 -08001291 deps = append(deps, mutatorDeps...)
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001292
Colin Cross910242b2016-04-11 15:41:52 -07001293 c.cloneModules()
1294
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001295 c.dependenciesReady = true
Colin Cross874a3462017-07-31 17:26:06 -07001296 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001297}
1298
Colin Cross763b6f12015-10-29 15:32:56 -07001299// Default dependencies handling. If the module implements the (deprecated)
Colin Cross65569e42015-03-10 20:08:19 -07001300// DynamicDependerModule interface then this set consists of the union of those
Colin Cross0b7e83e2016-05-17 14:58:05 -07001301// module names returned by its DynamicDependencies method and those added by calling
1302// AddDependencies or AddVariationDependencies on DynamicDependencyModuleContext.
Colin Cross763b6f12015-10-29 15:32:56 -07001303func blueprintDepsMutator(ctx BottomUpMutatorContext) {
Colin Cross763b6f12015-10-29 15:32:56 -07001304 if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001305 func() {
1306 defer func() {
1307 if r := recover(); r != nil {
1308 ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
1309 }
1310 }()
1311 dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001312
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001313 if ctx.Failed() {
1314 return
1315 }
Colin Cross763b6f12015-10-29 15:32:56 -07001316
Colin Cross2c1f3d12016-04-11 15:47:28 -07001317 ctx.AddDependency(ctx.Module(), nil, dynamicDeps...)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001318 }()
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001319 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001320}
1321
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001322// findMatchingVariant searches the moduleGroup for a module with the same variant as module,
1323// and returns the matching module, or nil if one is not found.
Colin Cross0b7e83e2016-05-17 14:58:05 -07001324func (c *Context) findMatchingVariant(module *moduleInfo, possible []*moduleInfo) *moduleInfo {
1325 if len(possible) == 1 {
1326 return possible[0]
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001327 } else {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001328 for _, m := range possible {
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001329 if m.variant.equal(module.dependencyVariant) {
1330 return m
1331 }
1332 }
1333 }
1334
1335 return nil
1336}
1337
Colin Cross2c1f3d12016-04-11 15:47:28 -07001338func (c *Context) addDependency(module *moduleInfo, tag DependencyTag, depName string) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001339 if _, ok := tag.(BaseDependencyTag); ok {
1340 panic("BaseDependencyTag is not allowed to be used directly!")
1341 }
1342
Colin Cross0b7e83e2016-05-17 14:58:05 -07001343 if depName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001344 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001345 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001346 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001347 }}
1348 }
1349
Colin Cross0b7e83e2016-05-17 14:58:05 -07001350 possibleDeps := c.modulesFromName(depName)
1351 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001352 if c.allowMissingDependencies {
1353 module.missingDeps = append(module.missingDeps, depName)
1354 return nil
1355 }
Colin Cross2c628442016-10-07 17:13:10 -07001356 return []error{&BlueprintError{
Colin Crossc9028482014-12-18 16:28:54 -08001357 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001358 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001359 Pos: module.pos,
Colin Crossc9028482014-12-18 16:28:54 -08001360 }}
1361 }
1362
Colin Cross0b7e83e2016-05-17 14:58:05 -07001363 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001364 for _, dep := range module.directDeps {
1365 if m == dep.module {
1366 // TODO(ccross): what if adding a dependency with a different tag?
1367 return nil
1368 }
Colin Cross65569e42015-03-10 20:08:19 -07001369 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001370 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001371 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001372 return nil
Colin Cross65569e42015-03-10 20:08:19 -07001373 }
Colin Crossc9028482014-12-18 16:28:54 -08001374
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001375 variants := make([]string, len(possibleDeps))
1376 for i, mod := range possibleDeps {
1377 variants[i] = c.prettyPrintVariant(mod.variant)
1378 }
1379 sort.Strings(variants)
1380
Colin Cross2c628442016-10-07 17:13:10 -07001381 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001382 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001383 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001384 c.prettyPrintVariant(module.dependencyVariant),
1385 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001386 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001387 }}
1388}
1389
Colin Cross8d8a7af2015-11-03 16:41:29 -08001390func (c *Context) findReverseDependency(module *moduleInfo, destName string) (*moduleInfo, []error) {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001391 if destName == module.Name() {
Colin Cross2c628442016-10-07 17:13:10 -07001392 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001393 Err: fmt.Errorf("%q depends on itself", destName),
1394 Pos: module.pos,
1395 }}
1396 }
1397
Colin Cross0b7e83e2016-05-17 14:58:05 -07001398 possibleDeps := c.modulesFromName(destName)
1399 if possibleDeps == nil {
Colin Cross2c628442016-10-07 17:13:10 -07001400 return nil, []error{&BlueprintError{
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001401 Err: fmt.Errorf("%q has a reverse dependency on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001402 module.Name(), destName),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001403 Pos: module.pos,
1404 }}
1405 }
1406
Colin Cross0b7e83e2016-05-17 14:58:05 -07001407 if m := c.findMatchingVariant(module, possibleDeps); m != nil {
Colin Cross8d8a7af2015-11-03 16:41:29 -08001408 return m, nil
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001409 }
1410
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001411 variants := make([]string, len(possibleDeps))
1412 for i, mod := range possibleDeps {
1413 variants[i] = c.prettyPrintVariant(mod.variant)
1414 }
1415 sort.Strings(variants)
1416
Colin Cross2c628442016-10-07 17:13:10 -07001417 return nil, []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001418 Err: fmt.Errorf("reverse dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001419 destName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001420 c.prettyPrintVariant(module.dependencyVariant),
1421 strings.Join(variants, "\n ")),
Dan Willemsenfdeb7242015-07-24 16:53:27 -07001422 Pos: module.pos,
1423 }}
1424}
1425
Colin Crossf5e34b92015-03-13 16:02:36 -07001426func (c *Context) addVariationDependency(module *moduleInfo, variations []Variation,
Colin Cross2c1f3d12016-04-11 15:47:28 -07001427 tag DependencyTag, depName string, far bool) []error {
Nan Zhang346b2d02017-03-10 16:39:27 -08001428 if _, ok := tag.(BaseDependencyTag); ok {
1429 panic("BaseDependencyTag is not allowed to be used directly!")
1430 }
Colin Cross65569e42015-03-10 20:08:19 -07001431
Colin Cross0b7e83e2016-05-17 14:58:05 -07001432 possibleDeps := c.modulesFromName(depName)
1433 if possibleDeps == nil {
Colin Cross036a1df2015-12-17 15:49:30 -08001434 if c.allowMissingDependencies {
1435 module.missingDeps = append(module.missingDeps, depName)
1436 return nil
1437 }
Colin Cross2c628442016-10-07 17:13:10 -07001438 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001439 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001440 module.Name(), depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001441 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001442 }}
1443 }
1444
1445 // We can't just append variant.Variant to module.dependencyVariants.variantName and
1446 // compare the strings because the result won't be in mutator registration order.
1447 // Create a new map instead, and then deep compare the maps.
Colin Cross89486232015-05-08 11:14:54 -07001448 var newVariant variationMap
1449 if !far {
1450 newVariant = module.dependencyVariant.clone()
1451 } else {
1452 newVariant = make(variationMap)
1453 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001454 for _, v := range variations {
1455 newVariant[v.Mutator] = v.Variation
Colin Cross65569e42015-03-10 20:08:19 -07001456 }
1457
Colin Cross0b7e83e2016-05-17 14:58:05 -07001458 for _, m := range possibleDeps {
Colin Cross89486232015-05-08 11:14:54 -07001459 var found bool
1460 if far {
1461 found = m.variant.subset(newVariant)
1462 } else {
1463 found = m.variant.equal(newVariant)
1464 }
1465 if found {
Colin Cross045a5972015-11-03 16:58:48 -08001466 if module == m {
Colin Cross2c628442016-10-07 17:13:10 -07001467 return []error{&BlueprintError{
Colin Cross045a5972015-11-03 16:58:48 -08001468 Err: fmt.Errorf("%q depends on itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001469 Pos: module.pos,
Colin Cross045a5972015-11-03 16:58:48 -08001470 }}
1471 }
Colin Crossf5e34b92015-03-13 16:02:36 -07001472 // AddVariationDependency allows adding a dependency on itself, but only if
Colin Cross65569e42015-03-10 20:08:19 -07001473 // that module is earlier in the module list than this one, since we always
Colin Crossf5e34b92015-03-13 16:02:36 -07001474 // run GenerateBuildActions in order for the variants of a module
Colin Cross0b7e83e2016-05-17 14:58:05 -07001475 if m.group == module.group && beforeInModuleList(module, m, module.group.modules) {
Colin Cross2c628442016-10-07 17:13:10 -07001476 return []error{&BlueprintError{
Colin Cross65569e42015-03-10 20:08:19 -07001477 Err: fmt.Errorf("%q depends on later version of itself", depName),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001478 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001479 }}
1480 }
Colin Cross2c1f3d12016-04-11 15:47:28 -07001481 module.directDeps = append(module.directDeps, depInfo{m, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001482 atomic.AddUint32(&c.depsModified, 1)
Colin Cross65569e42015-03-10 20:08:19 -07001483 return nil
1484 }
1485 }
1486
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001487 variants := make([]string, len(possibleDeps))
1488 for i, mod := range possibleDeps {
1489 variants[i] = c.prettyPrintVariant(mod.variant)
1490 }
1491 sort.Strings(variants)
1492
Colin Cross2c628442016-10-07 17:13:10 -07001493 return []error{&BlueprintError{
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001494 Err: fmt.Errorf("dependency %q of %q missing variant:\n %s\navailable variants:\n %s",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001495 depName, module.Name(),
Dan Willemsen978c4aa2017-03-20 14:11:38 -07001496 c.prettyPrintVariant(newVariant),
1497 strings.Join(variants, "\n ")),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001498 Pos: module.pos,
Colin Cross65569e42015-03-10 20:08:19 -07001499 }}
Colin Crossc9028482014-12-18 16:28:54 -08001500}
1501
Colin Crossf1875462016-04-11 17:33:13 -07001502func (c *Context) addInterVariantDependency(origModule *moduleInfo, tag DependencyTag,
1503 from, to Module) {
Nan Zhang346b2d02017-03-10 16:39:27 -08001504 if _, ok := tag.(BaseDependencyTag); ok {
1505 panic("BaseDependencyTag is not allowed to be used directly!")
1506 }
Colin Crossf1875462016-04-11 17:33:13 -07001507
1508 var fromInfo, toInfo *moduleInfo
1509 for _, m := range origModule.splitModules {
1510 if m.logicModule == from {
1511 fromInfo = m
1512 }
1513 if m.logicModule == to {
1514 toInfo = m
1515 if fromInfo != nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07001516 panic(fmt.Errorf("%q depends on later version of itself", origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001517 }
1518 }
1519 }
1520
1521 if fromInfo == nil || toInfo == nil {
1522 panic(fmt.Errorf("AddInterVariantDependency called for module %q on invalid variant",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001523 origModule.Name()))
Colin Crossf1875462016-04-11 17:33:13 -07001524 }
1525
1526 fromInfo.directDeps = append(fromInfo.directDeps, depInfo{toInfo, tag})
Colin Cross3702ac72016-08-11 11:09:00 -07001527 atomic.AddUint32(&c.depsModified, 1)
Colin Crossf1875462016-04-11 17:33:13 -07001528}
1529
Jeff Gastonc3e28442017-08-09 15:13:12 -07001530// findBlueprintDescendants returns a map linking parent Blueprints files to child Blueprints files
1531// For example, if paths = []string{"a/b/c/Android.bp", "a/Blueprints"},
1532// then descendants = {"":[]string{"a/Blueprints"}, "a/Blueprints":[]string{"a/b/c/Android.bp"}}
1533func findBlueprintDescendants(paths []string) (descendants map[string][]string, err error) {
1534 // make mapping from dir path to file path
1535 filesByDir := make(map[string]string, len(paths))
1536 for _, path := range paths {
1537 dir := filepath.Dir(path)
1538 _, alreadyFound := filesByDir[dir]
1539 if alreadyFound {
1540 return nil, fmt.Errorf("Found two Blueprint files in directory %v : %v and %v", dir, filesByDir[dir], path)
1541 }
1542 filesByDir[dir] = path
1543 }
1544
1545 // generate the descendants map
1546 descendants = make(map[string][]string, len(filesByDir))
1547 for childDir, childFile := range filesByDir {
1548 prevAncestorDir := childDir
1549 for {
1550 ancestorDir := filepath.Dir(prevAncestorDir)
1551 if ancestorDir == prevAncestorDir {
1552 // reached the root dir without any matches; assign this as a descendant of ""
1553 descendants[""] = append(descendants[""], childFile)
1554 break
1555 }
1556
1557 ancestorFile, ancestorExists := filesByDir[ancestorDir]
1558 if ancestorExists {
1559 descendants[ancestorFile] = append(descendants[ancestorFile], childFile)
1560 break
1561 }
1562 prevAncestorDir = ancestorDir
1563 }
1564 }
1565 return descendants, nil
1566}
1567
Colin Cross3702ac72016-08-11 11:09:00 -07001568type visitOrderer interface {
1569 // returns the number of modules that this module needs to wait for
1570 waitCount(module *moduleInfo) int
1571 // returns the list of modules that are waiting for this module
1572 propagate(module *moduleInfo) []*moduleInfo
1573 // visit modules in order
1574 visit(modules []*moduleInfo, visit func(*moduleInfo) bool)
1575}
1576
1577type bottomUpVisitorImpl struct{}
1578
1579func (bottomUpVisitorImpl) waitCount(module *moduleInfo) int {
1580 return len(module.forwardDeps)
1581}
1582
1583func (bottomUpVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1584 return module.reverseDeps
1585}
1586
1587func (bottomUpVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1588 for _, module := range modules {
Colin Cross49c279a2016-08-05 22:30:44 -07001589 if visit(module) {
1590 return
1591 }
1592 }
1593}
1594
Colin Cross3702ac72016-08-11 11:09:00 -07001595type topDownVisitorImpl struct{}
1596
1597func (topDownVisitorImpl) waitCount(module *moduleInfo) int {
1598 return len(module.reverseDeps)
1599}
1600
1601func (topDownVisitorImpl) propagate(module *moduleInfo) []*moduleInfo {
1602 return module.forwardDeps
1603}
1604
1605func (topDownVisitorImpl) visit(modules []*moduleInfo, visit func(*moduleInfo) bool) {
1606 for i := 0; i < len(modules); i++ {
1607 module := modules[len(modules)-1-i]
1608 if visit(module) {
1609 return
1610 }
1611 }
1612}
1613
1614var (
1615 bottomUpVisitor bottomUpVisitorImpl
1616 topDownVisitor topDownVisitorImpl
1617)
1618
Colin Cross49c279a2016-08-05 22:30:44 -07001619// Calls visit on each module, guaranteeing that visit is not called on a module until visit on all
1620// of its dependencies has finished.
Colin Cross3702ac72016-08-11 11:09:00 -07001621func (c *Context) parallelVisit(order visitOrderer, visit func(group *moduleInfo) bool) {
Colin Cross7addea32015-03-11 15:43:52 -07001622 doneCh := make(chan *moduleInfo)
Colin Cross0fff7422016-08-11 15:37:45 -07001623 cancelCh := make(chan bool)
Colin Cross691a60d2015-01-07 18:08:56 -08001624 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -08001625 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -08001626
Colin Cross7addea32015-03-11 15:43:52 -07001627 for _, module := range c.modulesSorted {
Colin Cross3702ac72016-08-11 11:09:00 -07001628 module.waitingCount = order.waitCount(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001629 }
1630
Colin Cross7addea32015-03-11 15:43:52 -07001631 visitOne := func(module *moduleInfo) {
Colin Cross691a60d2015-01-07 18:08:56 -08001632 count++
1633 go func() {
Colin Cross7addea32015-03-11 15:43:52 -07001634 ret := visit(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001635 if ret {
Colin Cross0fff7422016-08-11 15:37:45 -07001636 cancelCh <- true
Colin Cross8900e9b2015-03-02 14:03:01 -08001637 }
Colin Cross7addea32015-03-11 15:43:52 -07001638 doneCh <- module
Colin Cross691a60d2015-01-07 18:08:56 -08001639 }()
1640 }
1641
Colin Cross7addea32015-03-11 15:43:52 -07001642 for _, module := range c.modulesSorted {
1643 if module.waitingCount == 0 {
1644 visitOne(module)
Colin Cross691a60d2015-01-07 18:08:56 -08001645 }
1646 }
1647
Colin Cross11e3b0d2015-02-04 10:41:00 -08001648 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001649 select {
Colin Cross0fff7422016-08-11 15:37:45 -07001650 case cancel = <-cancelCh:
Colin Cross7addea32015-03-11 15:43:52 -07001651 case doneModule := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -08001652 if !cancel {
Colin Cross3702ac72016-08-11 11:09:00 -07001653 for _, module := range order.propagate(doneModule) {
1654 module.waitingCount--
1655 if module.waitingCount == 0 {
1656 visitOne(module)
Colin Cross8900e9b2015-03-02 14:03:01 -08001657 }
Colin Cross691a60d2015-01-07 18:08:56 -08001658 }
1659 }
1660 count--
Colin Cross691a60d2015-01-07 18:08:56 -08001661 }
1662 }
1663}
1664
1665// updateDependencies recursively walks the module dependency graph and updates
1666// additional fields based on the dependencies. It builds a sorted list of modules
1667// such that dependencies of a module always appear first, and populates reverse
1668// dependency links and counts of total dependencies. It also reports errors when
1669// it encounters dependency cycles. This should called after resolveDependencies,
1670// as well as after any mutator pass has called addDependency
1671func (c *Context) updateDependencies() (errs []error) {
Colin Cross7addea32015-03-11 15:43:52 -07001672 visited := make(map[*moduleInfo]bool) // modules that were already checked
1673 checking := make(map[*moduleInfo]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001674
Colin Cross7addea32015-03-11 15:43:52 -07001675 sorted := make([]*moduleInfo, 0, len(c.moduleInfo))
Colin Cross573a2fd2014-12-17 14:16:51 -08001676
Colin Cross7addea32015-03-11 15:43:52 -07001677 var check func(group *moduleInfo) []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001678
Colin Cross7addea32015-03-11 15:43:52 -07001679 cycleError := func(cycle []*moduleInfo) {
Colin Cross10b54db2015-03-11 14:40:30 -07001680 // We are the "start" of the cycle, so we're responsible
1681 // for generating the errors. The cycle list is in
1682 // reverse order because all the 'check' calls append
1683 // their own module to the list.
Colin Cross2c628442016-10-07 17:13:10 -07001684 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001685 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Cross7addea32015-03-11 15:43:52 -07001686 Pos: cycle[len(cycle)-1].pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001687 })
1688
1689 // Iterate backwards through the cycle list.
Colin Cross0e4607e2015-03-24 16:42:56 -07001690 curModule := cycle[0]
Colin Cross10b54db2015-03-11 14:40:30 -07001691 for i := len(cycle) - 1; i >= 0; i-- {
Colin Cross7addea32015-03-11 15:43:52 -07001692 nextModule := cycle[i]
Colin Cross2c628442016-10-07 17:13:10 -07001693 errs = append(errs, &BlueprintError{
Colin Cross10b54db2015-03-11 14:40:30 -07001694 Err: fmt.Errorf(" %q depends on %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07001695 curModule.Name(),
1696 nextModule.Name()),
Colin Cross7fcb7b02015-11-03 17:33:29 -08001697 Pos: curModule.pos,
Colin Cross10b54db2015-03-11 14:40:30 -07001698 })
Colin Cross7addea32015-03-11 15:43:52 -07001699 curModule = nextModule
Colin Cross10b54db2015-03-11 14:40:30 -07001700 }
1701 }
1702
Colin Cross7addea32015-03-11 15:43:52 -07001703 check = func(module *moduleInfo) []*moduleInfo {
1704 visited[module] = true
1705 checking[module] = true
1706 defer delete(checking, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001707
Colin Cross7addea32015-03-11 15:43:52 -07001708 deps := make(map[*moduleInfo]bool)
1709
1710 // Add an implicit dependency ordering on all earlier modules in the same module group
1711 for _, dep := range module.group.modules {
1712 if dep == module {
1713 break
Colin Crossbbfa51a2014-12-17 16:12:41 -08001714 }
Colin Cross7addea32015-03-11 15:43:52 -07001715 deps[dep] = true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001716 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001717
Colin Cross7addea32015-03-11 15:43:52 -07001718 for _, dep := range module.directDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07001719 deps[dep.module] = true
Colin Cross7addea32015-03-11 15:43:52 -07001720 }
1721
1722 module.reverseDeps = []*moduleInfo{}
Colin Cross3702ac72016-08-11 11:09:00 -07001723 module.forwardDeps = []*moduleInfo{}
Colin Cross691a60d2015-01-07 18:08:56 -08001724
Colin Crossbbfa51a2014-12-17 16:12:41 -08001725 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001726 if checking[dep] {
1727 // This is a cycle.
Colin Cross7addea32015-03-11 15:43:52 -07001728 return []*moduleInfo{dep, module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001729 }
1730
1731 if !visited[dep] {
1732 cycle := check(dep)
1733 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001734 if cycle[0] == module {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001735 // We are the "start" of the cycle, so we're responsible
1736 // for generating the errors. The cycle list is in
1737 // reverse order because all the 'check' calls append
1738 // their own module to the list.
Colin Cross10b54db2015-03-11 14:40:30 -07001739 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001740
1741 // We can continue processing this module's children to
1742 // find more cycles. Since all the modules that were
1743 // part of the found cycle were marked as visited we
1744 // won't run into that cycle again.
1745 } else {
1746 // We're not the "start" of the cycle, so we just append
1747 // our module to the list and return it.
Colin Cross7addea32015-03-11 15:43:52 -07001748 return append(cycle, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001749 }
1750 }
1751 }
Colin Cross691a60d2015-01-07 18:08:56 -08001752
Colin Cross3702ac72016-08-11 11:09:00 -07001753 module.forwardDeps = append(module.forwardDeps, dep)
Colin Cross7addea32015-03-11 15:43:52 -07001754 dep.reverseDeps = append(dep.reverseDeps, module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001755 }
1756
Colin Cross7addea32015-03-11 15:43:52 -07001757 sorted = append(sorted, module)
Colin Cross573a2fd2014-12-17 14:16:51 -08001758
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001759 return nil
1760 }
1761
Colin Cross7addea32015-03-11 15:43:52 -07001762 for _, module := range c.moduleInfo {
1763 if !visited[module] {
1764 cycle := check(module)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001765 if cycle != nil {
Colin Cross7addea32015-03-11 15:43:52 -07001766 if cycle[len(cycle)-1] != module {
Colin Cross10b54db2015-03-11 14:40:30 -07001767 panic("inconceivable!")
1768 }
1769 cycleError(cycle)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001770 }
1771 }
1772 }
1773
Colin Cross7addea32015-03-11 15:43:52 -07001774 c.modulesSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001775
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001776 return
1777}
1778
Jamie Gennisd4e10182014-06-12 20:06:50 -07001779// PrepareBuildActions generates an internal representation of all the build
1780// actions that need to be performed. This process involves invoking the
1781// GenerateBuildActions method on each of the Module objects created during the
1782// parse phase and then on each of the registered Singleton objects.
1783//
1784// If the ResolveDependencies method has not already been called it is called
1785// automatically by this method.
1786//
1787// The config argument is made available to all of the Module and Singleton
1788// objects via the Config method on the ModuleContext and SingletonContext
1789// objects passed to GenerateBuildActions. It is also passed to the functions
1790// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1791// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001792//
1793// The returned deps is a list of the ninja files dependencies that were added
Dan Willemsena481ae22015-12-18 15:18:03 -08001794// by the modules and singletons via the ModuleContext.AddNinjaFileDeps(),
1795// SingletonContext.AddNinjaFileDeps(), and PackageContext.AddNinjaFileDeps()
1796// methods.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001797func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 c.buildActionsReady = false
1799
1800 if !c.dependenciesReady {
Colin Cross874a3462017-07-31 17:26:06 -07001801 extraDeps, errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001802 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001803 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001804 }
Colin Cross874a3462017-07-31 17:26:06 -07001805 deps = append(deps, extraDeps...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001806 }
1807
Colin Cross5f03f112017-11-07 13:29:54 -08001808 depsModules, errs := c.generateModuleBuildActions(config, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001809 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001810 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001811 }
1812
Colin Cross5f03f112017-11-07 13:29:54 -08001813 depsSingletons, errs := c.generateSingletonBuildActions(config, c.singletonInfo, c.liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001814 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001815 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001816 }
1817
Colin Cross874a3462017-07-31 17:26:06 -07001818 deps = append(deps, depsModules...)
1819 deps = append(deps, depsSingletons...)
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001820
Colin Crossa2599452015-11-18 16:01:01 -08001821 if c.ninjaBuildDir != nil {
Colin Cross5f03f112017-11-07 13:29:54 -08001822 c.liveGlobals.addNinjaStringDeps(c.ninjaBuildDir)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001823 }
1824
Colin Cross5f03f112017-11-07 13:29:54 -08001825 pkgNames, depsPackages := c.makeUniquePackageNames(c.liveGlobals)
Dan Willemsena481ae22015-12-18 15:18:03 -08001826
1827 deps = append(deps, depsPackages...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001828
1829 // This will panic if it finds a problem since it's a programming error.
Colin Cross5f03f112017-11-07 13:29:54 -08001830 c.checkForVariableReferenceCycles(c.liveGlobals.variables, pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001831
1832 c.pkgNames = pkgNames
Colin Cross5f03f112017-11-07 13:29:54 -08001833 c.globalVariables = c.liveGlobals.variables
1834 c.globalPools = c.liveGlobals.pools
1835 c.globalRules = c.liveGlobals.rules
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001836
1837 c.buildActionsReady = true
1838
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001839 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001840}
1841
Colin Cross874a3462017-07-31 17:26:06 -07001842func (c *Context) runMutators(config interface{}) (deps []string, errs []error) {
Colin Crossf8b50422016-08-10 12:56:40 -07001843 var mutators []*mutatorInfo
Colin Cross763b6f12015-10-29 15:32:56 -07001844
Colin Crossf8b50422016-08-10 12:56:40 -07001845 mutators = append(mutators, c.earlyMutatorInfo...)
1846 mutators = append(mutators, c.mutatorInfo...)
1847
1848 for _, mutator := range mutators {
Colin Cross874a3462017-07-31 17:26:06 -07001849 var newDeps []string
Colin Crossc9028482014-12-18 16:28:54 -08001850 if mutator.topDownMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001851 newDeps, errs = c.runMutator(config, mutator, topDownMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001852 } else if mutator.bottomUpMutator != nil {
Colin Cross874a3462017-07-31 17:26:06 -07001853 newDeps, errs = c.runMutator(config, mutator, bottomUpMutator)
Colin Crossc9028482014-12-18 16:28:54 -08001854 } else {
1855 panic("no mutator set on " + mutator.name)
1856 }
1857 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07001858 return nil, errs
Colin Crossc9028482014-12-18 16:28:54 -08001859 }
Colin Cross874a3462017-07-31 17:26:06 -07001860 deps = append(deps, newDeps...)
Colin Crossc9028482014-12-18 16:28:54 -08001861 }
1862
Colin Cross874a3462017-07-31 17:26:06 -07001863 return deps, nil
Colin Crossc9028482014-12-18 16:28:54 -08001864}
1865
Colin Cross3702ac72016-08-11 11:09:00 -07001866type mutatorDirection interface {
1867 run(mutator *mutatorInfo, ctx *mutatorContext)
1868 orderer() visitOrderer
1869 fmt.Stringer
Colin Crossc9028482014-12-18 16:28:54 -08001870}
1871
Colin Cross3702ac72016-08-11 11:09:00 -07001872type bottomUpMutatorImpl struct{}
1873
1874func (bottomUpMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1875 mutator.bottomUpMutator(ctx)
1876}
1877
1878func (bottomUpMutatorImpl) orderer() visitOrderer {
1879 return bottomUpVisitor
1880}
1881
1882func (bottomUpMutatorImpl) String() string {
1883 return "bottom up mutator"
1884}
1885
1886type topDownMutatorImpl struct{}
1887
1888func (topDownMutatorImpl) run(mutator *mutatorInfo, ctx *mutatorContext) {
1889 mutator.topDownMutator(ctx)
1890}
1891
1892func (topDownMutatorImpl) orderer() visitOrderer {
1893 return topDownVisitor
1894}
1895
1896func (topDownMutatorImpl) String() string {
1897 return "top down mutator"
1898}
1899
1900var (
1901 topDownMutator topDownMutatorImpl
1902 bottomUpMutator bottomUpMutatorImpl
1903)
1904
Colin Cross49c279a2016-08-05 22:30:44 -07001905type reverseDep struct {
1906 module *moduleInfo
1907 dep depInfo
1908}
1909
Colin Cross3702ac72016-08-11 11:09:00 -07001910func (c *Context) runMutator(config interface{}, mutator *mutatorInfo,
Colin Cross874a3462017-07-31 17:26:06 -07001911 direction mutatorDirection) (deps []string, errs []error) {
Colin Cross49c279a2016-08-05 22:30:44 -07001912
1913 newModuleInfo := make(map[Module]*moduleInfo)
1914 for k, v := range c.moduleInfo {
1915 newModuleInfo[k] = v
1916 }
Colin Crossc9028482014-12-18 16:28:54 -08001917
Colin Cross0ce142c2016-12-09 10:29:05 -08001918 type globalStateChange struct {
Colin Crossaf4fd212017-07-28 14:32:36 -07001919 reverse []reverseDep
1920 rename []rename
1921 replace []replace
1922 newModules []*moduleInfo
Colin Cross874a3462017-07-31 17:26:06 -07001923 deps []string
Colin Cross0ce142c2016-12-09 10:29:05 -08001924 }
1925
Colin Cross2c1f3d12016-04-11 15:47:28 -07001926 reverseDeps := make(map[*moduleInfo][]depInfo)
Colin Cross0ce142c2016-12-09 10:29:05 -08001927 var rename []rename
1928 var replace []replace
Colin Crossaf4fd212017-07-28 14:32:36 -07001929 var newModules []*moduleInfo
Colin Cross8d8a7af2015-11-03 16:41:29 -08001930
Colin Cross49c279a2016-08-05 22:30:44 -07001931 errsCh := make(chan []error)
Colin Cross0ce142c2016-12-09 10:29:05 -08001932 globalStateCh := make(chan globalStateChange)
Colin Cross5fe225f2017-07-28 15:22:46 -07001933 newVariationsCh := make(chan []*moduleInfo)
Colin Cross49c279a2016-08-05 22:30:44 -07001934 done := make(chan bool)
Colin Crossc9028482014-12-18 16:28:54 -08001935
Colin Cross3702ac72016-08-11 11:09:00 -07001936 c.depsModified = 0
1937
Colin Cross49c279a2016-08-05 22:30:44 -07001938 visit := func(module *moduleInfo) bool {
Jamie Gennisc7988252015-04-14 23:28:10 -04001939 if module.splitModules != nil {
1940 panic("split module found in sorted module list")
1941 }
1942
Colin Cross7addea32015-03-11 15:43:52 -07001943 mctx := &mutatorContext{
1944 baseModuleContext: baseModuleContext{
1945 context: c,
1946 config: config,
1947 module: module,
1948 },
Colin Cross49c279a2016-08-05 22:30:44 -07001949 name: mutator.name,
Colin Cross7addea32015-03-11 15:43:52 -07001950 }
Colin Crossc9028482014-12-18 16:28:54 -08001951
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001952 func() {
1953 defer func() {
1954 if r := recover(); r != nil {
Colin Cross3702ac72016-08-11 11:09:00 -07001955 in := fmt.Sprintf("%s %q for %s", direction, mutator.name, module)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001956 if err, ok := r.(panicError); ok {
1957 err.addIn(in)
1958 mctx.error(err)
1959 } else {
1960 mctx.error(newPanicErrorf(r, in))
1961 }
1962 }
1963 }()
Colin Cross3702ac72016-08-11 11:09:00 -07001964 direction.run(mutator, mctx)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08001965 }()
Colin Cross49c279a2016-08-05 22:30:44 -07001966
Colin Cross7addea32015-03-11 15:43:52 -07001967 if len(mctx.errs) > 0 {
Colin Cross0fff7422016-08-11 15:37:45 -07001968 errsCh <- mctx.errs
Colin Cross49c279a2016-08-05 22:30:44 -07001969 return true
Colin Cross7addea32015-03-11 15:43:52 -07001970 }
Colin Crossc9028482014-12-18 16:28:54 -08001971
Colin Cross5fe225f2017-07-28 15:22:46 -07001972 if len(mctx.newVariations) > 0 {
1973 newVariationsCh <- mctx.newVariations
Colin Cross49c279a2016-08-05 22:30:44 -07001974 }
1975
Colin Crossaf4fd212017-07-28 14:32:36 -07001976 if len(mctx.reverseDeps) > 0 || len(mctx.replace) > 0 || len(mctx.rename) > 0 || len(mctx.newModules) > 0 {
Colin Cross0ce142c2016-12-09 10:29:05 -08001977 globalStateCh <- globalStateChange{
Colin Crossaf4fd212017-07-28 14:32:36 -07001978 reverse: mctx.reverseDeps,
1979 replace: mctx.replace,
1980 rename: mctx.rename,
1981 newModules: mctx.newModules,
Colin Cross874a3462017-07-31 17:26:06 -07001982 deps: mctx.ninjaFileDeps,
Colin Cross0ce142c2016-12-09 10:29:05 -08001983 }
Colin Cross49c279a2016-08-05 22:30:44 -07001984 }
1985
1986 return false
1987 }
1988
1989 // Process errs and reverseDeps in a single goroutine
1990 go func() {
1991 for {
1992 select {
1993 case newErrs := <-errsCh:
1994 errs = append(errs, newErrs...)
Colin Cross0ce142c2016-12-09 10:29:05 -08001995 case globalStateChange := <-globalStateCh:
1996 for _, r := range globalStateChange.reverse {
Colin Cross49c279a2016-08-05 22:30:44 -07001997 reverseDeps[r.module] = append(reverseDeps[r.module], r.dep)
1998 }
Colin Cross0ce142c2016-12-09 10:29:05 -08001999 replace = append(replace, globalStateChange.replace...)
2000 rename = append(rename, globalStateChange.rename...)
Colin Crossaf4fd212017-07-28 14:32:36 -07002001 newModules = append(newModules, globalStateChange.newModules...)
Colin Cross874a3462017-07-31 17:26:06 -07002002 deps = append(deps, globalStateChange.deps...)
Colin Cross5fe225f2017-07-28 15:22:46 -07002003 case newVariations := <-newVariationsCh:
2004 for _, m := range newVariations {
Colin Cross49c279a2016-08-05 22:30:44 -07002005 newModuleInfo[m.logicModule] = m
2006 }
2007 case <-done:
2008 return
Colin Crossc9028482014-12-18 16:28:54 -08002009 }
2010 }
Colin Cross49c279a2016-08-05 22:30:44 -07002011 }()
Colin Crossc9028482014-12-18 16:28:54 -08002012
Colin Cross49c279a2016-08-05 22:30:44 -07002013 if mutator.parallel {
Colin Cross3702ac72016-08-11 11:09:00 -07002014 c.parallelVisit(direction.orderer(), visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002015 } else {
Colin Cross3702ac72016-08-11 11:09:00 -07002016 direction.orderer().visit(c.modulesSorted, visit)
Colin Cross49c279a2016-08-05 22:30:44 -07002017 }
2018
2019 done <- true
2020
2021 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002022 return nil, errs
Colin Cross49c279a2016-08-05 22:30:44 -07002023 }
2024
2025 c.moduleInfo = newModuleInfo
2026
2027 for _, group := range c.moduleGroups {
2028 for i := 0; i < len(group.modules); i++ {
2029 module := group.modules[i]
2030
2031 // Update module group to contain newly split variants
2032 if module.splitModules != nil {
2033 group.modules, i = spliceModules(group.modules, i, module.splitModules)
2034 }
2035
2036 // Fix up any remaining dependencies on modules that were split into variants
2037 // by replacing them with the first variant
2038 for j, dep := range module.directDeps {
2039 if dep.module.logicModule == nil {
2040 module.directDeps[j].module = dep.module.splitModules[0]
2041 }
2042 }
Colin Cross7addea32015-03-11 15:43:52 -07002043 }
Colin Crossc9028482014-12-18 16:28:54 -08002044 }
2045
Colin Cross8d8a7af2015-11-03 16:41:29 -08002046 for module, deps := range reverseDeps {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002047 sort.Sort(depSorter(deps))
Colin Cross8d8a7af2015-11-03 16:41:29 -08002048 module.directDeps = append(module.directDeps, deps...)
Colin Cross3702ac72016-08-11 11:09:00 -07002049 c.depsModified++
Colin Cross8d8a7af2015-11-03 16:41:29 -08002050 }
2051
Colin Crossaf4fd212017-07-28 14:32:36 -07002052 for _, module := range newModules {
2053 errs = c.addModule(module)
2054 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002055 return nil, errs
Colin Crossaf4fd212017-07-28 14:32:36 -07002056 }
2057 atomic.AddUint32(&c.depsModified, 1)
2058 }
2059
Colin Cross0ce142c2016-12-09 10:29:05 -08002060 errs = c.handleRenames(rename)
2061 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002062 return nil, errs
Colin Cross0ce142c2016-12-09 10:29:05 -08002063 }
2064
2065 errs = c.handleReplacements(replace)
Colin Crossc4e5b812016-10-12 10:45:05 -07002066 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002067 return nil, errs
Colin Crossc4e5b812016-10-12 10:45:05 -07002068 }
2069
Colin Cross3702ac72016-08-11 11:09:00 -07002070 if c.depsModified > 0 {
2071 errs = c.updateDependencies()
2072 if len(errs) > 0 {
Colin Cross874a3462017-07-31 17:26:06 -07002073 return nil, errs
Colin Cross3702ac72016-08-11 11:09:00 -07002074 }
Colin Crossc9028482014-12-18 16:28:54 -08002075 }
2076
Colin Cross874a3462017-07-31 17:26:06 -07002077 return deps, errs
Colin Crossc9028482014-12-18 16:28:54 -08002078}
2079
Colin Cross910242b2016-04-11 15:41:52 -07002080// Replaces every build logic module with a clone of itself. Prevents introducing problems where
2081// a mutator sets a non-property member variable on a module, which works until a later mutator
2082// creates variants of that module.
2083func (c *Context) cloneModules() {
Colin Crossc93490c2016-08-09 14:21:02 -07002084 type update struct {
2085 orig Module
2086 clone *moduleInfo
2087 }
2088 ch := make(chan update, 100)
2089
Colin Cross910242b2016-04-11 15:41:52 -07002090 for _, m := range c.modulesSorted {
Colin Crossc93490c2016-08-09 14:21:02 -07002091 go func(m *moduleInfo) {
2092 origLogicModule := m.logicModule
Colin Crossd2f4ac12017-07-28 14:31:03 -07002093 m.logicModule, m.properties = c.cloneLogicModule(m)
Colin Crossc93490c2016-08-09 14:21:02 -07002094 ch <- update{origLogicModule, m}
2095 }(m)
2096 }
2097
2098 for i := 0; i < len(c.modulesSorted); i++ {
2099 update := <-ch
2100 delete(c.moduleInfo, update.orig)
2101 c.moduleInfo[update.clone.logicModule] = update.clone
Colin Cross910242b2016-04-11 15:41:52 -07002102 }
2103}
2104
Colin Cross49c279a2016-08-05 22:30:44 -07002105// Removes modules[i] from the list and inserts newModules... where it was located, returning
2106// the new slice and the index of the last inserted element
2107func spliceModules(modules []*moduleInfo, i int, newModules []*moduleInfo) ([]*moduleInfo, int) {
Colin Cross7addea32015-03-11 15:43:52 -07002108 spliceSize := len(newModules)
2109 newLen := len(modules) + spliceSize - 1
2110 var dest []*moduleInfo
2111 if cap(modules) >= len(modules)-1+len(newModules) {
2112 // We can fit the splice in the existing capacity, do everything in place
2113 dest = modules[:newLen]
2114 } else {
2115 dest = make([]*moduleInfo, newLen)
2116 copy(dest, modules[:i])
2117 }
2118
2119 // Move the end of the slice over by spliceSize-1
Colin Cross72bd1932015-03-16 00:13:59 -07002120 copy(dest[i+spliceSize:], modules[i+1:])
Colin Cross7addea32015-03-11 15:43:52 -07002121
2122 // Copy the new modules into the slice
Colin Cross72bd1932015-03-16 00:13:59 -07002123 copy(dest[i:], newModules)
Colin Cross7addea32015-03-11 15:43:52 -07002124
Colin Cross49c279a2016-08-05 22:30:44 -07002125 return dest, i + spliceSize - 1
Colin Cross7addea32015-03-11 15:43:52 -07002126}
2127
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002128func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002129 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002130
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002131 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002132 var errs []error
2133
Colin Cross691a60d2015-01-07 18:08:56 -08002134 cancelCh := make(chan struct{})
2135 errsCh := make(chan []error)
2136 depsCh := make(chan []string)
2137
2138 go func() {
2139 for {
2140 select {
2141 case <-cancelCh:
2142 close(cancelCh)
2143 return
2144 case newErrs := <-errsCh:
2145 errs = append(errs, newErrs...)
2146 case newDeps := <-depsCh:
2147 deps = append(deps, newDeps...)
2148
2149 }
2150 }
2151 }()
2152
Colin Cross3702ac72016-08-11 11:09:00 -07002153 c.parallelVisit(bottomUpVisitor, func(module *moduleInfo) bool {
Colin Cross7addea32015-03-11 15:43:52 -07002154 // The parent scope of the moduleContext's local scope gets overridden to be that of the
2155 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2156 // just set it to nil.
2157 prefix := moduleNamespacePrefix(module.group.ninjaName + "_" + module.variantName)
2158 scope := newLocalScope(nil, prefix)
Colin Cross6134a5c2015-02-10 11:26:26 -08002159
Colin Cross7addea32015-03-11 15:43:52 -07002160 mctx := &moduleContext{
2161 baseModuleContext: baseModuleContext{
2162 context: c,
2163 config: config,
2164 module: module,
2165 },
Colin Cross036a1df2015-12-17 15:49:30 -08002166 scope: scope,
2167 handledMissingDeps: module.missingDeps == nil,
Colin Cross7addea32015-03-11 15:43:52 -07002168 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002169
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002170 func() {
2171 defer func() {
2172 if r := recover(); r != nil {
2173 in := fmt.Sprintf("GenerateBuildActions for %s", module)
2174 if err, ok := r.(panicError); ok {
2175 err.addIn(in)
2176 mctx.error(err)
2177 } else {
2178 mctx.error(newPanicErrorf(r, in))
2179 }
2180 }
2181 }()
2182 mctx.module.logicModule.GenerateBuildActions(mctx)
2183 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002184
Colin Cross7addea32015-03-11 15:43:52 -07002185 if len(mctx.errs) > 0 {
2186 errsCh <- mctx.errs
2187 return true
2188 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002189
Colin Cross036a1df2015-12-17 15:49:30 -08002190 if module.missingDeps != nil && !mctx.handledMissingDeps {
2191 var errs []error
2192 for _, depName := range module.missingDeps {
Colin Cross2c628442016-10-07 17:13:10 -07002193 errs = append(errs, &BlueprintError{
Colin Cross036a1df2015-12-17 15:49:30 -08002194 Err: fmt.Errorf("%q depends on undefined module %q",
Colin Cross0b7e83e2016-05-17 14:58:05 -07002195 module.Name(), depName),
Colin Cross036a1df2015-12-17 15:49:30 -08002196 Pos: module.pos,
2197 })
2198 }
2199 errsCh <- errs
2200 return true
2201 }
2202
Colin Cross7addea32015-03-11 15:43:52 -07002203 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002204
Colin Crossab6d7902015-03-11 16:17:52 -07002205 newErrs := c.processLocalBuildActions(&module.actionDefs,
Colin Cross7addea32015-03-11 15:43:52 -07002206 &mctx.actionDefs, liveGlobals)
2207 if len(newErrs) > 0 {
2208 errsCh <- newErrs
2209 return true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002210 }
Colin Cross8900e9b2015-03-02 14:03:01 -08002211 return false
Colin Cross691a60d2015-01-07 18:08:56 -08002212 })
2213
2214 cancelCh <- struct{}{}
2215 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002216
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002217 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002218}
2219
Jamie Gennis6eb4d242014-06-11 18:31:16 -07002220func (c *Context) generateSingletonBuildActions(config interface{},
Colin Cross5f03f112017-11-07 13:29:54 -08002221 singletons []*singletonInfo, liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002222
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002223 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002224 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002225
Colin Cross5f03f112017-11-07 13:29:54 -08002226 for _, info := range singletons {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002227 // The parent scope of the singletonContext's local scope gets overridden to be that of the
2228 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
2229 // just set it to nil.
Yuchen Wub9103ef2015-08-25 17:58:17 -07002230 scope := newLocalScope(nil, singletonNamespacePrefix(info.name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002231
2232 sctx := &singletonContext{
2233 context: c,
2234 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002235 scope: scope,
Dan Willemsen4bb62762016-01-14 15:42:54 -08002236 globals: liveGlobals,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002237 }
2238
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002239 func() {
2240 defer func() {
2241 if r := recover(); r != nil {
2242 in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
2243 if err, ok := r.(panicError); ok {
2244 err.addIn(in)
2245 sctx.error(err)
2246 } else {
2247 sctx.error(newPanicErrorf(r, in))
2248 }
2249 }
2250 }()
2251 info.singleton.GenerateBuildActions(sctx)
2252 }()
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002253
2254 if len(sctx.errs) > 0 {
2255 errs = append(errs, sctx.errs...)
2256 if len(errs) > maxErrors {
2257 break
2258 }
2259 continue
2260 }
2261
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002262 deps = append(deps, sctx.ninjaFileDeps...)
2263
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002264 newErrs := c.processLocalBuildActions(&info.actionDefs,
2265 &sctx.actionDefs, liveGlobals)
2266 errs = append(errs, newErrs...)
2267 if len(errs) > maxErrors {
2268 break
2269 }
2270 }
2271
Mathias Agopian5b8477d2014-06-25 17:21:54 -07002272 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002273}
2274
2275func (c *Context) processLocalBuildActions(out, in *localBuildActions,
2276 liveGlobals *liveTracker) []error {
2277
2278 var errs []error
2279
2280 // First we go through and add everything referenced by the module's
2281 // buildDefs to the live globals set. This will end up adding the live
2282 // locals to the set as well, but we'll take them out after.
2283 for _, def := range in.buildDefs {
2284 err := liveGlobals.AddBuildDefDeps(def)
2285 if err != nil {
2286 errs = append(errs, err)
2287 }
2288 }
2289
2290 if len(errs) > 0 {
2291 return errs
2292 }
2293
Colin Crossc9028482014-12-18 16:28:54 -08002294 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002295
2296 // We use the now-incorrect set of live "globals" to determine which local
2297 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08002298 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002299 for _, v := range in.variables {
Colin Crossab6d7902015-03-11 16:17:52 -07002300 isLive := liveGlobals.RemoveVariableIfLive(v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002301 if isLive {
2302 out.variables = append(out.variables, v)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002303 }
2304 }
2305
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002306 for _, r := range in.rules {
Colin Crossab6d7902015-03-11 16:17:52 -07002307 isLive := liveGlobals.RemoveRuleIfLive(r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002308 if isLive {
2309 out.rules = append(out.rules, r)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002310 }
2311 }
2312
2313 return nil
2314}
2315
Yuchen Wu222e2452015-10-06 14:03:27 -07002316func (c *Context) walkDeps(topModule *moduleInfo,
Colin Crossbafd5f52016-08-06 22:52:01 -07002317 visitDown func(depInfo, *moduleInfo) bool, visitUp func(depInfo, *moduleInfo)) {
Yuchen Wu222e2452015-10-06 14:03:27 -07002318
2319 visited := make(map[*moduleInfo]bool)
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002320 var visiting *moduleInfo
2321
2322 defer func() {
2323 if r := recover(); r != nil {
Colin Crossbafd5f52016-08-06 22:52:01 -07002324 panic(newPanicErrorf(r, "WalkDeps(%s, %s, %s) for dependency %s",
2325 topModule, funcName(visitDown), funcName(visitUp), visiting))
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002326 }
2327 }()
Yuchen Wu222e2452015-10-06 14:03:27 -07002328
2329 var walk func(module *moduleInfo)
2330 walk = func(module *moduleInfo) {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002331 for _, dep := range module.directDeps {
2332 if !visited[dep.module] {
2333 visited[dep.module] = true
2334 visiting = dep.module
Colin Crossbafd5f52016-08-06 22:52:01 -07002335 recurse := true
2336 if visitDown != nil {
2337 recurse = visitDown(dep, module)
2338 }
2339 if recurse {
Colin Cross2c1f3d12016-04-11 15:47:28 -07002340 walk(dep.module)
Yuchen Wu222e2452015-10-06 14:03:27 -07002341 }
Colin Crossbafd5f52016-08-06 22:52:01 -07002342 if visitUp != nil {
2343 visitUp(dep, module)
2344 }
Yuchen Wu222e2452015-10-06 14:03:27 -07002345 }
2346 }
2347 }
2348
2349 walk(topModule)
2350}
2351
Colin Cross9cfd1982016-10-11 09:58:53 -07002352type replace struct {
2353 from, to *moduleInfo
2354}
2355
Colin Crossc4e5b812016-10-12 10:45:05 -07002356type rename struct {
2357 group *moduleGroup
2358 name string
2359}
2360
Colin Cross0ce142c2016-12-09 10:29:05 -08002361func (c *Context) moduleMatchingVariant(module *moduleInfo, name string) *moduleInfo {
Colin Cross9cfd1982016-10-11 09:58:53 -07002362 targets := c.modulesFromName(name)
2363
2364 if targets == nil {
Colin Cross0ce142c2016-12-09 10:29:05 -08002365 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002366 }
2367
Colin Cross9cfd1982016-10-11 09:58:53 -07002368 for _, m := range targets {
2369 if module.variantName == m.variantName {
Colin Cross0ce142c2016-12-09 10:29:05 -08002370 return m
Colin Cross9cfd1982016-10-11 09:58:53 -07002371 }
2372 }
2373
Colin Cross0ce142c2016-12-09 10:29:05 -08002374 return nil
Colin Cross9cfd1982016-10-11 09:58:53 -07002375}
2376
Colin Cross0ce142c2016-12-09 10:29:05 -08002377func (c *Context) handleRenames(renames []rename) []error {
Colin Crossc4e5b812016-10-12 10:45:05 -07002378 var errs []error
Colin Cross0ce142c2016-12-09 10:29:05 -08002379 for _, rename := range renames {
Colin Crossc4e5b812016-10-12 10:45:05 -07002380 group, name := rename.group, rename.name
2381 if name == group.name {
2382 continue
2383 }
2384
2385 existing := c.moduleNames[name]
2386 if existing != nil {
2387 errs = append(errs,
2388 &BlueprintError{
2389 Err: fmt.Errorf("renaming module %q to %q conflicts with existing module",
2390 group.name, name),
2391 Pos: group.modules[0].pos,
2392 },
2393 &BlueprintError{
2394 Err: fmt.Errorf("<-- existing module defined here"),
2395 Pos: existing.modules[0].pos,
2396 },
2397 )
2398 continue
2399 }
2400
2401 c.moduleNames[name] = group
2402 delete(c.moduleNames, group.name)
2403 group.name = name
2404 }
2405
Colin Cross0ce142c2016-12-09 10:29:05 -08002406 return errs
2407}
2408
2409func (c *Context) handleReplacements(replacements []replace) []error {
2410 var errs []error
2411 for _, replace := range replacements {
Colin Cross9cfd1982016-10-11 09:58:53 -07002412 for _, m := range replace.from.reverseDeps {
2413 for i, d := range m.directDeps {
2414 if d.module == replace.from {
2415 m.directDeps[i].module = replace.to
2416 }
2417 }
2418 }
2419
2420 atomic.AddUint32(&c.depsModified, 1)
2421 }
Colin Cross0ce142c2016-12-09 10:29:05 -08002422
Colin Crossc4e5b812016-10-12 10:45:05 -07002423 return errs
2424}
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002425
Colin Cross0b7e83e2016-05-17 14:58:05 -07002426func (c *Context) modulesFromName(name string) []*moduleInfo {
2427 if group := c.moduleNames[name]; group != nil {
2428 return group.modules
2429 }
2430 return nil
2431}
2432
Jamie Gennisc15544d2014-09-24 20:26:52 -07002433func (c *Context) sortedModuleNames() []string {
2434 if c.cachedSortedModuleNames == nil {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002435 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleNames))
2436 for moduleName := range c.moduleNames {
Jamie Gennisc15544d2014-09-24 20:26:52 -07002437 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
2438 moduleName)
2439 }
2440 sort.Strings(c.cachedSortedModuleNames)
2441 }
2442
2443 return c.cachedSortedModuleNames
2444}
2445
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002446func (c *Context) visitAllModules(visit func(Module)) {
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002447 var module *moduleInfo
2448
2449 defer func() {
2450 if r := recover(); r != nil {
2451 panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
2452 funcName(visit), module))
2453 }
2454 }()
2455
Jamie Gennisc15544d2014-09-24 20:26:52 -07002456 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002457 modules := c.modulesFromName(moduleName)
2458 for _, module = range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002459 visit(module.logicModule)
2460 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002461 }
2462}
2463
2464func (c *Context) visitAllModulesIf(pred func(Module) bool,
2465 visit func(Module)) {
2466
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002467 var module *moduleInfo
2468
2469 defer func() {
2470 if r := recover(); r != nil {
2471 panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
2472 funcName(pred), funcName(visit), module))
2473 }
2474 }()
2475
Jamie Gennisc15544d2014-09-24 20:26:52 -07002476 for _, moduleName := range c.sortedModuleNames() {
Colin Cross0b7e83e2016-05-17 14:58:05 -07002477 modules := c.modulesFromName(moduleName)
2478 for _, module := range modules {
Colin Crossbbfa51a2014-12-17 16:12:41 -08002479 if pred(module.logicModule) {
2480 visit(module.logicModule)
2481 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002482 }
2483 }
2484}
2485
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002486func (c *Context) visitAllModuleVariants(module *moduleInfo,
2487 visit func(Module)) {
2488
2489 var variant *moduleInfo
2490
2491 defer func() {
2492 if r := recover(); r != nil {
2493 panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
2494 module, funcName(visit), variant))
2495 }
2496 }()
2497
2498 for _, variant = range module.group.modules {
2499 visit(variant.logicModule)
2500 }
2501}
2502
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002503func (c *Context) requireNinjaVersion(major, minor, micro int) {
2504 if major != 1 {
2505 panic("ninja version with major version != 1 not supported")
2506 }
2507 if c.requiredNinjaMinor < minor {
2508 c.requiredNinjaMinor = minor
2509 c.requiredNinjaMicro = micro
2510 }
2511 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
2512 c.requiredNinjaMicro = micro
2513 }
2514}
2515
Colin Crossa2599452015-11-18 16:01:01 -08002516func (c *Context) setNinjaBuildDir(value *ninjaString) {
2517 if c.ninjaBuildDir == nil {
2518 c.ninjaBuildDir = value
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002519 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002520}
2521
2522func (c *Context) makeUniquePackageNames(
Dan Willemsena481ae22015-12-18 15:18:03 -08002523 liveGlobals *liveTracker) (map[*packageContext]string, []string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002524
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002525 pkgs := make(map[string]*packageContext)
2526 pkgNames := make(map[*packageContext]string)
2527 longPkgNames := make(map[*packageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002528
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002529 processPackage := func(pctx *packageContext) {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002530 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002531 // This is a built-in rule and has no package.
2532 return
2533 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07002534 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002535 // We've already processed this package.
2536 return
2537 }
2538
Jamie Gennis2fb20952014-10-03 02:49:58 -07002539 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002540 if present {
2541 // Short name collision. Both this package and the one that's
2542 // already there need to use their full names. We leave the short
2543 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002544 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002545 longPkgNames[otherPkg] = true
2546 } else {
2547 // No collision so far. Tentatively set the package's name to be
2548 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002549 pkgNames[pctx] = pctx.shortName
Colin Cross0d441252015-04-14 18:02:20 -07002550 pkgs[pctx.shortName] = pctx
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002551 }
2552 }
2553
2554 // We try to give all packages their short name, but when we get collisions
2555 // we need to use the full unique package name.
2556 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002557 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002558 }
2559 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002560 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002561 }
2562 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07002563 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002564 }
2565
2566 // Add the packages that had collisions using their full unique names. This
2567 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07002568 for pctx := range longPkgNames {
2569 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002570 }
2571
Dan Willemsena481ae22015-12-18 15:18:03 -08002572 // Create deps list from calls to PackageContext.AddNinjaFileDeps
2573 deps := []string{}
2574 for _, pkg := range pkgs {
2575 deps = append(deps, pkg.ninjaFileDeps...)
2576 }
2577
2578 return pkgNames, deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002579}
2580
2581func (c *Context) checkForVariableReferenceCycles(
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002582 variables map[Variable]*ninjaString, pkgNames map[*packageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002583
2584 visited := make(map[Variable]bool) // variables that were already checked
2585 checking := make(map[Variable]bool) // variables actively being checked
2586
2587 var check func(v Variable) []Variable
2588
2589 check = func(v Variable) []Variable {
2590 visited[v] = true
2591 checking[v] = true
2592 defer delete(checking, v)
2593
2594 value := variables[v]
2595 for _, dep := range value.variables {
2596 if checking[dep] {
2597 // This is a cycle.
2598 return []Variable{dep, v}
2599 }
2600
2601 if !visited[dep] {
2602 cycle := check(dep)
2603 if cycle != nil {
2604 if cycle[0] == v {
2605 // We are the "start" of the cycle, so we're responsible
2606 // for generating the errors. The cycle list is in
2607 // reverse order because all the 'check' calls append
2608 // their own module to the list.
2609 msgs := []string{"detected variable reference cycle:"}
2610
2611 // Iterate backwards through the cycle list.
2612 curName := v.fullName(pkgNames)
2613 curValue := value.Value(pkgNames)
2614 for i := len(cycle) - 1; i >= 0; i-- {
2615 next := cycle[i]
2616 nextName := next.fullName(pkgNames)
2617 nextValue := variables[next].Value(pkgNames)
2618
2619 msgs = append(msgs, fmt.Sprintf(
2620 " %q depends on %q", curName, nextName))
2621 msgs = append(msgs, fmt.Sprintf(
2622 " [%s = %s]", curName, curValue))
2623
2624 curName = nextName
2625 curValue = nextValue
2626 }
2627
2628 // Variable reference cycles are a programming error,
2629 // not the fault of the Blueprint file authors.
2630 panic(strings.Join(msgs, "\n"))
2631 } else {
2632 // We're not the "start" of the cycle, so we just append
2633 // our module to the list and return it.
2634 return append(cycle, v)
2635 }
2636 }
2637 }
2638 }
2639
2640 return nil
2641 }
2642
2643 for v := range variables {
2644 if !visited[v] {
2645 cycle := check(v)
2646 if cycle != nil {
2647 panic("inconceivable!")
2648 }
2649 }
2650 }
2651}
2652
Jamie Gennisaf435562014-10-27 22:34:56 -07002653// AllTargets returns a map all the build target names to the rule used to build
2654// them. This is the same information that is output by running 'ninja -t
2655// targets all'. If this is called before PrepareBuildActions successfully
2656// completes then ErrbuildActionsNotReady is returned.
2657func (c *Context) AllTargets() (map[string]string, error) {
2658 if !c.buildActionsReady {
2659 return nil, ErrBuildActionsNotReady
2660 }
2661
2662 targets := map[string]string{}
2663
2664 // Collect all the module build targets.
Colin Crossab6d7902015-03-11 16:17:52 -07002665 for _, module := range c.moduleInfo {
2666 for _, buildDef := range module.actionDefs.buildDefs {
Jamie Gennisaf435562014-10-27 22:34:56 -07002667 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002668 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002669 outputValue, err := output.Eval(c.globalVariables)
2670 if err != nil {
2671 return nil, err
2672 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002673 targets[outputValue] = ruleName
2674 }
2675 }
2676 }
2677
2678 // Collect all the singleton build targets.
2679 for _, info := range c.singletonInfo {
2680 for _, buildDef := range info.actionDefs.buildDefs {
2681 ruleName := buildDef.Rule.fullName(c.pkgNames)
Dan Willemsen5c43e072016-10-25 21:26:12 -07002682 for _, output := range append(buildDef.Outputs, buildDef.ImplicitOutputs...) {
Christian Zander6e2b2322014-11-21 15:12:08 -08002683 outputValue, err := output.Eval(c.globalVariables)
2684 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08002685 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08002686 }
Jamie Gennisaf435562014-10-27 22:34:56 -07002687 targets[outputValue] = ruleName
2688 }
2689 }
2690 }
2691
2692 return targets, nil
2693}
2694
Colin Crossa2599452015-11-18 16:01:01 -08002695func (c *Context) NinjaBuildDir() (string, error) {
2696 if c.ninjaBuildDir != nil {
2697 return c.ninjaBuildDir.Eval(c.globalVariables)
2698 } else {
2699 return "", nil
2700 }
2701}
2702
Colin Cross4572edd2015-05-13 14:36:24 -07002703// ModuleTypePropertyStructs returns a mapping from module type name to a list of pointers to
2704// property structs returned by the factory for that module type.
2705func (c *Context) ModuleTypePropertyStructs() map[string][]interface{} {
2706 ret := make(map[string][]interface{})
2707 for moduleType, factory := range c.moduleFactories {
2708 _, ret[moduleType] = factory()
2709 }
2710
2711 return ret
2712}
2713
2714func (c *Context) ModuleName(logicModule Module) string {
2715 module := c.moduleInfo[logicModule]
Colin Cross0b7e83e2016-05-17 14:58:05 -07002716 return module.Name()
Colin Cross4572edd2015-05-13 14:36:24 -07002717}
2718
2719func (c *Context) ModuleDir(logicModule Module) string {
2720 module := c.moduleInfo[logicModule]
2721 return filepath.Dir(module.relBlueprintsFile)
2722}
2723
Colin Cross8c602f72015-12-17 18:02:11 -08002724func (c *Context) ModuleSubDir(logicModule Module) string {
2725 module := c.moduleInfo[logicModule]
2726 return module.variantName
2727}
2728
Dan Willemsenc98e55b2016-07-25 15:51:50 -07002729func (c *Context) ModuleType(logicModule Module) string {
2730 module := c.moduleInfo[logicModule]
2731 return module.typeName
2732}
2733
Colin Cross4572edd2015-05-13 14:36:24 -07002734func (c *Context) BlueprintFile(logicModule Module) string {
2735 module := c.moduleInfo[logicModule]
2736 return module.relBlueprintsFile
2737}
2738
2739func (c *Context) ModuleErrorf(logicModule Module, format string,
2740 args ...interface{}) error {
2741
2742 module := c.moduleInfo[logicModule]
Colin Cross2c628442016-10-07 17:13:10 -07002743 return &BlueprintError{
Colin Cross4572edd2015-05-13 14:36:24 -07002744 Err: fmt.Errorf(format, args...),
2745 Pos: module.pos,
2746 }
2747}
2748
2749func (c *Context) VisitAllModules(visit func(Module)) {
2750 c.visitAllModules(visit)
2751}
2752
2753func (c *Context) VisitAllModulesIf(pred func(Module) bool,
2754 visit func(Module)) {
2755
2756 c.visitAllModulesIf(pred, visit)
2757}
2758
Colin Cross080c1332017-03-17 13:09:05 -07002759func (c *Context) VisitDirectDeps(module Module, visit func(Module)) {
2760 topModule := c.moduleInfo[module]
Colin Cross4572edd2015-05-13 14:36:24 -07002761
Colin Cross080c1332017-03-17 13:09:05 -07002762 var visiting *moduleInfo
2763
2764 defer func() {
2765 if r := recover(); r != nil {
2766 panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
2767 topModule, funcName(visit), visiting))
2768 }
2769 }()
2770
2771 for _, dep := range topModule.directDeps {
2772 visiting = dep.module
2773 visit(dep.module.logicModule)
2774 }
2775}
2776
2777func (c *Context) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
2778 topModule := c.moduleInfo[module]
2779
2780 var visiting *moduleInfo
2781
2782 defer func() {
2783 if r := recover(); r != nil {
2784 panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
2785 topModule, funcName(pred), funcName(visit), visiting))
2786 }
2787 }()
2788
2789 for _, dep := range topModule.directDeps {
2790 visiting = dep.module
2791 if pred(dep.module.logicModule) {
2792 visit(dep.module.logicModule)
2793 }
2794 }
2795}
2796
2797func (c *Context) VisitDepsDepthFirst(module Module, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002798 topModule := c.moduleInfo[module]
2799
2800 var visiting *moduleInfo
2801
2802 defer func() {
2803 if r := recover(); r != nil {
2804 panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
2805 topModule, funcName(visit), visiting))
2806 }
2807 }()
2808
2809 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2810 visiting = dep.module
2811 visit(dep.module.logicModule)
2812 })
Colin Cross4572edd2015-05-13 14:36:24 -07002813}
2814
Colin Cross080c1332017-03-17 13:09:05 -07002815func (c *Context) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
Colin Crossbafd5f52016-08-06 22:52:01 -07002816 topModule := c.moduleInfo[module]
2817
2818 var visiting *moduleInfo
2819
2820 defer func() {
2821 if r := recover(); r != nil {
2822 panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
2823 topModule, funcName(pred), funcName(visit), visiting))
2824 }
2825 }()
2826
2827 c.walkDeps(topModule, nil, func(dep depInfo, parent *moduleInfo) {
2828 if pred(dep.module.logicModule) {
2829 visiting = dep.module
2830 visit(dep.module.logicModule)
2831 }
2832 })
Colin Cross4572edd2015-05-13 14:36:24 -07002833}
2834
Colin Cross24ad5872015-11-17 16:22:29 -08002835func (c *Context) PrimaryModule(module Module) Module {
2836 return c.moduleInfo[module].group.modules[0].logicModule
2837}
2838
2839func (c *Context) FinalModule(module Module) Module {
2840 modules := c.moduleInfo[module].group.modules
2841 return modules[len(modules)-1].logicModule
2842}
2843
2844func (c *Context) VisitAllModuleVariants(module Module,
2845 visit func(Module)) {
2846
Colin Cross0aa6a5f2016-01-07 13:43:09 -08002847 c.visitAllModuleVariants(c.moduleInfo[module], visit)
Colin Cross24ad5872015-11-17 16:22:29 -08002848}
2849
Jamie Gennisd4e10182014-06-12 20:06:50 -07002850// WriteBuildFile writes the Ninja manifeset text for the generated build
2851// actions to w. If this is called before PrepareBuildActions successfully
2852// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002853func (c *Context) WriteBuildFile(w io.Writer) error {
2854 if !c.buildActionsReady {
2855 return ErrBuildActionsNotReady
2856 }
2857
2858 nw := newNinjaWriter(w)
2859
2860 err := c.writeBuildFileHeader(nw)
2861 if err != nil {
2862 return err
2863 }
2864
2865 err = c.writeNinjaRequiredVersion(nw)
2866 if err != nil {
2867 return err
2868 }
2869
2870 // TODO: Group the globals by package.
2871
2872 err = c.writeGlobalVariables(nw)
2873 if err != nil {
2874 return err
2875 }
2876
2877 err = c.writeGlobalPools(nw)
2878 if err != nil {
2879 return err
2880 }
2881
2882 err = c.writeBuildDir(nw)
2883 if err != nil {
2884 return err
2885 }
2886
2887 err = c.writeGlobalRules(nw)
2888 if err != nil {
2889 return err
2890 }
2891
2892 err = c.writeAllModuleActions(nw)
2893 if err != nil {
2894 return err
2895 }
2896
2897 err = c.writeAllSingletonActions(nw)
2898 if err != nil {
2899 return err
2900 }
2901
2902 return nil
2903}
2904
Jamie Gennisc15544d2014-09-24 20:26:52 -07002905type pkgAssociation struct {
2906 PkgName string
2907 PkgPath string
2908}
2909
2910type pkgAssociationSorter struct {
2911 pkgs []pkgAssociation
2912}
2913
2914func (s *pkgAssociationSorter) Len() int {
2915 return len(s.pkgs)
2916}
2917
2918func (s *pkgAssociationSorter) Less(i, j int) bool {
2919 iName := s.pkgs[i].PkgName
2920 jName := s.pkgs[j].PkgName
2921 return iName < jName
2922}
2923
2924func (s *pkgAssociationSorter) Swap(i, j int) {
2925 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
2926}
2927
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002928func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
2929 headerTemplate := template.New("fileHeader")
2930 _, err := headerTemplate.Parse(fileHeaderTemplate)
2931 if err != nil {
2932 // This is a programming error.
2933 panic(err)
2934 }
2935
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002936 var pkgs []pkgAssociation
2937 maxNameLen := 0
2938 for pkg, name := range c.pkgNames {
2939 pkgs = append(pkgs, pkgAssociation{
2940 PkgName: name,
2941 PkgPath: pkg.pkgPath,
2942 })
2943 if len(name) > maxNameLen {
2944 maxNameLen = len(name)
2945 }
2946 }
2947
2948 for i := range pkgs {
2949 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
2950 }
2951
Jamie Gennisc15544d2014-09-24 20:26:52 -07002952 sort.Sort(&pkgAssociationSorter{pkgs})
2953
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002954 params := map[string]interface{}{
2955 "Pkgs": pkgs,
2956 }
2957
2958 buf := bytes.NewBuffer(nil)
2959 err = headerTemplate.Execute(buf, params)
2960 if err != nil {
2961 return err
2962 }
2963
2964 return nw.Comment(buf.String())
2965}
2966
2967func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
2968 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
2969 c.requiredNinjaMicro)
2970
2971 err := nw.Assign("ninja_required_version", value)
2972 if err != nil {
2973 return err
2974 }
2975
2976 return nw.BlankLine()
2977}
2978
2979func (c *Context) writeBuildDir(nw *ninjaWriter) error {
Colin Crossa2599452015-11-18 16:01:01 -08002980 if c.ninjaBuildDir != nil {
2981 err := nw.Assign("builddir", c.ninjaBuildDir.Value(c.pkgNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002982 if err != nil {
2983 return err
2984 }
2985
2986 err = nw.BlankLine()
2987 if err != nil {
2988 return err
2989 }
2990 }
2991 return nil
2992}
2993
Jamie Gennisc15544d2014-09-24 20:26:52 -07002994type globalEntity interface {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002995 fullName(pkgNames map[*packageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002996}
2997
Jamie Gennisc15544d2014-09-24 20:26:52 -07002998type globalEntitySorter struct {
Dan Willemsenaeffbf72015-11-25 15:29:32 -08002999 pkgNames map[*packageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07003000 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003001}
3002
Jamie Gennisc15544d2014-09-24 20:26:52 -07003003func (s *globalEntitySorter) Len() int {
3004 return len(s.entities)
3005}
3006
3007func (s *globalEntitySorter) Less(i, j int) bool {
3008 iName := s.entities[i].fullName(s.pkgNames)
3009 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003010 return iName < jName
3011}
3012
Jamie Gennisc15544d2014-09-24 20:26:52 -07003013func (s *globalEntitySorter) Swap(i, j int) {
3014 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003015}
3016
3017func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
3018 visited := make(map[Variable]bool)
3019
3020 var walk func(v Variable) error
3021 walk = func(v Variable) error {
3022 visited[v] = true
3023
3024 // First visit variables on which this variable depends.
3025 value := c.globalVariables[v]
3026 for _, dep := range value.variables {
3027 if !visited[dep] {
3028 err := walk(dep)
3029 if err != nil {
3030 return err
3031 }
3032 }
3033 }
3034
3035 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
3036 if err != nil {
3037 return err
3038 }
3039
3040 err = nw.BlankLine()
3041 if err != nil {
3042 return err
3043 }
3044
3045 return nil
3046 }
3047
Jamie Gennisc15544d2014-09-24 20:26:52 -07003048 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
3049 for variable := range c.globalVariables {
3050 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003051 }
3052
Jamie Gennisc15544d2014-09-24 20:26:52 -07003053 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003054
Jamie Gennisc15544d2014-09-24 20:26:52 -07003055 for _, entity := range globalVariables {
3056 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003057 if !visited[v] {
3058 err := walk(v)
3059 if err != nil {
3060 return nil
3061 }
3062 }
3063 }
3064
3065 return nil
3066}
3067
3068func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003069 globalPools := make([]globalEntity, 0, len(c.globalPools))
3070 for pool := range c.globalPools {
3071 globalPools = append(globalPools, pool)
3072 }
3073
3074 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
3075
3076 for _, entity := range globalPools {
3077 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003078 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003079 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003080 err := def.WriteTo(nw, name)
3081 if err != nil {
3082 return err
3083 }
3084
3085 err = nw.BlankLine()
3086 if err != nil {
3087 return err
3088 }
3089 }
3090
3091 return nil
3092}
3093
3094func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07003095 globalRules := make([]globalEntity, 0, len(c.globalRules))
3096 for rule := range c.globalRules {
3097 globalRules = append(globalRules, rule)
3098 }
3099
3100 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
3101
3102 for _, entity := range globalRules {
3103 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003104 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07003105 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003106 err := def.WriteTo(nw, name, c.pkgNames)
3107 if err != nil {
3108 return err
3109 }
3110
3111 err = nw.BlankLine()
3112 if err != nil {
3113 return err
3114 }
3115 }
3116
3117 return nil
3118}
3119
Colin Cross2c1f3d12016-04-11 15:47:28 -07003120type depSorter []depInfo
3121
3122func (s depSorter) Len() int {
3123 return len(s)
3124}
3125
3126func (s depSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003127 iName := s[i].module.Name()
3128 jName := s[j].module.Name()
Colin Cross2c1f3d12016-04-11 15:47:28 -07003129 if iName == jName {
3130 iName = s[i].module.variantName
3131 jName = s[j].module.variantName
3132 }
3133 return iName < jName
3134}
3135
3136func (s depSorter) Swap(i, j int) {
3137 s[i], s[j] = s[j], s[i]
3138}
3139
Colin Crossab6d7902015-03-11 16:17:52 -07003140type moduleSorter []*moduleInfo
Jamie Gennis86179fe2014-06-11 16:27:16 -07003141
Colin Crossab6d7902015-03-11 16:17:52 -07003142func (s moduleSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07003143 return len(s)
3144}
3145
Colin Crossab6d7902015-03-11 16:17:52 -07003146func (s moduleSorter) Less(i, j int) bool {
Colin Cross0b7e83e2016-05-17 14:58:05 -07003147 iName := s[i].Name()
3148 jName := s[j].Name()
Colin Crossab6d7902015-03-11 16:17:52 -07003149 if iName == jName {
Colin Cross65569e42015-03-10 20:08:19 -07003150 iName = s[i].variantName
3151 jName = s[j].variantName
Colin Crossab6d7902015-03-11 16:17:52 -07003152 }
Jamie Gennis86179fe2014-06-11 16:27:16 -07003153 return iName < jName
3154}
3155
Colin Crossab6d7902015-03-11 16:17:52 -07003156func (s moduleSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07003157 s[i], s[j] = s[j], s[i]
3158}
3159
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003160func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
3161 headerTemplate := template.New("moduleHeader")
3162 _, err := headerTemplate.Parse(moduleHeaderTemplate)
3163 if err != nil {
3164 // This is a programming error.
3165 panic(err)
3166 }
3167
Colin Crossab6d7902015-03-11 16:17:52 -07003168 modules := make([]*moduleInfo, 0, len(c.moduleInfo))
3169 for _, module := range c.moduleInfo {
3170 modules = append(modules, module)
Jamie Gennis86179fe2014-06-11 16:27:16 -07003171 }
Colin Crossab6d7902015-03-11 16:17:52 -07003172 sort.Sort(moduleSorter(modules))
Jamie Gennis86179fe2014-06-11 16:27:16 -07003173
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003174 buf := bytes.NewBuffer(nil)
3175
Colin Crossab6d7902015-03-11 16:17:52 -07003176 for _, module := range modules {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003177 if len(module.actionDefs.variables)+len(module.actionDefs.rules)+len(module.actionDefs.buildDefs) == 0 {
3178 continue
3179 }
3180
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003181 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003182
3183 // In order to make the bootstrap build manifest independent of the
3184 // build dir we need to output the Blueprints file locations in the
3185 // comments as paths relative to the source directory.
Colin Crossab6d7902015-03-11 16:17:52 -07003186 relPos := module.pos
3187 relPos.Filename = module.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07003188
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003189 // Get the name and location of the factory function for the module.
Colin Crossaf4fd212017-07-28 14:32:36 -07003190 factoryFunc := runtime.FuncForPC(reflect.ValueOf(module.factory).Pointer())
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003191 factoryName := factoryFunc.Name()
3192
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003193 infoMap := map[string]interface{}{
Colin Cross0b7e83e2016-05-17 14:58:05 -07003194 "name": module.Name(),
3195 "typeName": module.typeName,
3196 "goFactory": factoryName,
3197 "pos": relPos,
3198 "variant": module.variantName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003199 }
3200 err = headerTemplate.Execute(buf, infoMap)
3201 if err != nil {
3202 return err
3203 }
3204
3205 err = nw.Comment(buf.String())
3206 if err != nil {
3207 return err
3208 }
3209
3210 err = nw.BlankLine()
3211 if err != nil {
3212 return err
3213 }
3214
Colin Crossab6d7902015-03-11 16:17:52 -07003215 err = c.writeLocalBuildActions(nw, &module.actionDefs)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003216 if err != nil {
3217 return err
3218 }
3219
3220 err = nw.BlankLine()
3221 if err != nil {
3222 return err
3223 }
3224 }
3225
3226 return nil
3227}
3228
3229func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
3230 headerTemplate := template.New("singletonHeader")
3231 _, err := headerTemplate.Parse(singletonHeaderTemplate)
3232 if err != nil {
3233 // This is a programming error.
3234 panic(err)
3235 }
3236
3237 buf := bytes.NewBuffer(nil)
3238
Yuchen Wub9103ef2015-08-25 17:58:17 -07003239 for _, info := range c.singletonInfo {
Dan Willemsen958b3ac2015-07-20 15:55:37 -07003240 if len(info.actionDefs.variables)+len(info.actionDefs.rules)+len(info.actionDefs.buildDefs) == 0 {
3241 continue
3242 }
3243
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003244 // Get the name of the factory function for the module.
3245 factory := info.factory
3246 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
3247 factoryName := factoryFunc.Name()
3248
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003249 buf.Reset()
3250 infoMap := map[string]interface{}{
Yuchen Wub9103ef2015-08-25 17:58:17 -07003251 "name": info.name,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003252 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003253 }
3254 err = headerTemplate.Execute(buf, infoMap)
3255 if err != nil {
3256 return err
3257 }
3258
3259 err = nw.Comment(buf.String())
3260 if err != nil {
3261 return err
3262 }
3263
3264 err = nw.BlankLine()
3265 if err != nil {
3266 return err
3267 }
3268
3269 err = c.writeLocalBuildActions(nw, &info.actionDefs)
3270 if err != nil {
3271 return err
3272 }
3273
3274 err = nw.BlankLine()
3275 if err != nil {
3276 return err
3277 }
3278 }
3279
3280 return nil
3281}
3282
3283func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
3284 defs *localBuildActions) error {
3285
3286 // Write the local variable assignments.
3287 for _, v := range defs.variables {
3288 // A localVariable doesn't need the package names or config to
3289 // determine its name or value.
3290 name := v.fullName(nil)
3291 value, err := v.value(nil)
3292 if err != nil {
3293 panic(err)
3294 }
3295 err = nw.Assign(name, value.Value(c.pkgNames))
3296 if err != nil {
3297 return err
3298 }
3299 }
3300
3301 if len(defs.variables) > 0 {
3302 err := nw.BlankLine()
3303 if err != nil {
3304 return err
3305 }
3306 }
3307
3308 // Write the local rules.
3309 for _, r := range defs.rules {
3310 // A localRule doesn't need the package names or config to determine
3311 // its name or definition.
3312 name := r.fullName(nil)
3313 def, err := r.def(nil)
3314 if err != nil {
3315 panic(err)
3316 }
3317
3318 err = def.WriteTo(nw, name, c.pkgNames)
3319 if err != nil {
3320 return err
3321 }
3322
3323 err = nw.BlankLine()
3324 if err != nil {
3325 return err
3326 }
3327 }
3328
3329 // Write the build definitions.
3330 for _, buildDef := range defs.buildDefs {
3331 err := buildDef.WriteTo(nw, c.pkgNames)
3332 if err != nil {
3333 return err
3334 }
3335
3336 if len(buildDef.Args) > 0 {
3337 err = nw.BlankLine()
3338 if err != nil {
3339 return err
3340 }
3341 }
3342 }
3343
3344 return nil
3345}
3346
Colin Cross65569e42015-03-10 20:08:19 -07003347func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
3348 found := false
Colin Cross045a5972015-11-03 16:58:48 -08003349 if a == b {
3350 return false
3351 }
Colin Cross65569e42015-03-10 20:08:19 -07003352 for _, l := range list {
3353 if l == a {
3354 found = true
3355 } else if l == b {
3356 return found
3357 }
3358 }
3359
3360 missing := a
3361 if found {
3362 missing = b
3363 }
3364 panic(fmt.Errorf("element %v not found in list %v", missing, list))
3365}
3366
Colin Cross0aa6a5f2016-01-07 13:43:09 -08003367type panicError struct {
3368 panic interface{}
3369 stack []byte
3370 in string
3371}
3372
3373func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
3374 buf := make([]byte, 4096)
3375 count := runtime.Stack(buf, false)
3376 return panicError{
3377 panic: panic,
3378 in: fmt.Sprintf(in, a...),
3379 stack: buf[:count],
3380 }
3381}
3382
3383func (p panicError) Error() string {
3384 return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
3385}
3386
3387func (p *panicError) addIn(in string) {
3388 p.in += " in " + in
3389}
3390
3391func funcName(f interface{}) string {
3392 return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
3393}
3394
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003395var fileHeaderTemplate = `******************************************************************************
3396*** This file is generated and should not be edited ***
3397******************************************************************************
3398{{if .Pkgs}}
3399This file contains variables, rules, and pools with name prefixes indicating
3400they were generated by the following Go packages:
3401{{range .Pkgs}}
3402 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
3403
3404`
3405
3406var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
Colin Cross0b7e83e2016-05-17 14:58:05 -07003407Module: {{.name}}
Colin Crossab6d7902015-03-11 16:17:52 -07003408Variant: {{.variant}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003409Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003410Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003411Defined: {{.pos}}
3412`
3413
3414var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
3415Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07003416Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07003417`