LTO Bp2build

Bug: 261733821
Test: Unit Tests
Change-Id: I8c3721d35c464e296012145b2e95a7f0866aac37
This commit is contained in:
Trevor Radcliffe 2023-02-06 21:58:30 +00:00
parent 7720f5704c
commit 56b1a2b575
6 changed files with 636 additions and 0 deletions

View file

@ -17,6 +17,7 @@ package bazel
import (
"fmt"
"path/filepath"
"reflect"
"regexp"
"sort"
"strings"
@ -533,6 +534,37 @@ func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelL
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.

View file

@ -868,3 +868,131 @@ func TestCcBinaryWithUBSanPropertiesArchSpecific(t *testing.T) {
},
})
}
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",
]`,
}},
},
})
}

View file

@ -4137,3 +4137,172 @@ cc_library {
},
})
}
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": `["."]`,
}),
},
})
}

View file

@ -974,3 +974,133 @@ cc_library_shared {
},
})
}
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": `["."]`,
}),
},
})
}

View file

@ -1889,3 +1889,133 @@ cc_library_static {
},
})
}
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": `["."]`,
}),
},
})
}

View file

@ -817,6 +817,7 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module)
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 @@ func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module
})
return sanitizerFeatures
}
func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
lto_feature_name := "android_thin_lto"
ltoBoolFeatures := bazel.BoolAttribute{}
bp2BuildPropParseHelper(ctx, m, &LTOProperties{}, 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, &LTOProperties{})
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
}