From 6a448ec1a346b5ace5f12687fc65933e75081a3f Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Wed, 19 Apr 2023 17:36:12 +0000 Subject: [PATCH] Add a function to create config_setting(s) The use case for this is creating config_setting(s) specific to an apex variant and selecting stub/impl in that config_setting. We likely need only a handful of such config_setting(s), but determining that list requires iterating the build graph. Test: go test ./bp2build Change-Id: I9aa552e3d0bcf67513023c3a7d4bbf8fae464ee4 --- android/mutator.go | 23 +++++++++++++++++++++ bazel/properties.go | 11 +++++++++++ bp2build/build_conversion.go | 5 +++++ bp2build/build_conversion_test.go | 33 +++++++++++++++++++++++++++++++ bp2build/bzl_conversion_test.go | 3 +++ bp2build/testing.go | 23 +++++++++++++++++++++ starlark_fmt/format.go | 10 ++++++++++ 7 files changed, 108 insertions(+) diff --git a/android/mutator.go b/android/mutator.go index 4ec960472..1eac1f0f8 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -273,6 +273,12 @@ type TopDownMutatorContext interface { // This function can be used to create alias definitions in a directory that is different // from the directory of the visited Soong module. CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label) + + // CreateBazelConfigSetting creates a config_setting in /BUILD.bazel + // build/bazel has several static config_setting(s) that are used in Bazel builds. + // This function can be used to createa additional config_setting(s) based on the build graph + // (e.g. a config_setting specific to an apex variant) + CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string) } type topDownMutatorContext struct { @@ -738,6 +744,23 @@ func (t *topDownMutatorContext) CreateBazelTargetAliasInDir( mod.base().addBp2buildInfo(info) } +func (t *topDownMutatorContext) CreateBazelConfigSetting( + csa bazel.ConfigSettingAttributes, + ca CommonAttributes, + dir string) { + mod := t.Module() + info := bp2buildInfo{ + Dir: dir, + BazelProps: bazel.BazelTargetModuleProperties{ + Rule_class: "config_setting", + }, + CommonAttrs: ca, + ConstraintAttrs: constraintAttributes{}, + Attrs: &csa, + } + mod.base().addBp2buildInfo(info) +} + // ApexAvailableTags converts the apex_available property value of an ApexModule // module and returns it as a list of keyed tags. func ApexAvailableTags(mod Module) bazel.StringListAttribute { diff --git a/bazel/properties.go b/bazel/properties.go index 40d0ba37a..1757bad49 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -1424,3 +1424,14 @@ func TryVariableSubstitution(s string, productVariable string) (string, bool) { sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")") return sub, s != sub } + +// StringMapAttribute is a map of strings. +// The use case for this is storing the flag_values in a config_setting object. +// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules. +type StringMapAttribute map[string]string + +// ConfigSettingAttributes stores the keys of a config_setting object. +type ConfigSettingAttributes struct { + // Each key in Flag_values is a label to a custom string_setting + Flag_values StringMapAttribute +} diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index b7678a469..a86048418 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -600,6 +600,11 @@ func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) ( // TODO(b/164227191): implement pretty print for interfaces. // Interfaces are used for for arch, multilib and target properties. return "", nil + case reflect.Map: + if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok { + return starlark_fmt.PrintStringStringDict(v, indent), nil + } + return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue) default: return "", fmt.Errorf( "unexpected kind for property struct field: %s", propertyValue.Kind()) diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 73ee26b60..1b64055f7 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -1898,3 +1898,36 @@ func TestGenerateApiBazelTargets(t *testing.T) { Description: "Generating API contribution Bazel targets for custom module", }) } + +func TestGenerateConfigSetting(t *testing.T) { + bp := ` + custom { + name: "foo", + test_config_setting: true, + } + ` + expectedBazelTargets := []string{ + MakeBazelTargetNoRestrictions( + "config_setting", + "foo_config_setting", + AttrNameToString{ + "flag_values": `{ + "//build/bazel/rules/my_string_setting": "foo", + }`, + }, + ), + MakeBazelTarget( + "custom", + "foo", + AttrNameToString{}, + ), + } + registerCustomModule := func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) + } + RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ + Blueprint: bp, + ExpectedBazelTargets: expectedBazelTargets, + Description: "Generating API contribution Bazel targets for custom module", + }) +} diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go index a8e557deb..fa1bf8af6 100644 --- a/bp2build/bzl_conversion_test.go +++ b/bp2build/bzl_conversion_test.go @@ -108,6 +108,7 @@ custom = rule( "string_literal_prop": attr.string(), "string_prop": attr.string(), "string_ptr_prop": attr.string(), + "test_config_setting": attr.bool(), }, ) @@ -139,6 +140,7 @@ custom_defaults = rule( "string_literal_prop": attr.string(), "string_prop": attr.string(), "string_ptr_prop": attr.string(), + "test_config_setting": attr.bool(), }, ) @@ -170,6 +172,7 @@ custom_test_ = rule( "string_literal_prop": attr.string(), "string_prop": attr.string(), "string_ptr_prop": attr.string(), + "test_config_setting": attr.bool(), # test_prop start # "test_string_prop": attr.string(), # test_prop end diff --git a/bp2build/testing.go b/bp2build/testing.go index 6e919db2b..fd99ff007 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -317,6 +317,8 @@ type customProps struct { One_to_many_prop *bool Api *string // File describing the APIs of this module + + Test_config_setting *bool // Used to test generation of config_setting targets } type customModule struct { @@ -490,6 +492,27 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs) + + if proptools.Bool(m.props.Test_config_setting) { + m.createConfigSetting(ctx) + } + +} + +func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) { + csa := bazel.ConfigSettingAttributes{ + Flag_values: bazel.StringMapAttribute{ + "//build/bazel/rules/my_string_setting": m.Name(), + }, + } + ca := android.CommonAttributes{ + Name: m.Name() + "_config_setting", + } + ctx.CreateBazelConfigSetting( + csa, + ca, + ctx.ModuleDir(), + ) } var _ android.ApiProvider = (*customModule)(nil) diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go index a97f71b87..42095075c 100644 --- a/starlark_fmt/format.go +++ b/starlark_fmt/format.go @@ -99,6 +99,16 @@ func PrintStringIntDict(dict map[string]int, indentLevel int) string { return PrintDict(valDict, indentLevel) } +// PrintStringStringDict returns a Starlark-compatible string formatted as dictionary with +// string keys and string values. +func PrintStringStringDict(dict map[string]string, indentLevel int) string { + valDict := make(map[string]string, len(dict)) + for k, v := range dict { + valDict[k] = fmt.Sprintf(`"%s"`, v) + } + return PrintDict(valDict, indentLevel) +} + // PrintDict returns a starlark-compatible string containing a dictionary with string keys and // values printed with no additional formatting. func PrintDict(dict map[string]string, indentLevel int) string {