Add support for targets in Blueprints.
The default target selector uses the name of the host OS. Modules can implement their own target selector by implementing the context.TargetSelector interface and its unique selectTarget() method. Targets are defined this way in Blueprint files: cc_library { name: "libmylib", deps: ["libmath", "libutils"], zones: ["frontend"], srcs: ["main.cpp"], targets: { darwin: { moduleCflags: "-framework OpenGL -framework GLUT", }, linux: { deps: ["libx11headers", "libglu"], }, }, } In this example, a set of C flags are defined on OS X only and on Linux, two new dependencies are added. When a target is selected, its properties are merged with the properties of the modules: - a list is appended to the original list (see deps above) - a string is concatenated to the original string - a bool replaces the original bool - a map adds or replaces the key/value pairs of the original map Change-Id: Ic627d47f795d6a4ff56ca5f6f099cad157621af1
This commit is contained in:
parent
2476f81d84
commit
285296519a
2 changed files with 140 additions and 14 deletions
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
|
@ -90,8 +91,9 @@ type moduleInfo struct {
|
|||
pos scanner.Position
|
||||
propertyPos map[string]scanner.Position
|
||||
properties struct {
|
||||
Name string
|
||||
Deps []string
|
||||
Name string
|
||||
Deps []string
|
||||
Targets map[string][]*parser.Property
|
||||
}
|
||||
|
||||
// set during ResolveDependencies
|
||||
|
@ -109,6 +111,18 @@ type singletonInfo struct {
|
|||
actionDefs localBuildActions
|
||||
}
|
||||
|
||||
type TargetSelector interface {
|
||||
SelectTarget() string
|
||||
}
|
||||
|
||||
// Default target selector that simply returns the host OS name
|
||||
type goosTargetSelector struct {
|
||||
}
|
||||
|
||||
func (g *goosTargetSelector) SelectTarget() string {
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
|
||||
return fmt.Sprintf("%s: %s", e.Pos, e.Err)
|
||||
|
@ -474,6 +488,21 @@ func (c *Context) processModuleDef(moduleDef *parser.Module,
|
|||
return errs
|
||||
}
|
||||
|
||||
var targetName string
|
||||
if selector, ok := module.(TargetSelector); ok {
|
||||
targetName = selector.SelectTarget()
|
||||
} else {
|
||||
defaultSelector := goosTargetSelector{}
|
||||
targetName = defaultSelector.SelectTarget()
|
||||
}
|
||||
|
||||
if targetProperties, ok := info.properties.Targets[targetName]; ok {
|
||||
errs = mergeProperties(targetProperties, properties...)
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
|
||||
info.pos = moduleDef.Pos
|
||||
info.propertyPos = make(map[string]scanner.Position)
|
||||
for _, propertyDef := range moduleDef.Properties {
|
||||
|
|
|
@ -13,9 +13,71 @@ type packedProperty struct {
|
|||
unpacked bool
|
||||
}
|
||||
|
||||
type valueHandler interface {
|
||||
assignBool(value reflect.Value, data bool)
|
||||
assignString(value reflect.Value, data string)
|
||||
assignValue(value reflect.Value, data reflect.Value)
|
||||
}
|
||||
|
||||
type valueSetter struct {
|
||||
}
|
||||
|
||||
func (v *valueSetter) assignBool(value reflect.Value, data bool) {
|
||||
value.SetBool(data)
|
||||
}
|
||||
|
||||
func (v *valueSetter) assignString(value reflect.Value, data string) {
|
||||
value.SetString(data)
|
||||
}
|
||||
|
||||
func (v *valueSetter) assignValue(value reflect.Value, data reflect.Value) {
|
||||
value.Set(data)
|
||||
}
|
||||
|
||||
type valueMerger struct {
|
||||
}
|
||||
|
||||
func (v *valueMerger) assignBool(value reflect.Value, data bool) {
|
||||
// when merging bools, the original value is replaced
|
||||
value.SetBool(data)
|
||||
}
|
||||
|
||||
func (v *valueMerger) assignString(value reflect.Value, data string) {
|
||||
value.SetString(value.String() + data)
|
||||
}
|
||||
|
||||
func (v *valueMerger) assignValue(value reflect.Value, data reflect.Value) {
|
||||
// this should never happen
|
||||
if value.Kind() != data.Kind() {
|
||||
panic("attempting to merge values of different kinds")
|
||||
}
|
||||
|
||||
if value.Kind() == reflect.Slice {
|
||||
value.Set(reflect.AppendSlice(value, data))
|
||||
} else if value.Kind() == reflect.Map {
|
||||
for _, key := range data.MapKeys() {
|
||||
value.SetMapIndex(key, data.MapIndex(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unpackProperties(propertyDefs []*parser.Property,
|
||||
propertiesStructs ...interface{}) (errs []error) {
|
||||
|
||||
setter := new(valueSetter);
|
||||
return unpackPropertiesWithHandler(setter, propertyDefs, propertiesStructs...)
|
||||
}
|
||||
|
||||
func mergeProperties(propertyDefs []*parser.Property,
|
||||
propertiesStructs ...interface{}) (errs []error) {
|
||||
|
||||
merger := new(valueMerger);
|
||||
return unpackPropertiesWithHandler(merger, propertyDefs, propertiesStructs...)
|
||||
}
|
||||
|
||||
func unpackPropertiesWithHandler(handler valueHandler, propertyDefs []*parser.Property,
|
||||
propertiesStructs ...interface{}) (errs []error) {
|
||||
|
||||
propertyMap := make(map[string]*packedProperty)
|
||||
for _, propertyDef := range propertyDefs {
|
||||
name := propertyDef.Name
|
||||
|
@ -51,7 +113,7 @@ func unpackProperties(propertyDefs []*parser.Property,
|
|||
panic("properties must be a pointer to a struct")
|
||||
}
|
||||
|
||||
newErrs := unpackStruct(propertiesValue, propertyMap)
|
||||
newErrs := unpackStruct(propertiesValue, propertyMap, handler)
|
||||
errs = append(errs, newErrs...)
|
||||
|
||||
if len(errs) >= maxErrors {
|
||||
|
@ -75,7 +137,7 @@ func unpackProperties(propertyDefs []*parser.Property,
|
|||
}
|
||||
|
||||
func unpackStruct(structValue reflect.Value,
|
||||
propertyMap map[string]*packedProperty) []error {
|
||||
propertyMap map[string]*packedProperty, handler valueHandler) []error {
|
||||
|
||||
structType := structValue.Type()
|
||||
|
||||
|
@ -104,12 +166,20 @@ func unpackStruct(structValue reflect.Value,
|
|||
panic(fmt.Errorf("field %s is a non-string slice", field.Name))
|
||||
}
|
||||
case reflect.Struct:
|
||||
newErrs := unpackStruct(fieldValue, propertyMap)
|
||||
newErrs := unpackStruct(fieldValue, propertyMap, handler)
|
||||
errs = append(errs, newErrs...)
|
||||
if len(errs) >= maxErrors {
|
||||
return errs
|
||||
}
|
||||
continue // This field doesn't correspond to a specific property.
|
||||
case reflect.Map:
|
||||
fieldType := field.Type
|
||||
if fieldType.Key().Kind() != reflect.String {
|
||||
panic(fmt.Errorf("field %s uses a non-string key", field.Name))
|
||||
}
|
||||
if fieldType.Elem().Kind() != reflect.TypeOf(([]*parser.Property)(nil)).Kind() {
|
||||
panic(fmt.Errorf("field %s uses a non-parser.Property value", field.Name))
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported kind for field %s: %s",
|
||||
field.Name, kind))
|
||||
|
@ -128,11 +198,13 @@ func unpackStruct(structValue reflect.Value,
|
|||
var newErrs []error
|
||||
switch kind := fieldValue.Kind(); kind {
|
||||
case reflect.Bool:
|
||||
newErrs = unpackBool(fieldValue, packedProperty.property)
|
||||
newErrs = unpackBool(fieldValue, packedProperty.property, handler)
|
||||
case reflect.String:
|
||||
newErrs = unpackString(fieldValue, packedProperty.property)
|
||||
newErrs = unpackString(fieldValue, packedProperty.property, handler)
|
||||
case reflect.Slice:
|
||||
newErrs = unpackSlice(fieldValue, packedProperty.property)
|
||||
newErrs = unpackSlice(fieldValue, packedProperty.property, handler)
|
||||
case reflect.Map:
|
||||
newErrs = unpackMap(fieldValue, packedProperty.property, handler)
|
||||
}
|
||||
errs = append(errs, newErrs...)
|
||||
if len(errs) >= maxErrors {
|
||||
|
@ -143,7 +215,7 @@ func unpackStruct(structValue reflect.Value,
|
|||
return errs
|
||||
}
|
||||
|
||||
func unpackBool(boolValue reflect.Value, property *parser.Property) []error {
|
||||
func unpackBool(boolValue reflect.Value, property *parser.Property, handler valueHandler) []error {
|
||||
if property.Value.Type != parser.Bool {
|
||||
return []error{
|
||||
fmt.Errorf("%s: can't assign %s value to %s property %q",
|
||||
|
@ -151,12 +223,12 @@ func unpackBool(boolValue reflect.Value, property *parser.Property) []error {
|
|||
property.Name),
|
||||
}
|
||||
}
|
||||
boolValue.SetBool(property.Value.BoolValue)
|
||||
handler.assignBool(boolValue, property.Value.BoolValue)
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackString(stringValue reflect.Value,
|
||||
property *parser.Property) []error {
|
||||
property *parser.Property, handler valueHandler) []error {
|
||||
|
||||
if property.Value.Type != parser.String {
|
||||
return []error{
|
||||
|
@ -165,11 +237,13 @@ func unpackString(stringValue reflect.Value,
|
|||
property.Name),
|
||||
}
|
||||
}
|
||||
stringValue.SetString(property.Value.StringValue)
|
||||
handler.assignString(stringValue, property.Value.StringValue)
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackSlice(sliceValue reflect.Value, property *parser.Property) []error {
|
||||
func unpackSlice(sliceValue reflect.Value, property *parser.Property,
|
||||
handler valueHandler) []error {
|
||||
|
||||
if property.Value.Type != parser.List {
|
||||
return []error{
|
||||
fmt.Errorf("%s: can't assign %s value to %s property %q",
|
||||
|
@ -187,10 +261,33 @@ func unpackSlice(sliceValue reflect.Value, property *parser.Property) []error {
|
|||
list = append(list, value.StringValue)
|
||||
}
|
||||
|
||||
sliceValue.Set(reflect.ValueOf(list))
|
||||
handler.assignValue(sliceValue, reflect.ValueOf(list))
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackMap(mapValue reflect.Value, property *parser.Property,
|
||||
handler valueHandler) []error {
|
||||
|
||||
if property.Value.Type != parser.Map {
|
||||
return []error{
|
||||
fmt.Errorf("%s: can't assign %s value to %s property %q",
|
||||
property.Value.Pos, property.Value.Type, parser.Map,
|
||||
property.Name),
|
||||
}
|
||||
}
|
||||
|
||||
m := make(map[string][]*parser.Property)
|
||||
for _, p := range property.Value.MapValue {
|
||||
if p.Value.Type != parser.Map {
|
||||
panic("non-map value found in map")
|
||||
}
|
||||
m[p.Name] = p.Value.MapValue
|
||||
}
|
||||
|
||||
handler.assignValue(mapValue, reflect.ValueOf(m))
|
||||
return nil;
|
||||
}
|
||||
|
||||
func propertyNameForField(field reflect.StructField) string {
|
||||
r, size := utf8.DecodeRuneInString(field.Name)
|
||||
propertyName := string(unicode.ToLower(r))
|
||||
|
|
Loading…
Reference in a new issue