• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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
15package blueprint
16
17import (
18	"fmt"
19
20	"github.com/google/blueprint/pathtools"
21)
22
23type Singleton interface {
24	GenerateBuildActions(SingletonContext)
25}
26
27type SingletonContext interface {
28	Config() interface{}
29
30	Name() string
31
32	ModuleName(module Module) string
33	ModuleDir(module Module) string
34	ModuleSubDir(module Module) string
35	ModuleType(module Module) string
36	BlueprintFile(module Module) string
37
38	ModuleErrorf(module Module, format string, args ...interface{})
39	Errorf(format string, args ...interface{})
40	Failed() bool
41
42	Variable(pctx PackageContext, name, value string)
43	Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) Rule
44	Build(pctx PackageContext, params BuildParams)
45	RequireNinjaVersion(major, minor, micro int)
46
47	// SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
48	// that controls where Ninja stores its build log files.  This value can be
49	// set at most one time for a single build, later calls are ignored.
50	SetNinjaBuildDir(pctx PackageContext, value string)
51
52	// AddSubninja adds a ninja file to include with subninja. This should likely
53	// only ever be used inside bootstrap to handle glob rules.
54	AddSubninja(file string)
55
56	// Eval takes a string with embedded ninja variables, and returns a string
57	// with all of the variables recursively expanded. Any variables references
58	// are expanded in the scope of the PackageContext.
59	Eval(pctx PackageContext, ninjaStr string) (string, error)
60
61	VisitAllModules(visit func(Module))
62	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
63	VisitDepsDepthFirst(module Module, visit func(Module))
64	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
65		visit func(Module))
66
67	VisitAllModuleVariants(module Module, visit func(Module))
68
69	PrimaryModule(module Module) Module
70	FinalModule(module Module) Module
71
72	AddNinjaFileDeps(deps ...string)
73
74	// GlobWithDeps returns a list of files and directories that match the
75	// specified pattern but do not match any of the patterns in excludes.
76	// Any directories will have a '/' suffix. It also adds efficient
77	// dependencies to rerun the primary builder whenever a file matching
78	// the pattern as added or removed, without rerunning if a file that
79	// does not match the pattern is added to a searched directory.
80	GlobWithDeps(pattern string, excludes []string) ([]string, error)
81
82	Fs() pathtools.FileSystem
83}
84
85var _ SingletonContext = (*singletonContext)(nil)
86
87type singletonContext struct {
88	name    string
89	context *Context
90	config  interface{}
91	scope   *localScope
92	globals *liveTracker
93
94	ninjaFileDeps []string
95	errs          []error
96
97	actionDefs localBuildActions
98}
99
100func (s *singletonContext) Config() interface{} {
101	return s.config
102}
103
104func (s *singletonContext) Name() string {
105	return s.name
106}
107
108func (s *singletonContext) ModuleName(logicModule Module) string {
109	return s.context.ModuleName(logicModule)
110}
111
112func (s *singletonContext) ModuleDir(logicModule Module) string {
113	return s.context.ModuleDir(logicModule)
114}
115
116func (s *singletonContext) ModuleSubDir(logicModule Module) string {
117	return s.context.ModuleSubDir(logicModule)
118}
119
120func (s *singletonContext) ModuleType(logicModule Module) string {
121	return s.context.ModuleType(logicModule)
122}
123
124func (s *singletonContext) BlueprintFile(logicModule Module) string {
125	return s.context.BlueprintFile(logicModule)
126}
127
128func (s *singletonContext) error(err error) {
129	if err != nil {
130		s.errs = append(s.errs, err)
131	}
132}
133
134func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
135	args ...interface{}) {
136
137	s.error(s.context.ModuleErrorf(logicModule, format, args...))
138}
139
140func (s *singletonContext) Errorf(format string, args ...interface{}) {
141	// TODO: Make this not result in the error being printed as "internal error"
142	s.error(fmt.Errorf(format, args...))
143}
144
145func (s *singletonContext) Failed() bool {
146	return len(s.errs) > 0
147}
148
149func (s *singletonContext) Variable(pctx PackageContext, name, value string) {
150	s.scope.ReparentTo(pctx)
151
152	v, err := s.scope.AddLocalVariable(name, value)
153	if err != nil {
154		panic(err)
155	}
156
157	s.actionDefs.variables = append(s.actionDefs.variables, v)
158}
159
160func (s *singletonContext) Rule(pctx PackageContext, name string,
161	params RuleParams, argNames ...string) Rule {
162
163	s.scope.ReparentTo(pctx)
164
165	r, err := s.scope.AddLocalRule(name, &params, argNames...)
166	if err != nil {
167		panic(err)
168	}
169
170	s.actionDefs.rules = append(s.actionDefs.rules, r)
171
172	return r
173}
174
175func (s *singletonContext) Build(pctx PackageContext, params BuildParams) {
176	s.scope.ReparentTo(pctx)
177
178	def, err := parseBuildParams(s.scope, &params)
179	if err != nil {
180		panic(err)
181	}
182
183	s.actionDefs.buildDefs = append(s.actionDefs.buildDefs, def)
184}
185
186func (s *singletonContext) Eval(pctx PackageContext, str string) (string, error) {
187	s.scope.ReparentTo(pctx)
188
189	ninjaStr, err := parseNinjaString(s.scope, str)
190	if err != nil {
191		return "", err
192	}
193
194	err = s.globals.addNinjaStringDeps(ninjaStr)
195	if err != nil {
196		return "", err
197	}
198
199	return ninjaStr.Eval(s.globals.variables)
200}
201
202func (s *singletonContext) RequireNinjaVersion(major, minor, micro int) {
203	s.context.requireNinjaVersion(major, minor, micro)
204}
205
206func (s *singletonContext) SetNinjaBuildDir(pctx PackageContext, value string) {
207	s.scope.ReparentTo(pctx)
208
209	ninjaValue, err := parseNinjaString(s.scope, value)
210	if err != nil {
211		panic(err)
212	}
213
214	s.context.setNinjaBuildDir(ninjaValue)
215}
216
217func (s *singletonContext) AddSubninja(file string) {
218	s.context.subninjas = append(s.context.subninjas, file)
219}
220
221func (s *singletonContext) VisitAllModules(visit func(Module)) {
222	var visitingModule Module
223	defer func() {
224		if r := recover(); r != nil {
225			panic(newPanicErrorf(r, "VisitAllModules(%s) for module %s",
226				funcName(visit), visitingModule))
227		}
228	}()
229
230	s.context.VisitAllModules(func(m Module) {
231		visitingModule = m
232		visit(m)
233	})
234}
235
236func (s *singletonContext) VisitAllModulesIf(pred func(Module) bool,
237	visit func(Module)) {
238
239	s.context.VisitAllModulesIf(pred, visit)
240}
241
242func (s *singletonContext) VisitDepsDepthFirst(module Module,
243	visit func(Module)) {
244
245	s.context.VisitDepsDepthFirst(module, visit)
246}
247
248func (s *singletonContext) VisitDepsDepthFirstIf(module Module,
249	pred func(Module) bool, visit func(Module)) {
250
251	s.context.VisitDepsDepthFirstIf(module, pred, visit)
252}
253
254func (s *singletonContext) PrimaryModule(module Module) Module {
255	return s.context.PrimaryModule(module)
256}
257
258func (s *singletonContext) FinalModule(module Module) Module {
259	return s.context.FinalModule(module)
260}
261
262func (s *singletonContext) VisitAllModuleVariants(module Module, visit func(Module)) {
263	s.context.VisitAllModuleVariants(module, visit)
264}
265
266func (s *singletonContext) AddNinjaFileDeps(deps ...string) {
267	s.ninjaFileDeps = append(s.ninjaFileDeps, deps...)
268}
269
270func (s *singletonContext) GlobWithDeps(pattern string,
271	excludes []string) ([]string, error) {
272	return s.context.glob(pattern, excludes)
273}
274
275func (s *singletonContext) Fs() pathtools.FileSystem {
276	return s.context.fs
277}
278