bp2build: add configurable attribute (select) support.
This CL adds a basic framework to support configurable string_list
attributes, selecting on the Arch variant (x86, x86_64, arm, arm64).
It offers fine-grained controls to map individual configurable
properties (arch_variant) to configurable Bazel attributes, starting
with the string_list type for the copts property for cc_object.
This design is primarily motivated to have minimal boilerplate in
bp2build mutators, allowing anyone to opt-in configurable attributes,
and modify intermediate states before passing them on into the
CreateBazelTargetModule instantiator.
Fixes: 178130668
Test: go tests
Test: build/bazel/scripts/milestone-2/demo.sh
Change-Id: Id6f04d7c560312a93e193d7ca4e1b7ceb6062260
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index f655842..1d4e322 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -99,15 +99,6 @@
cc_defaults {
name: "foo_defaults",
defaults: ["foo_bar_defaults"],
- // TODO(b/178130668): handle configurable attributes that depend on the platform
- arch: {
- x86: {
- cflags: ["-fPIC"],
- },
- x86_64: {
- cflags: ["-fPIC"],
- },
- },
}
cc_defaults {
@@ -233,3 +224,137 @@
}
}
}
+
+func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) {
+ testCases := []struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ blueprint string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ }{
+ {
+ description: "cc_object setting cflags for one arch",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
+ name: "foo",
+ arch: {
+ x86: {
+ cflags: ["-fPIC"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+`,
+ expectedBazelTargets: []string{
+ `cc_object(
+ name = "foo",
+ copts = [
+ "-fno-addrsig",
+ ] + select({
+ "@bazel_tools//platforms:x86_32": [
+ "-fPIC",
+ ],
+ "//conditions:default": [
+ ],
+ }),
+)`,
+ },
+ },
+ {
+ description: "cc_object setting cflags for 4 architectures",
+ moduleTypeUnderTest: "cc_object",
+ moduleTypeUnderTestFactory: cc.ObjectFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+ blueprint: `cc_object {
+ name: "foo",
+ arch: {
+ x86: {
+ cflags: ["-fPIC"],
+ },
+ x86_64: {
+ cflags: ["-fPIC"],
+ },
+ arm: {
+ cflags: ["-Wall"],
+ },
+ arm64: {
+ cflags: ["-Wall"],
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+`,
+ expectedBazelTargets: []string{
+ `cc_object(
+ name = "foo",
+ copts = [
+ "-fno-addrsig",
+ ] + select({
+ "@bazel_tools//platforms:arm": [
+ "-Wall",
+ ],
+ "@bazel_tools//platforms:aarch64": [
+ "-Wall",
+ ],
+ "@bazel_tools//platforms:x86_32": [
+ "-fPIC",
+ ],
+ "@bazel_tools//platforms:x86_64": [
+ "-fPIC",
+ ],
+ "//conditions:default": [
+ ],
+ }),
+)`,
+ },
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem)
+ ctx := android.NewTestContext(config)
+ // Always register cc_defaults module factory
+ ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
+
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
+ if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+ fmt.Println(bazelTargets)
+ t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ testCase.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+ }
+}