blob: d64d7d2e12150ebb8145a311b67863a4a12382f1 [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 (
18 "blueprint/parser"
Colin Crossc9028482014-12-18 16:28:54 -080019 "blueprint/proptools"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "bytes"
21 "errors"
22 "fmt"
23 "io"
24 "os"
25 "path/filepath"
26 "reflect"
Romain Guy28529652014-08-12 17:50:11 -070027 "runtime"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070028 "sort"
29 "strings"
30 "text/scanner"
31 "text/template"
32)
33
34var ErrBuildActionsNotReady = errors.New("build actions are not ready")
35
36const maxErrors = 10
37
Jamie Gennisd4e10182014-06-12 20:06:50 -070038// A Context contains all the state needed to parse a set of Blueprints files
39// and generate a Ninja file. The process of generating a Ninja file proceeds
40// through a series of four phases. Each phase corresponds with a some methods
41// on the Context object
42//
43// Phase Methods
44// ------------ -------------------------------------------
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070045// 1. Registration RegisterModuleType, RegisterSingletonType
Jamie Gennisd4e10182014-06-12 20:06:50 -070046//
47// 2. Parse ParseBlueprintsFiles, Parse
48//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -070049// 3. Generate ResolveDependencies, PrepareBuildActions
Jamie Gennisd4e10182014-06-12 20:06:50 -070050//
51// 4. Write WriteBuildFile
52//
53// The registration phase prepares the context to process Blueprints files
54// containing various types of modules. The parse phase reads in one or more
55// Blueprints files and validates their contents against the module types that
56// have been registered. The generate phase then analyzes the parsed Blueprints
57// contents to create an internal representation for the build actions that must
58// be performed. This phase also performs validation of the module dependencies
59// and property values defined in the parsed Blueprints files. Finally, the
60// write phase generates the Ninja manifest text based on the generated build
61// actions.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070062type Context struct {
63 // set at instantiation
Colin Crossbbfa51a2014-12-17 16:12:41 -080064 moduleFactories map[string]ModuleFactory
65 moduleGroups map[string]*moduleGroup
66 moduleInfo map[Module]*moduleInfo
67 moduleGroupsSorted []*moduleGroup
68 singletonInfo map[string]*singletonInfo
Colin Crossc9028482014-12-18 16:28:54 -080069 mutatorInfo []*mutatorInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -070070
71 dependenciesReady bool // set to true on a successful ResolveDependencies
72 buildActionsReady bool // set to true on a successful PrepareBuildActions
73
74 // set by SetIgnoreUnknownModuleTypes
75 ignoreUnknownModuleTypes bool
76
77 // set during PrepareBuildActions
Jamie Gennis2fb20952014-10-03 02:49:58 -070078 pkgNames map[*PackageContext]string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070079 globalVariables map[Variable]*ninjaString
80 globalPools map[Pool]*poolDef
81 globalRules map[Rule]*ruleDef
82
83 // set during PrepareBuildActions
84 buildDir *ninjaString // The builddir special Ninja variable
85 requiredNinjaMajor int // For the ninja_required_version variable
86 requiredNinjaMinor int // For the ninja_required_version variable
87 requiredNinjaMicro int // For the ninja_required_version variable
Jamie Gennisc15544d2014-09-24 20:26:52 -070088
89 // set lazily by sortedModuleNames
90 cachedSortedModuleNames []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070091}
92
Jamie Gennisd4e10182014-06-12 20:06:50 -070093// An Error describes a problem that was encountered that is related to a
94// particular location in a Blueprints file.
Jamie Gennis1bc967e2014-05-27 16:34:41 -070095type Error struct {
Jamie Gennisd4e10182014-06-12 20:06:50 -070096 Err error // the error that occurred
97 Pos scanner.Position // the relevant Blueprints file location
Jamie Gennis1bc967e2014-05-27 16:34:41 -070098}
99
100type localBuildActions struct {
101 variables []*localVariable
102 rules []*localRule
103 buildDefs []*buildDef
104}
105
Colin Crossbbfa51a2014-12-17 16:12:41 -0800106type moduleGroup struct {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700107 // set during Parse
Jamie Gennisec701282014-06-12 20:06:31 -0700108 typeName string
Jamie Gennisec701282014-06-12 20:06:31 -0700109 relBlueprintsFile string
110 pos scanner.Position
111 propertyPos map[string]scanner.Position
112 properties struct {
Jamie Gennis1174c692014-10-05 07:41:44 -0700113 Name string
114 Deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700115 }
116
Colin Crossbbfa51a2014-12-17 16:12:41 -0800117 modules []*moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118
Colin Cross691a60d2015-01-07 18:08:56 -0800119 // set during updateDependencies
120 reverseDeps []*moduleGroup
121 depsCount int
122
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700123 // set during PrepareBuildActions
124 actionDefs localBuildActions
Colin Cross691a60d2015-01-07 18:08:56 -0800125
126 // used by parallelVisitAllBottomUp
127 waitingCount int
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700128}
129
Colin Crossbbfa51a2014-12-17 16:12:41 -0800130type moduleInfo struct {
Colin Crossc9028482014-12-18 16:28:54 -0800131 name []subName
132 logicModule Module
133 group *moduleGroup
134 moduleProperties []interface{}
135
136 // set during ResolveDependencies
137 directDeps []*moduleInfo
138
139 // set during each runMutator
140 splitModules []*moduleInfo
141}
142
143type subName struct {
144 mutatorName string
145 variantName string
146}
147
148func (module *moduleInfo) subName() string {
149 names := []string{}
150 for _, subName := range module.name {
151 if subName.variantName != "" {
152 names = append(names, subName.variantName)
153 }
154 }
155 return strings.Join(names, "_")
Colin Crossbbfa51a2014-12-17 16:12:41 -0800156}
157
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700158type singletonInfo struct {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700159 // set during RegisterSingletonType
160 factory SingletonFactory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700161 singleton Singleton
162
163 // set during PrepareBuildActions
164 actionDefs localBuildActions
165}
166
Colin Crossc9028482014-12-18 16:28:54 -0800167type mutatorInfo struct {
168 // set during RegisterMutator
Colin Crossc0dbc552015-01-02 15:19:28 -0800169 topDownMutator TopDownMutator
170 bottomUpMutator BottomUpMutator
171 name string
Colin Crossc9028482014-12-18 16:28:54 -0800172}
173
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700174func (e *Error) Error() string {
175
176 return fmt.Sprintf("%s: %s", e.Pos, e.Err)
177}
178
Jamie Gennisd4e10182014-06-12 20:06:50 -0700179// NewContext creates a new Context object. The created context initially has
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700180// no module or singleton factories registered, so the RegisterModuleFactory and
181// RegisterSingletonFactory methods must be called before it can do anything
182// useful.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700183func NewContext() *Context {
184 return &Context{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700185 moduleFactories: make(map[string]ModuleFactory),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800186 moduleGroups: make(map[string]*moduleGroup),
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700187 moduleInfo: make(map[Module]*moduleInfo),
188 singletonInfo: make(map[string]*singletonInfo),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700189 }
190}
191
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700192// A ModuleFactory function creates a new Module object. See the
193// Context.RegisterModuleType method for details about how a registered
194// ModuleFactory is used by a Context.
195type ModuleFactory func() (m Module, propertyStructs []interface{})
196
Jamie Gennisd4e10182014-06-12 20:06:50 -0700197// RegisterModuleType associates a module type name (which can appear in a
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700198// Blueprints file) with a Module factory function. When the given module type
199// name is encountered in a Blueprints file during parsing, the Module factory
200// is invoked to instantiate a new Module object to handle the build action
Colin Crossc9028482014-12-18 16:28:54 -0800201// generation for the module. If a Mutator splits a module into multiple variants,
202// the factory is invoked again to create a new Module for each variant.
Jamie Gennisd4e10182014-06-12 20:06:50 -0700203//
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700204// The module type names given here must be unique for the context. The factory
205// function should be a named function so that its package and name can be
206// included in the generated Ninja file for debugging purposes.
207//
208// The factory function returns two values. The first is the newly created
209// Module object. The second is a slice of pointers to that Module object's
210// properties structs. Each properties struct is examined when parsing a module
211// definition of this type in a Blueprints file. Exported fields of the
212// properties structs are automatically set to the property values specified in
213// the Blueprints file. The properties struct field names determine the name of
214// the Blueprints file properties that are used - the Blueprints property name
215// matches that of the properties struct field name with the first letter
216// converted to lower-case.
217//
218// The fields of the properties struct must be either []string, a string, or
219// bool. The Context will panic if a Module gets instantiated with a properties
220// struct containing a field that is not one these supported types.
221//
222// Any properties that appear in the Blueprints files that are not built-in
223// module properties (such as "name" and "deps") and do not have a corresponding
224// field in the returned module properties struct result in an error during the
225// Context's parse phase.
226//
227// As an example, the follow code:
228//
229// type myModule struct {
230// properties struct {
231// Foo string
232// Bar []string
233// }
234// }
235//
236// func NewMyModule() (blueprint.Module, []interface{}) {
237// module := new(myModule)
238// properties := &module.properties
239// return module, []interface{}{properties}
240// }
241//
242// func main() {
243// ctx := blueprint.NewContext()
244// ctx.RegisterModuleType("my_module", NewMyModule)
245// // ...
246// }
247//
248// would support parsing a module defined in a Blueprints file as follows:
249//
250// my_module {
251// name: "myName",
252// foo: "my foo string",
253// bar: ["my", "bar", "strings"],
254// }
255//
Colin Cross7ad621c2015-01-07 16:22:45 -0800256// The factory function may be called from multiple goroutines. Any accesses
257// to global variables must be synchronized.
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700258func (c *Context) RegisterModuleType(name string, factory ModuleFactory) {
259 if _, present := c.moduleFactories[name]; present {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700260 panic(errors.New("module type name is already registered"))
261 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700262 c.moduleFactories[name] = factory
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700263}
264
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700265// A SingletonFactory function creates a new Singleton object. See the
266// Context.RegisterSingletonType method for details about how a registered
267// SingletonFactory is used by a Context.
268type SingletonFactory func() Singleton
269
270// RegisterSingletonType registers a singleton type that will be invoked to
271// generate build actions. Each registered singleton type is instantiated and
272// and invoked exactly once as part of the generate phase.
273//
274// The singleton type names given here must be unique for the context. The
275// factory function should be a named function so that its package and name can
276// be included in the generated Ninja file for debugging purposes.
277func (c *Context) RegisterSingletonType(name string, factory SingletonFactory) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700278 if _, present := c.singletonInfo[name]; present {
279 panic(errors.New("singleton name is already registered"))
280 }
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700281
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700282 c.singletonInfo[name] = &singletonInfo{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700283 factory: factory,
284 singleton: factory(),
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700285 }
286}
287
288func singletonPkgPath(singleton Singleton) string {
289 typ := reflect.TypeOf(singleton)
290 for typ.Kind() == reflect.Ptr {
291 typ = typ.Elem()
292 }
293 return typ.PkgPath()
294}
295
296func singletonTypeName(singleton Singleton) string {
297 typ := reflect.TypeOf(singleton)
298 for typ.Kind() == reflect.Ptr {
299 typ = typ.Elem()
300 }
301 return typ.PkgPath() + "." + typ.Name()
302}
303
Colin Crossc9028482014-12-18 16:28:54 -0800304// RegisterTopDownMutator registers a mutator that will be invoked to propagate
305// dependency info top-down between Modules. Each registered mutator
306// is invoked once per Module, and is invoked on a module before being invoked
307// on any of its dependencies
308//
309// The mutator type names given here must be unique for the context.
310func (c *Context) RegisterTopDownMutator(name string, mutator TopDownMutator) {
311 for _, m := range c.mutatorInfo {
312 if m.name == name && m.topDownMutator != nil {
313 panic(fmt.Errorf("mutator name %s is already registered", name))
314 }
315 }
316
317 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
318 topDownMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800319 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800320 })
321}
322
323// RegisterBottomUpMutator registers a mutator that will be invoked to split
324// Modules into variants. Each registered mutator is invoked once per Module,
325// and is invoked on dependencies before being invoked on dependers.
326//
327// The mutator type names given here must be unique for the context.
328func (c *Context) RegisterBottomUpMutator(name string, mutator BottomUpMutator) {
329 for _, m := range c.mutatorInfo {
330 if m.name == name && m.bottomUpMutator != nil {
331 panic(fmt.Errorf("mutator name %s is already registered", name))
332 }
333 }
334
335 c.mutatorInfo = append(c.mutatorInfo, &mutatorInfo{
336 bottomUpMutator: mutator,
Colin Crossc0dbc552015-01-02 15:19:28 -0800337 name: name,
Colin Crossc9028482014-12-18 16:28:54 -0800338 })
339}
340
Jamie Gennisd4e10182014-06-12 20:06:50 -0700341// SetIgnoreUnknownModuleTypes sets the behavior of the context in the case
342// where it encounters an unknown module type while parsing Blueprints files. By
343// default, the context will report unknown module types as an error. If this
344// method is called with ignoreUnknownModuleTypes set to true then the context
345// will silently ignore unknown module types.
346//
347// This method should generally not be used. It exists to facilitate the
348// bootstrapping process.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700349func (c *Context) SetIgnoreUnknownModuleTypes(ignoreUnknownModuleTypes bool) {
350 c.ignoreUnknownModuleTypes = ignoreUnknownModuleTypes
351}
352
Jamie Gennisd4e10182014-06-12 20:06:50 -0700353// Parse parses a single Blueprints file from r, creating Module objects for
354// each of the module definitions encountered. If the Blueprints file contains
355// an assignment to the "subdirs" variable, then the subdirectories listed are
356// returned in the subdirs first return value.
357//
358// rootDir specifies the path to the root directory of the source tree, while
359// filename specifies the path to the Blueprints file. These paths are used for
360// error reporting and for determining the module's directory.
Colin Cross7ad621c2015-01-07 16:22:45 -0800361func (c *Context) parse(rootDir, filename string, r io.Reader,
362 scope *parser.Scope) (subdirs []string, modules []*moduleInfo, errs []error,
363 outScope *parser.Scope) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700364
Jamie Gennisec701282014-06-12 20:06:31 -0700365 relBlueprintsFile, err := filepath.Rel(rootDir, filename)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700366 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800367 return nil, nil, []error{err}, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700368 }
369
Colin Crossc0dbc552015-01-02 15:19:28 -0800370 scope = parser.NewScope(scope)
371 scope.Remove("subdirs")
Colin Crossd1facc12015-01-08 14:56:03 -0800372 file, errs := parser.Parse(filename, r, scope)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700373 if len(errs) > 0 {
374 for i, err := range errs {
375 if parseErr, ok := err.(*parser.ParseError); ok {
376 err = &Error{
377 Err: parseErr.Err,
378 Pos: parseErr.Pos,
379 }
380 errs[i] = err
381 }
382 }
383
384 // If there were any parse errors don't bother trying to interpret the
385 // result.
Colin Cross7ad621c2015-01-07 16:22:45 -0800386 return nil, nil, errs, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700387 }
388
Colin Crossd1facc12015-01-08 14:56:03 -0800389 for _, def := range file.Defs {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700390 var newErrs []error
Colin Cross7ad621c2015-01-07 16:22:45 -0800391 var newModule *moduleInfo
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700392 switch def := def.(type) {
393 case *parser.Module:
Colin Cross7ad621c2015-01-07 16:22:45 -0800394 newModule, newErrs = c.processModuleDef(def, relBlueprintsFile)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700395
396 case *parser.Assignment:
Colin Crossc0dbc552015-01-02 15:19:28 -0800397 // Already handled via Scope object
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700398 default:
399 panic("unknown definition type")
400 }
401
402 if len(newErrs) > 0 {
403 errs = append(errs, newErrs...)
404 if len(errs) > maxErrors {
405 break
406 }
Colin Cross7ad621c2015-01-07 16:22:45 -0800407 } else if newModule != nil {
408 modules = append(modules, newModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700409 }
410 }
411
Colin Crossc0dbc552015-01-02 15:19:28 -0800412 subdirs, newErrs := c.processSubdirs(scope)
413 if len(newErrs) > 0 {
414 errs = append(errs, newErrs...)
415 }
416
Colin Cross7ad621c2015-01-07 16:22:45 -0800417 return subdirs, modules, errs, scope
Colin Crossc0dbc552015-01-02 15:19:28 -0800418}
419
Colin Cross7ad621c2015-01-07 16:22:45 -0800420type stringAndScope struct {
421 string
422 *parser.Scope
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700423}
424
Jamie Gennisd4e10182014-06-12 20:06:50 -0700425// ParseBlueprintsFiles parses a set of Blueprints files starting with the file
426// at rootFile. When it encounters a Blueprints file with a set of subdirs
427// listed it recursively parses any Blueprints files found in those
428// subdirectories.
429//
430// If no errors are encountered while parsing the files, the list of paths on
431// which the future output will depend is returned. This list will include both
432// Blueprints file paths as well as directory paths for cases where wildcard
433// subdirs are found.
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700434func (c *Context) ParseBlueprintsFiles(rootFile string) (deps []string,
435 errs []error) {
436
Colin Cross7ad621c2015-01-07 16:22:45 -0800437 c.dependenciesReady = false
438
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700439 rootDir := filepath.Dir(rootFile)
440
Colin Cross7ad621c2015-01-07 16:22:45 -0800441 blueprintsSet := make(map[string]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700442
Colin Cross7ad621c2015-01-07 16:22:45 -0800443 // Channels to receive data back from parseBlueprintsFile goroutines
444 blueprintsCh := make(chan stringAndScope)
445 errsCh := make(chan []error)
446 modulesCh := make(chan []*moduleInfo)
447 depsCh := make(chan string)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700448
Colin Cross7ad621c2015-01-07 16:22:45 -0800449 // Channel to notify main loop that a parseBlueprintsFile goroutine has finished
450 doneCh := make(chan struct{})
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700451
Colin Cross7ad621c2015-01-07 16:22:45 -0800452 // Number of outstanding goroutines to wait for
453 count := 0
454
455 startParseBlueprintsFile := func(filename string, scope *parser.Scope) {
456 count++
457 go func() {
458 c.parseBlueprintsFile(filename, scope, rootDir,
459 errsCh, modulesCh, blueprintsCh, depsCh)
460 doneCh <- struct{}{}
461 }()
462 }
463
464 tooManyErrors := false
465
466 startParseBlueprintsFile(rootFile, nil)
467
468loop:
469 for {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700470 if len(errs) > maxErrors {
Colin Cross7ad621c2015-01-07 16:22:45 -0800471 tooManyErrors = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700472 }
473
Colin Cross7ad621c2015-01-07 16:22:45 -0800474 select {
475 case newErrs := <-errsCh:
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700476 errs = append(errs, newErrs...)
Colin Cross7ad621c2015-01-07 16:22:45 -0800477 case dep := <-depsCh:
478 deps = append(deps, dep)
479 case modules := <-modulesCh:
480 newErrs := c.addModules(modules)
481 errs = append(errs, newErrs...)
482 case blueprint := <-blueprintsCh:
483 if tooManyErrors {
484 continue
485 }
486 if blueprintsSet[blueprint.string] {
487 continue
488 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700489
Colin Cross7ad621c2015-01-07 16:22:45 -0800490 blueprintsSet[blueprint.string] = true
491 startParseBlueprintsFile(blueprint.string, blueprint.Scope)
492 case <-doneCh:
493 count--
494 if count == 0 {
495 break loop
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700496 }
497 }
498 }
499
Colin Cross7ad621c2015-01-07 16:22:45 -0800500 return
501}
502
503// parseBlueprintFile parses a single Blueprints file, returning any errors through
504// errsCh, any defined modules through modulesCh, any sub-Blueprints files through
505// blueprintsCh, and any dependencies on Blueprints files or directories through
506// depsCh.
507func (c *Context) parseBlueprintsFile(filename string, scope *parser.Scope, rootDir string,
508 errsCh chan<- []error, modulesCh chan<- []*moduleInfo, blueprintsCh chan<- stringAndScope,
509 depsCh chan<- string) {
510
511 dir := filepath.Dir(filename)
512
513 file, err := os.Open(filename)
514 if err != nil {
515 errsCh <- []error{err}
516 return
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700517 }
518
Colin Cross7ad621c2015-01-07 16:22:45 -0800519 subdirs, modules, errs, subScope := c.parse(rootDir, filename, file, scope)
520 if len(errs) > 0 {
521 errsCh <- errs
522 }
523
524 err = file.Close()
525 if err != nil {
526 errsCh <- []error{err}
527 }
528
529 modulesCh <- modules
530
531 for _, subdir := range subdirs {
532 subdir = filepath.Join(dir, subdir)
533
534 dirPart, filePart := filepath.Split(subdir)
535 dirPart = filepath.Clean(dirPart)
536
537 if filePart == "*" {
538 foundSubdirs, err := listSubdirs(dirPart)
539 if err != nil {
540 errsCh <- []error{err}
541 return
542 }
543
544 for _, foundSubdir := range foundSubdirs {
545 subBlueprints := filepath.Join(dirPart, foundSubdir,
546 "Blueprints")
547
548 _, err := os.Stat(subBlueprints)
549 if os.IsNotExist(err) {
550 // There is no Blueprints file in this subdirectory. We
551 // need to add the directory to the list of dependencies
552 // so that if someone adds a Blueprints file in the
553 // future we'll pick it up.
554 depsCh <- filepath.Dir(subBlueprints)
555 } else {
556 depsCh <- subBlueprints
557 blueprintsCh <- stringAndScope{
558 subBlueprints,
559 subScope,
560 }
561 }
562 }
563
564 // We now depend on the directory itself because if any new
565 // subdirectories get added or removed we need to rebuild the
566 // Ninja manifest.
567 depsCh <- dirPart
568 } else {
569 subBlueprints := filepath.Join(subdir, "Blueprints")
570 depsCh <- subBlueprints
571 blueprintsCh <- stringAndScope{
572 subBlueprints,
573 subScope,
574 }
575
576 }
577 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700578}
579
580func listSubdirs(dir string) ([]string, error) {
581 d, err := os.Open(dir)
582 if err != nil {
583 return nil, err
584 }
585 defer d.Close()
586
587 infos, err := d.Readdir(-1)
588 if err != nil {
589 return nil, err
590 }
591
592 var subdirs []string
593 for _, info := range infos {
Jamie Gennis0c35b2d2014-09-25 13:15:10 -0700594 isDotFile := strings.HasPrefix(info.Name(), ".")
595 if info.IsDir() && !isDotFile {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700596 subdirs = append(subdirs, info.Name())
597 }
598 }
599
600 return subdirs, nil
601}
602
Colin Crossc0dbc552015-01-02 15:19:28 -0800603func (c *Context) processSubdirs(
604 scope *parser.Scope) (subdirs []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700605
Colin Crossc0dbc552015-01-02 15:19:28 -0800606 if assignment, err := scope.Get("subdirs"); err == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700607 switch assignment.Value.Type {
608 case parser.List:
609 subdirs = make([]string, 0, len(assignment.Value.ListValue))
610
611 for _, value := range assignment.Value.ListValue {
612 if value.Type != parser.String {
613 // The parser should not produce this.
614 panic("non-string value found in list")
615 }
616
617 dirPart, filePart := filepath.Split(value.StringValue)
618 if (filePart != "*" && strings.ContainsRune(filePart, '*')) ||
619 strings.ContainsRune(dirPart, '*') {
620
621 errs = append(errs, &Error{
622 Err: fmt.Errorf("subdirs may only wildcard whole " +
623 "directories"),
624 Pos: value.Pos,
625 })
626
627 continue
628 }
629
630 subdirs = append(subdirs, value.StringValue)
631 }
632
633 if len(errs) > 0 {
634 subdirs = nil
635 }
636
637 return
638
639 case parser.Bool, parser.String:
640 errs = []error{
641 &Error{
642 Err: fmt.Errorf("subdirs must be a list of strings"),
643 Pos: assignment.Pos,
644 },
645 }
646
647 return
648
649 default:
650 panic(fmt.Errorf("unknown value type: %d", assignment.Value.Type))
651 }
652 }
653
Colin Crossc0dbc552015-01-02 15:19:28 -0800654 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700655}
656
Colin Crossc9028482014-12-18 16:28:54 -0800657func (c *Context) createVariants(origModule *moduleInfo, mutatorName string,
658 variantNames []string) []*moduleInfo {
659
660 newModules := []*moduleInfo{}
661 origVariantName := origModule.name
662 group := origModule.group
663
664 for i, variantName := range variantNames {
665 typeName := group.typeName
666 factory, ok := c.moduleFactories[typeName]
667 if !ok {
668 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
669 }
670
671 var newLogicModule Module
672 var newProperties []interface{}
673
674 if i == 0 {
675 // Reuse the existing module for the first new variant
676 newLogicModule = origModule.logicModule
677 newProperties = origModule.moduleProperties
678 } else {
679 props := []interface{}{
680 &group.properties,
681 }
682 newLogicModule, newProperties = factory()
683
684 newProperties = append(props, newProperties...)
685
686 if len(newProperties) != len(origModule.moduleProperties) {
687 panic("mismatched properties array length in " + group.properties.Name)
688 }
689
690 for i := range newProperties {
691 dst := reflect.ValueOf(newProperties[i]).Elem()
692 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
693
694 proptools.CopyProperties(dst, src)
695 }
696 }
697
698 newVariantName := append([]subName(nil), origVariantName...)
699 newSubName := subName{
700 mutatorName: mutatorName,
701 variantName: variantName,
702 }
703 newVariantName = append(newVariantName, newSubName)
704
705 newModule := &moduleInfo{
706 group: group,
707 directDeps: append([]*moduleInfo(nil), origModule.directDeps...),
708 logicModule: newLogicModule,
709 name: newVariantName,
710 moduleProperties: newProperties,
711 }
712
713 newModules = append(newModules, newModule)
714 c.moduleInfo[newModule.logicModule] = newModule
715
716 c.convertDepsToVariant(newModule, newSubName)
717 }
718
719 // Mark original variant as invalid. Modules that depend on this module will still
720 // depend on origModule, but we'll fix it when the mutator is called on them.
721 origModule.logicModule = nil
722 origModule.splitModules = newModules
723
724 return newModules
725}
726
727func (c *Context) convertDepsToVariant(module *moduleInfo, newSubName subName) {
728 for i, dep := range module.directDeps {
729 if dep.logicModule == nil {
730 var newDep *moduleInfo
731 for _, m := range dep.splitModules {
732 if len(m.name) > 0 && m.name[len(m.name)-1] == newSubName {
733 newDep = m
734 break
735 }
736 }
737 if newDep == nil {
738 panic(fmt.Sprintf("failed to find variant %s for module %s needed by %s",
739 newSubName.variantName, dep.group.properties.Name, module.group.properties.Name))
740 }
741 module.directDeps[i] = newDep
742 }
743 }
744}
745
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700746func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800747 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700748
Colin Crossd1facc12015-01-08 14:56:03 -0800749 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700750 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700751 if !ok {
752 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800753 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700754 }
755
Colin Cross7ad621c2015-01-07 16:22:45 -0800756 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700757 &Error{
758 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800759 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700760 },
761 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700762 }
763
Colin Crossbbfa51a2014-12-17 16:12:41 -0800764 logicModule, properties := factory()
765 group := &moduleGroup{
Jamie Gennisec701282014-06-12 20:06:31 -0700766 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700767 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700768 }
769
Jamie Gennis87622922014-09-30 11:38:25 -0700770 props := []interface{}{
Colin Crossbbfa51a2014-12-17 16:12:41 -0800771 &group.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700772 }
773 properties = append(props, properties...)
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700774
Jamie Gennis87622922014-09-30 11:38:25 -0700775 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700776 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800777 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700778 }
779
Colin Crossd1facc12015-01-08 14:56:03 -0800780 group.pos = moduleDef.Type.Pos
Colin Crossbbfa51a2014-12-17 16:12:41 -0800781 group.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700782 for name, propertyDef := range propertyMap {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800783 group.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700784 }
785
Colin Crossbbfa51a2014-12-17 16:12:41 -0800786 name := group.properties.Name
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700787 err := validateNinjaName(name)
788 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800789 return nil, []error{
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700790 &Error{
791 Err: fmt.Errorf("invalid module name %q: %s", err),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800792 Pos: group.propertyPos["name"],
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700793 },
794 }
795 }
796
Colin Crossbbfa51a2014-12-17 16:12:41 -0800797 module := &moduleInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800798 group: group,
799 logicModule: logicModule,
800 moduleProperties: properties,
Colin Crossbbfa51a2014-12-17 16:12:41 -0800801 }
Colin Crossbbfa51a2014-12-17 16:12:41 -0800802 group.modules = []*moduleInfo{module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700803
Colin Cross7ad621c2015-01-07 16:22:45 -0800804 return module, nil
805}
806
807func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
808 for _, module := range modules {
809 name := module.group.properties.Name
810 if first, present := c.moduleGroups[name]; present {
811 errs = append(errs, []error{
812 &Error{
813 Err: fmt.Errorf("module %q already defined", name),
814 Pos: module.group.pos,
815 },
816 &Error{
817 Err: fmt.Errorf("<-- previous definition here"),
818 Pos: first.pos,
819 },
820 }...)
821 continue
822 }
823
824 c.moduleGroups[name] = module.group
825 c.moduleInfo[module.logicModule] = module
826 }
827
828 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700829}
830
Jamie Gennisd4e10182014-06-12 20:06:50 -0700831// ResolveDependencies checks that the dependencies specified by all of the
832// modules defined in the parsed Blueprints files are valid. This means that
833// the modules depended upon are defined and that no circular dependencies
834// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700835//
836// The config argument is made available to all of the DynamicDependerModule
837// objects via the Config method on the DynamicDependerModuleContext objects
838// passed to their DynamicDependencies method.
839func (c *Context) ResolveDependencies(config interface{}) []error {
840 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700841 if len(errs) > 0 {
842 return errs
843 }
844
Colin Cross691a60d2015-01-07 18:08:56 -0800845 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700846 if len(errs) > 0 {
847 return errs
848 }
849
850 c.dependenciesReady = true
851 return nil
852}
853
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700854// moduleDepNames returns the sorted list of dependency names for a given
855// module. If the module implements the DynamicDependerModule interface then
856// this set consists of the union of those module names listed in its "deps"
857// property and those returned by its DynamicDependencies method. Otherwise it
858// is simply those names listed in its "deps" property.
Colin Crossbbfa51a2014-12-17 16:12:41 -0800859func (c *Context) moduleDepNames(group *moduleGroup,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700860 config interface{}) ([]string, []error) {
861
862 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800863 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700864
Colin Crossbbfa51a2014-12-17 16:12:41 -0800865 for _, depName := range group.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800866 if !depNamesSet[depName] {
867 depNamesSet[depName] = true
868 depNames = append(depNames, depName)
869 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700870 }
871
Colin Crossbbfa51a2014-12-17 16:12:41 -0800872 if len(group.modules) != 1 {
873 panic("expected a single module during moduleDepNames")
874 }
875 logicModule := group.modules[0].logicModule
876 dynamicDepender, ok := logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700877 if ok {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800878 ddmctx := &baseModuleContext{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700879 context: c,
880 config: config,
Colin Crossbbfa51a2014-12-17 16:12:41 -0800881 group: group,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700882 }
883
884 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
885
886 if len(ddmctx.errs) > 0 {
887 return nil, ddmctx.errs
888 }
889
890 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800891 if !depNamesSet[depName] {
892 depNamesSet[depName] = true
893 depNames = append(depNames, depName)
894 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700895 }
896 }
897
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700898 return depNames, nil
899}
900
Colin Crossbbfa51a2014-12-17 16:12:41 -0800901// resolveDependencies populates the moduleGroup.modules[0].directDeps list for every
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700902// module. In doing so it checks for missing dependencies and self-dependant
903// modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700904func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800905 for _, group := range c.moduleGroups {
906 depNames, newErrs := c.moduleDepNames(group, config)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700907 if len(newErrs) > 0 {
908 errs = append(errs, newErrs...)
909 continue
910 }
911
Colin Crossbbfa51a2014-12-17 16:12:41 -0800912 if len(group.modules) != 1 {
913 panic("expected a single module in resolveDependencies")
914 }
915 group.modules[0].directDeps = make([]*moduleInfo, 0, len(depNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700916
917 for _, depName := range depNames {
Colin Crossc9028482014-12-18 16:28:54 -0800918 newErrs := c.addDependency(group.modules[0], depName)
919 if len(newErrs) > 0 {
920 errs = append(errs, newErrs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700921 continue
922 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700923 }
924 }
925
926 return
927}
928
Colin Crossc9028482014-12-18 16:28:54 -0800929func (c *Context) addDependency(module *moduleInfo, depName string) []error {
930 depsPos := module.group.propertyPos["deps"]
931
932 if depName == module.group.properties.Name {
933 return []error{&Error{
934 Err: fmt.Errorf("%q depends on itself", depName),
935 Pos: depsPos,
936 }}
937 }
938
939 depInfo, ok := c.moduleGroups[depName]
940 if !ok {
941 return []error{&Error{
942 Err: fmt.Errorf("%q depends on undefined module %q",
943 module.group.properties.Name, depName),
944 Pos: depsPos,
945 }}
946 }
947
948 if len(depInfo.modules) != 1 {
949 panic(fmt.Sprintf("cannot add dependency from %s to %s, it already has multiple variants",
950 module.group.properties.Name, depInfo.properties.Name))
951 }
952
953 module.directDeps = append(module.directDeps, depInfo.modules[0])
954
955 return nil
956}
957
Colin Cross8900e9b2015-03-02 14:03:01 -0800958func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleGroup) bool) {
Colin Cross691a60d2015-01-07 18:08:56 -0800959 doneCh := make(chan *moduleGroup)
960 count := 0
Colin Cross8900e9b2015-03-02 14:03:01 -0800961 cancel := false
Colin Cross691a60d2015-01-07 18:08:56 -0800962
963 for _, group := range c.moduleGroupsSorted {
964 group.waitingCount = group.depsCount
965 }
966
967 visitOne := func(group *moduleGroup) {
968 count++
969 go func() {
Colin Cross8900e9b2015-03-02 14:03:01 -0800970 ret := visit(group)
971 if ret {
972 cancel = true
973 }
Colin Cross691a60d2015-01-07 18:08:56 -0800974 doneCh <- group
975 }()
976 }
977
978 for _, group := range c.moduleGroupsSorted {
979 if group.waitingCount == 0 {
980 visitOne(group)
981 }
982 }
983
Colin Cross11e3b0d2015-02-04 10:41:00 -0800984 for count > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -0800985 select {
986 case doneGroup := <-doneCh:
Colin Cross8900e9b2015-03-02 14:03:01 -0800987 if !cancel {
988 for _, parent := range doneGroup.reverseDeps {
989 parent.waitingCount--
990 if parent.waitingCount == 0 {
991 visitOne(parent)
992 }
Colin Cross691a60d2015-01-07 18:08:56 -0800993 }
994 }
995 count--
Colin Cross691a60d2015-01-07 18:08:56 -0800996 }
997 }
998}
999
1000// updateDependencies recursively walks the module dependency graph and updates
1001// additional fields based on the dependencies. It builds a sorted list of modules
1002// such that dependencies of a module always appear first, and populates reverse
1003// dependency links and counts of total dependencies. It also reports errors when
1004// it encounters dependency cycles. This should called after resolveDependencies,
1005// as well as after any mutator pass has called addDependency
1006func (c *Context) updateDependencies() (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001007 visited := make(map[*moduleGroup]bool) // modules that were already checked
1008 checking := make(map[*moduleGroup]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001009
Colin Crossbbfa51a2014-12-17 16:12:41 -08001010 sorted := make([]*moduleGroup, 0, len(c.moduleGroups))
Colin Cross573a2fd2014-12-17 14:16:51 -08001011
Colin Crossbbfa51a2014-12-17 16:12:41 -08001012 var check func(group *moduleGroup) []*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001013
Colin Crossbbfa51a2014-12-17 16:12:41 -08001014 check = func(group *moduleGroup) []*moduleGroup {
1015 visited[group] = true
1016 checking[group] = true
1017 defer delete(checking, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001018
Colin Crossbbfa51a2014-12-17 16:12:41 -08001019 deps := make(map[*moduleGroup]bool)
1020 for _, module := range group.modules {
1021 for _, dep := range module.directDeps {
1022 deps[dep.group] = true
1023 }
1024 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001025
Colin Cross691a60d2015-01-07 18:08:56 -08001026 group.reverseDeps = []*moduleGroup{}
1027 group.depsCount = len(deps)
1028
Colin Crossbbfa51a2014-12-17 16:12:41 -08001029 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001030 if checking[dep] {
1031 // This is a cycle.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001032 return []*moduleGroup{dep, group}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001033 }
1034
1035 if !visited[dep] {
1036 cycle := check(dep)
1037 if cycle != nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001038 if cycle[0] == group {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001039 // We are the "start" of the cycle, so we're responsible
1040 // for generating the errors. The cycle list is in
1041 // reverse order because all the 'check' calls append
1042 // their own module to the list.
1043 errs = append(errs, &Error{
1044 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Crossbbfa51a2014-12-17 16:12:41 -08001045 Pos: group.pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001046 })
1047
1048 // Iterate backwards through the cycle list.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001049 curGroup := group
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001050 for i := len(cycle) - 1; i >= 0; i-- {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001051 nextGroup := cycle[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001052 errs = append(errs, &Error{
1053 Err: fmt.Errorf(" %q depends on %q",
Colin Crossbbfa51a2014-12-17 16:12:41 -08001054 curGroup.properties.Name,
1055 nextGroup.properties.Name),
1056 Pos: curGroup.propertyPos["deps"],
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001057 })
Colin Crossbbfa51a2014-12-17 16:12:41 -08001058 curGroup = nextGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001059 }
1060
1061 // We can continue processing this module's children to
1062 // find more cycles. Since all the modules that were
1063 // part of the found cycle were marked as visited we
1064 // won't run into that cycle again.
1065 } else {
1066 // We're not the "start" of the cycle, so we just append
1067 // our module to the list and return it.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001068 return append(cycle, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001069 }
1070 }
1071 }
Colin Cross691a60d2015-01-07 18:08:56 -08001072
1073 dep.reverseDeps = append(dep.reverseDeps, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001074 }
1075
Colin Crossbbfa51a2014-12-17 16:12:41 -08001076 sorted = append(sorted, group)
Colin Cross573a2fd2014-12-17 14:16:51 -08001077
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001078 return nil
1079 }
1080
Colin Crossbbfa51a2014-12-17 16:12:41 -08001081 for _, group := range c.moduleGroups {
1082 if !visited[group] {
1083 cycle := check(group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001084 if cycle != nil {
1085 panic("inconceivable!")
1086 }
1087 }
1088 }
1089
Colin Crossbbfa51a2014-12-17 16:12:41 -08001090 c.moduleGroupsSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001091
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001092 return
1093}
1094
Jamie Gennisd4e10182014-06-12 20:06:50 -07001095// PrepareBuildActions generates an internal representation of all the build
1096// actions that need to be performed. This process involves invoking the
1097// GenerateBuildActions method on each of the Module objects created during the
1098// parse phase and then on each of the registered Singleton objects.
1099//
1100// If the ResolveDependencies method has not already been called it is called
1101// automatically by this method.
1102//
1103// The config argument is made available to all of the Module and Singleton
1104// objects via the Config method on the ModuleContext and SingletonContext
1105// objects passed to GenerateBuildActions. It is also passed to the functions
1106// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1107// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001108//
1109// The returned deps is a list of the ninja files dependencies that were added
1110// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1111// SingletonContext.AddNinjaFileDeps() methods.
1112func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001113 c.buildActionsReady = false
1114
1115 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001116 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001117 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001118 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001119 }
1120 }
1121
Colin Crossc9028482014-12-18 16:28:54 -08001122 errs = c.runMutators(config)
1123 if len(errs) > 0 {
1124 return nil, errs
1125 }
1126
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001127 liveGlobals := newLiveTracker(config)
1128
1129 c.initSpecialVariables()
1130
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001131 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001132 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001133 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001134 }
1135
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001136 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001137 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001138 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001139 }
1140
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001141 deps = append(depsModules, depsSingletons...)
1142
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001143 if c.buildDir != nil {
1144 liveGlobals.addNinjaStringDeps(c.buildDir)
1145 }
1146
1147 pkgNames := c.makeUniquePackageNames(liveGlobals)
1148
1149 // This will panic if it finds a problem since it's a programming error.
1150 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1151
1152 c.pkgNames = pkgNames
1153 c.globalVariables = liveGlobals.variables
1154 c.globalPools = liveGlobals.pools
1155 c.globalRules = liveGlobals.rules
1156
1157 c.buildActionsReady = true
1158
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001159 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001160}
1161
Colin Crossc9028482014-12-18 16:28:54 -08001162func (c *Context) runMutators(config interface{}) (errs []error) {
1163 for _, mutator := range c.mutatorInfo {
1164 if mutator.topDownMutator != nil {
1165 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1166 } else if mutator.bottomUpMutator != nil {
1167 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1168 } else {
1169 panic("no mutator set on " + mutator.name)
1170 }
1171 if len(errs) > 0 {
1172 return errs
1173 }
1174 }
1175
1176 return nil
1177}
1178
1179func (c *Context) runTopDownMutator(config interface{},
1180 name string, mutator TopDownMutator) (errs []error) {
1181
1182 for i := 0; i < len(c.moduleGroupsSorted); i++ {
1183 group := c.moduleGroupsSorted[len(c.moduleGroupsSorted)-1-i]
1184 for _, module := range group.modules {
1185 mctx := &mutatorContext{
1186 baseModuleContext: baseModuleContext{
1187 context: c,
1188 config: config,
1189 group: group,
1190 },
1191 module: module,
1192 name: name,
1193 }
1194
1195 mutator(mctx)
1196 if len(mctx.errs) > 0 {
1197 errs = append(errs, mctx.errs...)
1198 return errs
1199 }
1200 }
1201 }
1202
1203 return errs
1204}
1205
1206func (c *Context) runBottomUpMutator(config interface{},
1207 name string, mutator BottomUpMutator) (errs []error) {
1208
1209 dependenciesModified := false
1210
1211 for _, group := range c.moduleGroupsSorted {
1212 newModules := make([]*moduleInfo, 0, len(group.modules))
1213
1214 for _, module := range group.modules {
1215 mctx := &mutatorContext{
1216 baseModuleContext: baseModuleContext{
1217 context: c,
1218 config: config,
1219 group: group,
1220 },
1221 module: module,
1222 name: name,
1223 }
1224
1225 mutator(mctx)
1226 if len(mctx.errs) > 0 {
1227 errs = append(errs, mctx.errs...)
1228 return errs
1229 }
1230
1231 // Fix up any remaining dependencies on modules that were split into variants
1232 // by replacing them with the first variant
1233 for i, dep := range module.directDeps {
1234 if dep.logicModule == nil {
1235 module.directDeps[i] = dep.splitModules[0]
1236 }
1237 }
1238
1239 if mctx.dependenciesModified {
1240 dependenciesModified = true
1241 }
1242
1243 if module.splitModules != nil {
1244 newModules = append(newModules, module.splitModules...)
1245 } else {
1246 newModules = append(newModules, module)
1247 }
1248 }
1249
1250 group.modules = newModules
1251 }
1252
1253 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001254 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001255 if len(errs) > 0 {
1256 return errs
1257 }
1258 }
1259
1260 return errs
1261}
1262
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001263func (c *Context) initSpecialVariables() {
1264 c.buildDir = nil
1265 c.requiredNinjaMajor = 1
1266 c.requiredNinjaMinor = 1
1267 c.requiredNinjaMicro = 0
1268}
1269
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001270func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001271 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001272
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001273 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001274 var errs []error
1275
Colin Cross691a60d2015-01-07 18:08:56 -08001276 cancelCh := make(chan struct{})
1277 errsCh := make(chan []error)
1278 depsCh := make(chan []string)
1279
1280 go func() {
1281 for {
1282 select {
1283 case <-cancelCh:
1284 close(cancelCh)
1285 return
1286 case newErrs := <-errsCh:
1287 errs = append(errs, newErrs...)
1288 case newDeps := <-depsCh:
1289 deps = append(deps, newDeps...)
1290
1291 }
1292 }
1293 }()
1294
Colin Cross8900e9b2015-03-02 14:03:01 -08001295 c.parallelVisitAllBottomUp(func(group *moduleGroup) bool {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001296 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1297 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1298 // just set it to nil.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001299 scope := newLocalScope(nil, moduleNamespacePrefix(group.properties.Name))
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001300
Colin Crossbbfa51a2014-12-17 16:12:41 -08001301 for _, module := range group.modules {
1302 mctx := &moduleContext{
Colin Cross1455a0f2014-12-17 13:23:56 -08001303 baseModuleContext: baseModuleContext{
1304 context: c,
1305 config: config,
1306 group: group,
Colin Crossb2e7b5d2014-11-11 14:18:53 -08001307 },
Colin Cross1455a0f2014-12-17 13:23:56 -08001308 module: module,
1309 scope: scope,
Colin Crossbbfa51a2014-12-17 16:12:41 -08001310 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001311
Colin Crossbbfa51a2014-12-17 16:12:41 -08001312 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001313
Colin Crossbbfa51a2014-12-17 16:12:41 -08001314 if len(mctx.errs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001315 errsCh <- mctx.errs
Colin Cross8900e9b2015-03-02 14:03:01 -08001316 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001317 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001318
Colin Cross691a60d2015-01-07 18:08:56 -08001319 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001320
Colin Crossbbfa51a2014-12-17 16:12:41 -08001321 newErrs := c.processLocalBuildActions(&group.actionDefs,
1322 &mctx.actionDefs, liveGlobals)
1323 if len(newErrs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001324 errsCh <- newErrs
Colin Cross8900e9b2015-03-02 14:03:01 -08001325 return true
Colin Crossbbfa51a2014-12-17 16:12:41 -08001326 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001327 }
Colin Cross8900e9b2015-03-02 14:03:01 -08001328 return false
Colin Cross691a60d2015-01-07 18:08:56 -08001329 })
1330
1331 cancelCh <- struct{}{}
1332 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001333
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001334 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001335}
1336
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001337func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001338 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001339
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001340 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001341 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001342
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001343 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001344 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1345 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1346 // just set it to nil.
1347 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001348
1349 sctx := &singletonContext{
1350 context: c,
1351 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001352 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001353 }
1354
1355 info.singleton.GenerateBuildActions(sctx)
1356
1357 if len(sctx.errs) > 0 {
1358 errs = append(errs, sctx.errs...)
1359 if len(errs) > maxErrors {
1360 break
1361 }
1362 continue
1363 }
1364
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001365 deps = append(deps, sctx.ninjaFileDeps...)
1366
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001367 newErrs := c.processLocalBuildActions(&info.actionDefs,
1368 &sctx.actionDefs, liveGlobals)
1369 errs = append(errs, newErrs...)
1370 if len(errs) > maxErrors {
1371 break
1372 }
1373 }
1374
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001375 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001376}
1377
1378func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1379 liveGlobals *liveTracker) []error {
1380
1381 var errs []error
1382
1383 // First we go through and add everything referenced by the module's
1384 // buildDefs to the live globals set. This will end up adding the live
1385 // locals to the set as well, but we'll take them out after.
1386 for _, def := range in.buildDefs {
1387 err := liveGlobals.AddBuildDefDeps(def)
1388 if err != nil {
1389 errs = append(errs, err)
1390 }
1391 }
1392
1393 if len(errs) > 0 {
1394 return errs
1395 }
1396
Colin Crossc9028482014-12-18 16:28:54 -08001397 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001398
1399 // We use the now-incorrect set of live "globals" to determine which local
1400 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001401 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001402 for _, v := range in.variables {
1403 _, isLive := liveGlobals.variables[v]
1404 if isLive {
1405 out.variables = append(out.variables, v)
1406 delete(liveGlobals.variables, v)
1407 }
1408 }
1409
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001410 for _, r := range in.rules {
1411 _, isLive := liveGlobals.rules[r]
1412 if isLive {
1413 out.rules = append(out.rules, r)
1414 delete(liveGlobals.rules, r)
1415 }
1416 }
1417
1418 return nil
1419}
1420
Colin Crossbbfa51a2014-12-17 16:12:41 -08001421func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1422 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001423
Colin Crossbbfa51a2014-12-17 16:12:41 -08001424 var walk func(module *moduleInfo)
1425 walk = func(module *moduleInfo) {
1426 visited[module] = true
1427 for _, moduleDep := range module.directDeps {
1428 if !visited[moduleDep] {
1429 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001430 }
1431 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001432
Colin Crossbbfa51a2014-12-17 16:12:41 -08001433 if module != topModule {
1434 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001435 }
1436 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001437
1438 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001439}
1440
Colin Crossbbfa51a2014-12-17 16:12:41 -08001441func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001442 visit func(Module)) {
1443
Colin Crossbbfa51a2014-12-17 16:12:41 -08001444 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001445
Colin Crossbbfa51a2014-12-17 16:12:41 -08001446 var walk func(module *moduleInfo)
1447 walk = func(module *moduleInfo) {
1448 visited[module] = true
1449 for _, moduleDep := range module.directDeps {
1450 if !visited[moduleDep] {
1451 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001452 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001453 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001454
1455 if module != topModule {
1456 if pred(module.logicModule) {
1457 visit(module.logicModule)
1458 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001459 }
1460 }
1461
Colin Crossbbfa51a2014-12-17 16:12:41 -08001462 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001463}
1464
Colin Crossc9028482014-12-18 16:28:54 -08001465func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1466 for _, dep := range module.directDeps {
1467 visit(dep.logicModule)
1468 }
1469}
1470
1471func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1472 visit func(Module)) {
1473
1474 for _, dep := range module.directDeps {
1475 if pred(dep.logicModule) {
1476 visit(dep.logicModule)
1477 }
1478 }
1479}
1480
Jamie Gennisc15544d2014-09-24 20:26:52 -07001481func (c *Context) sortedModuleNames() []string {
1482 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001483 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1484 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001485 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1486 moduleName)
1487 }
1488 sort.Strings(c.cachedSortedModuleNames)
1489 }
1490
1491 return c.cachedSortedModuleNames
1492}
1493
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001494func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001495 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001496 group := c.moduleGroups[moduleName]
1497 for _, module := range group.modules {
1498 visit(module.logicModule)
1499 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001500 }
1501}
1502
1503func (c *Context) visitAllModulesIf(pred func(Module) bool,
1504 visit func(Module)) {
1505
Jamie Gennisc15544d2014-09-24 20:26:52 -07001506 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001507 group := c.moduleGroups[moduleName]
1508 for _, module := range group.modules {
1509 if pred(module.logicModule) {
1510 visit(module.logicModule)
1511 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001512 }
1513 }
1514}
1515
1516func (c *Context) requireNinjaVersion(major, minor, micro int) {
1517 if major != 1 {
1518 panic("ninja version with major version != 1 not supported")
1519 }
1520 if c.requiredNinjaMinor < minor {
1521 c.requiredNinjaMinor = minor
1522 c.requiredNinjaMicro = micro
1523 }
1524 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1525 c.requiredNinjaMicro = micro
1526 }
1527}
1528
1529func (c *Context) setBuildDir(value *ninjaString) {
1530 if c.buildDir != nil {
1531 panic("buildDir set multiple times")
1532 }
1533 c.buildDir = value
1534}
1535
1536func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001537 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001538
Jamie Gennis2fb20952014-10-03 02:49:58 -07001539 pkgs := make(map[string]*PackageContext)
1540 pkgNames := make(map[*PackageContext]string)
1541 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001542
Jamie Gennis2fb20952014-10-03 02:49:58 -07001543 processPackage := func(pctx *PackageContext) {
1544 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001545 // This is a built-in rule and has no package.
1546 return
1547 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001548 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001549 // We've already processed this package.
1550 return
1551 }
1552
Jamie Gennis2fb20952014-10-03 02:49:58 -07001553 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001554 if present {
1555 // Short name collision. Both this package and the one that's
1556 // already there need to use their full names. We leave the short
1557 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001558 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001559 longPkgNames[otherPkg] = true
1560 } else {
1561 // No collision so far. Tentatively set the package's name to be
1562 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001563 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001564 }
1565 }
1566
1567 // We try to give all packages their short name, but when we get collisions
1568 // we need to use the full unique package name.
1569 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001570 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001571 }
1572 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001573 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001574 }
1575 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001576 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001577 }
1578
1579 // Add the packages that had collisions using their full unique names. This
1580 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001581 for pctx := range longPkgNames {
1582 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001583 }
1584
1585 return pkgNames
1586}
1587
1588func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001589 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001590
1591 visited := make(map[Variable]bool) // variables that were already checked
1592 checking := make(map[Variable]bool) // variables actively being checked
1593
1594 var check func(v Variable) []Variable
1595
1596 check = func(v Variable) []Variable {
1597 visited[v] = true
1598 checking[v] = true
1599 defer delete(checking, v)
1600
1601 value := variables[v]
1602 for _, dep := range value.variables {
1603 if checking[dep] {
1604 // This is a cycle.
1605 return []Variable{dep, v}
1606 }
1607
1608 if !visited[dep] {
1609 cycle := check(dep)
1610 if cycle != nil {
1611 if cycle[0] == v {
1612 // We are the "start" of the cycle, so we're responsible
1613 // for generating the errors. The cycle list is in
1614 // reverse order because all the 'check' calls append
1615 // their own module to the list.
1616 msgs := []string{"detected variable reference cycle:"}
1617
1618 // Iterate backwards through the cycle list.
1619 curName := v.fullName(pkgNames)
1620 curValue := value.Value(pkgNames)
1621 for i := len(cycle) - 1; i >= 0; i-- {
1622 next := cycle[i]
1623 nextName := next.fullName(pkgNames)
1624 nextValue := variables[next].Value(pkgNames)
1625
1626 msgs = append(msgs, fmt.Sprintf(
1627 " %q depends on %q", curName, nextName))
1628 msgs = append(msgs, fmt.Sprintf(
1629 " [%s = %s]", curName, curValue))
1630
1631 curName = nextName
1632 curValue = nextValue
1633 }
1634
1635 // Variable reference cycles are a programming error,
1636 // not the fault of the Blueprint file authors.
1637 panic(strings.Join(msgs, "\n"))
1638 } else {
1639 // We're not the "start" of the cycle, so we just append
1640 // our module to the list and return it.
1641 return append(cycle, v)
1642 }
1643 }
1644 }
1645 }
1646
1647 return nil
1648 }
1649
1650 for v := range variables {
1651 if !visited[v] {
1652 cycle := check(v)
1653 if cycle != nil {
1654 panic("inconceivable!")
1655 }
1656 }
1657 }
1658}
1659
Jamie Gennisaf435562014-10-27 22:34:56 -07001660// AllTargets returns a map all the build target names to the rule used to build
1661// them. This is the same information that is output by running 'ninja -t
1662// targets all'. If this is called before PrepareBuildActions successfully
1663// completes then ErrbuildActionsNotReady is returned.
1664func (c *Context) AllTargets() (map[string]string, error) {
1665 if !c.buildActionsReady {
1666 return nil, ErrBuildActionsNotReady
1667 }
1668
1669 targets := map[string]string{}
1670
1671 // Collect all the module build targets.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001672 for _, info := range c.moduleGroups {
Jamie Gennisaf435562014-10-27 22:34:56 -07001673 for _, buildDef := range info.actionDefs.buildDefs {
1674 ruleName := buildDef.Rule.fullName(c.pkgNames)
1675 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001676 outputValue, err := output.Eval(c.globalVariables)
1677 if err != nil {
1678 return nil, err
1679 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001680 targets[outputValue] = ruleName
1681 }
1682 }
1683 }
1684
1685 // Collect all the singleton build targets.
1686 for _, info := range c.singletonInfo {
1687 for _, buildDef := range info.actionDefs.buildDefs {
1688 ruleName := buildDef.Rule.fullName(c.pkgNames)
1689 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001690 outputValue, err := output.Eval(c.globalVariables)
1691 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001692 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001693 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001694 targets[outputValue] = ruleName
1695 }
1696 }
1697 }
1698
1699 return targets, nil
1700}
1701
Jamie Gennisd4e10182014-06-12 20:06:50 -07001702// WriteBuildFile writes the Ninja manifeset text for the generated build
1703// actions to w. If this is called before PrepareBuildActions successfully
1704// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001705func (c *Context) WriteBuildFile(w io.Writer) error {
1706 if !c.buildActionsReady {
1707 return ErrBuildActionsNotReady
1708 }
1709
1710 nw := newNinjaWriter(w)
1711
1712 err := c.writeBuildFileHeader(nw)
1713 if err != nil {
1714 return err
1715 }
1716
1717 err = c.writeNinjaRequiredVersion(nw)
1718 if err != nil {
1719 return err
1720 }
1721
1722 // TODO: Group the globals by package.
1723
1724 err = c.writeGlobalVariables(nw)
1725 if err != nil {
1726 return err
1727 }
1728
1729 err = c.writeGlobalPools(nw)
1730 if err != nil {
1731 return err
1732 }
1733
1734 err = c.writeBuildDir(nw)
1735 if err != nil {
1736 return err
1737 }
1738
1739 err = c.writeGlobalRules(nw)
1740 if err != nil {
1741 return err
1742 }
1743
1744 err = c.writeAllModuleActions(nw)
1745 if err != nil {
1746 return err
1747 }
1748
1749 err = c.writeAllSingletonActions(nw)
1750 if err != nil {
1751 return err
1752 }
1753
1754 return nil
1755}
1756
Jamie Gennisc15544d2014-09-24 20:26:52 -07001757type pkgAssociation struct {
1758 PkgName string
1759 PkgPath string
1760}
1761
1762type pkgAssociationSorter struct {
1763 pkgs []pkgAssociation
1764}
1765
1766func (s *pkgAssociationSorter) Len() int {
1767 return len(s.pkgs)
1768}
1769
1770func (s *pkgAssociationSorter) Less(i, j int) bool {
1771 iName := s.pkgs[i].PkgName
1772 jName := s.pkgs[j].PkgName
1773 return iName < jName
1774}
1775
1776func (s *pkgAssociationSorter) Swap(i, j int) {
1777 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1778}
1779
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001780func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1781 headerTemplate := template.New("fileHeader")
1782 _, err := headerTemplate.Parse(fileHeaderTemplate)
1783 if err != nil {
1784 // This is a programming error.
1785 panic(err)
1786 }
1787
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001788 var pkgs []pkgAssociation
1789 maxNameLen := 0
1790 for pkg, name := range c.pkgNames {
1791 pkgs = append(pkgs, pkgAssociation{
1792 PkgName: name,
1793 PkgPath: pkg.pkgPath,
1794 })
1795 if len(name) > maxNameLen {
1796 maxNameLen = len(name)
1797 }
1798 }
1799
1800 for i := range pkgs {
1801 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1802 }
1803
Jamie Gennisc15544d2014-09-24 20:26:52 -07001804 sort.Sort(&pkgAssociationSorter{pkgs})
1805
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001806 params := map[string]interface{}{
1807 "Pkgs": pkgs,
1808 }
1809
1810 buf := bytes.NewBuffer(nil)
1811 err = headerTemplate.Execute(buf, params)
1812 if err != nil {
1813 return err
1814 }
1815
1816 return nw.Comment(buf.String())
1817}
1818
1819func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1820 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1821 c.requiredNinjaMicro)
1822
1823 err := nw.Assign("ninja_required_version", value)
1824 if err != nil {
1825 return err
1826 }
1827
1828 return nw.BlankLine()
1829}
1830
1831func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1832 if c.buildDir != nil {
1833 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1834 if err != nil {
1835 return err
1836 }
1837
1838 err = nw.BlankLine()
1839 if err != nil {
1840 return err
1841 }
1842 }
1843 return nil
1844}
1845
Jamie Gennisc15544d2014-09-24 20:26:52 -07001846type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001847 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001848}
1849
Jamie Gennisc15544d2014-09-24 20:26:52 -07001850type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001851 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001852 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001853}
1854
Jamie Gennisc15544d2014-09-24 20:26:52 -07001855func (s *globalEntitySorter) Len() int {
1856 return len(s.entities)
1857}
1858
1859func (s *globalEntitySorter) Less(i, j int) bool {
1860 iName := s.entities[i].fullName(s.pkgNames)
1861 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001862 return iName < jName
1863}
1864
Jamie Gennisc15544d2014-09-24 20:26:52 -07001865func (s *globalEntitySorter) Swap(i, j int) {
1866 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001867}
1868
1869func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1870 visited := make(map[Variable]bool)
1871
1872 var walk func(v Variable) error
1873 walk = func(v Variable) error {
1874 visited[v] = true
1875
1876 // First visit variables on which this variable depends.
1877 value := c.globalVariables[v]
1878 for _, dep := range value.variables {
1879 if !visited[dep] {
1880 err := walk(dep)
1881 if err != nil {
1882 return err
1883 }
1884 }
1885 }
1886
1887 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1888 if err != nil {
1889 return err
1890 }
1891
1892 err = nw.BlankLine()
1893 if err != nil {
1894 return err
1895 }
1896
1897 return nil
1898 }
1899
Jamie Gennisc15544d2014-09-24 20:26:52 -07001900 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1901 for variable := range c.globalVariables {
1902 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001903 }
1904
Jamie Gennisc15544d2014-09-24 20:26:52 -07001905 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001906
Jamie Gennisc15544d2014-09-24 20:26:52 -07001907 for _, entity := range globalVariables {
1908 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001909 if !visited[v] {
1910 err := walk(v)
1911 if err != nil {
1912 return nil
1913 }
1914 }
1915 }
1916
1917 return nil
1918}
1919
1920func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001921 globalPools := make([]globalEntity, 0, len(c.globalPools))
1922 for pool := range c.globalPools {
1923 globalPools = append(globalPools, pool)
1924 }
1925
1926 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1927
1928 for _, entity := range globalPools {
1929 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001930 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001931 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001932 err := def.WriteTo(nw, name)
1933 if err != nil {
1934 return err
1935 }
1936
1937 err = nw.BlankLine()
1938 if err != nil {
1939 return err
1940 }
1941 }
1942
1943 return nil
1944}
1945
1946func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001947 globalRules := make([]globalEntity, 0, len(c.globalRules))
1948 for rule := range c.globalRules {
1949 globalRules = append(globalRules, rule)
1950 }
1951
1952 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
1953
1954 for _, entity := range globalRules {
1955 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001956 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001957 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001958 err := def.WriteTo(nw, name, c.pkgNames)
1959 if err != nil {
1960 return err
1961 }
1962
1963 err = nw.BlankLine()
1964 if err != nil {
1965 return err
1966 }
1967 }
1968
1969 return nil
1970}
1971
Colin Crossbbfa51a2014-12-17 16:12:41 -08001972type moduleGroupSorter []*moduleGroup
Jamie Gennis86179fe2014-06-11 16:27:16 -07001973
Colin Crossbbfa51a2014-12-17 16:12:41 -08001974func (s moduleGroupSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001975 return len(s)
1976}
1977
Colin Crossbbfa51a2014-12-17 16:12:41 -08001978func (s moduleGroupSorter) Less(i, j int) bool {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001979 iName := s[i].properties.Name
1980 jName := s[j].properties.Name
1981 return iName < jName
1982}
1983
Colin Crossbbfa51a2014-12-17 16:12:41 -08001984func (s moduleGroupSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001985 s[i], s[j] = s[j], s[i]
1986}
1987
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001988func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
1989 headerTemplate := template.New("moduleHeader")
1990 _, err := headerTemplate.Parse(moduleHeaderTemplate)
1991 if err != nil {
1992 // This is a programming error.
1993 panic(err)
1994 }
1995
Colin Crossbbfa51a2014-12-17 16:12:41 -08001996 infos := make([]*moduleGroup, 0, len(c.moduleGroups))
1997 for _, info := range c.moduleGroups {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001998 infos = append(infos, info)
1999 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002000 sort.Sort(moduleGroupSorter(infos))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002001
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002002 buf := bytes.NewBuffer(nil)
2003
Jamie Gennis86179fe2014-06-11 16:27:16 -07002004 for _, info := range infos {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002005 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002006
2007 // In order to make the bootstrap build manifest independent of the
2008 // build dir we need to output the Blueprints file locations in the
2009 // comments as paths relative to the source directory.
2010 relPos := info.pos
Jamie Gennisec701282014-06-12 20:06:31 -07002011 relPos.Filename = info.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002012
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002013 // Get the name and location of the factory function for the module.
2014 factory := c.moduleFactories[info.typeName]
2015 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2016 factoryName := factoryFunc.Name()
2017
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002018 infoMap := map[string]interface{}{
2019 "properties": info.properties,
2020 "typeName": info.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002021 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002022 "pos": relPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002023 }
2024 err = headerTemplate.Execute(buf, infoMap)
2025 if err != nil {
2026 return err
2027 }
2028
2029 err = nw.Comment(buf.String())
2030 if err != nil {
2031 return err
2032 }
2033
2034 err = nw.BlankLine()
2035 if err != nil {
2036 return err
2037 }
2038
2039 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2040 if err != nil {
2041 return err
2042 }
2043
2044 err = nw.BlankLine()
2045 if err != nil {
2046 return err
2047 }
2048 }
2049
2050 return nil
2051}
2052
2053func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2054 headerTemplate := template.New("singletonHeader")
2055 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2056 if err != nil {
2057 // This is a programming error.
2058 panic(err)
2059 }
2060
2061 buf := bytes.NewBuffer(nil)
2062
Jamie Gennis86179fe2014-06-11 16:27:16 -07002063 singletonNames := make([]string, 0, len(c.singletonInfo))
2064 for name := range c.singletonInfo {
2065 singletonNames = append(singletonNames, name)
2066 }
2067 sort.Strings(singletonNames)
2068
2069 for _, name := range singletonNames {
2070 info := c.singletonInfo[name]
2071
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002072 // Get the name of the factory function for the module.
2073 factory := info.factory
2074 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2075 factoryName := factoryFunc.Name()
2076
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002077 buf.Reset()
2078 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002079 "name": name,
2080 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002081 }
2082 err = headerTemplate.Execute(buf, infoMap)
2083 if err != nil {
2084 return err
2085 }
2086
2087 err = nw.Comment(buf.String())
2088 if err != nil {
2089 return err
2090 }
2091
2092 err = nw.BlankLine()
2093 if err != nil {
2094 return err
2095 }
2096
2097 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2098 if err != nil {
2099 return err
2100 }
2101
2102 err = nw.BlankLine()
2103 if err != nil {
2104 return err
2105 }
2106 }
2107
2108 return nil
2109}
2110
2111func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2112 defs *localBuildActions) error {
2113
2114 // Write the local variable assignments.
2115 for _, v := range defs.variables {
2116 // A localVariable doesn't need the package names or config to
2117 // determine its name or value.
2118 name := v.fullName(nil)
2119 value, err := v.value(nil)
2120 if err != nil {
2121 panic(err)
2122 }
2123 err = nw.Assign(name, value.Value(c.pkgNames))
2124 if err != nil {
2125 return err
2126 }
2127 }
2128
2129 if len(defs.variables) > 0 {
2130 err := nw.BlankLine()
2131 if err != nil {
2132 return err
2133 }
2134 }
2135
2136 // Write the local rules.
2137 for _, r := range defs.rules {
2138 // A localRule doesn't need the package names or config to determine
2139 // its name or definition.
2140 name := r.fullName(nil)
2141 def, err := r.def(nil)
2142 if err != nil {
2143 panic(err)
2144 }
2145
2146 err = def.WriteTo(nw, name, c.pkgNames)
2147 if err != nil {
2148 return err
2149 }
2150
2151 err = nw.BlankLine()
2152 if err != nil {
2153 return err
2154 }
2155 }
2156
2157 // Write the build definitions.
2158 for _, buildDef := range defs.buildDefs {
2159 err := buildDef.WriteTo(nw, c.pkgNames)
2160 if err != nil {
2161 return err
2162 }
2163
2164 if len(buildDef.Args) > 0 {
2165 err = nw.BlankLine()
2166 if err != nil {
2167 return err
2168 }
2169 }
2170 }
2171
2172 return nil
2173}
2174
2175var fileHeaderTemplate = `******************************************************************************
2176*** This file is generated and should not be edited ***
2177******************************************************************************
2178{{if .Pkgs}}
2179This file contains variables, rules, and pools with name prefixes indicating
2180they were generated by the following Go packages:
2181{{range .Pkgs}}
2182 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2183
2184`
2185
2186var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2187Module: {{.properties.Name}}
2188Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002189Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002190Defined: {{.pos}}
2191`
2192
2193var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2194Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002195Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002196`