blob: 9ab359a550fc3d94ba4d6cde51a52c68165e3583 [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,
Colin Cross174ae052015-03-03 17:37:03 -0800658 variantNames []string) ([]*moduleInfo, []error) {
Colin Crossc9028482014-12-18 16:28:54 -0800659
660 newModules := []*moduleInfo{}
661 origVariantName := origModule.name
662 group := origModule.group
663
Colin Cross174ae052015-03-03 17:37:03 -0800664 var errs []error
665
Colin Crossc9028482014-12-18 16:28:54 -0800666 for i, variantName := range variantNames {
667 typeName := group.typeName
668 factory, ok := c.moduleFactories[typeName]
669 if !ok {
670 panic(fmt.Sprintf("unrecognized module type %q during cloning", typeName))
671 }
672
673 var newLogicModule Module
674 var newProperties []interface{}
675
676 if i == 0 {
677 // Reuse the existing module for the first new variant
678 newLogicModule = origModule.logicModule
679 newProperties = origModule.moduleProperties
680 } else {
681 props := []interface{}{
682 &group.properties,
683 }
684 newLogicModule, newProperties = factory()
685
686 newProperties = append(props, newProperties...)
687
688 if len(newProperties) != len(origModule.moduleProperties) {
689 panic("mismatched properties array length in " + group.properties.Name)
690 }
691
692 for i := range newProperties {
693 dst := reflect.ValueOf(newProperties[i]).Elem()
694 src := reflect.ValueOf(origModule.moduleProperties[i]).Elem()
695
696 proptools.CopyProperties(dst, src)
697 }
698 }
699
700 newVariantName := append([]subName(nil), origVariantName...)
701 newSubName := subName{
702 mutatorName: mutatorName,
703 variantName: variantName,
704 }
705 newVariantName = append(newVariantName, newSubName)
706
707 newModule := &moduleInfo{
708 group: group,
709 directDeps: append([]*moduleInfo(nil), origModule.directDeps...),
710 logicModule: newLogicModule,
711 name: newVariantName,
712 moduleProperties: newProperties,
713 }
714
715 newModules = append(newModules, newModule)
716 c.moduleInfo[newModule.logicModule] = newModule
717
Colin Cross174ae052015-03-03 17:37:03 -0800718 newErrs := c.convertDepsToVariant(newModule, newSubName)
719 if len(newErrs) > 0 {
720 errs = append(errs, newErrs...)
721 }
Colin Crossc9028482014-12-18 16:28:54 -0800722 }
723
724 // Mark original variant as invalid. Modules that depend on this module will still
725 // depend on origModule, but we'll fix it when the mutator is called on them.
726 origModule.logicModule = nil
727 origModule.splitModules = newModules
728
Colin Cross174ae052015-03-03 17:37:03 -0800729 return newModules, errs
Colin Crossc9028482014-12-18 16:28:54 -0800730}
731
Colin Cross174ae052015-03-03 17:37:03 -0800732func (c *Context) convertDepsToVariant(module *moduleInfo, newSubName subName) (errs []error) {
733
Colin Crossc9028482014-12-18 16:28:54 -0800734 for i, dep := range module.directDeps {
735 if dep.logicModule == nil {
736 var newDep *moduleInfo
737 for _, m := range dep.splitModules {
738 if len(m.name) > 0 && m.name[len(m.name)-1] == newSubName {
739 newDep = m
740 break
741 }
742 }
743 if newDep == nil {
Colin Cross174ae052015-03-03 17:37:03 -0800744 errs = append(errs, &Error{
745 Err: fmt.Errorf("failed to find variant %q for module %q needed by %q",
746 newSubName.variantName, dep.group.properties.Name,
747 module.group.properties.Name),
748 Pos: module.group.pos,
749 })
750 continue
Colin Crossc9028482014-12-18 16:28:54 -0800751 }
752 module.directDeps[i] = newDep
753 }
754 }
Colin Cross174ae052015-03-03 17:37:03 -0800755
756 return errs
Colin Crossc9028482014-12-18 16:28:54 -0800757}
758
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700759func (c *Context) processModuleDef(moduleDef *parser.Module,
Colin Cross7ad621c2015-01-07 16:22:45 -0800760 relBlueprintsFile string) (*moduleInfo, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700761
Colin Crossd1facc12015-01-08 14:56:03 -0800762 typeName := moduleDef.Type.Name
Jamie Gennis7d5b2f82014-09-24 17:51:52 -0700763 factory, ok := c.moduleFactories[typeName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700764 if !ok {
765 if c.ignoreUnknownModuleTypes {
Colin Cross7ad621c2015-01-07 16:22:45 -0800766 return nil, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700767 }
768
Colin Cross7ad621c2015-01-07 16:22:45 -0800769 return nil, []error{
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700770 &Error{
771 Err: fmt.Errorf("unrecognized module type %q", typeName),
Colin Crossd1facc12015-01-08 14:56:03 -0800772 Pos: moduleDef.Type.Pos,
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700773 },
774 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700775 }
776
Colin Crossbbfa51a2014-12-17 16:12:41 -0800777 logicModule, properties := factory()
778 group := &moduleGroup{
Jamie Gennisec701282014-06-12 20:06:31 -0700779 typeName: typeName,
Jamie Gennisec701282014-06-12 20:06:31 -0700780 relBlueprintsFile: relBlueprintsFile,
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700781 }
782
Jamie Gennis87622922014-09-30 11:38:25 -0700783 props := []interface{}{
Colin Crossbbfa51a2014-12-17 16:12:41 -0800784 &group.properties,
Jamie Gennis87622922014-09-30 11:38:25 -0700785 }
786 properties = append(props, properties...)
Jamie Gennisd4c53d82014-06-22 17:02:55 -0700787
Jamie Gennis87622922014-09-30 11:38:25 -0700788 propertyMap, errs := unpackProperties(moduleDef.Properties, properties...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700789 if len(errs) > 0 {
Colin Cross7ad621c2015-01-07 16:22:45 -0800790 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700791 }
792
Colin Crossd1facc12015-01-08 14:56:03 -0800793 group.pos = moduleDef.Type.Pos
Colin Crossbbfa51a2014-12-17 16:12:41 -0800794 group.propertyPos = make(map[string]scanner.Position)
Jamie Gennis87622922014-09-30 11:38:25 -0700795 for name, propertyDef := range propertyMap {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800796 group.propertyPos[name] = propertyDef.Pos
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700797 }
798
Colin Crossbbfa51a2014-12-17 16:12:41 -0800799 name := group.properties.Name
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700800 err := validateNinjaName(name)
801 if err != nil {
Colin Cross7ad621c2015-01-07 16:22:45 -0800802 return nil, []error{
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700803 &Error{
804 Err: fmt.Errorf("invalid module name %q: %s", err),
Colin Crossbbfa51a2014-12-17 16:12:41 -0800805 Pos: group.propertyPos["name"],
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700806 },
807 }
808 }
809
Colin Crossbbfa51a2014-12-17 16:12:41 -0800810 module := &moduleInfo{
Colin Crossc9028482014-12-18 16:28:54 -0800811 group: group,
812 logicModule: logicModule,
813 moduleProperties: properties,
Colin Crossbbfa51a2014-12-17 16:12:41 -0800814 }
Colin Crossbbfa51a2014-12-17 16:12:41 -0800815 group.modules = []*moduleInfo{module}
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700816
Colin Cross7ad621c2015-01-07 16:22:45 -0800817 return module, nil
818}
819
820func (c *Context) addModules(modules []*moduleInfo) (errs []error) {
821 for _, module := range modules {
822 name := module.group.properties.Name
823 if first, present := c.moduleGroups[name]; present {
824 errs = append(errs, []error{
825 &Error{
826 Err: fmt.Errorf("module %q already defined", name),
827 Pos: module.group.pos,
828 },
829 &Error{
830 Err: fmt.Errorf("<-- previous definition here"),
831 Pos: first.pos,
832 },
833 }...)
834 continue
835 }
836
837 c.moduleGroups[name] = module.group
838 c.moduleInfo[module.logicModule] = module
839 }
840
841 return errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700842}
843
Jamie Gennisd4e10182014-06-12 20:06:50 -0700844// ResolveDependencies checks that the dependencies specified by all of the
845// modules defined in the parsed Blueprints files are valid. This means that
846// the modules depended upon are defined and that no circular dependencies
847// exist.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700848//
849// The config argument is made available to all of the DynamicDependerModule
850// objects via the Config method on the DynamicDependerModuleContext objects
851// passed to their DynamicDependencies method.
852func (c *Context) ResolveDependencies(config interface{}) []error {
853 errs := c.resolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700854 if len(errs) > 0 {
855 return errs
856 }
857
Colin Cross691a60d2015-01-07 18:08:56 -0800858 errs = c.updateDependencies()
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700859 if len(errs) > 0 {
860 return errs
861 }
862
863 c.dependenciesReady = true
864 return nil
865}
866
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700867// moduleDepNames returns the sorted list of dependency names for a given
868// module. If the module implements the DynamicDependerModule interface then
869// this set consists of the union of those module names listed in its "deps"
870// property and those returned by its DynamicDependencies method. Otherwise it
871// is simply those names listed in its "deps" property.
Colin Crossbbfa51a2014-12-17 16:12:41 -0800872func (c *Context) moduleDepNames(group *moduleGroup,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700873 config interface{}) ([]string, []error) {
874
875 depNamesSet := make(map[string]bool)
Colin Crossa434b3f2015-01-13 10:59:52 -0800876 depNames := []string{}
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700877
Colin Crossbbfa51a2014-12-17 16:12:41 -0800878 for _, depName := range group.properties.Deps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800879 if !depNamesSet[depName] {
880 depNamesSet[depName] = true
881 depNames = append(depNames, depName)
882 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700883 }
884
Colin Crossbbfa51a2014-12-17 16:12:41 -0800885 if len(group.modules) != 1 {
886 panic("expected a single module during moduleDepNames")
887 }
888 logicModule := group.modules[0].logicModule
889 dynamicDepender, ok := logicModule.(DynamicDependerModule)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700890 if ok {
Colin Crossbe1a9a12014-12-18 11:05:45 -0800891 ddmctx := &baseModuleContext{
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700892 context: c,
893 config: config,
Colin Crossbbfa51a2014-12-17 16:12:41 -0800894 group: group,
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700895 }
896
897 dynamicDeps := dynamicDepender.DynamicDependencies(ddmctx)
898
899 if len(ddmctx.errs) > 0 {
900 return nil, ddmctx.errs
901 }
902
903 for _, depName := range dynamicDeps {
Colin Crossa434b3f2015-01-13 10:59:52 -0800904 if !depNamesSet[depName] {
905 depNamesSet[depName] = true
906 depNames = append(depNames, depName)
907 }
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700908 }
909 }
910
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700911 return depNames, nil
912}
913
Colin Crossbbfa51a2014-12-17 16:12:41 -0800914// resolveDependencies populates the moduleGroup.modules[0].directDeps list for every
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700915// module. In doing so it checks for missing dependencies and self-dependant
916// modules.
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700917func (c *Context) resolveDependencies(config interface{}) (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -0800918 for _, group := range c.moduleGroups {
919 depNames, newErrs := c.moduleDepNames(group, config)
Jamie Gennisb9e87f62014-09-24 20:28:11 -0700920 if len(newErrs) > 0 {
921 errs = append(errs, newErrs...)
922 continue
923 }
924
Colin Crossbbfa51a2014-12-17 16:12:41 -0800925 if len(group.modules) != 1 {
926 panic("expected a single module in resolveDependencies")
927 }
928 group.modules[0].directDeps = make([]*moduleInfo, 0, len(depNames))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700929
930 for _, depName := range depNames {
Colin Crossc9028482014-12-18 16:28:54 -0800931 newErrs := c.addDependency(group.modules[0], depName)
932 if len(newErrs) > 0 {
933 errs = append(errs, newErrs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700934 continue
935 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700936 }
937 }
938
939 return
940}
941
Colin Crossc9028482014-12-18 16:28:54 -0800942func (c *Context) addDependency(module *moduleInfo, depName string) []error {
943 depsPos := module.group.propertyPos["deps"]
944
945 if depName == module.group.properties.Name {
946 return []error{&Error{
947 Err: fmt.Errorf("%q depends on itself", depName),
948 Pos: depsPos,
949 }}
950 }
951
952 depInfo, ok := c.moduleGroups[depName]
953 if !ok {
954 return []error{&Error{
955 Err: fmt.Errorf("%q depends on undefined module %q",
956 module.group.properties.Name, depName),
957 Pos: depsPos,
958 }}
959 }
960
961 if len(depInfo.modules) != 1 {
962 panic(fmt.Sprintf("cannot add dependency from %s to %s, it already has multiple variants",
963 module.group.properties.Name, depInfo.properties.Name))
964 }
965
966 module.directDeps = append(module.directDeps, depInfo.modules[0])
967
968 return nil
969}
970
Colin Cross691a60d2015-01-07 18:08:56 -0800971func (c *Context) parallelVisitAllBottomUp(visit func(group *moduleGroup)) {
972 doneCh := make(chan *moduleGroup)
973 count := 0
974
975 for _, group := range c.moduleGroupsSorted {
976 group.waitingCount = group.depsCount
977 }
978
979 visitOne := func(group *moduleGroup) {
980 count++
981 go func() {
982 visit(group)
983 doneCh <- group
984 }()
985 }
986
987 for _, group := range c.moduleGroupsSorted {
988 if group.waitingCount == 0 {
989 visitOne(group)
990 }
991 }
992
993loop:
994 for {
995 select {
996 case doneGroup := <-doneCh:
997 for _, parent := range doneGroup.reverseDeps {
998 parent.waitingCount--
999 if parent.waitingCount == 0 {
1000 visitOne(parent)
1001 }
1002 }
1003 count--
1004 if count == 0 {
1005 break loop
1006 }
1007 }
1008 }
1009}
1010
1011// updateDependencies recursively walks the module dependency graph and updates
1012// additional fields based on the dependencies. It builds a sorted list of modules
1013// such that dependencies of a module always appear first, and populates reverse
1014// dependency links and counts of total dependencies. It also reports errors when
1015// it encounters dependency cycles. This should called after resolveDependencies,
1016// as well as after any mutator pass has called addDependency
1017func (c *Context) updateDependencies() (errs []error) {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001018 visited := make(map[*moduleGroup]bool) // modules that were already checked
1019 checking := make(map[*moduleGroup]bool) // modules actively being checked
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001020
Colin Crossbbfa51a2014-12-17 16:12:41 -08001021 sorted := make([]*moduleGroup, 0, len(c.moduleGroups))
Colin Cross573a2fd2014-12-17 14:16:51 -08001022
Colin Crossbbfa51a2014-12-17 16:12:41 -08001023 var check func(group *moduleGroup) []*moduleGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001024
Colin Crossbbfa51a2014-12-17 16:12:41 -08001025 check = func(group *moduleGroup) []*moduleGroup {
1026 visited[group] = true
1027 checking[group] = true
1028 defer delete(checking, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001029
Colin Crossbbfa51a2014-12-17 16:12:41 -08001030 deps := make(map[*moduleGroup]bool)
1031 for _, module := range group.modules {
1032 for _, dep := range module.directDeps {
1033 deps[dep.group] = true
1034 }
1035 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001036
Colin Cross691a60d2015-01-07 18:08:56 -08001037 group.reverseDeps = []*moduleGroup{}
1038 group.depsCount = len(deps)
1039
Colin Crossbbfa51a2014-12-17 16:12:41 -08001040 for dep := range deps {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001041 if checking[dep] {
1042 // This is a cycle.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001043 return []*moduleGroup{dep, group}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001044 }
1045
1046 if !visited[dep] {
1047 cycle := check(dep)
1048 if cycle != nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001049 if cycle[0] == group {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001050 // We are the "start" of the cycle, so we're responsible
1051 // for generating the errors. The cycle list is in
1052 // reverse order because all the 'check' calls append
1053 // their own module to the list.
1054 errs = append(errs, &Error{
1055 Err: fmt.Errorf("encountered dependency cycle:"),
Colin Crossbbfa51a2014-12-17 16:12:41 -08001056 Pos: group.pos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001057 })
1058
1059 // Iterate backwards through the cycle list.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001060 curGroup := group
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001061 for i := len(cycle) - 1; i >= 0; i-- {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001062 nextGroup := cycle[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001063 errs = append(errs, &Error{
1064 Err: fmt.Errorf(" %q depends on %q",
Colin Crossbbfa51a2014-12-17 16:12:41 -08001065 curGroup.properties.Name,
1066 nextGroup.properties.Name),
1067 Pos: curGroup.propertyPos["deps"],
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001068 })
Colin Crossbbfa51a2014-12-17 16:12:41 -08001069 curGroup = nextGroup
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001070 }
1071
1072 // We can continue processing this module's children to
1073 // find more cycles. Since all the modules that were
1074 // part of the found cycle were marked as visited we
1075 // won't run into that cycle again.
1076 } else {
1077 // We're not the "start" of the cycle, so we just append
1078 // our module to the list and return it.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001079 return append(cycle, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001080 }
1081 }
1082 }
Colin Cross691a60d2015-01-07 18:08:56 -08001083
1084 dep.reverseDeps = append(dep.reverseDeps, group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001085 }
1086
Colin Crossbbfa51a2014-12-17 16:12:41 -08001087 sorted = append(sorted, group)
Colin Cross573a2fd2014-12-17 14:16:51 -08001088
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001089 return nil
1090 }
1091
Colin Crossbbfa51a2014-12-17 16:12:41 -08001092 for _, group := range c.moduleGroups {
1093 if !visited[group] {
1094 cycle := check(group)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001095 if cycle != nil {
1096 panic("inconceivable!")
1097 }
1098 }
1099 }
1100
Colin Crossbbfa51a2014-12-17 16:12:41 -08001101 c.moduleGroupsSorted = sorted
Colin Cross573a2fd2014-12-17 14:16:51 -08001102
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001103 return
1104}
1105
Jamie Gennisd4e10182014-06-12 20:06:50 -07001106// PrepareBuildActions generates an internal representation of all the build
1107// actions that need to be performed. This process involves invoking the
1108// GenerateBuildActions method on each of the Module objects created during the
1109// parse phase and then on each of the registered Singleton objects.
1110//
1111// If the ResolveDependencies method has not already been called it is called
1112// automatically by this method.
1113//
1114// The config argument is made available to all of the Module and Singleton
1115// objects via the Config method on the ModuleContext and SingletonContext
1116// objects passed to GenerateBuildActions. It is also passed to the functions
1117// specified via PoolFunc, RuleFunc, and VariableFunc so that they can compute
1118// config-specific values.
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001119//
1120// The returned deps is a list of the ninja files dependencies that were added
1121// by the modules and singletons via the ModuleContext.AddNinjaFileDeps() and
1122// SingletonContext.AddNinjaFileDeps() methods.
1123func (c *Context) PrepareBuildActions(config interface{}) (deps []string, errs []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001124 c.buildActionsReady = false
1125
1126 if !c.dependenciesReady {
Jamie Gennisb9e87f62014-09-24 20:28:11 -07001127 errs := c.ResolveDependencies(config)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001128 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001129 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001130 }
1131 }
1132
Colin Crossc9028482014-12-18 16:28:54 -08001133 errs = c.runMutators(config)
1134 if len(errs) > 0 {
1135 return nil, errs
1136 }
1137
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001138 liveGlobals := newLiveTracker(config)
1139
1140 c.initSpecialVariables()
1141
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001142 depsModules, errs := c.generateModuleBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001143 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001144 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001145 }
1146
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001147 depsSingletons, errs := c.generateSingletonBuildActions(config, liveGlobals)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001148 if len(errs) > 0 {
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001149 return nil, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001150 }
1151
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001152 deps = append(depsModules, depsSingletons...)
1153
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001154 if c.buildDir != nil {
1155 liveGlobals.addNinjaStringDeps(c.buildDir)
1156 }
1157
1158 pkgNames := c.makeUniquePackageNames(liveGlobals)
1159
1160 // This will panic if it finds a problem since it's a programming error.
1161 c.checkForVariableReferenceCycles(liveGlobals.variables, pkgNames)
1162
1163 c.pkgNames = pkgNames
1164 c.globalVariables = liveGlobals.variables
1165 c.globalPools = liveGlobals.pools
1166 c.globalRules = liveGlobals.rules
1167
1168 c.buildActionsReady = true
1169
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001170 return deps, nil
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001171}
1172
Colin Crossc9028482014-12-18 16:28:54 -08001173func (c *Context) runMutators(config interface{}) (errs []error) {
1174 for _, mutator := range c.mutatorInfo {
1175 if mutator.topDownMutator != nil {
1176 errs = c.runTopDownMutator(config, mutator.name, mutator.topDownMutator)
1177 } else if mutator.bottomUpMutator != nil {
1178 errs = c.runBottomUpMutator(config, mutator.name, mutator.bottomUpMutator)
1179 } else {
1180 panic("no mutator set on " + mutator.name)
1181 }
1182 if len(errs) > 0 {
1183 return errs
1184 }
1185 }
1186
1187 return nil
1188}
1189
1190func (c *Context) runTopDownMutator(config interface{},
1191 name string, mutator TopDownMutator) (errs []error) {
1192
1193 for i := 0; i < len(c.moduleGroupsSorted); i++ {
1194 group := c.moduleGroupsSorted[len(c.moduleGroupsSorted)-1-i]
1195 for _, module := range group.modules {
1196 mctx := &mutatorContext{
1197 baseModuleContext: baseModuleContext{
1198 context: c,
1199 config: config,
1200 group: group,
1201 },
1202 module: module,
1203 name: name,
1204 }
1205
1206 mutator(mctx)
1207 if len(mctx.errs) > 0 {
1208 errs = append(errs, mctx.errs...)
1209 return errs
1210 }
1211 }
1212 }
1213
1214 return errs
1215}
1216
1217func (c *Context) runBottomUpMutator(config interface{},
1218 name string, mutator BottomUpMutator) (errs []error) {
1219
1220 dependenciesModified := false
1221
1222 for _, group := range c.moduleGroupsSorted {
1223 newModules := make([]*moduleInfo, 0, len(group.modules))
1224
1225 for _, module := range group.modules {
1226 mctx := &mutatorContext{
1227 baseModuleContext: baseModuleContext{
1228 context: c,
1229 config: config,
1230 group: group,
1231 },
1232 module: module,
1233 name: name,
1234 }
1235
1236 mutator(mctx)
1237 if len(mctx.errs) > 0 {
1238 errs = append(errs, mctx.errs...)
1239 return errs
1240 }
1241
1242 // Fix up any remaining dependencies on modules that were split into variants
1243 // by replacing them with the first variant
1244 for i, dep := range module.directDeps {
1245 if dep.logicModule == nil {
1246 module.directDeps[i] = dep.splitModules[0]
1247 }
1248 }
1249
1250 if mctx.dependenciesModified {
1251 dependenciesModified = true
1252 }
1253
1254 if module.splitModules != nil {
1255 newModules = append(newModules, module.splitModules...)
1256 } else {
1257 newModules = append(newModules, module)
1258 }
1259 }
1260
1261 group.modules = newModules
1262 }
1263
1264 if dependenciesModified {
Colin Cross691a60d2015-01-07 18:08:56 -08001265 errs = c.updateDependencies()
Colin Crossc9028482014-12-18 16:28:54 -08001266 if len(errs) > 0 {
1267 return errs
1268 }
1269 }
1270
1271 return errs
1272}
1273
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001274func (c *Context) initSpecialVariables() {
1275 c.buildDir = nil
1276 c.requiredNinjaMajor = 1
1277 c.requiredNinjaMinor = 1
1278 c.requiredNinjaMicro = 0
1279}
1280
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001281func (c *Context) generateModuleBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001282 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001283
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001284 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001285 var errs []error
1286
Colin Cross691a60d2015-01-07 18:08:56 -08001287 cancelCh := make(chan struct{})
1288 errsCh := make(chan []error)
1289 depsCh := make(chan []string)
1290
1291 go func() {
1292 for {
1293 select {
1294 case <-cancelCh:
1295 close(cancelCh)
1296 return
1297 case newErrs := <-errsCh:
1298 errs = append(errs, newErrs...)
1299 case newDeps := <-depsCh:
1300 deps = append(deps, newDeps...)
1301
1302 }
1303 }
1304 }()
1305
1306 c.parallelVisitAllBottomUp(func(group *moduleGroup) {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001307 // The parent scope of the moduleContext's local scope gets overridden to be that of the
1308 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1309 // just set it to nil.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001310 scope := newLocalScope(nil, moduleNamespacePrefix(group.properties.Name))
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001311
Colin Crossbbfa51a2014-12-17 16:12:41 -08001312 for _, module := range group.modules {
1313 mctx := &moduleContext{
Colin Cross1455a0f2014-12-17 13:23:56 -08001314 baseModuleContext: baseModuleContext{
1315 context: c,
1316 config: config,
1317 group: group,
Colin Crossb2e7b5d2014-11-11 14:18:53 -08001318 },
Colin Cross1455a0f2014-12-17 13:23:56 -08001319 module: module,
1320 scope: scope,
Colin Crossbbfa51a2014-12-17 16:12:41 -08001321 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001322
Colin Crossbbfa51a2014-12-17 16:12:41 -08001323 mctx.module.logicModule.GenerateBuildActions(mctx)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001324
Colin Crossbbfa51a2014-12-17 16:12:41 -08001325 if len(mctx.errs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001326 errsCh <- mctx.errs
Colin Crossbbfa51a2014-12-17 16:12:41 -08001327 break
1328 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001329
Colin Cross691a60d2015-01-07 18:08:56 -08001330 depsCh <- mctx.ninjaFileDeps
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001331
Colin Crossbbfa51a2014-12-17 16:12:41 -08001332 newErrs := c.processLocalBuildActions(&group.actionDefs,
1333 &mctx.actionDefs, liveGlobals)
1334 if len(newErrs) > 0 {
Colin Cross691a60d2015-01-07 18:08:56 -08001335 errsCh <- newErrs
Colin Crossbbfa51a2014-12-17 16:12:41 -08001336 break
1337 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001338 }
Colin Cross691a60d2015-01-07 18:08:56 -08001339 })
1340
1341 cancelCh <- struct{}{}
1342 <-cancelCh
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001343
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001344 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001345}
1346
Jamie Gennis6eb4d242014-06-11 18:31:16 -07001347func (c *Context) generateSingletonBuildActions(config interface{},
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001348 liveGlobals *liveTracker) ([]string, []error) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001349
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001350 var deps []string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001351 var errs []error
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001352
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001353 for name, info := range c.singletonInfo {
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001354 // The parent scope of the singletonContext's local scope gets overridden to be that of the
1355 // calling Go package on a per-call basis. Since the initial parent scope doesn't matter we
1356 // just set it to nil.
1357 scope := newLocalScope(nil, singletonNamespacePrefix(name))
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001358
1359 sctx := &singletonContext{
1360 context: c,
1361 config: config,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07001362 scope: scope,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001363 }
1364
1365 info.singleton.GenerateBuildActions(sctx)
1366
1367 if len(sctx.errs) > 0 {
1368 errs = append(errs, sctx.errs...)
1369 if len(errs) > maxErrors {
1370 break
1371 }
1372 continue
1373 }
1374
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001375 deps = append(deps, sctx.ninjaFileDeps...)
1376
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001377 newErrs := c.processLocalBuildActions(&info.actionDefs,
1378 &sctx.actionDefs, liveGlobals)
1379 errs = append(errs, newErrs...)
1380 if len(errs) > maxErrors {
1381 break
1382 }
1383 }
1384
Mathias Agopian5b8477d2014-06-25 17:21:54 -07001385 return deps, errs
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001386}
1387
1388func (c *Context) processLocalBuildActions(out, in *localBuildActions,
1389 liveGlobals *liveTracker) []error {
1390
1391 var errs []error
1392
1393 // First we go through and add everything referenced by the module's
1394 // buildDefs to the live globals set. This will end up adding the live
1395 // locals to the set as well, but we'll take them out after.
1396 for _, def := range in.buildDefs {
1397 err := liveGlobals.AddBuildDefDeps(def)
1398 if err != nil {
1399 errs = append(errs, err)
1400 }
1401 }
1402
1403 if len(errs) > 0 {
1404 return errs
1405 }
1406
Colin Crossc9028482014-12-18 16:28:54 -08001407 out.buildDefs = append(out.buildDefs, in.buildDefs...)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001408
1409 // We use the now-incorrect set of live "globals" to determine which local
1410 // definitions are live. As we go through copying those live locals to the
Colin Crossc9028482014-12-18 16:28:54 -08001411 // moduleGroup we remove them from the live globals set.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001412 for _, v := range in.variables {
1413 _, isLive := liveGlobals.variables[v]
1414 if isLive {
1415 out.variables = append(out.variables, v)
1416 delete(liveGlobals.variables, v)
1417 }
1418 }
1419
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001420 for _, r := range in.rules {
1421 _, isLive := liveGlobals.rules[r]
1422 if isLive {
1423 out.rules = append(out.rules, r)
1424 delete(liveGlobals.rules, r)
1425 }
1426 }
1427
1428 return nil
1429}
1430
Colin Crossbbfa51a2014-12-17 16:12:41 -08001431func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
1432 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001433
Colin Crossbbfa51a2014-12-17 16:12:41 -08001434 var walk func(module *moduleInfo)
1435 walk = func(module *moduleInfo) {
1436 visited[module] = true
1437 for _, moduleDep := range module.directDeps {
1438 if !visited[moduleDep] {
1439 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001440 }
1441 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001442
Colin Crossbbfa51a2014-12-17 16:12:41 -08001443 if module != topModule {
1444 visit(module.logicModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001445 }
1446 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001447
1448 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001449}
1450
Colin Crossbbfa51a2014-12-17 16:12:41 -08001451func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module) bool,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001452 visit func(Module)) {
1453
Colin Crossbbfa51a2014-12-17 16:12:41 -08001454 visited := make(map[*moduleInfo]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001455
Colin Crossbbfa51a2014-12-17 16:12:41 -08001456 var walk func(module *moduleInfo)
1457 walk = func(module *moduleInfo) {
1458 visited[module] = true
1459 for _, moduleDep := range module.directDeps {
1460 if !visited[moduleDep] {
1461 walk(moduleDep)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001462 }
Jamie Gennis0bb5d8a2014-11-26 14:45:37 -08001463 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08001464
1465 if module != topModule {
1466 if pred(module.logicModule) {
1467 visit(module.logicModule)
1468 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001469 }
1470 }
1471
Colin Crossbbfa51a2014-12-17 16:12:41 -08001472 walk(topModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001473}
1474
Colin Crossc9028482014-12-18 16:28:54 -08001475func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
1476 for _, dep := range module.directDeps {
1477 visit(dep.logicModule)
1478 }
1479}
1480
1481func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
1482 visit func(Module)) {
1483
1484 for _, dep := range module.directDeps {
1485 if pred(dep.logicModule) {
1486 visit(dep.logicModule)
1487 }
1488 }
1489}
1490
Jamie Gennisc15544d2014-09-24 20:26:52 -07001491func (c *Context) sortedModuleNames() []string {
1492 if c.cachedSortedModuleNames == nil {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001493 c.cachedSortedModuleNames = make([]string, 0, len(c.moduleGroups))
1494 for moduleName := range c.moduleGroups {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001495 c.cachedSortedModuleNames = append(c.cachedSortedModuleNames,
1496 moduleName)
1497 }
1498 sort.Strings(c.cachedSortedModuleNames)
1499 }
1500
1501 return c.cachedSortedModuleNames
1502}
1503
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001504func (c *Context) visitAllModules(visit func(Module)) {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001505 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001506 group := c.moduleGroups[moduleName]
1507 for _, module := range group.modules {
1508 visit(module.logicModule)
1509 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001510 }
1511}
1512
1513func (c *Context) visitAllModulesIf(pred func(Module) bool,
1514 visit func(Module)) {
1515
Jamie Gennisc15544d2014-09-24 20:26:52 -07001516 for _, moduleName := range c.sortedModuleNames() {
Colin Crossbbfa51a2014-12-17 16:12:41 -08001517 group := c.moduleGroups[moduleName]
1518 for _, module := range group.modules {
1519 if pred(module.logicModule) {
1520 visit(module.logicModule)
1521 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001522 }
1523 }
1524}
1525
1526func (c *Context) requireNinjaVersion(major, minor, micro int) {
1527 if major != 1 {
1528 panic("ninja version with major version != 1 not supported")
1529 }
1530 if c.requiredNinjaMinor < minor {
1531 c.requiredNinjaMinor = minor
1532 c.requiredNinjaMicro = micro
1533 }
1534 if c.requiredNinjaMinor == minor && c.requiredNinjaMicro < micro {
1535 c.requiredNinjaMicro = micro
1536 }
1537}
1538
1539func (c *Context) setBuildDir(value *ninjaString) {
1540 if c.buildDir != nil {
1541 panic("buildDir set multiple times")
1542 }
1543 c.buildDir = value
1544}
1545
1546func (c *Context) makeUniquePackageNames(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001547 liveGlobals *liveTracker) map[*PackageContext]string {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001548
Jamie Gennis2fb20952014-10-03 02:49:58 -07001549 pkgs := make(map[string]*PackageContext)
1550 pkgNames := make(map[*PackageContext]string)
1551 longPkgNames := make(map[*PackageContext]bool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001552
Jamie Gennis2fb20952014-10-03 02:49:58 -07001553 processPackage := func(pctx *PackageContext) {
1554 if pctx == nil {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001555 // This is a built-in rule and has no package.
1556 return
1557 }
Jamie Gennis2fb20952014-10-03 02:49:58 -07001558 if _, ok := pkgNames[pctx]; ok {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001559 // We've already processed this package.
1560 return
1561 }
1562
Jamie Gennis2fb20952014-10-03 02:49:58 -07001563 otherPkg, present := pkgs[pctx.shortName]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001564 if present {
1565 // Short name collision. Both this package and the one that's
1566 // already there need to use their full names. We leave the short
1567 // name in pkgNames for now so future collisions still get caught.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001568 longPkgNames[pctx] = true
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001569 longPkgNames[otherPkg] = true
1570 } else {
1571 // No collision so far. Tentatively set the package's name to be
1572 // its short name.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001573 pkgNames[pctx] = pctx.shortName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001574 }
1575 }
1576
1577 // We try to give all packages their short name, but when we get collisions
1578 // we need to use the full unique package name.
1579 for v, _ := range liveGlobals.variables {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001580 processPackage(v.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001581 }
1582 for p, _ := range liveGlobals.pools {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001583 processPackage(p.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001584 }
1585 for r, _ := range liveGlobals.rules {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001586 processPackage(r.packageContext())
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001587 }
1588
1589 // Add the packages that had collisions using their full unique names. This
1590 // will overwrite any short names that were added in the previous step.
Jamie Gennis2fb20952014-10-03 02:49:58 -07001591 for pctx := range longPkgNames {
1592 pkgNames[pctx] = pctx.fullName
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001593 }
1594
1595 return pkgNames
1596}
1597
1598func (c *Context) checkForVariableReferenceCycles(
Jamie Gennis2fb20952014-10-03 02:49:58 -07001599 variables map[Variable]*ninjaString, pkgNames map[*PackageContext]string) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001600
1601 visited := make(map[Variable]bool) // variables that were already checked
1602 checking := make(map[Variable]bool) // variables actively being checked
1603
1604 var check func(v Variable) []Variable
1605
1606 check = func(v Variable) []Variable {
1607 visited[v] = true
1608 checking[v] = true
1609 defer delete(checking, v)
1610
1611 value := variables[v]
1612 for _, dep := range value.variables {
1613 if checking[dep] {
1614 // This is a cycle.
1615 return []Variable{dep, v}
1616 }
1617
1618 if !visited[dep] {
1619 cycle := check(dep)
1620 if cycle != nil {
1621 if cycle[0] == v {
1622 // We are the "start" of the cycle, so we're responsible
1623 // for generating the errors. The cycle list is in
1624 // reverse order because all the 'check' calls append
1625 // their own module to the list.
1626 msgs := []string{"detected variable reference cycle:"}
1627
1628 // Iterate backwards through the cycle list.
1629 curName := v.fullName(pkgNames)
1630 curValue := value.Value(pkgNames)
1631 for i := len(cycle) - 1; i >= 0; i-- {
1632 next := cycle[i]
1633 nextName := next.fullName(pkgNames)
1634 nextValue := variables[next].Value(pkgNames)
1635
1636 msgs = append(msgs, fmt.Sprintf(
1637 " %q depends on %q", curName, nextName))
1638 msgs = append(msgs, fmt.Sprintf(
1639 " [%s = %s]", curName, curValue))
1640
1641 curName = nextName
1642 curValue = nextValue
1643 }
1644
1645 // Variable reference cycles are a programming error,
1646 // not the fault of the Blueprint file authors.
1647 panic(strings.Join(msgs, "\n"))
1648 } else {
1649 // We're not the "start" of the cycle, so we just append
1650 // our module to the list and return it.
1651 return append(cycle, v)
1652 }
1653 }
1654 }
1655 }
1656
1657 return nil
1658 }
1659
1660 for v := range variables {
1661 if !visited[v] {
1662 cycle := check(v)
1663 if cycle != nil {
1664 panic("inconceivable!")
1665 }
1666 }
1667 }
1668}
1669
Jamie Gennisaf435562014-10-27 22:34:56 -07001670// AllTargets returns a map all the build target names to the rule used to build
1671// them. This is the same information that is output by running 'ninja -t
1672// targets all'. If this is called before PrepareBuildActions successfully
1673// completes then ErrbuildActionsNotReady is returned.
1674func (c *Context) AllTargets() (map[string]string, error) {
1675 if !c.buildActionsReady {
1676 return nil, ErrBuildActionsNotReady
1677 }
1678
1679 targets := map[string]string{}
1680
1681 // Collect all the module build targets.
Colin Crossbbfa51a2014-12-17 16:12:41 -08001682 for _, info := range c.moduleGroups {
Jamie Gennisaf435562014-10-27 22:34:56 -07001683 for _, buildDef := range info.actionDefs.buildDefs {
1684 ruleName := buildDef.Rule.fullName(c.pkgNames)
1685 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001686 outputValue, err := output.Eval(c.globalVariables)
1687 if err != nil {
1688 return nil, err
1689 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001690 targets[outputValue] = ruleName
1691 }
1692 }
1693 }
1694
1695 // Collect all the singleton build targets.
1696 for _, info := range c.singletonInfo {
1697 for _, buildDef := range info.actionDefs.buildDefs {
1698 ruleName := buildDef.Rule.fullName(c.pkgNames)
1699 for _, output := range buildDef.Outputs {
Christian Zander6e2b2322014-11-21 15:12:08 -08001700 outputValue, err := output.Eval(c.globalVariables)
1701 if err != nil {
Colin Crossfea2b752014-12-30 16:05:02 -08001702 return nil, err
Christian Zander6e2b2322014-11-21 15:12:08 -08001703 }
Jamie Gennisaf435562014-10-27 22:34:56 -07001704 targets[outputValue] = ruleName
1705 }
1706 }
1707 }
1708
1709 return targets, nil
1710}
1711
Jamie Gennisd4e10182014-06-12 20:06:50 -07001712// WriteBuildFile writes the Ninja manifeset text for the generated build
1713// actions to w. If this is called before PrepareBuildActions successfully
1714// completes then ErrBuildActionsNotReady is returned.
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001715func (c *Context) WriteBuildFile(w io.Writer) error {
1716 if !c.buildActionsReady {
1717 return ErrBuildActionsNotReady
1718 }
1719
1720 nw := newNinjaWriter(w)
1721
1722 err := c.writeBuildFileHeader(nw)
1723 if err != nil {
1724 return err
1725 }
1726
1727 err = c.writeNinjaRequiredVersion(nw)
1728 if err != nil {
1729 return err
1730 }
1731
1732 // TODO: Group the globals by package.
1733
1734 err = c.writeGlobalVariables(nw)
1735 if err != nil {
1736 return err
1737 }
1738
1739 err = c.writeGlobalPools(nw)
1740 if err != nil {
1741 return err
1742 }
1743
1744 err = c.writeBuildDir(nw)
1745 if err != nil {
1746 return err
1747 }
1748
1749 err = c.writeGlobalRules(nw)
1750 if err != nil {
1751 return err
1752 }
1753
1754 err = c.writeAllModuleActions(nw)
1755 if err != nil {
1756 return err
1757 }
1758
1759 err = c.writeAllSingletonActions(nw)
1760 if err != nil {
1761 return err
1762 }
1763
1764 return nil
1765}
1766
Jamie Gennisc15544d2014-09-24 20:26:52 -07001767type pkgAssociation struct {
1768 PkgName string
1769 PkgPath string
1770}
1771
1772type pkgAssociationSorter struct {
1773 pkgs []pkgAssociation
1774}
1775
1776func (s *pkgAssociationSorter) Len() int {
1777 return len(s.pkgs)
1778}
1779
1780func (s *pkgAssociationSorter) Less(i, j int) bool {
1781 iName := s.pkgs[i].PkgName
1782 jName := s.pkgs[j].PkgName
1783 return iName < jName
1784}
1785
1786func (s *pkgAssociationSorter) Swap(i, j int) {
1787 s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i]
1788}
1789
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001790func (c *Context) writeBuildFileHeader(nw *ninjaWriter) error {
1791 headerTemplate := template.New("fileHeader")
1792 _, err := headerTemplate.Parse(fileHeaderTemplate)
1793 if err != nil {
1794 // This is a programming error.
1795 panic(err)
1796 }
1797
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001798 var pkgs []pkgAssociation
1799 maxNameLen := 0
1800 for pkg, name := range c.pkgNames {
1801 pkgs = append(pkgs, pkgAssociation{
1802 PkgName: name,
1803 PkgPath: pkg.pkgPath,
1804 })
1805 if len(name) > maxNameLen {
1806 maxNameLen = len(name)
1807 }
1808 }
1809
1810 for i := range pkgs {
1811 pkgs[i].PkgName += strings.Repeat(" ", maxNameLen-len(pkgs[i].PkgName))
1812 }
1813
Jamie Gennisc15544d2014-09-24 20:26:52 -07001814 sort.Sort(&pkgAssociationSorter{pkgs})
1815
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001816 params := map[string]interface{}{
1817 "Pkgs": pkgs,
1818 }
1819
1820 buf := bytes.NewBuffer(nil)
1821 err = headerTemplate.Execute(buf, params)
1822 if err != nil {
1823 return err
1824 }
1825
1826 return nw.Comment(buf.String())
1827}
1828
1829func (c *Context) writeNinjaRequiredVersion(nw *ninjaWriter) error {
1830 value := fmt.Sprintf("%d.%d.%d", c.requiredNinjaMajor, c.requiredNinjaMinor,
1831 c.requiredNinjaMicro)
1832
1833 err := nw.Assign("ninja_required_version", value)
1834 if err != nil {
1835 return err
1836 }
1837
1838 return nw.BlankLine()
1839}
1840
1841func (c *Context) writeBuildDir(nw *ninjaWriter) error {
1842 if c.buildDir != nil {
1843 err := nw.Assign("builddir", c.buildDir.Value(c.pkgNames))
1844 if err != nil {
1845 return err
1846 }
1847
1848 err = nw.BlankLine()
1849 if err != nil {
1850 return err
1851 }
1852 }
1853 return nil
1854}
1855
Jamie Gennisc15544d2014-09-24 20:26:52 -07001856type globalEntity interface {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001857 fullName(pkgNames map[*PackageContext]string) string
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001858}
1859
Jamie Gennisc15544d2014-09-24 20:26:52 -07001860type globalEntitySorter struct {
Jamie Gennis2fb20952014-10-03 02:49:58 -07001861 pkgNames map[*PackageContext]string
Jamie Gennisc15544d2014-09-24 20:26:52 -07001862 entities []globalEntity
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001863}
1864
Jamie Gennisc15544d2014-09-24 20:26:52 -07001865func (s *globalEntitySorter) Len() int {
1866 return len(s.entities)
1867}
1868
1869func (s *globalEntitySorter) Less(i, j int) bool {
1870 iName := s.entities[i].fullName(s.pkgNames)
1871 jName := s.entities[j].fullName(s.pkgNames)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001872 return iName < jName
1873}
1874
Jamie Gennisc15544d2014-09-24 20:26:52 -07001875func (s *globalEntitySorter) Swap(i, j int) {
1876 s.entities[i], s.entities[j] = s.entities[j], s.entities[i]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001877}
1878
1879func (c *Context) writeGlobalVariables(nw *ninjaWriter) error {
1880 visited := make(map[Variable]bool)
1881
1882 var walk func(v Variable) error
1883 walk = func(v Variable) error {
1884 visited[v] = true
1885
1886 // First visit variables on which this variable depends.
1887 value := c.globalVariables[v]
1888 for _, dep := range value.variables {
1889 if !visited[dep] {
1890 err := walk(dep)
1891 if err != nil {
1892 return err
1893 }
1894 }
1895 }
1896
1897 err := nw.Assign(v.fullName(c.pkgNames), value.Value(c.pkgNames))
1898 if err != nil {
1899 return err
1900 }
1901
1902 err = nw.BlankLine()
1903 if err != nil {
1904 return err
1905 }
1906
1907 return nil
1908 }
1909
Jamie Gennisc15544d2014-09-24 20:26:52 -07001910 globalVariables := make([]globalEntity, 0, len(c.globalVariables))
1911 for variable := range c.globalVariables {
1912 globalVariables = append(globalVariables, variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001913 }
1914
Jamie Gennisc15544d2014-09-24 20:26:52 -07001915 sort.Sort(&globalEntitySorter{c.pkgNames, globalVariables})
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001916
Jamie Gennisc15544d2014-09-24 20:26:52 -07001917 for _, entity := range globalVariables {
1918 v := entity.(Variable)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001919 if !visited[v] {
1920 err := walk(v)
1921 if err != nil {
1922 return nil
1923 }
1924 }
1925 }
1926
1927 return nil
1928}
1929
1930func (c *Context) writeGlobalPools(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001931 globalPools := make([]globalEntity, 0, len(c.globalPools))
1932 for pool := range c.globalPools {
1933 globalPools = append(globalPools, pool)
1934 }
1935
1936 sort.Sort(&globalEntitySorter{c.pkgNames, globalPools})
1937
1938 for _, entity := range globalPools {
1939 pool := entity.(Pool)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001940 name := pool.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001941 def := c.globalPools[pool]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001942 err := def.WriteTo(nw, name)
1943 if err != nil {
1944 return err
1945 }
1946
1947 err = nw.BlankLine()
1948 if err != nil {
1949 return err
1950 }
1951 }
1952
1953 return nil
1954}
1955
1956func (c *Context) writeGlobalRules(nw *ninjaWriter) error {
Jamie Gennisc15544d2014-09-24 20:26:52 -07001957 globalRules := make([]globalEntity, 0, len(c.globalRules))
1958 for rule := range c.globalRules {
1959 globalRules = append(globalRules, rule)
1960 }
1961
1962 sort.Sort(&globalEntitySorter{c.pkgNames, globalRules})
1963
1964 for _, entity := range globalRules {
1965 rule := entity.(Rule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001966 name := rule.fullName(c.pkgNames)
Jamie Gennisc15544d2014-09-24 20:26:52 -07001967 def := c.globalRules[rule]
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001968 err := def.WriteTo(nw, name, c.pkgNames)
1969 if err != nil {
1970 return err
1971 }
1972
1973 err = nw.BlankLine()
1974 if err != nil {
1975 return err
1976 }
1977 }
1978
1979 return nil
1980}
1981
Colin Crossbbfa51a2014-12-17 16:12:41 -08001982type moduleGroupSorter []*moduleGroup
Jamie Gennis86179fe2014-06-11 16:27:16 -07001983
Colin Crossbbfa51a2014-12-17 16:12:41 -08001984func (s moduleGroupSorter) Len() int {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001985 return len(s)
1986}
1987
Colin Crossbbfa51a2014-12-17 16:12:41 -08001988func (s moduleGroupSorter) Less(i, j int) bool {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001989 iName := s[i].properties.Name
1990 jName := s[j].properties.Name
1991 return iName < jName
1992}
1993
Colin Crossbbfa51a2014-12-17 16:12:41 -08001994func (s moduleGroupSorter) Swap(i, j int) {
Jamie Gennis86179fe2014-06-11 16:27:16 -07001995 s[i], s[j] = s[j], s[i]
1996}
1997
Jamie Gennis1bc967e2014-05-27 16:34:41 -07001998func (c *Context) writeAllModuleActions(nw *ninjaWriter) error {
1999 headerTemplate := template.New("moduleHeader")
2000 _, err := headerTemplate.Parse(moduleHeaderTemplate)
2001 if err != nil {
2002 // This is a programming error.
2003 panic(err)
2004 }
2005
Colin Crossbbfa51a2014-12-17 16:12:41 -08002006 infos := make([]*moduleGroup, 0, len(c.moduleGroups))
2007 for _, info := range c.moduleGroups {
Jamie Gennis86179fe2014-06-11 16:27:16 -07002008 infos = append(infos, info)
2009 }
Colin Crossbbfa51a2014-12-17 16:12:41 -08002010 sort.Sort(moduleGroupSorter(infos))
Jamie Gennis86179fe2014-06-11 16:27:16 -07002011
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002012 buf := bytes.NewBuffer(nil)
2013
Jamie Gennis86179fe2014-06-11 16:27:16 -07002014 for _, info := range infos {
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002015 buf.Reset()
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002016
2017 // In order to make the bootstrap build manifest independent of the
2018 // build dir we need to output the Blueprints file locations in the
2019 // comments as paths relative to the source directory.
2020 relPos := info.pos
Jamie Gennisec701282014-06-12 20:06:31 -07002021 relPos.Filename = info.relBlueprintsFile
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002022
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002023 // Get the name and location of the factory function for the module.
2024 factory := c.moduleFactories[info.typeName]
2025 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2026 factoryName := factoryFunc.Name()
2027
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002028 infoMap := map[string]interface{}{
2029 "properties": info.properties,
2030 "typeName": info.typeName,
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002031 "goFactory": factoryName,
Jamie Gennis1ebd3b82014-06-04 15:33:08 -07002032 "pos": relPos,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002033 }
2034 err = headerTemplate.Execute(buf, infoMap)
2035 if err != nil {
2036 return err
2037 }
2038
2039 err = nw.Comment(buf.String())
2040 if err != nil {
2041 return err
2042 }
2043
2044 err = nw.BlankLine()
2045 if err != nil {
2046 return err
2047 }
2048
2049 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2050 if err != nil {
2051 return err
2052 }
2053
2054 err = nw.BlankLine()
2055 if err != nil {
2056 return err
2057 }
2058 }
2059
2060 return nil
2061}
2062
2063func (c *Context) writeAllSingletonActions(nw *ninjaWriter) error {
2064 headerTemplate := template.New("singletonHeader")
2065 _, err := headerTemplate.Parse(singletonHeaderTemplate)
2066 if err != nil {
2067 // This is a programming error.
2068 panic(err)
2069 }
2070
2071 buf := bytes.NewBuffer(nil)
2072
Jamie Gennis86179fe2014-06-11 16:27:16 -07002073 singletonNames := make([]string, 0, len(c.singletonInfo))
2074 for name := range c.singletonInfo {
2075 singletonNames = append(singletonNames, name)
2076 }
2077 sort.Strings(singletonNames)
2078
2079 for _, name := range singletonNames {
2080 info := c.singletonInfo[name]
2081
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002082 // Get the name of the factory function for the module.
2083 factory := info.factory
2084 factoryFunc := runtime.FuncForPC(reflect.ValueOf(factory).Pointer())
2085 factoryName := factoryFunc.Name()
2086
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002087 buf.Reset()
2088 infoMap := map[string]interface{}{
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002089 "name": name,
2090 "goFactory": factoryName,
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002091 }
2092 err = headerTemplate.Execute(buf, infoMap)
2093 if err != nil {
2094 return err
2095 }
2096
2097 err = nw.Comment(buf.String())
2098 if err != nil {
2099 return err
2100 }
2101
2102 err = nw.BlankLine()
2103 if err != nil {
2104 return err
2105 }
2106
2107 err = c.writeLocalBuildActions(nw, &info.actionDefs)
2108 if err != nil {
2109 return err
2110 }
2111
2112 err = nw.BlankLine()
2113 if err != nil {
2114 return err
2115 }
2116 }
2117
2118 return nil
2119}
2120
2121func (c *Context) writeLocalBuildActions(nw *ninjaWriter,
2122 defs *localBuildActions) error {
2123
2124 // Write the local variable assignments.
2125 for _, v := range defs.variables {
2126 // A localVariable doesn't need the package names or config to
2127 // determine its name or value.
2128 name := v.fullName(nil)
2129 value, err := v.value(nil)
2130 if err != nil {
2131 panic(err)
2132 }
2133 err = nw.Assign(name, value.Value(c.pkgNames))
2134 if err != nil {
2135 return err
2136 }
2137 }
2138
2139 if len(defs.variables) > 0 {
2140 err := nw.BlankLine()
2141 if err != nil {
2142 return err
2143 }
2144 }
2145
2146 // Write the local rules.
2147 for _, r := range defs.rules {
2148 // A localRule doesn't need the package names or config to determine
2149 // its name or definition.
2150 name := r.fullName(nil)
2151 def, err := r.def(nil)
2152 if err != nil {
2153 panic(err)
2154 }
2155
2156 err = def.WriteTo(nw, name, c.pkgNames)
2157 if err != nil {
2158 return err
2159 }
2160
2161 err = nw.BlankLine()
2162 if err != nil {
2163 return err
2164 }
2165 }
2166
2167 // Write the build definitions.
2168 for _, buildDef := range defs.buildDefs {
2169 err := buildDef.WriteTo(nw, c.pkgNames)
2170 if err != nil {
2171 return err
2172 }
2173
2174 if len(buildDef.Args) > 0 {
2175 err = nw.BlankLine()
2176 if err != nil {
2177 return err
2178 }
2179 }
2180 }
2181
2182 return nil
2183}
2184
2185var fileHeaderTemplate = `******************************************************************************
2186*** This file is generated and should not be edited ***
2187******************************************************************************
2188{{if .Pkgs}}
2189This file contains variables, rules, and pools with name prefixes indicating
2190they were generated by the following Go packages:
2191{{range .Pkgs}}
2192 {{.PkgName}} [from Go package {{.PkgPath}}]{{end}}{{end}}
2193
2194`
2195
2196var moduleHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2197Module: {{.properties.Name}}
2198Type: {{.typeName}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002199Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002200Defined: {{.pos}}
2201`
2202
2203var singletonHeaderTemplate = `# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2204Singleton: {{.name}}
Jamie Gennis7d5b2f82014-09-24 17:51:52 -07002205Factory: {{.goFactory}}
Jamie Gennis1bc967e2014-05-27 16:34:41 -07002206`