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