blob: 7906e946cb6c7ae242369f86b86772e6020d381a [file] [log] [blame]
Colin Crosscfad1192015-11-02 16:43:11 -08001// 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
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Colin Crosscfad1192015-11-02 16:43:11 -080016
17import (
Paul Duffin79996272022-05-04 11:39:52 +000018 "bytes"
19 "fmt"
Colin Crosseabaedd2020-02-06 17:01:55 -080020 "reflect"
21
Colin Crosscfad1192015-11-02 16:43:11 -080022 "github.com/google/blueprint"
23 "github.com/google/blueprint/proptools"
24)
25
Colin Crossc99deeb2016-04-11 15:06:20 -070026type defaultsDependencyTag struct {
27 blueprint.BaseDependencyTag
28}
29
30var DefaultsDepTag defaultsDependencyTag
31
Colin Crosscfad1192015-11-02 16:43:11 -080032type defaultsProperties struct {
33 Defaults []string
34}
35
Colin Cross1f44a3a2017-07-07 14:33:33 -070036type DefaultableModuleBase struct {
Colin Crosseabaedd2020-02-06 17:01:55 -080037 defaultsProperties defaultsProperties
38 defaultableProperties []interface{}
39 defaultableVariableProperties interface{}
Paul Duffinafa9fa12020-04-29 16:47:28 +010040
41 // The optional hook to call after any defaults have been applied.
42 hook DefaultableHook
Colin Crosscfad1192015-11-02 16:43:11 -080043}
44
Colin Cross1f44a3a2017-07-07 14:33:33 -070045func (d *DefaultableModuleBase) defaults() *defaultsProperties {
Colin Crosscfad1192015-11-02 16:43:11 -080046 return &d.defaultsProperties
47}
48
Colin Crosseabaedd2020-02-06 17:01:55 -080049func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
Colin Crosscfad1192015-11-02 16:43:11 -080050 d.defaultableProperties = props
Colin Crosseabaedd2020-02-06 17:01:55 -080051 d.defaultableVariableProperties = variableProperties
Colin Crosscfad1192015-11-02 16:43:11 -080052}
53
Paul Duffinafa9fa12020-04-29 16:47:28 +010054func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
55 d.hook = hook
56}
57
58func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
59 if d.hook != nil {
60 d.hook(ctx)
61 }
62}
63
Paul Duffin7df7fb02019-07-24 12:26:14 +010064// Interface that must be supported by any module to which defaults can be applied.
Colin Crosscfad1192015-11-02 16:43:11 -080065type Defaultable interface {
Paul Duffin7df7fb02019-07-24 12:26:14 +010066 // Get a pointer to the struct containing the Defaults property.
Colin Crosscfad1192015-11-02 16:43:11 -080067 defaults() *defaultsProperties
Paul Duffin7df7fb02019-07-24 12:26:14 +010068
69 // Set the property structures into which defaults will be added.
Colin Crosseabaedd2020-02-06 17:01:55 -080070 setProperties(props []interface{}, variableProperties interface{})
Paul Duffin7df7fb02019-07-24 12:26:14 +010071
Paul Duffin79996272022-05-04 11:39:52 +000072 // Apply defaults from the supplied DefaultsModule to the property structures supplied to
Paul Duffin7df7fb02019-07-24 12:26:14 +010073 // setProperties(...).
Paul Duffin79996272022-05-04 11:39:52 +000074 applyDefaults(TopDownMutatorContext, []DefaultsModule)
75
76 applySingleDefaultsWithTracker(EarlyModuleContext, DefaultsModule, defaultsTrackerFunc)
Paul Duffinafa9fa12020-04-29 16:47:28 +010077
78 // Set the hook to be called after any defaults have been applied.
79 //
80 // Should be used in preference to a AddLoadHook when the behavior of the load
81 // hook is dependent on properties supplied in the Android.bp file.
82 SetDefaultableHook(hook DefaultableHook)
83
84 // Call the hook if specified.
85 callHookIfAvailable(context DefaultableHookContext)
Colin Crosscfad1192015-11-02 16:43:11 -080086}
87
Colin Cross1f44a3a2017-07-07 14:33:33 -070088type DefaultableModule interface {
89 Module
90 Defaultable
Colin Crosscfad1192015-11-02 16:43:11 -080091}
92
Colin Cross1f44a3a2017-07-07 14:33:33 -070093var _ Defaultable = (*DefaultableModuleBase)(nil)
94
95func InitDefaultableModule(module DefaultableModule) {
Ustafe201fe2021-12-06 15:13:36 -050096 if module.base().module == nil {
Colin Crosseabaedd2020-02-06 17:01:55 -080097 panic("InitAndroidModule must be called before InitDefaultableModule")
98 }
Liz Kammer416201d2021-12-15 13:18:42 -050099
Ustafe201fe2021-12-06 15:13:36 -0500100 module.setProperties(module.GetProperties(), module.base().variableProperties)
Colin Cross1f44a3a2017-07-07 14:33:33 -0700101
102 module.AddProperties(module.defaults())
103}
104
Paul Duffinafa9fa12020-04-29 16:47:28 +0100105// A restricted subset of context methods, similar to LoadHookContext.
106type DefaultableHookContext interface {
107 EarlyModuleContext
108
109 CreateModule(ModuleFactory, ...interface{}) Module
Colin Cross18f840c2021-05-20 17:56:54 -0700110 AddMissingDependencies(missingDeps []string)
Paul Duffinafa9fa12020-04-29 16:47:28 +0100111}
112
113type DefaultableHook func(ctx DefaultableHookContext)
114
Paul Duffin95d53b52019-07-24 13:45:05 +0100115// The Defaults_visibility property.
116type DefaultsVisibilityProperties struct {
117
118 // Controls the visibility of the defaults module itself.
119 Defaults_visibility []string
120}
121
Paul Duffin79996272022-05-04 11:39:52 +0000122// AdditionalDefaultsProperties contains properties of defaults modules which
123// can have other defaults applied.
124type AdditionalDefaultsProperties struct {
125
126 // The list of properties set by the default whose values must not be changed by any module that
127 // applies these defaults. It is an error if a property is not supported by the defaults module or
128 // has not been set to a non-zero value. If this contains "*" then that must be the only entry in
129 // which case all properties that are set on this defaults will be protected (except the
130 // protected_properties and visibility.
131 Protected_properties []string
132}
133
Colin Cross1f44a3a2017-07-07 14:33:33 -0700134type DefaultsModuleBase struct {
135 DefaultableModuleBase
Liz Kammer416201d2021-12-15 13:18:42 -0500136
Paul Duffin79996272022-05-04 11:39:52 +0000137 defaultsProperties AdditionalDefaultsProperties
138
Liz Kammer416201d2021-12-15 13:18:42 -0500139 // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
140 // target. This is primarily useful for modules that were architecture specific and instead are
141 // handled in Bazel as a select().
142 BazelModuleBase
Colin Crosscfad1192015-11-02 16:43:11 -0800143}
144
Martin Stjernholmebd757d2019-05-24 11:00:30 +0100145// The common pattern for defaults modules is to register separate instances of
146// the xxxProperties structs in the AddProperties calls, rather than reusing the
147// ones inherited from Module.
148//
149// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
150// contain the values that have been set for the defaults module. Rather, to
151// retrieve the values it is necessary to iterate over properties(). E.g. to get
152// the commonProperties instance that have the real values:
153//
Colin Crossd079e0b2022-08-16 10:27:33 -0700154// d := myModule.(Defaults)
155// for _, props := range d.properties() {
156// if cp, ok := props.(*commonProperties); ok {
157// ... access property values in cp ...
158// }
159// }
Martin Stjernholmebd757d2019-05-24 11:00:30 +0100160//
161// The rationale is that the properties on a defaults module apply to the
162// defaultable modules using it, not to the defaults module itself. E.g. setting
163// the "enabled" property false makes inheriting modules disabled by default,
164// rather than disabling the defaults module itself.
Colin Crosscfad1192015-11-02 16:43:11 -0800165type Defaults interface {
Colin Crosse7b07132016-07-27 10:15:06 -0700166 Defaultable
Paul Duffin7df7fb02019-07-24 12:26:14 +0100167
168 // Although this function is unused it is actually needed to ensure that only modules that embed
169 // DefaultsModuleBase will type-assert to the Defaults interface.
Colin Crosscfad1192015-11-02 16:43:11 -0800170 isDefaults() bool
Paul Duffin7df7fb02019-07-24 12:26:14 +0100171
Paul Duffin79996272022-05-04 11:39:52 +0000172 // additionalDefaultableProperties returns additional properties provided by the defaults which
173 // can themselves have defaults applied.
174 additionalDefaultableProperties() []interface{}
175
176 // protectedProperties returns the names of the properties whose values cannot be changed by a
177 // module that applies these defaults.
178 protectedProperties() []string
179
180 // setProtectedProperties sets the names of the properties whose values cannot be changed by a
181 // module that applies these defaults.
182 setProtectedProperties(protectedProperties []string)
183
Paul Duffin7df7fb02019-07-24 12:26:14 +0100184 // Get the structures containing the properties for which defaults can be provided.
Colin Crosscfad1192015-11-02 16:43:11 -0800185 properties() []interface{}
Paul Duffin63c6e182019-07-24 14:24:38 +0100186
Colin Crosseabaedd2020-02-06 17:01:55 -0800187 productVariableProperties() interface{}
Colin Crosscfad1192015-11-02 16:43:11 -0800188}
189
Colin Cross1f44a3a2017-07-07 14:33:33 -0700190func (d *DefaultsModuleBase) isDefaults() bool {
Colin Crosscfad1192015-11-02 16:43:11 -0800191 return true
192}
193
Paul Duffine62432f2019-07-24 12:51:21 +0100194type DefaultsModule interface {
195 Module
196 Defaults
Liz Kammer416201d2021-12-15 13:18:42 -0500197 Bazelable
Paul Duffine62432f2019-07-24 12:51:21 +0100198}
199
Paul Duffin79996272022-05-04 11:39:52 +0000200func (d *DefaultsModuleBase) additionalDefaultableProperties() []interface{} {
201 return []interface{}{&d.defaultsProperties}
202}
203
204func (d *DefaultsModuleBase) protectedProperties() []string {
205 return d.defaultsProperties.Protected_properties
206}
207
208func (d *DefaultsModuleBase) setProtectedProperties(protectedProperties []string) {
209 d.defaultsProperties.Protected_properties = protectedProperties
210}
211
Colin Cross1f44a3a2017-07-07 14:33:33 -0700212func (d *DefaultsModuleBase) properties() []interface{} {
Colin Crosse7b07132016-07-27 10:15:06 -0700213 return d.defaultableProperties
Colin Crosscfad1192015-11-02 16:43:11 -0800214}
215
Colin Crosseabaedd2020-02-06 17:01:55 -0800216func (d *DefaultsModuleBase) productVariableProperties() interface{} {
217 return d.defaultableVariableProperties
218}
219
Liz Kammer416201d2021-12-15 13:18:42 -0500220func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
Colin Cross59037622019-06-10 13:12:56 -0700221
Liz Kammerbe46fcc2021-11-01 15:32:43 -0400222// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
223// *NOT* converted with bp2build
224func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {}
225
Paul Duffine62432f2019-07-24 12:51:21 +0100226func InitDefaultsModule(module DefaultsModule) {
Paul Duffin3f98d142020-09-02 13:28:25 +0100227 commonProperties := &commonProperties{}
Paul Duffin63c6e182019-07-24 14:24:38 +0100228
Colin Cross36242852017-06-23 15:06:31 -0700229 module.AddProperties(
Colin Crossfc754582016-05-17 16:34:16 -0700230 &hostAndDeviceProperties{},
Paul Duffin63c6e182019-07-24 14:24:38 +0100231 commonProperties,
Paul Duffined875132020-09-02 13:08:57 +0100232 &ApexProperties{},
233 &distProperties{})
Colin Crossfc754582016-05-17 16:34:16 -0700234
Paul Duffin79996272022-05-04 11:39:52 +0000235 // Additional properties of defaults modules that can themselves have
236 // defaults applied.
237 module.AddProperties(module.additionalDefaultableProperties()...)
238
Liz Kammer416201d2021-12-15 13:18:42 -0500239 // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
240 InitBazelModule(module)
Colin Crosseabaedd2020-02-06 17:01:55 -0800241 initAndroidModuleBase(module)
242 initProductVariableModule(module)
Colin Crossa6845402020-11-16 15:08:19 -0800243 initArchModule(module)
Colin Cross1f44a3a2017-07-07 14:33:33 -0700244 InitDefaultableModule(module)
Colin Crossfc754582016-05-17 16:34:16 -0700245
Paul Duffin7df7fb02019-07-24 12:26:14 +0100246 // Add properties that will not have defaults applied to them.
Colin Cross08d6f8f2020-11-19 02:33:19 +0000247 base := module.base()
Paul Duffin3f98d142020-09-02 13:28:25 +0100248 defaultsVisibility := &DefaultsVisibilityProperties{}
Paul Duffin95d53b52019-07-24 13:45:05 +0100249 module.AddProperties(&base.nameProperties, defaultsVisibility)
Colin Crossfc754582016-05-17 16:34:16 -0700250
Paul Duffin63c6e182019-07-24 14:24:38 +0100251 // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
Paul Duffin5ec73ec2020-05-01 17:52:01 +0100252 // Instead it is stored in a separate instance of commonProperties created above so clear the
253 // existing list of properties.
254 clearVisibilityProperties(module)
255
256 // The defaults_visibility property controls the visibility of a defaults module so it must be
257 // set as the primary property, which also adds it to the list.
258 setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
259
Paul Duffin63c6e182019-07-24 14:24:38 +0100260 // The visibility property needs to be checked (but not parsed) by the visibility module during
Paul Duffin5ec73ec2020-05-01 17:52:01 +0100261 // its checking phase and parsing phase so add it to the list as a normal property.
262 AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
Paul Duffin63c6e182019-07-24 14:24:38 +0100263
Bob Badour37af0462021-01-07 03:34:31 +0000264 // The applicable licenses property for defaults is 'licenses'.
265 setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses)
266
Paul Duffin79996272022-05-04 11:39:52 +0000267 AddLoadHook(module, func(ctx LoadHookContext) {
268
269 protectedProperties := module.protectedProperties()
270 if len(protectedProperties) == 0 {
271 return
272 }
273
274 propertiesAvailable := map[string]struct{}{}
275 propertiesSet := map[string]struct{}{}
276
277 // A defaults tracker which will keep track of which properties have been set on this module.
278 collector := func(defaults DefaultsModule, property string, dstValue interface{}, srcValue interface{}) bool {
279 value := reflect.ValueOf(dstValue)
280 propertiesAvailable[property] = struct{}{}
281 if !value.IsZero() {
282 propertiesSet[property] = struct{}{}
283 }
284 // Skip all the properties so that there are no changes to the defaults.
285 return false
286 }
287
288 // Try and apply this module's defaults to itself, so that the properties can be collected but
289 // skip all the properties so it doesn't actually do anything.
290 module.applySingleDefaultsWithTracker(ctx, module, collector)
291
292 if InList("*", protectedProperties) {
293 if len(protectedProperties) != 1 {
294 ctx.PropertyErrorf("protected_properties", `if specified then "*" must be the only property listed`)
295 return
296 }
297
298 // Do not automatically protect the protected_properties property.
299 delete(propertiesSet, "protected_properties")
300
301 // Or the visibility property.
302 delete(propertiesSet, "visibility")
303
304 // Replace the "*" with the names of all the properties that have been set.
305 protectedProperties = SortedStringKeys(propertiesSet)
306 module.setProtectedProperties(protectedProperties)
307 } else {
308 for _, property := range protectedProperties {
309 if _, ok := propertiesAvailable[property]; !ok {
310 ctx.PropertyErrorf(property, "property is not supported by this module type %q",
311 ctx.ModuleType())
312 } else if _, ok := propertiesSet[property]; !ok {
313 ctx.PropertyErrorf(property, "is not set; protected properties must be explicitly set")
314 }
315 }
316 }
317 })
Colin Crosscfad1192015-11-02 16:43:11 -0800318}
319
Colin Cross1f44a3a2017-07-07 14:33:33 -0700320var _ Defaults = (*DefaultsModuleBase)(nil)
Colin Crosscfad1192015-11-02 16:43:11 -0800321
Jingwen Chen84817de2021-11-17 10:57:35 +0000322// applyNamespacedVariableDefaults only runs in bp2build mode for
323// defaultable/defaults modules. Its purpose is to merge namespaced product
324// variable props from defaults deps, even if those defaults are custom module
325// types created from soong_config_module_type, e.g. one that's wrapping a
326// cc_defaults or java_defaults.
327func applyNamespacedVariableDefaults(defaultDep Defaults, ctx TopDownMutatorContext) {
328 var dep, b Bazelable
329
330 dep, ok := defaultDep.(Bazelable)
331 if !ok {
332 if depMod, ok := defaultDep.(Module); ok {
333 // Track that this dependency hasn't been converted to bp2build yet.
334 ctx.AddUnconvertedBp2buildDep(depMod.Name())
335 return
336 } else {
337 panic("Expected default dep to be a Module.")
338 }
339 }
340
341 b, ok = ctx.Module().(Bazelable)
342 if !ok {
343 return
344 }
345
346 // namespacedVariableProps is a map from namespaces (e.g. acme, android,
347 // vendor_foo) to a slice of soong_config_variable struct pointers,
348 // containing properties for that particular module.
349 src := dep.namespacedVariableProps()
350 dst := b.namespacedVariableProps()
351 if dst == nil {
352 dst = make(namespacedVariableProperties)
353 }
354
355 // Propagate all soong_config_variable structs from the dep. We'll merge the
356 // actual property values later in variable.go.
357 for namespace := range src {
358 if dst[namespace] == nil {
359 dst[namespace] = []interface{}{}
360 }
361 for _, i := range src[namespace] {
362 dst[namespace] = append(dst[namespace], i)
363 }
364 }
365
366 b.setNamespacedVariableProps(dst)
367}
368
Paul Duffin79996272022-05-04 11:39:52 +0000369// defaultValueInfo contains information about each default value that applies to a protected
370// property.
371type defaultValueInfo struct {
372 // The DefaultsModule providing the value, which may be defined on that module or applied as a
373 // default from other modules.
374 module Module
375
376 // The default value, as returned by getComparableValue
377 defaultValue reflect.Value
378}
379
380// protectedPropertyInfo contains information about each property that has to be protected when
381// applying defaults.
382type protectedPropertyInfo struct {
383 // True if the property was set on the module to which defaults are applied, this is an error.
384 propertySet bool
385
386 // The original value of the property on the module, as returned by getComparableValue.
387 originalValue reflect.Value
388
389 // A list of defaults for the property that are being applied.
390 defaultValues []defaultValueInfo
391}
392
393// getComparableValue takes a reflect.Value that may be a pointer to another value and returns a
394// reflect.Value to the underlying data or the original if was not a pointer or was nil. The
395// returned values can then be compared for equality.
396func getComparableValue(value reflect.Value) reflect.Value {
397 if value.IsZero() {
398 return value
399 }
400 for value.Kind() == reflect.Ptr {
401 value = value.Elem()
402 }
403 return value
404}
405
Colin Cross1f44a3a2017-07-07 14:33:33 -0700406func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
Paul Duffin79996272022-05-04 11:39:52 +0000407 defaultsList []DefaultsModule) {
408
409 // Collate information on all the properties protected by each of the default modules applied
410 // to this module.
411 allProtectedProperties := map[string]*protectedPropertyInfo{}
412 for _, defaults := range defaultsList {
413 for _, property := range defaults.protectedProperties() {
414 info := allProtectedProperties[property]
415 if info == nil {
416 info = &protectedPropertyInfo{}
417 allProtectedProperties[property] = info
418 }
419 }
420 }
421
422 // If there are any protected properties then collate information about attempts to change them.
423 var protectedPropertyInfoCollector defaultsTrackerFunc
424 if len(allProtectedProperties) > 0 {
425 protectedPropertyInfoCollector = func(defaults DefaultsModule, property string,
426 dstValue interface{}, srcValue interface{}) bool {
427
428 // If the property is not protected then return immediately.
429 info := allProtectedProperties[property]
430 if info == nil {
431 return true
432 }
433
434 currentValue := reflect.ValueOf(dstValue)
435 if info.defaultValues == nil {
436 info.propertySet = !currentValue.IsZero()
437 info.originalValue = getComparableValue(currentValue)
438 }
439
440 defaultValue := reflect.ValueOf(srcValue)
441 if !defaultValue.IsZero() {
442 info.defaultValues = append(info.defaultValues,
443 defaultValueInfo{defaults, getComparableValue(defaultValue)})
444 }
445
446 return true
447 }
448 }
Colin Crosscfad1192015-11-02 16:43:11 -0800449
Colin Cross13177012016-08-09 12:00:45 -0700450 for _, defaults := range defaultsList {
Chris Parsonsad876012022-08-20 14:48:32 -0400451 if ctx.Config().BuildMode == Bp2build {
Jingwen Chen84817de2021-11-17 10:57:35 +0000452 applyNamespacedVariableDefaults(defaults, ctx)
453 }
Paul Duffin79996272022-05-04 11:39:52 +0000454
455 defaultable.applySingleDefaultsWithTracker(ctx, defaults, protectedPropertyInfoCollector)
456 }
457
458 // Check the status of any protected properties.
459 for property, info := range allProtectedProperties {
460 if len(info.defaultValues) == 0 {
461 // No defaults were applied to the protected properties. Possibly because this module type
462 // does not support any of them.
463 continue
464 }
465
466 // Check to make sure that there are no conflicts between the defaults.
467 conflictingDefaults := false
468 previousDefaultValue := reflect.ValueOf(false)
469 for _, defaultInfo := range info.defaultValues {
470 defaultValue := defaultInfo.defaultValue
471 if previousDefaultValue.IsZero() {
472 previousDefaultValue = defaultValue
473 } else if !reflect.DeepEqual(previousDefaultValue.Interface(), defaultValue.Interface()) {
474 conflictingDefaults = true
475 break
Colin Crosseabaedd2020-02-06 17:01:55 -0800476 }
477 }
Paul Duffin79996272022-05-04 11:39:52 +0000478
479 if conflictingDefaults {
480 var buf bytes.Buffer
481 for _, defaultInfo := range info.defaultValues {
482 buf.WriteString(fmt.Sprintf("\n defaults module %q provides value %#v",
483 ctx.OtherModuleName(defaultInfo.module), defaultInfo.defaultValue))
484 }
485 result := buf.String()
486 ctx.ModuleErrorf("has conflicting default values for protected property %q:%s", property, result)
487 continue
488 }
489
490 // Now check to see whether there the current module tried to override/append to the defaults.
491 if info.propertySet {
492 originalValue := info.originalValue
493 // Just compare against the first defaults.
494 defaultValue := info.defaultValues[0].defaultValue
495 defaults := info.defaultValues[0].module
496
497 if originalValue.Kind() == reflect.Slice {
498 ctx.ModuleErrorf("attempts to append %q to protected property %q's value of %q defined in module %q",
499 originalValue,
500 property,
501 defaultValue,
502 ctx.OtherModuleName(defaults))
503 } else {
504 same := reflect.DeepEqual(originalValue.Interface(), defaultValue.Interface())
505 message := ""
506 if same {
507 message = fmt.Sprintf(" with a matching value (%#v) so this property can simply be removed.", originalValue)
508 } else {
509 message = fmt.Sprintf(" with a different value (override %#v with %#v) so removing the property may necessitate other changes.", defaultValue, originalValue)
510 }
511 ctx.ModuleErrorf("attempts to override protected property %q defined in module %q%s",
512 property,
513 ctx.OtherModuleName(defaults), message)
514 }
515 }
516 }
517}
518
519func (defaultable *DefaultableModuleBase) applySingleDefaultsWithTracker(ctx EarlyModuleContext, defaults DefaultsModule, tracker defaultsTrackerFunc) {
520 for _, prop := range defaultable.defaultableProperties {
521 var err error
522 if prop == defaultable.defaultableVariableProperties {
523 err = defaultable.applyDefaultVariableProperties(defaults, prop, tracker)
524 } else {
525 err = defaultable.applyDefaultProperties(defaults, prop, tracker)
526 }
527 if err != nil {
528 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
529 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
530 } else {
531 panic(err)
532 }
533 }
534 }
535}
536
537// defaultsTrackerFunc is the type of a function that can be used to track how defaults are applied.
538type defaultsTrackerFunc func(defaults DefaultsModule, property string,
539 dstValue interface{}, srcValue interface{}) bool
540
541// filterForTracker wraps a defaultsTrackerFunc in a proptools.ExtendPropertyFilterFunc
542func filterForTracker(defaults DefaultsModule, tracker defaultsTrackerFunc) proptools.ExtendPropertyFilterFunc {
543 if tracker == nil {
544 return nil
545 }
546 return func(property string,
547 dstField, srcField reflect.StructField,
548 dstValue, srcValue interface{}) (bool, error) {
549
550 apply := tracker(defaults, property, dstValue, srcValue)
551 return apply, nil
Colin Crosseabaedd2020-02-06 17:01:55 -0800552 }
553}
554
555// Product variable properties need special handling, the type of the filtered product variable
556// property struct may not be identical between the defaults module and the defaultable module.
557// Use PrependMatchingProperties to apply whichever properties match.
Paul Duffin79996272022-05-04 11:39:52 +0000558func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(defaults DefaultsModule,
559 defaultableProp interface{}, tracker defaultsTrackerFunc) error {
Colin Crosseabaedd2020-02-06 17:01:55 -0800560 if defaultableProp == nil {
Paul Duffin79996272022-05-04 11:39:52 +0000561 return nil
Colin Crosseabaedd2020-02-06 17:01:55 -0800562 }
563
564 defaultsProp := defaults.productVariableProperties()
565 if defaultsProp == nil {
Paul Duffin79996272022-05-04 11:39:52 +0000566 return nil
Colin Crosseabaedd2020-02-06 17:01:55 -0800567 }
568
569 dst := []interface{}{
570 defaultableProp,
571 // Put an empty copy of the src properties into dst so that properties in src that are not in dst
572 // don't cause a "failed to find property to extend" error.
573 proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
574 }
575
Paul Duffin79996272022-05-04 11:39:52 +0000576 filter := filterForTracker(defaults, tracker)
577
578 return proptools.PrependMatchingProperties(dst, defaultsProp, filter)
Colin Crosseabaedd2020-02-06 17:01:55 -0800579}
580
Paul Duffin79996272022-05-04 11:39:52 +0000581func (defaultable *DefaultableModuleBase) applyDefaultProperties(defaults DefaultsModule,
582 defaultableProp interface{}, checker defaultsTrackerFunc) error {
583
584 filter := filterForTracker(defaults, checker)
Colin Crosseabaedd2020-02-06 17:01:55 -0800585
586 for _, def := range defaults.properties() {
587 if proptools.TypeEqual(defaultableProp, def) {
Paul Duffin79996272022-05-04 11:39:52 +0000588 err := proptools.PrependProperties(defaultableProp, def, filter)
Colin Crosseabaedd2020-02-06 17:01:55 -0800589 if err != nil {
Paul Duffin79996272022-05-04 11:39:52 +0000590 return err
Colin Crosscfad1192015-11-02 16:43:11 -0800591 }
592 }
593 }
Paul Duffin79996272022-05-04 11:39:52 +0000594
595 return nil
Colin Crosscfad1192015-11-02 16:43:11 -0800596}
597
Colin Cross89536d42017-07-07 14:35:50 -0700598func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
Colin Crosscec81712017-07-13 14:43:27 -0700599 ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
600 ctx.TopDown("defaults", defaultsMutator).Parallel()
601}
602
Colin Cross635c3b02016-05-18 15:37:25 -0700603func defaultsDepsMutator(ctx BottomUpMutatorContext) {
Colin Crosscfad1192015-11-02 16:43:11 -0800604 if defaultable, ok := ctx.Module().(Defaultable); ok {
Colin Crossc99deeb2016-04-11 15:06:20 -0700605 ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
Colin Crosscfad1192015-11-02 16:43:11 -0800606 }
607}
608
Colin Cross13177012016-08-09 12:00:45 -0700609func defaultsMutator(ctx TopDownMutatorContext) {
Paul Duffinafa9fa12020-04-29 16:47:28 +0100610 if defaultable, ok := ctx.Module().(Defaultable); ok {
611 if len(defaultable.defaults().Defaults) > 0 {
Paul Duffin79996272022-05-04 11:39:52 +0000612 var defaultsList []DefaultsModule
Paul Duffinafa9fa12020-04-29 16:47:28 +0100613 seen := make(map[Defaults]bool)
Colin Crossa1ce2a02018-06-20 15:19:39 -0700614
Paul Duffinafa9fa12020-04-29 16:47:28 +0100615 ctx.WalkDeps(func(module, parent Module) bool {
616 if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
Paul Duffin79996272022-05-04 11:39:52 +0000617 if defaults, ok := module.(DefaultsModule); ok {
Paul Duffinafa9fa12020-04-29 16:47:28 +0100618 if !seen[defaults] {
619 seen[defaults] = true
620 defaultsList = append(defaultsList, defaults)
621 return len(defaults.defaults().Defaults) > 0
622 }
623 } else {
624 ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
625 ctx.OtherModuleName(module))
Colin Crossa1ce2a02018-06-20 15:19:39 -0700626 }
Colin Crosscfad1192015-11-02 16:43:11 -0800627 }
Paul Duffinafa9fa12020-04-29 16:47:28 +0100628 return false
629 })
630 defaultable.applyDefaults(ctx, defaultsList)
631 }
632
633 defaultable.callHookIfAvailable(ctx)
Colin Crosscfad1192015-11-02 16:43:11 -0800634 }
635}