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 &baseProperties{}, 182 &ApexProperties{}, 183 &distProperties{}) 184 185 initAndroidModuleBase(module) 186 initProductVariableModule(module) 187 initArchModule(module) 188 InitDefaultableModule(module) 189 190 // Add properties that will not have defaults applied to them. 191 base := module.base() 192 defaultsVisibility := &DefaultsVisibilityProperties{} 193 module.AddProperties(&base.nameProperties, defaultsVisibility) 194 195 // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties. 196 // Instead it is stored in a separate instance of commonProperties created above so clear the 197 // existing list of properties. 198 clearVisibilityProperties(module) 199 200 // The defaults_visibility property controls the visibility of a defaults module so it must be 201 // set as the primary property, which also adds it to the list. 202 setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility) 203 204 // The visibility property needs to be checked (but not parsed) by the visibility module during 205 // its checking phase and parsing phase so add it to the list as a normal property. 206 AddVisibilityProperty(module, "visibility", &commonProperties.Visibility) 207 208 // The applicable licenses property for defaults is 'licenses'. 209 setPrimaryLicensesProperty(module, "licenses", &commonProperties.Licenses) 210} 211 212var _ Defaults = (*DefaultsModuleBase)(nil) 213 214func (defaultable *DefaultableModuleBase) applyDefaults(ctx BottomUpMutatorContext, 215 defaultsList []Defaults) { 216 217 for _, defaults := range defaultsList { 218 for _, prop := range defaultable.defaultableProperties { 219 if prop == defaultable.defaultableVariableProperties { 220 defaultable.applyDefaultVariableProperties(ctx, defaults, prop) 221 } else { 222 defaultable.applyDefaultProperties(ctx, defaults, prop) 223 } 224 } 225 } 226} 227 228// Product variable properties need special handling, the type of the filtered product variable 229// property struct may not be identical between the defaults module and the defaultable module. 230// Use PrependMatchingProperties to apply whichever properties match. 231func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx BottomUpMutatorContext, 232 defaults Defaults, defaultableProp interface{}) { 233 if defaultableProp == nil { 234 return 235 } 236 237 defaultsProp := defaults.productVariableProperties() 238 if defaultsProp == nil { 239 return 240 } 241 242 dst := []interface{}{ 243 defaultableProp, 244 // Put an empty copy of the src properties into dst so that properties in src that are not in dst 245 // don't cause a "failed to find property to extend" error. 246 proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(), 247 } 248 249 err := proptools.PrependMatchingProperties(dst, defaultsProp, nil) 250 if err != nil { 251 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 252 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 253 } else { 254 panic(err) 255 } 256 } 257} 258 259func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx BottomUpMutatorContext, 260 defaults Defaults, defaultableProp interface{}) { 261 262 for _, def := range defaults.properties() { 263 if proptools.TypeEqual(defaultableProp, def) { 264 err := proptools.PrependProperties(defaultableProp, def, nil) 265 if err != nil { 266 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 267 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 268 } else { 269 panic(err) 270 } 271 } 272 } 273 } 274} 275 276func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) { 277 ctx.BottomUp("defaults_deps", defaultsDepsMutator) 278 ctx.BottomUp("defaults", defaultsMutator).UsesCreateModule() 279} 280 281func defaultsDepsMutator(ctx BottomUpMutatorContext) { 282 if defaultable, ok := ctx.Module().(Defaultable); ok { 283 ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...) 284 } 285} 286 287func defaultsMutator(ctx BottomUpMutatorContext) { 288 if defaultable, ok := ctx.Module().(Defaultable); ok { 289 if _, isDefaultsModule := ctx.Module().(Defaults); isDefaultsModule { 290 // Don't squash transitive defaults into defaults modules 291 return 292 } 293 defaults := defaultable.defaults().Defaults 294 if len(defaults) > 0 { 295 var defaultsList []Defaults 296 seen := make(map[Defaults]bool) 297 298 ctx.WalkDeps(func(module, parent Module) bool { 299 if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag { 300 if defaults, ok := module.(Defaults); ok { 301 if !seen[defaults] { 302 seen[defaults] = true 303 defaultsList = append(defaultsList, defaults) 304 return len(defaults.defaults().Defaults) > 0 305 } 306 } else { 307 ctx.PropertyErrorf("defaults", "module %s is not an defaults module", 308 ctx.OtherModuleName(module)) 309 } 310 } 311 return false 312 }) 313 defaultable.applyDefaults(ctx, defaultsList) 314 } 315 316 defaultable.CallHookIfAvailable(ctx) 317 } 318} 319