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 "fmt" 19 "reflect" 20 "runtime" 21 "strings" 22 23 "github.com/google/blueprint/proptools" 24) 25 26func init() { 27 PreDepsMutators(func(ctx RegisterMutatorsContext) { 28 ctx.BottomUp("variable", variableMutator).Parallel() 29 }) 30} 31 32type variableProperties struct { 33 Product_variables struct { 34 Platform_sdk_version struct { 35 Asflags []string 36 } 37 38 // unbundled_build is a catch-all property to annotate modules that don't build in one or 39 // more unbundled branches, usually due to dependencies missing from the manifest. 40 Unbundled_build struct { 41 Enabled *bool `android:"arch_variant"` 42 } `android:"arch_variant"` 43 44 Brillo struct { 45 Cflags []string 46 Version_script *string `android:"arch_variant"` 47 } `android:"arch_variant"` 48 49 Malloc_not_svelte struct { 50 Cflags []string 51 } 52 53 Safestack struct { 54 Cflags []string `android:"arch_variant"` 55 } `android:"arch_variant"` 56 57 Binder32bit struct { 58 Cflags []string 59 } 60 61 // treble is true when a build is a Treble compliant device. This is automatically set when 62 // a build is shipped with Android O, but can be overriden. This controls such things as 63 // the sepolicy split and enabling the Treble linker namespaces. 64 Treble struct { 65 Cflags []string 66 } 67 68 Override_rs_driver struct { 69 Cflags []string 70 } 71 72 // debuggable is true for eng and userdebug builds, and can be used to turn on additional 73 // debugging features that don't significantly impact runtime behavior. userdebug builds 74 // are used for dogfooding and performance testing, and should be as similar to user builds 75 // as possible. 76 Debuggable struct { 77 Cflags []string 78 Cppflags []string 79 Init_rc []string 80 } 81 82 // eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging 83 // features. 84 Eng struct { 85 Cflags []string 86 Cppflags []string 87 } 88 } `android:"arch_variant"` 89} 90 91var zeroProductVariables variableProperties 92 93type productVariables struct { 94 // Suffix to add to generated Makefiles 95 Make_suffix *string `json:",omitempty"` 96 97 Platform_sdk_version *int `json:",omitempty"` 98 99 DeviceName *string `json:",omitempty"` 100 DeviceArch *string `json:",omitempty"` 101 DeviceArchVariant *string `json:",omitempty"` 102 DeviceCpuVariant *string `json:",omitempty"` 103 DeviceAbi *[]string `json:",omitempty"` 104 DeviceUsesClang *bool `json:",omitempty"` 105 DeviceVndkVersion *string `json:",omitempty"` 106 107 DeviceSecondaryArch *string `json:",omitempty"` 108 DeviceSecondaryArchVariant *string `json:",omitempty"` 109 DeviceSecondaryCpuVariant *string `json:",omitempty"` 110 DeviceSecondaryAbi *[]string `json:",omitempty"` 111 112 HostArch *string `json:",omitempty"` 113 HostSecondaryArch *string `json:",omitempty"` 114 115 CrossHost *string `json:",omitempty"` 116 CrossHostArch *string `json:",omitempty"` 117 CrossHostSecondaryArch *string `json:",omitempty"` 118 119 Allow_missing_dependencies *bool `json:",omitempty"` 120 Unbundled_build *bool `json:",omitempty"` 121 Brillo *bool `json:",omitempty"` 122 Malloc_not_svelte *bool `json:",omitempty"` 123 Safestack *bool `json:",omitempty"` 124 HostStaticBinaries *bool `json:",omitempty"` 125 Binder32bit *bool `json:",omitempty"` 126 UseGoma *bool `json:",omitempty"` 127 Debuggable *bool `json:",omitempty"` 128 Eng *bool `json:",omitempty"` 129 EnableCFI *bool `json:",omitempty"` 130 Treble *bool `json:",omitempty"` 131 132 VendorPath *string `json:",omitempty"` 133 134 ClangTidy *bool `json:",omitempty"` 135 TidyChecks *string `json:",omitempty"` 136 137 NativeCoverage *bool `json:",omitempty"` 138 CoveragePaths *[]string `json:",omitempty"` 139 CoverageExcludePaths *[]string `json:",omitempty"` 140 141 DevicePrefer32BitExecutables *bool `json:",omitempty"` 142 HostPrefer32BitExecutables *bool `json:",omitempty"` 143 144 SanitizeHost []string `json:",omitempty"` 145 SanitizeDevice []string `json:",omitempty"` 146 SanitizeDeviceArch []string `json:",omitempty"` 147 148 ArtUseReadBarrier *bool `json:",omitempty"` 149 150 BtConfigIncludeDir *string `json:",omitempty"` 151 152 Override_rs_driver *string `json:",omitempty"` 153} 154 155func boolPtr(v bool) *bool { 156 return &v 157} 158 159func intPtr(v int) *int { 160 return &v 161} 162 163func stringPtr(v string) *string { 164 return &v 165} 166 167func (v *productVariables) SetDefaultConfig() { 168 *v = productVariables{ 169 Platform_sdk_version: intPtr(24), 170 HostArch: stringPtr("x86_64"), 171 HostSecondaryArch: stringPtr("x86"), 172 DeviceName: stringPtr("flounder"), 173 DeviceArch: stringPtr("arm64"), 174 DeviceArchVariant: stringPtr("armv8-a"), 175 DeviceCpuVariant: stringPtr("denver64"), 176 DeviceAbi: &[]string{"arm64-v8a"}, 177 DeviceUsesClang: boolPtr(true), 178 DeviceSecondaryArch: stringPtr("arm"), 179 DeviceSecondaryArchVariant: stringPtr("armv7-a-neon"), 180 DeviceSecondaryCpuVariant: stringPtr("denver"), 181 DeviceSecondaryAbi: &[]string{"armeabi-v7a"}, 182 Malloc_not_svelte: boolPtr(false), 183 Safestack: boolPtr(false), 184 } 185 186 if runtime.GOOS == "linux" { 187 v.CrossHost = stringPtr("windows") 188 v.CrossHostArch = stringPtr("x86") 189 v.CrossHostSecondaryArch = stringPtr("x86_64") 190 } 191} 192 193func variableMutator(mctx BottomUpMutatorContext) { 194 var module Module 195 var ok bool 196 if module, ok = mctx.Module().(Module); !ok { 197 return 198 } 199 200 // TODO: depend on config variable, create variants, propagate variants up tree 201 a := module.base() 202 variableValues := reflect.ValueOf(&a.variableProperties.Product_variables).Elem() 203 zeroValues := reflect.ValueOf(zeroProductVariables.Product_variables) 204 205 for i := 0; i < variableValues.NumField(); i++ { 206 variableValue := variableValues.Field(i) 207 zeroValue := zeroValues.Field(i) 208 name := variableValues.Type().Field(i).Name 209 property := "product_variables." + proptools.PropertyNameForField(name) 210 211 // Check that the variable was set for the product 212 val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name) 213 if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() { 214 continue 215 } 216 217 val = val.Elem() 218 219 // For bools, check that the value is true 220 if val.Kind() == reflect.Bool && val.Bool() == false { 221 continue 222 } 223 224 // Check if any properties were set for the module 225 if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) { 226 continue 227 } 228 229 a.setVariableProperties(mctx, property, variableValue, val.Interface()) 230 } 231} 232 233func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext, 234 prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) { 235 236 printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue) 237 238 err := proptools.AppendMatchingProperties(a.generalProperties, 239 productVariablePropertyValue.Addr().Interface(), nil) 240 if err != nil { 241 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 242 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 243 } else { 244 panic(err) 245 } 246 } 247} 248 249func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string, 250 productVariablePropertyValue reflect.Value, i int, err error) { 251 252 field := productVariablePropertyValue.Type().Field(i).Name 253 property := prefix + "." + proptools.PropertyNameForField(field) 254 ctx.PropertyErrorf(property, "%s", err) 255} 256 257func printfIntoProperties(ctx BottomUpMutatorContext, prefix string, 258 productVariablePropertyValue reflect.Value, variableValue interface{}) { 259 260 for i := 0; i < productVariablePropertyValue.NumField(); i++ { 261 propertyValue := productVariablePropertyValue.Field(i) 262 kind := propertyValue.Kind() 263 if kind == reflect.Ptr { 264 if propertyValue.IsNil() { 265 continue 266 } 267 propertyValue = propertyValue.Elem() 268 } 269 switch propertyValue.Kind() { 270 case reflect.String: 271 err := printfIntoProperty(propertyValue, variableValue) 272 if err != nil { 273 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 274 } 275 case reflect.Slice: 276 for j := 0; j < propertyValue.Len(); j++ { 277 err := printfIntoProperty(propertyValue.Index(j), variableValue) 278 if err != nil { 279 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 280 } 281 } 282 case reflect.Bool: 283 // Nothing 284 case reflect.Struct: 285 printfIntoProperties(ctx, prefix, propertyValue, variableValue) 286 default: 287 panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind())) 288 } 289 } 290} 291 292func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error { 293 s := propertyValue.String() 294 295 count := strings.Count(s, "%") 296 if count == 0 { 297 return nil 298 } 299 300 if count > 1 { 301 return fmt.Errorf("product variable properties only support a single '%%'") 302 } 303 304 if strings.Contains(s, "%d") { 305 switch v := variableValue.(type) { 306 case int: 307 // Nothing 308 case bool: 309 if v { 310 variableValue = 1 311 } else { 312 variableValue = 0 313 } 314 default: 315 return fmt.Errorf("unsupported type %T for %%d", variableValue) 316 } 317 } else if strings.Contains(s, "%s") { 318 switch variableValue.(type) { 319 case string: 320 // Nothing 321 default: 322 return fmt.Errorf("unsupported type %T for %%s", variableValue) 323 } 324 } else { 325 return fmt.Errorf("unsupported %% in product variable property") 326 } 327 328 propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue))) 329 330 return nil 331} 332