Browse Source

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
Spandan Das 1 year ago
parent
commit
6a448ec1a3

+ 23 - 0
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 <dir>/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 {

+ 11 - 0
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
+}

+ 5 - 0
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())

+ 33 - 0
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",
+	})
+}

+ 3 - 0
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

+ 23 - 0
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)

+ 10 - 0
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 {