xref: /aosp_15_r20/build/soong/android/defaults.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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(BottomUpMutatorContext, []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	OtherModuleProviderContext
105
106	CreateModule(ModuleFactory, ...interface{}) Module
107	AddMissingDependencies(missingDeps []string)
108}
109
110type DefaultableHook func(ctx DefaultableHookContext)
111
112// The Defaults_visibility property.
113type DefaultsVisibilityProperties struct {
114
115	// Controls the visibility of the defaults module itself.
116	Defaults_visibility []string
117}
118
119type DefaultsModuleBase struct {
120	DefaultableModuleBase
121}
122
123// The common pattern for defaults modules is to register separate instances of
124// the xxxProperties structs in the AddProperties calls, rather than reusing the
125// ones inherited from Module.
126//
127// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
128// contain the values that have been set for the defaults module. Rather, to
129// retrieve the values it is necessary to iterate over properties(). E.g. to get
130// the commonProperties instance that have the real values:
131//
132//	d := myModule.(Defaults)
133//	for _, props := range d.properties() {
134//	  if cp, ok := props.(*commonProperties); ok {
135//	    ... access property values in cp ...
136//	  }
137//	}
138//
139// The rationale is that the properties on a defaults module apply to the
140// defaultable modules using it, not to the defaults module itself. E.g. setting
141// the "enabled" property false makes inheriting modules disabled by default,
142// rather than disabling the defaults module itself.
143type Defaults interface {
144	Defaultable
145
146	// Although this function is unused it is actually needed to ensure that only modules that embed
147	// DefaultsModuleBase will type-assert to the Defaults interface.
148	isDefaults() bool
149
150	// Get the structures containing the properties for which defaults can be provided.
151	properties() []interface{}
152
153	productVariableProperties() interface{}
154}
155
156func (d *DefaultsModuleBase) isDefaults() bool {
157	return true
158}
159
160type DefaultsModule interface {
161	Module
162	Defaults
163}
164
165func (d *DefaultsModuleBase) properties() []interface{} {
166	return d.defaultableProperties
167}
168
169func (d *DefaultsModuleBase) productVariableProperties() interface{} {
170	return d.defaultableVariableProperties
171}
172
173func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
174
175func InitDefaultsModule(module DefaultsModule) {
176	commonProperties := &commonProperties{}
177
178	module.AddProperties(
179		&hostAndDeviceProperties{},
180		commonProperties,
181		&ApexProperties{},
182		&distProperties{})
183
184	initAndroidModuleBase(module)
185	initProductVariableModule(module)
186	initArchModule(module)
187	InitDefaultableModule(module)
188
189	// Add properties that will not have defaults applied to them.
190	base := module.base()
191	defaultsVisibility := &DefaultsVisibilityProperties{}
192	module.AddProperties(&base.nameProperties, defaultsVisibility)
193
194	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
195	// Instead it is stored in a separate instance of commonProperties created above so clear the
196	// existing list of properties.
197	clearVisibilityProperties(module)
198
199	// The defaults_visibility property controls the visibility of a defaults module so it must be
200	// set as the primary property, which also adds it to the list.
201	setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
202
203	// The visibility property needs to be checked (but not parsed) by the visibility module during
204	// its checking phase and parsing phase so add it to the list as a normal property.
205	AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
206
207	// The applicable licenses property for defaults is 'licenses'.
208	setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
209}
210
211var _ Defaults = (*DefaultsModuleBase)(nil)
212
213func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext,
214	defaultsList []Defaults) {
215
216	for _, defaults := range defaultsList {
217		for _, prop := range defaultable.defaultableProperties {
218			if prop == defaultable.defaultableVariableProperties {
219				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
220			} else {
221				defaultable.applyDefaultProperties(ctx, defaults, prop)
222			}
223		}
224	}
225}
226
227// Product variable properties need special handling, the type of the filtered product variable
228// property struct may not be identical between the defaults module and the defaultable module.
229// Use PrependMatchingProperties to apply whichever properties match.
230func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx BottomUpMutatorContext,
231	defaults Defaults, defaultableProp interface{}) {
232	if defaultableProp == nil {
233		return
234	}
235
236	defaultsProp := defaults.productVariableProperties()
237	if defaultsProp == nil {
238		return
239	}
240
241	dst := []interface{}{
242		defaultableProp,
243		// Put an empty copy of the src properties into dst so that properties in src that are not in dst
244		// don't cause a "failed to find property to extend" error.
245		proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
246	}
247
248	err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
249	if err != nil {
250		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
251			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
252		} else {
253			panic(err)
254		}
255	}
256}
257
258func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext,
259	defaults Defaults, defaultableProp interface{}) {
260
261	for _, def := range defaults.properties() {
262		if proptools.TypeEqual(defaultableProp, def) {
263			err := proptools.PrependProperties(defaultableProp, def, nil)
264			if err != nil {
265				if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
266					ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
267				} else {
268					panic(err)
269				}
270			}
271		}
272	}
273}
274
275func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
276	ctx.BottomUp("defaults_deps", defaultsDepsMutator)
277	ctx.BottomUp("defaults", defaultsMutator).UsesCreateModule()
278}
279
280func defaultsDepsMutator(ctx BottomUpMutatorContext) {
281	if defaultable, ok := ctx.Module().(Defaultable); ok {
282		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
283	}
284}
285
286func defaultsMutator(ctx BottomUpMutatorContext) {
287	if defaultable, ok := ctx.Module().(Defaultable); ok {
288		if _, isDefaultsModule := ctx.Module().(Defaults); isDefaultsModule {
289			// Don't squash transitive defaults into defaults modules
290			return
291		}
292		defaults := defaultable.defaults().Defaults
293		if len(defaults) > 0 {
294			var defaultsList []Defaults
295			seen := make(map[Defaults]bool)
296
297			ctx.WalkDeps(func(module, parent Module) bool {
298				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
299					if defaults, ok := module.(Defaults); ok {
300						if !seen[defaults] {
301							seen[defaults] = true
302							defaultsList = append(defaultsList, defaults)
303							return len(defaults.defaults().Defaults) > 0
304						}
305					} else {
306						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
307							ctx.OtherModuleName(module))
308					}
309				}
310				return false
311			})
312			defaultable.applyDefaults(ctx, defaultsList)
313		}
314
315		defaultable.CallHookIfAvailable(ctx)
316	}
317}
318