LTO Bp2build
Bug: 261733821
Test: Unit Tests
Change-Id: I8c3721d35c464e296012145b2e95a7f0866aac37
diff --git a/bazel/properties.go b/bazel/properties.go
index f4acd26..40d0ba3 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -17,6 +17,7 @@
import (
"fmt"
"path/filepath"
+ "reflect"
"regexp"
"sort"
"strings"
@@ -533,6 +534,37 @@
return result, nil
}
+// ToStringListAttribute creates a StringListAttribute from this BoolAttribute,
+// where each bool corresponds to a string list value generated by the provided
+// function.
+// TODO(b/271425661): Generalize this
+func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) {
+ mainVal := valueFunc(ba.Value, NoConfigAxis, "")
+ if !ba.HasConfigurableValues() {
+ return MakeStringListAttribute(mainVal), nil
+ }
+
+ result := StringListAttribute{}
+ if err := ba.Collapse(); err != nil {
+ return result, err
+ }
+
+ for axis, configToBools := range ba.ConfigurableValues {
+ if len(configToBools) < 1 {
+ continue
+ }
+ for config, boolPtr := range configToBools {
+ val := valueFunc(&boolPtr, axis, config)
+ if !reflect.DeepEqual(val, mainVal) {
+ result.SetSelectValue(axis, config, val)
+ }
+ }
+ result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
+ }
+
+ return result, nil
+}
+
// Collapse reduces the configurable axes of the boolean attribute to a single axis.
// This is necessary for final writing to bp2build, as a configurable boolean
// attribute can only be comprised by a single select.
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index a39ed7d..0315732 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -868,3 +868,131 @@
},
})
}
+
+func TestCcBinaryWithThinLto(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when thin LTO is enabled",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["android_thin_lto"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithLtoNever(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO is explicitly disabled",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["-android_thin_lto"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoArchSpecific(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO differs across arch and os variants",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when LTO disabled by default but enabled on a particular variant",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary has correct features when thin LTO is enabled with whole_program_vtables",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index af14f64..e20cffd 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -4137,3 +4137,172 @@
},
})
}
+
+func TestCcLibraryWithThinLto(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when thin LTO is enabled",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithLtoNever(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO is explicitly disabled",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO differs across arch and os variants",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when LTO disabled by default but enabled on a particular variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryWithThinLtoWholeProgramVtables(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library has correct features when thin LTO is enabled with whole_program_vtables",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 6207421..838b297 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -974,3 +974,133 @@
},
})
}
+
+func TestCcLibrarySharedWithThinLto(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithLtoNever(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when LTO differs across arch and os variants",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared with thin lto disabled by default but enabled on a particular variant",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared has correct features when thin LTO is enabled with whole_program_vtables",
+ Blueprint: `
+cc_library_shared {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index d5256f6..d16c5cc 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1889,3 +1889,133 @@
},
})
}
+
+func TestCcLibraryStaticWithThinLto(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithLtoNever(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["-android_thin_lto"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoArchSpecific(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when LTO differs across arch and os variants",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ },
+ },
+ },
+ arch: {
+ riscv64: {
+ lto: {
+ thin: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
+ "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
+ "//conditions:default": [],
+ })`}),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when LTO disabled by default but enabled on a particular variant",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ never: true,
+ },
+ target: {
+ android: {
+ lto: {
+ thin: true,
+ never: false,
+ },
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["android_thin_lto"],
+ "//conditions:default": ["-android_thin_lto"],
+ })`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticWithThinLtoAndWholeProgramVtables(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static has correct features when thin lto is enabled with whole_program_vtables",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ lto: {
+ thin: true,
+ },
+ whole_program_vtables: true,
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `[
+ "android_thin_lto",
+ "android_thin_lto_whole_program_vtables",
+ ]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 9751a2e..1ea8bda 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -817,6 +817,7 @@
compilerAttrs.hdrs.Prepend = true
features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
+ features = features.Append(bp2buildLtoFeatures(ctx, module))
features.DeduplicateAxesFromBase()
addMuslSystemDynamicDeps(ctx, linkerAttrs)
@@ -1459,3 +1460,49 @@
})
return sanitizerFeatures
}
+
+func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+ lto_feature_name := "android_thin_lto"
+ ltoBoolFeatures := bazel.BoolAttribute{}
+ bp2BuildPropParseHelper(ctx, m, <OProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
+ if ltoProps, ok := props.(*LTOProperties); ok {
+ thinProp := ltoProps.Lto.Thin != nil && *ltoProps.Lto.Thin
+ thinPropSetToFalse := ltoProps.Lto.Thin != nil && !*ltoProps.Lto.Thin
+ neverProp := ltoProps.Lto.Never != nil && *ltoProps.Lto.Never
+ if thinProp {
+ ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(true))
+ return
+ }
+ if neverProp || thinPropSetToFalse {
+ if thinProp {
+ ctx.ModuleErrorf("lto.thin and lto.never are mutually exclusive but were specified together")
+ } else {
+ ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(false))
+ }
+ return
+ }
+ }
+ ltoBoolFeatures.SetSelectValue(axis, config, nil)
+ })
+
+ props := m.GetArchVariantProperties(ctx, <OProperties{})
+ ltoStringFeatures, err := ltoBoolFeatures.ToStringListAttribute(func(boolPtr *bool, axis bazel.ConfigurationAxis, config string) []string {
+ if boolPtr == nil {
+ return []string{}
+ }
+ if !*boolPtr {
+ return []string{"-" + lto_feature_name}
+ }
+ features := []string{lto_feature_name}
+ if ltoProps, ok := props[axis][config].(*LTOProperties); ok {
+ if ltoProps.Whole_program_vtables != nil && *ltoProps.Whole_program_vtables {
+ features = append(features, "android_thin_lto_whole_program_vtables")
+ }
+ }
+ return features
+ })
+ if err != nil {
+ ctx.ModuleErrorf("Error processing LTO attributes: %s", err)
+ }
+ return ltoStringFeatures
+}