diff options
Diffstat (limited to 'android/defaults.go')
| -rw-r--r-- | android/defaults.go | 252 |
1 files changed, 213 insertions, 39 deletions
diff --git a/android/defaults.go b/android/defaults.go index d4fbf487d..81e340e8e 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -15,6 +15,8 @@ package android import ( + "reflect" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -30,22 +32,53 @@ type defaultsProperties struct { } type DefaultableModuleBase struct { - defaultsProperties defaultsProperties - defaultableProperties []interface{} + defaultsProperties defaultsProperties + defaultableProperties []interface{} + defaultableVariableProperties interface{} + + // The optional hook to call after any defaults have been applied. + hook DefaultableHook } func (d *DefaultableModuleBase) defaults() *defaultsProperties { return &d.defaultsProperties } -func (d *DefaultableModuleBase) setProperties(props []interface{}) { +func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) { d.defaultableProperties = props + d.defaultableVariableProperties = variableProperties } +func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) { + d.hook = hook +} + +func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) { + if d.hook != nil { + d.hook(ctx) + } +} + +// Interface that must be supported by any module to which defaults can be applied. type Defaultable interface { + // Get a pointer to the struct containing the Defaults property. defaults() *defaultsProperties - setProperties([]interface{}) + + // Set the property structures into which defaults will be added. + setProperties(props []interface{}, variableProperties interface{}) + + // Apply defaults from the supplied Defaults to the property structures supplied to + // setProperties(...). applyDefaults(TopDownMutatorContext, []Defaults) + + // Set the hook to be called after any defaults have been applied. + // + // Should be used in preference to a AddLoadHook when the behavior of the load + // hook is dependent on properties supplied in the Android.bp file. + SetDefaultableHook(hook DefaultableHook) + + // Call the hook if specified. + callHookIfAvailable(context DefaultableHookContext) } type DefaultableModule interface { @@ -56,42 +89,138 @@ type DefaultableModule interface { var _ Defaultable = (*DefaultableModuleBase)(nil) func InitDefaultableModule(module DefaultableModule) { - module.(Defaultable).setProperties(module.(Module).GetProperties()) + if module.(Module).base().module == nil { + panic("InitAndroidModule must be called before InitDefaultableModule") + } + module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties) module.AddProperties(module.defaults()) } +// A restricted subset of context methods, similar to LoadHookContext. +type DefaultableHookContext interface { + EarlyModuleContext + + CreateModule(ModuleFactory, ...interface{}) Module +} + +type DefaultableHook func(ctx DefaultableHookContext) + +// The Defaults_visibility property. +type DefaultsVisibilityProperties struct { + + // Controls the visibility of the defaults module itself. + Defaults_visibility []string +} + type DefaultsModuleBase struct { DefaultableModuleBase - defaultProperties []interface{} + + // Container for defaults of the common properties + commonProperties commonProperties + + defaultsVisibilityProperties DefaultsVisibilityProperties } +// The common pattern for defaults modules is to register separate instances of +// the xxxProperties structs in the AddProperties calls, rather than reusing the +// ones inherited from Module. +// +// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't +// contain the values that have been set for the defaults module. Rather, to +// retrieve the values it is necessary to iterate over properties(). E.g. to get +// the commonProperties instance that have the real values: +// +// d := myModule.(Defaults) +// for _, props := range d.properties() { +// if cp, ok := props.(*commonProperties); ok { +// ... access property values in cp ... +// } +// } +// +// The rationale is that the properties on a defaults module apply to the +// defaultable modules using it, not to the defaults module itself. E.g. setting +// the "enabled" property false makes inheriting modules disabled by default, +// rather than disabling the defaults module itself. type Defaults interface { Defaultable + + // Although this function is unused it is actually needed to ensure that only modules that embed + // DefaultsModuleBase will type-assert to the Defaults interface. isDefaults() bool + + // Get the structures containing the properties for which defaults can be provided. properties() []interface{} + + productVariableProperties() interface{} + + // Return the defaults common properties. + common() *commonProperties + + // Return the defaults visibility properties. + defaultsVisibility() *DefaultsVisibilityProperties } func (d *DefaultsModuleBase) isDefaults() bool { return true } +type DefaultsModule interface { + Module + Defaults +} + func (d *DefaultsModuleBase) properties() []interface{} { return d.defaultableProperties } -func InitDefaultsModule(module DefaultableModule) { +func (d *DefaultsModuleBase) productVariableProperties() interface{} { + return d.defaultableVariableProperties +} + +func (d *DefaultsModuleBase) common() *commonProperties { + return &d.commonProperties +} + +func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties { + return &d.defaultsVisibilityProperties +} + +func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) { +} + +func InitDefaultsModule(module DefaultsModule) { + commonProperties := module.common() + module.AddProperties( &hostAndDeviceProperties{}, - &commonProperties{}, - &variableProperties{}) + commonProperties, + &ApexProperties{}) + initAndroidModuleBase(module) + initProductVariableModule(module) InitArchModule(module) InitDefaultableModule(module) - module.AddProperties(&module.base().nameProperties) + // Add properties that will not have defaults applied to them. + base := module.base() + defaultsVisibility := module.defaultsVisibility() + module.AddProperties(&base.nameProperties, defaultsVisibility) + + // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties. + // Instead it is stored in a separate instance of commonProperties created above so clear the + // existing list of properties. + clearVisibilityProperties(module) + + // The defaults_visibility property controls the visibility of a defaults module so it must be + // set as the primary property, which also adds it to the list. + setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility) + + // The visibility property needs to be checked (but not parsed) by the visibility module during + // its checking phase and parsing phase so add it to the list as a normal property. + AddVisibilityProperty(module, "visibility", &commonProperties.Visibility) - module.base().module = module + base.module = module } var _ Defaults = (*DefaultsModuleBase)(nil) @@ -101,16 +230,57 @@ func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContex for _, defaults := range defaultsList { for _, prop := range defaultable.defaultableProperties { - for _, def := range defaults.properties() { - if proptools.TypeEqual(prop, def) { - err := proptools.PrependProperties(prop, def, nil) - if err != nil { - if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { - ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) - } else { - panic(err) - } - } + if prop == defaultable.defaultableVariableProperties { + defaultable.applyDefaultVariableProperties(ctx, defaults, prop) + } else { + defaultable.applyDefaultProperties(ctx, defaults, prop) + } + } + } +} + +// Product variable properties need special handling, the type of the filtered product variable +// property struct may not be identical between the defaults module and the defaultable module. +// Use PrependMatchingProperties to apply whichever properties match. +func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext, + defaults Defaults, defaultableProp interface{}) { + if defaultableProp == nil { + return + } + + defaultsProp := defaults.productVariableProperties() + if defaultsProp == nil { + return + } + + dst := []interface{}{ + defaultableProp, + // Put an empty copy of the src properties into dst so that properties in src that are not in dst + // don't cause a "failed to find property to extend" error. + proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(), + } + + err := proptools.PrependMatchingProperties(dst, defaultsProp, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } +} + +func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext, + defaults Defaults, defaultableProp interface{}) { + + for _, def := range defaults.properties() { + if proptools.TypeEqual(defaultableProp, def) { + err := proptools.PrependProperties(defaultableProp, def, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) } } } @@ -129,25 +299,29 @@ func defaultsDepsMutator(ctx BottomUpMutatorContext) { } func defaultsMutator(ctx TopDownMutatorContext) { - if defaultable, ok := ctx.Module().(Defaultable); ok && len(defaultable.defaults().Defaults) > 0 { - var defaultsList []Defaults - seen := make(map[Defaults]bool) - - ctx.WalkDeps(func(module, parent Module) bool { - if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag { - if defaults, ok := module.(Defaults); ok { - if !seen[defaults] { - seen[defaults] = true - defaultsList = append(defaultsList, defaults) - return len(defaults.defaults().Defaults) > 0 + if defaultable, ok := ctx.Module().(Defaultable); ok { + if len(defaultable.defaults().Defaults) > 0 { + var defaultsList []Defaults + seen := make(map[Defaults]bool) + + ctx.WalkDeps(func(module, parent Module) bool { + if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag { + if defaults, ok := module.(Defaults); ok { + if !seen[defaults] { + seen[defaults] = true + defaultsList = append(defaultsList, defaults) + return len(defaults.defaults().Defaults) > 0 + } + } else { + ctx.PropertyErrorf("defaults", "module %s is not an defaults module", + ctx.OtherModuleName(module)) } - } else { - ctx.PropertyErrorf("defaults", "module %s is not an defaults module", - ctx.OtherModuleName(module)) } - } - return false - }) - defaultable.applyDefaults(ctx, defaultsList) + return false + }) + defaultable.applyDefaults(ctx, defaultsList) + } + + defaultable.callHookIfAvailable(ctx) } } |