1// Copyright 2017 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 android
16
17import (
18	"github.com/google/blueprint"
19)
20
21// SingletonContext
22type SingletonContext interface {
23	Config() Config
24	DeviceConfig() DeviceConfig
25
26	ModuleName(module blueprint.Module) string
27	ModuleDir(module blueprint.Module) string
28	ModuleSubDir(module blueprint.Module) string
29	ModuleType(module blueprint.Module) string
30	BlueprintFile(module blueprint.Module) string
31
32	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
33	Errorf(format string, args ...interface{})
34	Failed() bool
35
36	Variable(pctx PackageContext, name, value string)
37	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
38	Build(pctx PackageContext, params BuildParams)
39
40	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
41	// phony rules or real files.  Phony can be called on the same name multiple times to add
42	// additional dependencies.
43	Phony(name string, deps ...Path)
44
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	// Eval takes a string with embedded ninja variables, and returns a string
53	// with all of the variables recursively expanded. Any variables references
54	// are expanded in the scope of the PackageContext.
55	Eval(pctx PackageContext, ninjaStr string) (string, error)
56
57	VisitAllModulesBlueprint(visit func(blueprint.Module))
58	VisitAllModules(visit func(Module))
59	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
60
61	VisitDirectDeps(module Module, visit func(Module))
62	VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module))
63
64	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
65	VisitDepsDepthFirst(module Module, visit func(Module))
66	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
67	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
68		visit func(Module))
69
70	VisitAllModuleVariants(module Module, visit func(Module))
71
72	PrimaryModule(module Module) Module
73	FinalModule(module Module) Module
74
75	AddNinjaFileDeps(deps ...string)
76
77	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
78	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
79	// builder whenever a file matching the pattern as added or removed, without rerunning if a
80	// file that does not match the pattern is added to a searched directory.
81	GlobWithDeps(pattern string, excludes []string) ([]string, error)
82}
83
84type singletonAdaptor struct {
85	Singleton
86
87	buildParams []BuildParams
88	ruleParams  map[blueprint.Rule]blueprint.RuleParams
89}
90
91var _ testBuildProvider = (*singletonAdaptor)(nil)
92
93func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
94	sctx := &singletonContextAdaptor{SingletonContext: ctx}
95	if sctx.Config().captureBuild {
96		sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
97	}
98
99	s.Singleton.GenerateBuildActions(sctx)
100
101	s.buildParams = sctx.buildParams
102	s.ruleParams = sctx.ruleParams
103}
104
105func (s *singletonAdaptor) BuildParamsForTests() []BuildParams {
106	return s.buildParams
107}
108
109func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
110	return s.ruleParams
111}
112
113type Singleton interface {
114	GenerateBuildActions(SingletonContext)
115}
116
117type singletonContextAdaptor struct {
118	blueprint.SingletonContext
119
120	buildParams []BuildParams
121	ruleParams  map[blueprint.Rule]blueprint.RuleParams
122}
123
124func (s *singletonContextAdaptor) Config() Config {
125	return s.SingletonContext.Config().(Config)
126}
127
128func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig {
129	return DeviceConfig{s.Config().deviceConfig}
130}
131
132func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
133	s.SingletonContext.Variable(pctx.PackageContext, name, value)
134}
135
136func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
137	if s.Config().UseRemoteBuild() {
138		if params.Pool == nil {
139			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
140			// jobs to the local parallelism value
141			params.Pool = localPool
142		} else if params.Pool == remotePool {
143			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
144			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
145			// parallelism.
146			params.Pool = nil
147		}
148	}
149	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
150	if s.Config().captureBuild {
151		s.ruleParams[rule] = params
152	}
153	return rule
154}
155
156func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
157	if s.Config().captureBuild {
158		s.buildParams = append(s.buildParams, params)
159	}
160	bparams := convertBuildParams(params)
161	s.SingletonContext.Build(pctx.PackageContext, bparams)
162
163}
164
165func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
166	addPhony(s.Config(), name, deps...)
167}
168
169func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
170	s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
171}
172
173func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
174	return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
175}
176
177// visitAdaptor wraps a visit function that takes an android.Module parameter into
178// a function that takes an blueprint.Module parameter and only calls the visit function if the
179// blueprint.Module is an android.Module.
180func visitAdaptor(visit func(Module)) func(blueprint.Module) {
181	return func(module blueprint.Module) {
182		if aModule, ok := module.(Module); ok {
183			visit(aModule)
184		}
185	}
186}
187
188// predAdaptor wraps a pred function that takes an android.Module parameter
189// into a function that takes an blueprint.Module parameter and only calls the visit function if the
190// blueprint.Module is an android.Module, otherwise returns false.
191func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool {
192	return func(module blueprint.Module) bool {
193		if aModule, ok := module.(Module); ok {
194			return pred(aModule)
195		} else {
196			return false
197		}
198	}
199}
200
201func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
202	s.SingletonContext.VisitAllModules(visit)
203}
204
205func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) {
206	s.SingletonContext.VisitAllModules(visitAdaptor(visit))
207}
208
209func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
210	s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
211}
212
213func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) {
214	s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit))
215}
216
217func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
218	s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit))
219}
220
221func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
222	s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
223}
224
225func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
226	s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
227}
228
229func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
230	s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
231}
232
233func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
234	return s.SingletonContext.PrimaryModule(module).(Module)
235}
236
237func (s *singletonContextAdaptor) FinalModule(module Module) Module {
238	return s.SingletonContext.FinalModule(module).(Module)
239}
240