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