1// Copyright 2015 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	"github.com/google/blueprint/proptools"
20)
21
22// Phases:
23//   run Pre-arch mutators
24//   run archMutator
25//   run Pre-deps mutators
26//   run depsMutator
27//   run PostDeps mutators
28//   continue on to GenerateAndroidBuildActions
29
30func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
31	for _, t := range mutators {
32		var handle blueprint.MutatorHandle
33		if t.bottomUpMutator != nil {
34			handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
35		} else if t.topDownMutator != nil {
36			handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator)
37		}
38		if t.parallel {
39			handle.Parallel()
40		}
41	}
42}
43
44func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps []RegisterMutatorFunc) {
45	mctx := &registerMutatorsContext{}
46
47	register := func(funcs []RegisterMutatorFunc) {
48		for _, f := range funcs {
49			f(mctx)
50		}
51	}
52
53	register(preArch)
54
55	register(preDeps)
56
57	mctx.BottomUp("deps", depsMutator).Parallel()
58
59	register(postDeps)
60
61	registerMutatorsToContext(ctx, mctx.mutators)
62}
63
64type registerMutatorsContext struct {
65	mutators []*mutator
66}
67
68type RegisterMutatorsContext interface {
69	TopDown(name string, m AndroidTopDownMutator) MutatorHandle
70	BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle
71}
72
73type RegisterMutatorFunc func(RegisterMutatorsContext)
74
75var preArch = []RegisterMutatorFunc{
76	func(ctx RegisterMutatorsContext) {
77		ctx.TopDown("load_hooks", loadHookMutator).Parallel()
78	},
79	RegisterNamespaceMutator,
80	RegisterPrebuiltsPreArchMutators,
81	RegisterDefaultsPreArchMutators,
82}
83
84func registerArchMutator(ctx RegisterMutatorsContext) {
85	ctx.BottomUp("arch", archMutator).Parallel()
86	ctx.TopDown("arch_hooks", archHookMutator).Parallel()
87}
88
89var preDeps = []RegisterMutatorFunc{
90	registerArchMutator,
91}
92
93var postDeps = []RegisterMutatorFunc{
94	RegisterPrebuiltsPostDepsMutators,
95	registerNeverallowMutator,
96}
97
98func PreArchMutators(f RegisterMutatorFunc) {
99	preArch = append(preArch, f)
100}
101
102func PreDepsMutators(f RegisterMutatorFunc) {
103	preDeps = append(preDeps, f)
104}
105
106func PostDepsMutators(f RegisterMutatorFunc) {
107	postDeps = append(postDeps, f)
108}
109
110type AndroidTopDownMutator func(TopDownMutatorContext)
111
112type TopDownMutatorContext interface {
113	BaseModuleContext
114	androidBaseContext
115
116	OtherModuleExists(name string) bool
117	Rename(name string)
118	Module() Module
119
120	OtherModuleName(m blueprint.Module) string
121	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
122	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
123
124	CreateModule(blueprint.ModuleFactory, ...interface{})
125
126	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
127	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
128
129	VisitDirectDeps(visit func(Module))
130	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
131	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
132	VisitDepsDepthFirst(visit func(Module))
133	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
134	WalkDeps(visit func(Module, Module) bool)
135}
136
137type androidTopDownMutatorContext struct {
138	blueprint.TopDownMutatorContext
139	androidBaseContextImpl
140}
141
142type AndroidBottomUpMutator func(BottomUpMutatorContext)
143
144type BottomUpMutatorContext interface {
145	BaseModuleContext
146	androidBaseContext
147
148	OtherModuleExists(name string) bool
149	Rename(name string)
150	Module() blueprint.Module
151
152	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
153	AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
154	CreateVariations(...string) []blueprint.Module
155	CreateLocalVariations(...string) []blueprint.Module
156	SetDependencyVariation(string)
157	AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
158	AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
159	AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
160	ReplaceDependencies(string)
161}
162
163type androidBottomUpMutatorContext struct {
164	blueprint.BottomUpMutatorContext
165	androidBaseContextImpl
166}
167
168func (x *registerMutatorsContext) BottomUp(name string, m AndroidBottomUpMutator) MutatorHandle {
169	f := func(ctx blueprint.BottomUpMutatorContext) {
170		if a, ok := ctx.Module().(Module); ok {
171			actx := &androidBottomUpMutatorContext{
172				BottomUpMutatorContext: ctx,
173				androidBaseContextImpl: a.base().androidBaseContextFactory(ctx),
174			}
175			m(actx)
176		}
177	}
178	mutator := &mutator{name: name, bottomUpMutator: f}
179	x.mutators = append(x.mutators, mutator)
180	return mutator
181}
182
183func (x *registerMutatorsContext) TopDown(name string, m AndroidTopDownMutator) MutatorHandle {
184	f := func(ctx blueprint.TopDownMutatorContext) {
185		if a, ok := ctx.Module().(Module); ok {
186			actx := &androidTopDownMutatorContext{
187				TopDownMutatorContext:  ctx,
188				androidBaseContextImpl: a.base().androidBaseContextFactory(ctx),
189			}
190			m(actx)
191		}
192	}
193	mutator := &mutator{name: name, topDownMutator: f}
194	x.mutators = append(x.mutators, mutator)
195	return mutator
196}
197
198type MutatorHandle interface {
199	Parallel() MutatorHandle
200}
201
202func (mutator *mutator) Parallel() MutatorHandle {
203	mutator.parallel = true
204	return mutator
205}
206
207func depsMutator(ctx BottomUpMutatorContext) {
208	if m, ok := ctx.Module().(Module); ok {
209		m.DepsMutator(ctx)
210	}
211}
212
213func (a *androidTopDownMutatorContext) Config() Config {
214	return a.config
215}
216
217func (a *androidBottomUpMutatorContext) Config() Config {
218	return a.config
219}
220
221func (a *androidTopDownMutatorContext) Module() Module {
222	module, _ := a.TopDownMutatorContext.Module().(Module)
223	return module
224}
225
226func (a *androidTopDownMutatorContext) VisitDirectDeps(visit func(Module)) {
227	a.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) {
228		if aModule, _ := module.(Module); aModule != nil {
229			visit(aModule)
230		}
231	})
232}
233
234func (a *androidTopDownMutatorContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
235	a.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) {
236		if aModule, _ := module.(Module); aModule != nil {
237			if a.TopDownMutatorContext.OtherModuleDependencyTag(aModule) == tag {
238				visit(aModule)
239			}
240		}
241	})
242}
243
244func (a *androidTopDownMutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
245	a.TopDownMutatorContext.VisitDirectDepsIf(
246		// pred
247		func(module blueprint.Module) bool {
248			if aModule, _ := module.(Module); aModule != nil {
249				return pred(aModule)
250			} else {
251				return false
252			}
253		},
254		// visit
255		func(module blueprint.Module) {
256			visit(module.(Module))
257		})
258}
259
260func (a *androidTopDownMutatorContext) VisitDepsDepthFirst(visit func(Module)) {
261	a.TopDownMutatorContext.VisitDepsDepthFirst(func(module blueprint.Module) {
262		if aModule, _ := module.(Module); aModule != nil {
263			visit(aModule)
264		}
265	})
266}
267
268func (a *androidTopDownMutatorContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
269	a.TopDownMutatorContext.VisitDepsDepthFirstIf(
270		// pred
271		func(module blueprint.Module) bool {
272			if aModule, _ := module.(Module); aModule != nil {
273				return pred(aModule)
274			} else {
275				return false
276			}
277		},
278		// visit
279		func(module blueprint.Module) {
280			visit(module.(Module))
281		})
282}
283
284func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) {
285	a.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool {
286		childAndroidModule, _ := child.(Module)
287		parentAndroidModule, _ := parent.(Module)
288		if childAndroidModule != nil && parentAndroidModule != nil {
289			return visit(childAndroidModule, parentAndroidModule)
290		} else {
291			return false
292		}
293	})
294}
295
296func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) {
297	for _, p := range props {
298		err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties,
299			p, nil)
300		if err != nil {
301			if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
302				a.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
303			} else {
304				panic(err)
305			}
306		}
307	}
308}
309
310func (a *androidTopDownMutatorContext) PrependProperties(props ...interface{}) {
311	for _, p := range props {
312		err := proptools.PrependMatchingProperties(a.Module().base().customizableProperties,
313			p, nil)
314		if err != nil {
315			if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
316				a.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
317			} else {
318				panic(err)
319			}
320		}
321	}
322}
323