Merge "Update the ConfigurableEvaluator for typed selects" into main am: 1a8906d938

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/3037517

Change-Id: I8732516b695ce343fa55419709d8900eebdba86c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Cole Faust
2024-04-16 18:27:41 +00:00
committed by Automerger Merge Worker
3 changed files with 225 additions and 26 deletions

View File

@@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/google/blueprint" "github.com/google/blueprint"
"github.com/google/blueprint/parser" "github.com/google/blueprint/proptools"
) )
// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
@@ -219,7 +219,7 @@ type BaseModuleContext interface {
// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
// can be used to evaluate the final value of Configurable properties. // can be used to evaluate the final value of Configurable properties.
EvaluateConfiguration(parser.SelectType, string, string) (string, bool) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
} }
type baseModuleContext struct { type baseModuleContext struct {
@@ -577,6 +577,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string {
return sb.String() return sb.String()
} }
func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition) return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property)
} }

View File

@@ -29,7 +29,6 @@ import (
"android/soong/bazel" "android/soong/bazel"
"github.com/google/blueprint" "github.com/google/blueprint"
"github.com/google/blueprint/parser"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
) )
@@ -2140,41 +2139,75 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args
e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args) e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args)
} }
func (e configurationEvalutor) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
ctx := e.ctx ctx := e.ctx
m := e.m m := e.m
switch ty { switch condition.FunctionName {
case parser.SelectTypeReleaseVariable: case "release_variable":
if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok { if len(condition.Args) != 1 {
return v, true ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", len(condition.Args))
return proptools.ConfigurableValueUndefined()
} }
return "", false if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok {
case parser.SelectTypeProductVariable: return proptools.ConfigurableValueString(v)
}
return proptools.ConfigurableValueUndefined()
case "product_variable":
// TODO(b/323382414): Might add these on a case-by-case basis // TODO(b/323382414): Might add these on a case-by-case basis
ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects") ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects")
return "", false return proptools.ConfigurableValueUndefined()
case parser.SelectTypeSoongConfigVariable: case "soong_config_variable":
parts := strings.Split(condition, ":") if len(condition.Args) != 2 {
namespace := parts[0] ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", len(condition.Args))
variable := parts[1] return proptools.ConfigurableValueUndefined()
}
namespace := condition.Args[0]
variable := condition.Args[1]
if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok {
if v, ok := n[variable]; ok { if v, ok := n[variable]; ok {
return v, true return proptools.ConfigurableValueString(v)
} }
} }
return "", false return proptools.ConfigurableValueUndefined()
case parser.SelectTypeVariant: case "variant":
if condition == "arch" { if len(condition.Args) != 1 {
ctx.OtherModulePropertyErrorf(m, property, "variant requires 1 argument, found %d", len(condition.Args))
return proptools.ConfigurableValueUndefined()
}
if condition.Args[0] == "arch" {
if !m.base().ArchReady() { if !m.base().ArchReady() {
ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran")
return "", false return proptools.ConfigurableValueUndefined()
} }
return m.base().Arch().ArchType.Name, true return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name)
} }
ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition) ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition.Args[0])
return "", false return proptools.ConfigurableValueUndefined()
case "boolean_var_for_testing":
// We currently don't have any other boolean variables (we should add support for typing
// the soong config variables), so add this fake one for testing the boolean select
// functionality.
if len(condition.Args) != 0 {
ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", len(condition.Args))
return proptools.ConfigurableValueUndefined()
}
if n, ok := ctx.Config().productVariables.VendorVars["boolean_var"]; ok {
if v, ok := n["for_testing"]; ok {
switch v {
case "true":
return proptools.ConfigurableValueBool(true)
case "false":
return proptools.ConfigurableValueBool(false)
default:
ctx.OtherModulePropertyErrorf(m, property, "testing:my_boolean_var can only be true or false, found %q", v)
}
}
}
return proptools.ConfigurableValueUndefined()
default: default:
panic("Should be unreachable") ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName)
return proptools.ConfigurableValueUndefined()
} }
} }

View File

@@ -327,8 +327,10 @@ func TestSelects(t *testing.T) {
my_module_type { my_module_type {
name: "foo", name: "foo",
my_string: select(soong_config_variable("my_namespace", "my_variable"), { my_string: select(soong_config_variable("my_namespace", "my_variable"), {
"foo": "bar",
default: unset, default: unset,
}) + select(soong_config_variable("my_namespace", "my_variable2"), { }) + select(soong_config_variable("my_namespace", "my_variable2"), {
"baz": "qux",
default: unset, default: unset,
}) })
} }
@@ -341,6 +343,7 @@ func TestSelects(t *testing.T) {
my_module_type { my_module_type {
name: "foo", name: "foo",
my_string: select(soong_config_variable("my_namespace", "my_variable"), { my_string: select(soong_config_variable("my_namespace", "my_variable"), {
"foo": "bar",
default: unset, default: unset,
}) + select(soong_config_variable("my_namespace", "my_variable2"), { }) + select(soong_config_variable("my_namespace", "my_variable2"), {
default: "a", default: "a",
@@ -414,6 +417,169 @@ func TestSelects(t *testing.T) {
replacing_string_list: &[]string{"b1"}, replacing_string_list: &[]string{"b1"},
}, },
}, },
{
name: "Multi-condition string 1",
bp: `
my_module_type {
name: "foo",
my_string: select((
soong_config_variable("my_namespace", "my_variable"),
soong_config_variable("my_namespace", "my_variable2"),
), {
("a", "b"): "a+b",
("a", default): "a+default",
(default, default): "default",
}),
}
`,
vendorVars: map[string]map[string]string{
"my_namespace": {
"my_variable": "a",
"my_variable2": "b",
},
},
provider: selectsTestProvider{
my_string: proptools.StringPtr("a+b"),
},
},
{
name: "Multi-condition string 2",
bp: `
my_module_type {
name: "foo",
my_string: select((
soong_config_variable("my_namespace", "my_variable"),
soong_config_variable("my_namespace", "my_variable2"),
), {
("a", "b"): "a+b",
("a", default): "a+default",
(default, default): "default",
}),
}
`,
vendorVars: map[string]map[string]string{
"my_namespace": {
"my_variable": "a",
"my_variable2": "c",
},
},
provider: selectsTestProvider{
my_string: proptools.StringPtr("a+default"),
},
},
{
name: "Multi-condition string 3",
bp: `
my_module_type {
name: "foo",
my_string: select((
soong_config_variable("my_namespace", "my_variable"),
soong_config_variable("my_namespace", "my_variable2"),
), {
("a", "b"): "a+b",
("a", default): "a+default",
(default, default): "default",
}),
}
`,
vendorVars: map[string]map[string]string{
"my_namespace": {
"my_variable": "c",
"my_variable2": "b",
},
},
provider: selectsTestProvider{
my_string: proptools.StringPtr("default"),
},
},
{
name: "Select on boolean",
bp: `
my_module_type {
name: "foo",
my_string: select(boolean_var_for_testing(), {
true: "t",
false: "f",
}),
}
`,
vendorVars: map[string]map[string]string{
"boolean_var": {
"for_testing": "true",
},
},
provider: selectsTestProvider{
my_string: proptools.StringPtr("t"),
},
},
{
name: "Select on boolean false",
bp: `
my_module_type {
name: "foo",
my_string: select(boolean_var_for_testing(), {
true: "t",
false: "f",
}),
}
`,
vendorVars: map[string]map[string]string{
"boolean_var": {
"for_testing": "false",
},
},
provider: selectsTestProvider{
my_string: proptools.StringPtr("f"),
},
},
{
name: "Select on boolean undefined",
bp: `
my_module_type {
name: "foo",
my_string: select(boolean_var_for_testing(), {
true: "t",
false: "f",
}),
}
`,
expectedError: "foo",
},
{
name: "Select on boolean undefined with default",
bp: `
my_module_type {
name: "foo",
my_string: select(boolean_var_for_testing(), {
true: "t",
false: "f",
default: "default",
}),
}
`,
provider: selectsTestProvider{
my_string: proptools.StringPtr("default"),
},
},
{
name: "Mismatched condition types",
bp: `
my_module_type {
name: "foo",
my_string: select(boolean_var_for_testing(), {
"true": "t",
"false": "f",
default: "default",
}),
}
`,
vendorVars: map[string]map[string]string{
"boolean_var": {
"for_testing": "false",
},
},
expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string",
},
} }
for _, tc := range testCases { for _, tc := range testCases {