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	blueprintSingletonContext() blueprint.SingletonContext
24
25	Config() Config
26	DeviceConfig() DeviceConfig
27
28	ModuleName(module blueprint.Module) string
29	ModuleDir(module blueprint.Module) string
30	ModuleSubDir(module blueprint.Module) string
31	ModuleType(module blueprint.Module) string
32	BlueprintFile(module blueprint.Module) string
33
34	// ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules.
35	// Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
36	ModuleVariantsFromName(referer Module, name string) []Module
37
38	moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
39
40	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
41	Errorf(format string, args ...interface{})
42	Failed() bool
43
44	Variable(pctx PackageContext, name, value string)
45	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
46	Build(pctx PackageContext, params BuildParams)
47
48	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
49	// phony rules or real files.  Phony can be called on the same name multiple times to add
50	// additional dependencies.
51	Phony(name string, deps ...Path)
52
53	RequireNinjaVersion(major, minor, micro int)
54
55	// SetOutDir sets the value of the top-level "builddir" Ninja variable
56	// that controls where Ninja stores its build log files.  This value can be
57	// set at most one time for a single build, later calls are ignored.
58	SetOutDir(pctx PackageContext, value string)
59
60	// Eval takes a string with embedded ninja variables, and returns a string
61	// with all of the variables recursively expanded. Any variables references
62	// are expanded in the scope of the PackageContext.
63	Eval(pctx PackageContext, ninjaStr string) (string, error)
64
65	VisitAllModulesBlueprint(visit func(blueprint.Module))
66	VisitAllModules(visit func(Module))
67	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
68
69	VisitDirectDeps(module Module, visit func(Module))
70	VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module))
71
72	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
73	VisitDepsDepthFirst(module Module, visit func(Module))
74	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
75	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
76		visit func(Module))
77
78	VisitAllModuleVariants(module Module, visit func(Module))
79
80	PrimaryModule(module Module) Module
81	FinalModule(module Module) Module
82
83	AddNinjaFileDeps(deps ...string)
84
85	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
86	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
87	// builder whenever a file matching the pattern as added or removed, without rerunning if a
88	// file that does not match the pattern is added to a searched directory.
89	GlobWithDeps(pattern string, excludes []string) ([]string, error)
90
91	// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
92	OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
93}
94
95type singletonAdaptor struct {
96	Singleton
97
98	buildParams []BuildParams
99	ruleParams  map[blueprint.Rule]blueprint.RuleParams
100}
101
102var _ testBuildProvider = (*singletonAdaptor)(nil)
103
104func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
105	sctx := &singletonContextAdaptor{SingletonContext: ctx}
106	if sctx.Config().captureBuild {
107		sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
108	}
109
110	s.Singleton.GenerateBuildActions(sctx)
111
112	s.buildParams = sctx.buildParams
113	s.ruleParams = sctx.ruleParams
114}
115
116func (s *singletonAdaptor) BuildParamsForTests() []BuildParams {
117	return s.buildParams
118}
119
120func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
121	return s.ruleParams
122}
123
124type Singleton interface {
125	GenerateBuildActions(SingletonContext)
126}
127
128type singletonContextAdaptor struct {
129	blueprint.SingletonContext
130
131	buildParams []BuildParams
132	ruleParams  map[blueprint.Rule]blueprint.RuleParams
133}
134
135func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext {
136	return s.SingletonContext
137}
138
139func (s *singletonContextAdaptor) Config() Config {
140	return s.SingletonContext.Config().(Config)
141}
142
143func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig {
144	return DeviceConfig{s.Config().deviceConfig}
145}
146
147func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
148	s.SingletonContext.Variable(pctx.PackageContext, name, value)
149}
150
151func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
152	if s.Config().UseRemoteBuild() {
153		if params.Pool == nil {
154			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
155			// jobs to the local parallelism value
156			params.Pool = localPool
157		} else if params.Pool == remotePool {
158			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
159			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
160			// parallelism.
161			params.Pool = nil
162		}
163	}
164	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
165	if s.Config().captureBuild {
166		s.ruleParams[rule] = params
167	}
168	return rule
169}
170
171func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
172	if s.Config().captureBuild {
173		s.buildParams = append(s.buildParams, params)
174	}
175	bparams := convertBuildParams(params)
176	s.SingletonContext.Build(pctx.PackageContext, bparams)
177}
178
179func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
180	addPhony(s.Config(), name, deps...)
181}
182
183func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) {
184	s.SingletonContext.SetOutDir(pctx.PackageContext, value)
185}
186
187func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
188	return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
189}
190
191// visitAdaptor wraps a visit function that takes an android.Module parameter into
192// a function that takes an blueprint.Module parameter and only calls the visit function if the
193// blueprint.Module is an android.Module.
194func visitAdaptor(visit func(Module)) func(blueprint.Module) {
195	return func(module blueprint.Module) {
196		if aModule, ok := module.(Module); ok {
197			visit(aModule)
198		}
199	}
200}
201
202// predAdaptor wraps a pred function that takes an android.Module parameter
203// into a function that takes an blueprint.Module parameter and only calls the visit function if the
204// blueprint.Module is an android.Module, otherwise returns false.
205func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool {
206	return func(module blueprint.Module) bool {
207		if aModule, ok := module.(Module); ok {
208			return pred(aModule)
209		} else {
210			return false
211		}
212	}
213}
214
215func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
216	s.SingletonContext.VisitAllModules(visit)
217}
218
219func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) {
220	s.SingletonContext.VisitAllModules(visitAdaptor(visit))
221}
222
223func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
224	s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
225}
226
227func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) {
228	s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit))
229}
230
231func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
232	s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit))
233}
234
235func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
236	s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
237}
238
239func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
240	s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
241}
242
243func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
244	s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
245}
246
247func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
248	return s.SingletonContext.PrimaryModule(module).(Module)
249}
250
251func (s *singletonContextAdaptor) FinalModule(module Module) Module {
252	return s.SingletonContext.FinalModule(module).(Module)
253}
254
255func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
256	// get module reference for visibility enforcement
257	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
258
259	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
260	result := make([]Module, 0, len(modules))
261	for _, m := range modules {
262		if module, ok := m.(Module); ok {
263			// enforce visibility
264			depName := s.ModuleName(module)
265			depDir := s.ModuleDir(module)
266			depQualified := qualifiedModuleName{depDir, depName}
267			// Targets are always visible to other targets in their own package.
268			if depQualified.pkg != qualified.name.pkg {
269				rule := effectiveVisibilityRules(s.Config(), depQualified)
270				if !rule.matches(qualified) {
271					s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
272						referer.Name(), depQualified, "//"+s.ModuleDir(referer))
273					continue
274				}
275			}
276			result = append(result, module)
277		}
278	}
279	return result
280}
281
282func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
283	return s.SingletonContext.ModuleProvider(module, provider)
284}
285
286func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
287	s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...)
288}
289