xref: /aosp_15_r20/build/soong/android/singleton.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	otherModuleProvider(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	VisitAllModuleProxies(visit func(proxy ModuleProxy))
68	VisitAllModulesIf(pred func(Module) bool, visit func(Module))
69
70	VisitDirectDeps(module Module, visit func(Module))
71	VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module))
72
73	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
74	VisitDepsDepthFirst(module Module, visit func(Module))
75	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
76	VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
77		visit func(Module))
78
79	VisitAllModuleVariants(module Module, visit func(Module))
80
81	VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy))
82
83	PrimaryModule(module Module) Module
84	IsFinalModule(module Module) bool
85
86	AddNinjaFileDeps(deps ...string)
87
88	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
89	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
90	// builder whenever a file matching the pattern as added or removed, without rerunning if a
91	// file that does not match the pattern is added to a searched directory.
92	GlobWithDeps(pattern string, excludes []string) ([]string, error)
93
94	// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
95	OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
96
97	// HasMutatorFinished returns true if the given mutator has finished running.
98	// It will panic if given an invalid mutator name.
99	HasMutatorFinished(mutatorName string) bool
100}
101
102type singletonAdaptor struct {
103	Singleton
104
105	buildParams []BuildParams
106	ruleParams  map[blueprint.Rule]blueprint.RuleParams
107}
108
109var _ testBuildProvider = (*singletonAdaptor)(nil)
110
111func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
112	sctx := &singletonContextAdaptor{SingletonContext: ctx}
113	if sctx.Config().captureBuild {
114		sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
115	}
116
117	s.Singleton.GenerateBuildActions(sctx)
118
119	s.buildParams = sctx.buildParams
120	s.ruleParams = sctx.ruleParams
121}
122
123func (s *singletonAdaptor) BuildParamsForTests() []BuildParams {
124	return s.buildParams
125}
126
127func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
128	return s.ruleParams
129}
130
131type Singleton interface {
132	GenerateBuildActions(SingletonContext)
133}
134
135type singletonContextAdaptor struct {
136	blueprint.SingletonContext
137
138	buildParams []BuildParams
139	ruleParams  map[blueprint.Rule]blueprint.RuleParams
140}
141
142func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext {
143	return s.SingletonContext
144}
145
146func (s *singletonContextAdaptor) Config() Config {
147	return s.SingletonContext.Config().(Config)
148}
149
150func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig {
151	return DeviceConfig{s.Config().deviceConfig}
152}
153
154func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
155	s.SingletonContext.Variable(pctx.PackageContext, name, value)
156}
157
158func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
159	if s.Config().UseRemoteBuild() {
160		if params.Pool == nil {
161			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
162			// jobs to the local parallelism value
163			params.Pool = localPool
164		} else if params.Pool == remotePool {
165			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
166			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
167			// parallelism.
168			params.Pool = nil
169		}
170	}
171	rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
172	if s.Config().captureBuild {
173		s.ruleParams[rule] = params
174	}
175	return rule
176}
177
178func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
179	if s.Config().captureBuild {
180		s.buildParams = append(s.buildParams, params)
181	}
182	bparams := convertBuildParams(params)
183	s.SingletonContext.Build(pctx.PackageContext, bparams)
184}
185
186func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
187	addSingletonPhony(s.Config(), name, deps...)
188}
189
190func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) {
191	s.SingletonContext.SetOutDir(pctx.PackageContext, value)
192}
193
194func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
195	return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
196}
197
198// visitAdaptor wraps a visit function that takes an android.Module parameter into
199// a function that takes a blueprint.Module parameter and only calls the visit function if the
200// blueprint.Module is an android.Module.
201func visitAdaptor(visit func(Module)) func(blueprint.Module) {
202	return func(module blueprint.Module) {
203		if aModule, ok := module.(Module); ok {
204			visit(aModule)
205		}
206	}
207}
208
209// visitProxyAdaptor wraps a visit function that takes an android.ModuleProxy parameter into
210// a function that takes a blueprint.ModuleProxy parameter.
211func visitProxyAdaptor(visit func(proxy ModuleProxy)) func(proxy blueprint.ModuleProxy) {
212	return func(module blueprint.ModuleProxy) {
213		visit(ModuleProxy{
214			module: module,
215		})
216	}
217}
218
219// predAdaptor wraps a pred function that takes an android.Module parameter
220// into a function that takes an blueprint.Module parameter and only calls the visit function if the
221// blueprint.Module is an android.Module, otherwise returns false.
222func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool {
223	return func(module blueprint.Module) bool {
224		if aModule, ok := module.(Module); ok {
225			return pred(aModule)
226		} else {
227			return false
228		}
229	}
230}
231
232func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
233	s.SingletonContext.VisitAllModules(visit)
234}
235
236func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) {
237	s.SingletonContext.VisitAllModules(visitAdaptor(visit))
238}
239
240func (s *singletonContextAdaptor) VisitAllModuleProxies(visit func(proxy ModuleProxy)) {
241	s.SingletonContext.VisitAllModuleProxies(visitProxyAdaptor(visit))
242}
243
244func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
245	s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
246}
247
248func (s *singletonContextAdaptor) VisitDirectDeps(module Module, visit func(Module)) {
249	s.SingletonContext.VisitDirectDeps(module, visitAdaptor(visit))
250}
251
252func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) {
253	s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit))
254}
255
256func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
257	s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
258}
259
260func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
261	s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
262}
263
264func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
265	s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
266}
267
268func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) {
269	s.SingletonContext.VisitAllModuleVariantProxies(module, visitProxyAdaptor(visit))
270}
271
272func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
273	return s.SingletonContext.PrimaryModule(module).(Module)
274}
275
276func (s *singletonContextAdaptor) IsFinalModule(module Module) bool {
277	return s.SingletonContext.IsFinalModule(module)
278}
279
280func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
281	// get module reference for visibility enforcement
282	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
283
284	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
285	result := make([]Module, 0, len(modules))
286	for _, m := range modules {
287		if module, ok := m.(Module); ok {
288			// enforce visibility
289			depName := s.ModuleName(module)
290			depDir := s.ModuleDir(module)
291			depQualified := qualifiedModuleName{depDir, depName}
292			// Targets are always visible to other targets in their own package.
293			if depQualified.pkg != qualified.name.pkg {
294				rule := effectiveVisibilityRules(s.Config(), depQualified)
295				if !rule.matches(qualified) {
296					s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
297						referer.Name(), depQualified, "//"+s.ModuleDir(referer))
298					continue
299				}
300			}
301			result = append(result, module)
302		}
303	}
304	return result
305}
306
307func (s *singletonContextAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
308	return s.SingletonContext.ModuleProvider(module, provider)
309}
310
311func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
312	s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...)
313}
314
315func (s *singletonContextAdaptor) HasMutatorFinished(mutatorName string) bool {
316	return s.blueprintSingletonContext().HasMutatorFinished(mutatorName)
317}
318