Loading android/base_module_context.go +4 −4 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ import ( "strings" "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 Loading Loading @@ -219,7 +219,7 @@ type BaseModuleContext interface { // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context // 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 { Loading Loading @@ -577,6 +577,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string { return sb.String() } func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition) func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property) } android/module.go +55 −22 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import ( "android/soong/bazel" "github.com/google/blueprint" "github.com/google/blueprint/parser" "github.com/google/blueprint/proptools" ) Loading Loading @@ -2140,41 +2139,75 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, 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 m := e.m switch ty { case parser.SelectTypeReleaseVariable: if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok { return v, true switch condition.FunctionName { case "release_variable": if len(condition.Args) != 1 { ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } return "", false case parser.SelectTypeProductVariable: if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok { return proptools.ConfigurableValueString(v) } return proptools.ConfigurableValueUndefined() case "product_variable": // 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") return "", false case parser.SelectTypeSoongConfigVariable: parts := strings.Split(condition, ":") namespace := parts[0] variable := parts[1] return proptools.ConfigurableValueUndefined() case "soong_config_variable": if len(condition.Args) != 2 { ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } namespace := condition.Args[0] variable := condition.Args[1] if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if v, ok := n[variable]; ok { return v, true return proptools.ConfigurableValueString(v) } } return proptools.ConfigurableValueUndefined() case "variant": if len(condition.Args) != 1 { ctx.OtherModulePropertyErrorf(m, property, "variant requires 1 argument, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } return "", false case parser.SelectTypeVariant: if condition == "arch" { if condition.Args[0] == "arch" { if !m.base().ArchReady() { ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") return "", false return proptools.ConfigurableValueUndefined() } return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name) } ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition.Args[0]) 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 m.base().Arch().ArchType.Name, true } ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition) return "", false return proptools.ConfigurableValueUndefined() default: panic("Should be unreachable") ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName) return proptools.ConfigurableValueUndefined() } } Loading android/selects_test.go +166 −0 Original line number Diff line number Diff line Loading @@ -327,8 +327,10 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { "baz": "qux", default: unset, }) } Loading @@ -341,6 +343,7 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { default: "a", Loading Loading @@ -414,6 +417,169 @@ func TestSelects(t *testing.T) { 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 { Loading Loading
android/base_module_context.go +4 −4 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ import ( "strings" "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 Loading Loading @@ -219,7 +219,7 @@ type BaseModuleContext interface { // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context // 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 { Loading Loading @@ -577,6 +577,6 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string { return sb.String() } func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, property, condition string) (string, bool) { return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(ty, property, condition) func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property) }
android/module.go +55 −22 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import ( "android/soong/bazel" "github.com/google/blueprint" "github.com/google/blueprint/parser" "github.com/google/blueprint/proptools" ) Loading Loading @@ -2140,41 +2139,75 @@ func (e configurationEvalutor) PropertyErrorf(property string, fmt string, 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 m := e.m switch ty { case parser.SelectTypeReleaseVariable: if v, ok := ctx.Config().productVariables.BuildFlags[condition]; ok { return v, true switch condition.FunctionName { case "release_variable": if len(condition.Args) != 1 { ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } return "", false case parser.SelectTypeProductVariable: if v, ok := ctx.Config().productVariables.BuildFlags[condition.Args[0]]; ok { return proptools.ConfigurableValueString(v) } return proptools.ConfigurableValueUndefined() case "product_variable": // 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") return "", false case parser.SelectTypeSoongConfigVariable: parts := strings.Split(condition, ":") namespace := parts[0] variable := parts[1] return proptools.ConfigurableValueUndefined() case "soong_config_variable": if len(condition.Args) != 2 { ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } namespace := condition.Args[0] variable := condition.Args[1] if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if v, ok := n[variable]; ok { return v, true return proptools.ConfigurableValueString(v) } } return proptools.ConfigurableValueUndefined() case "variant": if len(condition.Args) != 1 { ctx.OtherModulePropertyErrorf(m, property, "variant requires 1 argument, found %d", len(condition.Args)) return proptools.ConfigurableValueUndefined() } return "", false case parser.SelectTypeVariant: if condition == "arch" { if condition.Args[0] == "arch" { if !m.base().ArchReady() { ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") return "", false return proptools.ConfigurableValueUndefined() } return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name) } ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition.Args[0]) 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 m.base().Arch().ArchType.Name, true } ctx.OtherModulePropertyErrorf(m, property, "Unknown variant %s", condition) return "", false return proptools.ConfigurableValueUndefined() default: panic("Should be unreachable") ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName) return proptools.ConfigurableValueUndefined() } } Loading
android/selects_test.go +166 −0 Original line number Diff line number Diff line Loading @@ -327,8 +327,10 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { "baz": "qux", default: unset, }) } Loading @@ -341,6 +343,7 @@ func TestSelects(t *testing.T) { my_module_type { name: "foo", my_string: select(soong_config_variable("my_namespace", "my_variable"), { "foo": "bar", default: unset, }) + select(soong_config_variable("my_namespace", "my_variable2"), { default: "a", Loading Loading @@ -414,6 +417,169 @@ func TestSelects(t *testing.T) { 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 { Loading