7f64b6de31
Allow modules to vary their properties based on product variables. For now, DEVICE_USES_LOGD, DEVICE_USES_JEMALLOC, and DEVICE_USES_DLMALLOC, and BOARD_MALLOC_ALIGNMENT are supported. Product variables can provide a value (only bool and int supported for now), and if any of the product variable properties contains a "%d" then Sprintf will be called with the property value as the format and the product variable value convert to an int as the only argument. For example: product_variables: { dlmalloc_alignment: { cflags: ["-DMALLOC_ALIGNMENT=%d"], }, }, will cause -DMALLOC_ALIGNMENT=16 to be added to any top level properties called "cflags". Change-Id: I74882a6ab4914d3e222f8d06cfac371b7b829ae5
152 lines
4.5 KiB
Go
152 lines
4.5 KiB
Go
// 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 common
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
// TODO: move this to proptools
|
|
func extendProperties(ctx blueprint.EarlyMutatorContext,
|
|
requiredTag, srcPrefix string, dstValues []reflect.Value, srcValue reflect.Value,
|
|
callback func(string, string)) {
|
|
if srcPrefix != "" {
|
|
srcPrefix += "."
|
|
}
|
|
extendPropertiesRecursive(ctx, requiredTag, srcValue, dstValues, srcPrefix, "", callback)
|
|
}
|
|
|
|
func extendPropertiesRecursive(ctx blueprint.EarlyMutatorContext, requiredTag string,
|
|
srcValue reflect.Value, dstValues []reflect.Value, srcPrefix, dstPrefix string,
|
|
callback func(string, string)) {
|
|
|
|
typ := srcValue.Type()
|
|
for i := 0; i < srcValue.NumField(); i++ {
|
|
srcField := typ.Field(i)
|
|
if srcField.PkgPath != "" {
|
|
// The field is not exported so just skip it.
|
|
continue
|
|
}
|
|
|
|
localPropertyName := proptools.PropertyNameForField(srcField.Name)
|
|
srcPropertyName := srcPrefix + localPropertyName
|
|
srcFieldValue := srcValue.Field(i)
|
|
|
|
if !ctx.ContainsProperty(srcPropertyName) {
|
|
continue
|
|
}
|
|
|
|
found := false
|
|
for _, dstValue := range dstValues {
|
|
dstField, ok := dstValue.Type().FieldByName(srcField.Name)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
dstFieldValue := dstValue.FieldByIndex(dstField.Index)
|
|
|
|
if srcFieldValue.Type() != dstFieldValue.Type() {
|
|
panic(fmt.Errorf("can't extend mismatching types for %q (%s <- %s)",
|
|
srcPropertyName, dstFieldValue.Type(), srcFieldValue.Type()))
|
|
}
|
|
|
|
dstPropertyName := dstPrefix + localPropertyName
|
|
|
|
if requiredTag != "" {
|
|
tag := dstField.Tag.Get("android")
|
|
tags := map[string]bool{}
|
|
for _, entry := range strings.Split(tag, ",") {
|
|
if entry != "" {
|
|
tags[entry] = true
|
|
}
|
|
}
|
|
|
|
if !tags[requiredTag] {
|
|
ctx.PropertyErrorf(srcPropertyName, "property can't be specific to a build variant")
|
|
continue
|
|
}
|
|
}
|
|
|
|
if callback != nil {
|
|
callback(srcPropertyName, dstPropertyName)
|
|
}
|
|
|
|
found = true
|
|
|
|
switch srcFieldValue.Kind() {
|
|
case reflect.Bool:
|
|
// Replace the original value.
|
|
dstFieldValue.Set(srcFieldValue)
|
|
case reflect.String:
|
|
// Append the extension string.
|
|
dstFieldValue.SetString(dstFieldValue.String() +
|
|
srcFieldValue.String())
|
|
case reflect.Slice:
|
|
dstFieldValue.Set(reflect.AppendSlice(dstFieldValue, srcFieldValue))
|
|
case reflect.Interface:
|
|
if dstFieldValue.IsNil() != srcFieldValue.IsNil() {
|
|
panic(fmt.Errorf("can't extend field %q: nilitude mismatch", srcPropertyName))
|
|
}
|
|
if dstFieldValue.IsNil() {
|
|
continue
|
|
}
|
|
|
|
dstFieldValue = dstFieldValue.Elem()
|
|
srcFieldValue = srcFieldValue.Elem()
|
|
|
|
if dstFieldValue.Type() != srcFieldValue.Type() {
|
|
panic(fmt.Errorf("can't extend field %q: type mismatch", srcPropertyName))
|
|
}
|
|
if srcFieldValue.Kind() != reflect.Ptr {
|
|
panic(fmt.Errorf("can't extend field %q: interface not a pointer", srcPropertyName))
|
|
}
|
|
fallthrough
|
|
case reflect.Ptr:
|
|
if dstFieldValue.IsNil() != srcFieldValue.IsNil() {
|
|
panic(fmt.Errorf("can't extend field %q: nilitude mismatch", srcPropertyName))
|
|
}
|
|
if dstFieldValue.IsNil() {
|
|
continue
|
|
}
|
|
|
|
dstFieldValue = dstFieldValue.Elem()
|
|
srcFieldValue = srcFieldValue.Elem()
|
|
|
|
if dstFieldValue.Type() != srcFieldValue.Type() {
|
|
panic(fmt.Errorf("can't extend field %q: type mismatch", srcPropertyName))
|
|
}
|
|
if srcFieldValue.Kind() != reflect.Struct {
|
|
panic(fmt.Errorf("can't extend field %q: pointer not to a struct", srcPropertyName))
|
|
}
|
|
fallthrough
|
|
case reflect.Struct:
|
|
// Recursively extend the struct's fields.
|
|
extendPropertiesRecursive(ctx, requiredTag, srcFieldValue, []reflect.Value{dstFieldValue},
|
|
srcPropertyName+".", srcPropertyName+".", callback)
|
|
default:
|
|
panic(fmt.Errorf("unexpected kind for property struct field %q: %s",
|
|
srcPropertyName, srcFieldValue.Kind()))
|
|
}
|
|
}
|
|
if !found {
|
|
ctx.PropertyErrorf(srcPropertyName, "failed to find property to extend")
|
|
}
|
|
}
|
|
}
|