diff options
Diffstat (limited to 'android/variable.go')
-rw-r--r-- | android/variable.go | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/android/variable.go b/android/variable.go new file mode 100644 index 00000000..29d7a080 --- /dev/null +++ b/android/variable.go @@ -0,0 +1,232 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "fmt" + "reflect" + "runtime" + "strings" + + "github.com/google/blueprint/proptools" +) + +func init() { + RegisterBottomUpMutator("variable", variableMutator) +} + +type variableProperties struct { + Product_variables struct { + Platform_sdk_version struct { + Asflags []string + } + + // unbundled_build is a catch-all property to annotate modules that don't build in one or + // more unbundled branches, usually due to dependencies missing from the manifest. + Unbundled_build struct { + Enabled *bool `android:"arch_variant"` + } `android:"arch_variant"` + + Brillo struct { + Version_script *string `android:"arch_variant"` + } `android:"arch_variant"` + + Malloc_not_svelte struct { + Cflags []string + } + + Safestack struct { + Cflags []string `android:"arch_variant"` + } `android:"arch_variant"` + } `android:"arch_variant"` +} + +var zeroProductVariables variableProperties + +type productVariables struct { + // Suffix to add to generated Makefiles + Make_suffix *string `json:",omitempty"` + + Platform_sdk_version *int `json:",omitempty"` + + DeviceName *string `json:",omitempty"` + DeviceArch *string `json:",omitempty"` + DeviceArchVariant *string `json:",omitempty"` + DeviceCpuVariant *string `json:",omitempty"` + DeviceAbi *[]string `json:",omitempty"` + DeviceUsesClang *bool `json:",omitempty"` + + DeviceSecondaryArch *string `json:",omitempty"` + DeviceSecondaryArchVariant *string `json:",omitempty"` + DeviceSecondaryCpuVariant *string `json:",omitempty"` + DeviceSecondaryAbi *[]string `json:",omitempty"` + + HostArch *string `json:",omitempty"` + HostSecondaryArch *string `json:",omitempty"` + + CrossHost *string `json:",omitempty"` + CrossHostArch *string `json:",omitempty"` + CrossHostSecondaryArch *string `json:",omitempty"` + + Allow_missing_dependencies *bool `json:",omitempty"` + Unbundled_build *bool `json:",omitempty"` + Brillo *bool `json:",omitempty"` + Malloc_not_svelte *bool `json:",omitempty"` + Safestack *bool `json:",omitempty"` + HostStaticBinaries *bool `json:",omitempty"` + + SanitizeHost *[]string `json:",omitempty"` + SanitizeDevice *[]string `json:",omitempty"` +} + +func boolPtr(v bool) *bool { + return &v +} + +func intPtr(v int) *int { + return &v +} + +func stringPtr(v string) *string { + return &v +} + +func (v *productVariables) SetDefaultConfig() { + *v = productVariables{ + Platform_sdk_version: intPtr(22), + HostArch: stringPtr("x86_64"), + HostSecondaryArch: stringPtr("x86"), + DeviceName: stringPtr("flounder"), + DeviceArch: stringPtr("arm64"), + DeviceArchVariant: stringPtr("armv8-a"), + DeviceCpuVariant: stringPtr("denver64"), + DeviceAbi: &[]string{"arm64-v8a"}, + DeviceUsesClang: boolPtr(true), + DeviceSecondaryArch: stringPtr("arm"), + DeviceSecondaryArchVariant: stringPtr("armv7-a-neon"), + DeviceSecondaryCpuVariant: stringPtr("denver"), + DeviceSecondaryAbi: &[]string{"armeabi-v7a"}, + Malloc_not_svelte: boolPtr(false), + Safestack: boolPtr(false), + } + + if runtime.GOOS == "linux" { + v.CrossHost = stringPtr("windows") + v.CrossHostArch = stringPtr("x86") + v.CrossHostSecondaryArch = stringPtr("x86_64") + } +} + +func variableMutator(mctx BottomUpMutatorContext) { + var module Module + var ok bool + if module, ok = mctx.Module().(Module); !ok { + return + } + + // TODO: depend on config variable, create variants, propagate variants up tree + a := module.base() + variableValues := reflect.ValueOf(&a.variableProperties.Product_variables).Elem() + zeroValues := reflect.ValueOf(zeroProductVariables.Product_variables) + + for i := 0; i < variableValues.NumField(); i++ { + variableValue := variableValues.Field(i) + zeroValue := zeroValues.Field(i) + name := variableValues.Type().Field(i).Name + property := "product_variables." + proptools.PropertyNameForField(name) + + // Check that the variable was set for the product + val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name) + if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() { + continue + } + + val = val.Elem() + + // For bools, check that the value is true + if val.Kind() == reflect.Bool && val.Bool() == false { + continue + } + + // Check if any properties were set for the module + if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) { + continue + } + + a.setVariableProperties(mctx, property, variableValue, val.Interface()) + } +} + +func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext, + prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) { + + printfIntoProperties(productVariablePropertyValue, variableValue) + + err := proptools.AppendMatchingProperties(a.generalProperties, + productVariablePropertyValue.Addr().Interface(), nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } +} + +func printfIntoProperties(productVariablePropertyValue reflect.Value, variableValue interface{}) { + for i := 0; i < productVariablePropertyValue.NumField(); i++ { + propertyValue := productVariablePropertyValue.Field(i) + kind := propertyValue.Kind() + if kind == reflect.Ptr { + if propertyValue.IsNil() { + continue + } + propertyValue = propertyValue.Elem() + } + switch propertyValue.Kind() { + case reflect.String: + printfIntoProperty(propertyValue, variableValue) + case reflect.Slice: + for j := 0; j < propertyValue.Len(); j++ { + printfIntoProperty(propertyValue.Index(j), variableValue) + } + case reflect.Bool: + // Nothing + case reflect.Struct: + printfIntoProperties(propertyValue, variableValue) + default: + panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind())) + } + } +} + +func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) { + s := propertyValue.String() + // For now, we only support int formats + var i int + if strings.Contains(s, "%d") { + switch v := variableValue.(type) { + case int: + i = v + case bool: + if v { + i = 1 + } + default: + panic(fmt.Errorf("unsupported type %T", variableValue)) + } + propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, i))) + } +} |