• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	"reflect"
19
20	"github.com/google/blueprint"
21	"github.com/google/blueprint/proptools"
22)
23
24type defaultsDependencyTag struct {
25	blueprint.BaseDependencyTag
26}
27
28var DefaultsDepTag defaultsDependencyTag
29
30type defaultsProperties struct {
31	Defaults []string
32}
33
34type DefaultableModuleBase struct {
35	defaultsProperties            defaultsProperties
36	defaultableProperties         []interface{}
37	defaultableVariableProperties interface{}
38
39	// The optional hook to call after any defaults have been applied.
40	hook DefaultableHook
41}
42
43func (d *DefaultableModuleBase) defaults() *defaultsProperties {
44	return &d.defaultsProperties
45}
46
47func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
48	d.defaultableProperties = props
49	d.defaultableVariableProperties = variableProperties
50}
51
52func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
53	d.hook = hook
54}
55
56func (d *DefaultableModuleBase) CallHookIfAvailable(ctx DefaultableHookContext) {
57	if d.hook != nil {
58		d.hook(ctx)
59	}
60}
61
62// Interface that must be supported by any module to which defaults can be applied.
63type Defaultable interface {
64	// Get a pointer to the struct containing the Defaults property.
65	defaults() *defaultsProperties
66
67	// Set the property structures into which defaults will be added.
68	setProperties(props []interface{}, variableProperties interface{})
69
70	// Apply defaults from the supplied Defaults to the property structures supplied to
71	// setProperties(...).
72	applyDefaults(TopDownMutatorContext, []Defaults)
73
74	// Set the hook to be called after any defaults have been applied.
75	//
76	// Should be used in preference to a AddLoadHook when the behavior of the load
77	// hook is dependent on properties supplied in the Android.bp file.
78	SetDefaultableHook(hook DefaultableHook)
79
80	// Call the hook if specified.
81	CallHookIfAvailable(context DefaultableHookContext)
82}
83
84type DefaultableModule interface {
85	Module
86	Defaultable
87}
88
89var _ Defaultable = (*DefaultableModuleBase)(nil)
90
91func InitDefaultableModule(module DefaultableModule) {
92	if module.base().module == nil {
93		panic("InitAndroidModule must be called before InitDefaultableModule")
94	}
95
96	module.setProperties(module.GetProperties(), module.base().variableProperties)
97
98	module.AddProperties(module.defaults())
99}
100
101// A restricted subset of context methods, similar to LoadHookContext.
102type DefaultableHookContext interface {
103	EarlyModuleContext
104
105	CreateModule(ModuleFactory, ...interface{}) Module
106	AddMissingDependencies(missingDeps []string)
107}
108
109type DefaultableHook func(ctx DefaultableHookContext)
110
111// The Defaults_visibility property.
112type DefaultsVisibilityProperties struct {
113
114	// Controls the visibility of the defaults module itself.
115	Defaults_visibility []string
116}
117
118type DefaultsModuleBase struct {
119	DefaultableModuleBase
120
121	// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
122	// target. This is primarily useful for modules that were architecture specific and instead are
123	// handled in Bazel as a select().
124	BazelModuleBase
125}
126
127// The common pattern for defaults modules is to register separate instances of
128// the xxxProperties structs in the AddProperties calls, rather than reusing the
129// ones inherited from Module.
130//
131// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
132// contain the values that have been set for the defaults module. Rather, to
133// retrieve the values it is necessary to iterate over properties(). E.g. to get
134// the commonProperties instance that have the real values:
135//
136//	d := myModule.(Defaults)
137//	for _, props := range d.properties() {
138//	  if cp, ok := props.(*commonProperties); ok {
139//	    ... access property values in cp ...
140//	  }
141//	}
142//
143// The rationale is that the properties on a defaults module apply to the
144// defaultable modules using it, not to the defaults module itself. E.g. setting
145// the "enabled" property false makes inheriting modules disabled by default,
146// rather than disabling the defaults module itself.
147type Defaults interface {
148	Defaultable
149
150	// Although this function is unused it is actually needed to ensure that only modules that embed
151	// DefaultsModuleBase will type-assert to the Defaults interface.
152	isDefaults() bool
153
154	// Get the structures containing the properties for which defaults can be provided.
155	properties() []interface{}
156
157	productVariableProperties() interface{}
158}
159
160func (d *DefaultsModuleBase) isDefaults() bool {
161	return true
162}
163
164type DefaultsModule interface {
165	Module
166	Defaults
167	Bazelable
168}
169
170func (d *DefaultsModuleBase) properties() []interface{} {
171	return d.defaultableProperties
172}
173
174func (d *DefaultsModuleBase) productVariableProperties() interface{} {
175	return d.defaultableVariableProperties
176}
177
178func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
179
180// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
181// *NOT* converted with bp2build
182func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {}
183
184func InitDefaultsModule(module DefaultsModule) {
185	commonProperties := &commonProperties{}
186
187	module.AddProperties(
188		&hostAndDeviceProperties{},
189		commonProperties,
190		&ApexProperties{},
191		&distProperties{})
192
193	// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
194	InitBazelModule(module)
195	initAndroidModuleBase(module)
196	initProductVariableModule(module)
197	initArchModule(module)
198	InitDefaultableModule(module)
199
200	// Add properties that will not have defaults applied to them.
201	base := module.base()
202	defaultsVisibility := &DefaultsVisibilityProperties{}
203	module.AddProperties(&base.nameProperties, defaultsVisibility)
204
205	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
206	// Instead it is stored in a separate instance of commonProperties created above so clear the
207	// existing list of properties.
208	clearVisibilityProperties(module)
209
210	// The defaults_visibility property controls the visibility of a defaults module so it must be
211	// set as the primary property, which also adds it to the list.
212	setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
213
214	// The visibility property needs to be checked (but not parsed) by the visibility module during
215	// its checking phase and parsing phase so add it to the list as a normal property.
216	AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
217
218	// The applicable licenses property for defaults is 'licenses'.
219	setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
220}
221
222var _ Defaults = (*DefaultsModuleBase)(nil)
223
224// applyNamespacedVariableDefaults only runs in bp2build mode for
225// defaultable/defaults modules. Its purpose is to merge namespaced product
226// variable props from defaults deps, even if those defaults are custom module
227// types created from soong_config_module_type, e.g. one that's wrapping a
228// cc_defaults or java_defaults.
229func applyNamespacedVariableDefaults(defaultDep Defaults, ctx TopDownMutatorContext) {
230	var dep, b Bazelable
231
232	dep, ok := defaultDep.(Bazelable)
233	if !ok {
234		if depMod, ok := defaultDep.(Module); ok {
235			// Track that this dependency hasn't been converted to bp2build yet.
236			ctx.AddUnconvertedBp2buildDep(depMod.Name())
237			return
238		} else {
239			panic("Expected default dep to be a Module.")
240		}
241	}
242
243	b, ok = ctx.Module().(Bazelable)
244	if !ok {
245		return
246	}
247
248	// namespacedVariableProps is a map from namespaces (e.g. acme, android,
249	// vendor_foo) to a slice of soong_config_variable struct pointers,
250	// containing properties for that particular module.
251	src := dep.namespacedVariableProps()
252	dst := b.namespacedVariableProps()
253	if dst == nil {
254		dst = make(namespacedVariableProperties)
255	}
256
257	// Propagate all soong_config_variable structs from the dep. We'll merge the
258	// actual property values later in variable.go.
259	for namespace := range src {
260		if dst[namespace] == nil {
261			dst[namespace] = []interface{}{}
262		}
263		for _, i := range src[namespace] {
264			dst[namespace] = append(dst[namespace], i)
265		}
266	}
267
268	b.setNamespacedVariableProps(dst)
269}
270
271func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
272	defaultsList []Defaults) {
273
274	for _, defaults := range defaultsList {
275		if ctx.Config().BuildMode == Bp2build {
276			applyNamespacedVariableDefaults(defaults, ctx)
277		}
278		for _, prop := range defaultable.defaultableProperties {
279			if prop == defaultable.defaultableVariableProperties {
280				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
281			} else {
282				defaultable.applyDefaultProperties(ctx, defaults, prop)
283			}
284		}
285	}
286}
287
288// Product variable properties need special handling, the type of the filtered product variable
289// property struct may not be identical between the defaults module and the defaultable module.
290// Use PrependMatchingProperties to apply whichever properties match.
291func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
292	defaults Defaults, defaultableProp interface{}) {
293	if defaultableProp == nil {
294		return
295	}
296
297	defaultsProp := defaults.productVariableProperties()
298	if defaultsProp == nil {
299		return
300	}
301
302	dst := []interface{}{
303		defaultableProp,
304		// Put an empty copy of the src properties into dst so that properties in src that are not in dst
305		// don't cause a "failed to find property to extend" error.
306		proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
307	}
308
309	err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
310	if err != nil {
311		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
312			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
313		} else {
314			panic(err)
315		}
316	}
317}
318
319func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
320	defaults Defaults, defaultableProp interface{}) {
321
322	for _, def := range defaults.properties() {
323		if proptools.TypeEqual(defaultableProp, def) {
324			err := proptools.PrependProperties(defaultableProp, def, nil)
325			if err != nil {
326				if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
327					ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
328				} else {
329					panic(err)
330				}
331			}
332		}
333	}
334}
335
336func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
337	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
338	ctx.TopDown("defaults", defaultsMutator).Parallel()
339}
340
341func defaultsDepsMutator(ctx BottomUpMutatorContext) {
342	if defaultable, ok := ctx.Module().(Defaultable); ok {
343		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
344	}
345}
346
347func defaultsMutator(ctx TopDownMutatorContext) {
348	if defaultable, ok := ctx.Module().(Defaultable); ok {
349		if len(defaultable.defaults().Defaults) > 0 {
350			var defaultsList []Defaults
351			seen := make(map[Defaults]bool)
352
353			ctx.WalkDeps(func(module, parent Module) bool {
354				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
355					if defaults, ok := module.(Defaults); ok {
356						if !seen[defaults] {
357							seen[defaults] = true
358							defaultsList = append(defaultsList, defaults)
359							return len(defaults.defaults().Defaults) > 0
360						}
361					} else {
362						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
363							ctx.OtherModuleName(module))
364					}
365				}
366				return false
367			})
368			defaultable.applyDefaults(ctx, defaultsList)
369		}
370
371		defaultable.CallHookIfAvailable(ctx)
372	}
373}
374