diff --git a/android/bazel.go b/android/bazel.go index f4f9a7242..970ad0d71 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -367,13 +367,21 @@ var ( "libandroid_runtime_lazy", // depends on unconverted modules: libbinder_headers "libcmd", // depends on unconverted modules: libbinder + "libdexfile_support_static", // Depends on unconverted module: libdexfile_external_headers + "libunwindstack_local", "libunwindstack_utils", "libc_malloc_debug", "libfdtrack", // Depends on unconverted module: libunwindstack + + "libdexfile_support", // TODO(b/210546943): Enabled based on product variables. + "libdexfile_external_headers", // TODO(b/210546943): Enabled based on product variables. + + "libunwindstack", // Depends on unconverted module libdexfile_support. + "libnativehelper_compat_libc++", // Broken compile: implicit declaration of function 'strerror_r' is invalid in C99 + "chkcon", "sefcontext_compile", // depends on unconverted modules: libsepol "libsepol", // TODO(b/207408632): Unsupported case of .l sources in cc library rules "gen-kotlin-build-file.py", // module has same name as source - "libbinder", // TODO(b/188503688): Disabled for some archs, "libactivitymanager_aidl", // TODO(b/207426160): Depends on activity_manager_procstate_aidl, which is an aidl filegroup. "libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libgmock_ndk @@ -434,8 +442,7 @@ var ( "linkerconfig", // http://b/202876379 has arch-variant static_executable "mdnsd", // http://b/202876379 has arch-variant static_executable - "acvp_modulewrapper", // disabled for android x86/x86_64 - "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib + "CarHTMLViewer", // depends on unconverted modules android.car-stubs, car-ui-lib "libdexfile", // depends on unconverted modules: dexfile_operator_srcs, libartbase, libartpalette, "libdexfiled", // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette @@ -443,9 +450,7 @@ var ( // Per-module denylist of cc_library modules to only generate the static // variant if their shared variant isn't ready or buildable by Bazel. - bp2buildCcLibraryStaticOnlyList = []string{ - "libjemalloc5", // http://b/188503688, cc_library, `target: { android: { enabled: false } }` for android targets. - } + bp2buildCcLibraryStaticOnlyList = []string{} // Per-module denylist to opt modules out of mixed builds. Such modules will // still be generated via bp2build. @@ -513,6 +518,9 @@ func (b *BazelModuleBase) MixedBuildsEnabled(ctx ModuleContext) bool { // Windows toolchains are not currently supported. return false } + if !ctx.Module().Enabled() { + return false + } if !ctx.Config().BazelContext.BazelEnabled() { return false } diff --git a/android/module.go b/android/module.go index 6de416535..2750131d8 100644 --- a/android/module.go +++ b/android/module.go @@ -869,6 +869,13 @@ type CommonAttributes struct { Data bazel.LabelListAttribute } +// constraintAttributes represents Bazel attributes pertaining to build constraints, +// which make restrict building a Bazel target for some set of platforms. +type constraintAttributes struct { + // Constraint values this target can be built for. + Target_compatible_with bazel.LabelListAttribute +} + type distProperties struct { // configuration to distribute output files from this module to the distribution // directory (default: $OUT/dist, configurable with $DIST_DIR) @@ -1089,7 +1096,8 @@ func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupport m.base().commonProperties.CreateCommonOSVariant = true } -func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext) { +func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext, + enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes { // Assert passed-in attributes include Name name := attrs.Name if len(name) == 0 { @@ -1107,14 +1115,45 @@ func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutator required := depsToLabelList(props.Required) archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{}) + + var enabledProperty bazel.BoolAttribute + if props.Enabled != nil { + enabledProperty.Value = props.Enabled + } + for axis, configToProps := range archVariantProps { for config, _props := range configToProps { if archProps, ok := _props.(*commonProperties); ok { required.SetSelectValue(axis, config, depsToLabelList(archProps.Required).Value) + if archProps.Enabled != nil { + enabledProperty.SetSelectValue(axis, config, archProps.Enabled) + } } } } + + if enabledPropertyOverrides.Value != nil { + enabledProperty.Value = enabledPropertyOverrides.Value + } + for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() { + configToBools := enabledPropertyOverrides.ConfigurableValues[axis] + for cfg, val := range configToBools { + enabledProperty.SetSelectValue(axis, cfg, &val) + } + } + data.Append(required) + + var err error + constraints := constraintAttributes{} + constraints.Target_compatible_with, err = enabledProperty.ToLabelListAttribute( + bazel.LabelList{[]bazel.Label{bazel.Label{Label: "@platforms//:incompatible"}}, nil}, + bazel.LabelList{[]bazel.Label{}, nil}) + + if err != nil { + ctx.ModuleErrorf("Error processing enabled attribute: %s", err) + } + return constraints } // A ModuleBase object contains the properties that are common to all Android @@ -1233,10 +1272,11 @@ type ModuleBase struct { // A struct containing all relevant information about a Bazel target converted via bp2build. type bp2buildInfo struct { - Dir string - BazelProps bazel.BazelTargetModuleProperties - CommonAttrs CommonAttributes - Attrs interface{} + Dir string + BazelProps bazel.BazelTargetModuleProperties + CommonAttrs CommonAttributes + ConstraintAttrs constraintAttributes + Attrs interface{} } // TargetName returns the Bazel target name of a bp2build converted target. @@ -1262,7 +1302,7 @@ func (b bp2buildInfo) BazelRuleLoadLocation() string { // BazelAttributes returns the Bazel attributes of a bp2build converted target. func (b bp2buildInfo) BazelAttributes() []interface{} { - return []interface{}{&b.CommonAttrs, b.Attrs} + return []interface{}{&b.CommonAttrs, &b.ConstraintAttrs, b.Attrs} } func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) { diff --git a/android/mutator.go b/android/mutator.go index dbd8c04db..fa6f2be8d 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -254,6 +254,14 @@ type TopDownMutatorContext interface { // BazelTargetModuleProperties containing additional metadata for the // bp2build codegenerator. CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}) + + // CreateBazelTargetModuleWithRestrictions creates a BazelTargetModule by calling the + // factory method, just like in CreateModule, but also requires + // BazelTargetModuleProperties containing additional metadata for the + // bp2build codegenerator. The generated target is restricted to only be buildable for certain + // platforms, as dictated by a given bool attribute: the target will not be buildable in + // any platform for which this bool attribute is false. + CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute) } type topDownMutatorContext struct { @@ -502,13 +510,30 @@ func (t *topDownMutatorContext) CreateBazelTargetModule( bazelProps bazel.BazelTargetModuleProperties, commonAttrs CommonAttributes, attrs interface{}) { - commonAttrs.fillCommonBp2BuildModuleAttrs(t) + t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{}) +} + +func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions( + bazelProps bazel.BazelTargetModuleProperties, + commonAttrs CommonAttributes, + attrs interface{}, + enabledProperty bazel.BoolAttribute) { + t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty) +} + +func (t *topDownMutatorContext) createBazelTargetModule( + bazelProps bazel.BazelTargetModuleProperties, + commonAttrs CommonAttributes, + attrs interface{}, + enabledProperty bazel.BoolAttribute) { + constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty) mod := t.Module() info := bp2buildInfo{ - Dir: t.OtherModuleDir(mod), - BazelProps: bazelProps, - CommonAttrs: commonAttrs, - Attrs: attrs, + Dir: t.OtherModuleDir(mod), + BazelProps: bazelProps, + CommonAttrs: commonAttrs, + ConstraintAttrs: constraintAttributes, + Attrs: attrs, } mod.base().addBp2buildInfo(info) } diff --git a/bazel/configurability.go b/bazel/configurability.go index 1993f76fc..7355ac7d3 100644 --- a/bazel/configurability.go +++ b/bazel/configurability.go @@ -109,6 +109,21 @@ var ( osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64", ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. } + + // Map where keys are OsType names, and values are slices containing the archs + // that that OS supports. + // These definitions copied from arch.go. + // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results + // in a cyclic dependency. + osToArchMap = map[string][]string{ + osAndroid: {archArm, archArm64, archX86, archX86_64}, + osLinux: {archX86, archX86_64}, + osLinuxMusl: {archX86, archX86_64}, + osDarwin: {archArm64, archX86_64}, + osLinuxBionic: {archArm64, archX86_64}, + // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well. + osWindows: {archX86, archX86_64}, + } ) // basic configuration types @@ -122,6 +137,10 @@ const ( productVariables ) +func osArchString(os string, arch string) string { + return fmt.Sprintf("%s_%s", os, arch) +} + func (ct configurationType) String() string { return map[configurationType]string{ noConfig: "no_config", diff --git a/bazel/properties.go b/bazel/properties.go index 76be0581b..d8b3a3a02 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -244,9 +244,69 @@ type LabelAttribute struct { ConfigurableValues configurableLabels } +func (la *LabelAttribute) axisTypes() map[configurationType]bool { + types := map[configurationType]bool{} + for k := range la.ConfigurableValues { + if len(la.ConfigurableValues[k]) > 0 { + types[k.configurationType] = true + } + } + return types +} + +// Collapse reduces the configurable axes of the label attribute to a single axis. +// This is necessary for final writing to bp2build, as a configurable label +// attribute can only be comprised by a single select. +func (la *LabelAttribute) Collapse() error { + axisTypes := la.axisTypes() + _, containsOs := axisTypes[os] + _, containsArch := axisTypes[arch] + _, containsOsArch := axisTypes[osArch] + _, containsProductVariables := axisTypes[productVariables] + if containsProductVariables { + if containsOs || containsArch || containsOsArch { + return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes") + } + } + if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) { + // If a bool attribute has both os and arch configuration axes, the only + // way to successfully union their values is to increase the granularity + // of the configuration criteria to os_arch. + for osType, supportedArchs := range osToArchMap { + for _, supportedArch := range supportedArchs { + osArch := osArchString(osType, supportedArch) + if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil { + // Do nothing, as the arch_os is explicitly defined already. + } else { + archVal := la.SelectValue(ArchConfigurationAxis, supportedArch) + osVal := la.SelectValue(OsConfigurationAxis, osType) + if osVal != nil && archVal != nil { + // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator + // runs after os mutator. + la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal) + } else if osVal != nil && archVal == nil { + la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal) + } else if osVal == nil && archVal != nil { + la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal) + } + } + } + } + // All os_arch values are now set. Clear os and arch axes. + delete(la.ConfigurableValues, ArchConfigurationAxis) + delete(la.ConfigurableValues, OsConfigurationAxis) + } + return nil +} + // HasConfigurableValues returns whether there are configurable values set for this label. func (la LabelAttribute) HasConfigurableValues() bool { - return len(la.ConfigurableValues) > 0 + for _, selectValues := range la.ConfigurableValues { + if len(selectValues) > 0 { + return true + } + } + return false } // SetValue sets the base, non-configured value for the Label @@ -271,13 +331,13 @@ func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, } // SelectValue gets a value for a bazel select for the given axis and config. -func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) Label { +func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label { axis.validateConfig(config) switch axis.configurationType { case noConfig: - return *la.Value + return la.Value case arch, os, osArch, productVariables: - return *la.ConfigurableValues[axis][config] + return la.ConfigurableValues[axis][config] default: panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis)) } @@ -324,7 +384,12 @@ type BoolAttribute struct { // HasConfigurableValues returns whether there are configurable values for this attribute. func (ba BoolAttribute) HasConfigurableValues() bool { - return len(ba.ConfigurableValues) > 0 + for _, cfgToBools := range ba.ConfigurableValues { + if len(cfgToBools) > 0 { + return true + } + } + return false } // SetSelectValue sets value for the given axis/config. @@ -343,6 +408,106 @@ func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, v } } +// ToLabelListAttribute creates and returns a LabelListAttribute from this +// bool attribute, where each bool in this attribute corresponds to a +// label list value in the resultant attribute. +func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) { + getLabelList := func(boolPtr *bool) LabelList { + if boolPtr == nil { + return LabelList{nil, nil} + } else if *boolPtr { + return trueVal + } else { + return falseVal + } + } + + mainVal := getLabelList(ba.Value) + if !ba.HasConfigurableValues() { + return MakeLabelListAttribute(mainVal), nil + } + + result := LabelListAttribute{} + 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 := getLabelList(&boolPtr) + if !val.Equals(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. +func (ba *BoolAttribute) Collapse() error { + axisTypes := ba.axisTypes() + _, containsOs := axisTypes[os] + _, containsArch := axisTypes[arch] + _, containsOsArch := axisTypes[osArch] + _, containsProductVariables := axisTypes[productVariables] + if containsProductVariables { + if containsOs || containsArch || containsOsArch { + return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes") + } + } + if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) { + // If a bool attribute has both os and arch configuration axes, the only + // way to successfully union their values is to increase the granularity + // of the configuration criteria to os_arch. + for osType, supportedArchs := range osToArchMap { + for _, supportedArch := range supportedArchs { + osArch := osArchString(osType, supportedArch) + if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil { + // Do nothing, as the arch_os is explicitly defined already. + } else { + archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch) + osVal := ba.SelectValue(OsConfigurationAxis, osType) + if osVal != nil && archVal != nil { + // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator + // runs after os mutator. + ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal) + } else if osVal != nil && archVal == nil { + ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal) + } else if osVal == nil && archVal != nil { + ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal) + } + } + } + } + // All os_arch values are now set. Clear os and arch axes. + delete(ba.ConfigurableValues, ArchConfigurationAxis) + delete(ba.ConfigurableValues, OsConfigurationAxis) + // Verify post-condition; this should never fail, provided no additional + // axes are introduced. + if len(ba.ConfigurableValues) > 1 { + panic(fmt.Errorf("error in collapsing attribute: %s", ba)) + } + } + return nil +} + +func (ba *BoolAttribute) axisTypes() map[configurationType]bool { + types := map[configurationType]bool{} + for k := range ba.ConfigurableValues { + if len(ba.ConfigurableValues[k]) > 0 { + types[k.configurationType] = true + } + } + return types +} + // SelectValue gets the value for the given axis/config. func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool { axis.validateConfig(config) @@ -550,7 +715,12 @@ func (lla *LabelListAttribute) Add(label *LabelAttribute) { // HasConfigurableValues returns true if the attribute contains axis-specific label list values. func (lla LabelListAttribute) HasConfigurableValues() bool { - return len(lla.ConfigurableValues) > 0 + for _, selectValues := range lla.ConfigurableValues { + if len(selectValues) > 0 { + return true + } + } + return false } // IsEmpty returns true if the attribute has no values under any configuration. @@ -800,7 +970,12 @@ func MakeStringListAttribute(value []string) StringListAttribute { // HasConfigurableValues returns true if the attribute contains axis-specific string_list values. func (sla StringListAttribute) HasConfigurableValues() bool { - return len(sla.ConfigurableValues) > 0 + for _, selectValues := range sla.ConfigurableValues { + if len(selectValues) > 0 { + return true + } + } + return false } // Append appends all values, including os and arch specific ones, from another diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index eaceea969..59a238976 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -1369,6 +1369,94 @@ cc_library { }) } +func TestCCLibraryNoLibCrtArchAndTargetVariant(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + filesystem: map[string]string{ + "impl.cpp": "", + }, + blueprint: soongCcLibraryPreamble + ` +cc_library { + name: "foo-lib", + srcs: ["impl.cpp"], + arch: { + arm: { + no_libcrt: true, + }, + x86: { + no_libcrt: true, + }, + }, + target: { + darwin: { + no_libcrt: true, + } + }, + include_build_directory: false, +} +`, + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + "use_libcrt": `select({ + "//build/bazel/platforms/os_arch:android_arm": False, + "//build/bazel/platforms/os_arch:android_x86": False, + "//build/bazel/platforms/os_arch:darwin_arm64": False, + "//build/bazel/platforms/os_arch:darwin_x86_64": False, + "//build/bazel/platforms/os_arch:linux_glibc_x86": False, + "//build/bazel/platforms/os_arch:linux_musl_x86": False, + "//build/bazel/platforms/os_arch:windows_x86": False, + "//conditions:default": None, + })`, + }), + }) +} + +func TestCCLibraryNoLibCrtArchAndTargetVariantConflict(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + filesystem: map[string]string{ + "impl.cpp": "", + }, + blueprint: soongCcLibraryPreamble + ` +cc_library { + name: "foo-lib", + srcs: ["impl.cpp"], + arch: { + arm: { + no_libcrt: true, + }, + // This is expected to override the value for darwin_x86_64. + x86_64: { + no_libcrt: true, + }, + }, + target: { + darwin: { + no_libcrt: false, + } + }, + include_build_directory: false, +} +`, + expectedBazelTargets: makeCcLibraryTargets("foo-lib", attrNameToString{ + "srcs": `["impl.cpp"]`, + "use_libcrt": `select({ + "//build/bazel/platforms/os_arch:android_arm": False, + "//build/bazel/platforms/os_arch:android_x86_64": False, + "//build/bazel/platforms/os_arch:darwin_arm64": True, + "//build/bazel/platforms/os_arch:darwin_x86_64": False, + "//build/bazel/platforms/os_arch:linux_bionic_x86_64": False, + "//build/bazel/platforms/os_arch:linux_glibc_x86_64": False, + "//build/bazel/platforms/os_arch:linux_musl_x86_64": False, + "//build/bazel/platforms/os_arch:windows_x86_64": False, + "//conditions:default": None, + })`, + }), + }) +} + func TestCcLibraryStrip(t *testing.T) { expectedTargets := []string{} expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", attrNameToString{ @@ -2159,3 +2247,146 @@ cc_library { }, }) } + +func TestCcLibraryDisabledArchAndTarget(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.cpp"], + target: { + darwin: { + enabled: false, + }, + windows: { + enabled: false, + }, + linux_glibc_x86: { + enabled: false, + }, + }, + include_build_directory: false, +}`, + expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"], + "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"], + "//build/bazel/platforms/os_arch:linux_glibc_x86": ["@platforms//:incompatible"], + "//build/bazel/platforms/os_arch:windows_x86": ["@platforms//:incompatible"], + "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + }) +} + +func TestCcLibraryDisabledArchAndTargetWithDefault(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.cpp"], + enabled: false, + target: { + darwin: { + enabled: true, + }, + windows: { + enabled: false, + }, + linux_glibc_x86: { + enabled: false, + }, + }, + include_build_directory: false, +}`, + expectedBazelTargets: makeCcLibraryTargets("foo", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os_arch:darwin_arm64": [], + "//build/bazel/platforms/os_arch:darwin_x86_64": [], + "//conditions:default": ["@platforms//:incompatible"], + })`, + }), + }) +} + +func TestCcLibrarySharedDisabled(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.cpp"], + enabled: false, + shared: { + enabled: true, + }, + target: { + android: { + shared: { + enabled: false, + }, + } + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `["@platforms//:incompatible"]`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os:android": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), + }, + }) +} + +func TestCcLibraryStaticDisabledForSomeArch(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + blueprint: soongCcProtoPreamble + `cc_library { + name: "foo", + srcs: ["foo.cpp"], + shared: { + enabled: false + }, + target: { + darwin: { + enabled: true, + }, + windows: { + enabled: false, + }, + linux_glibc_x86: { + shared: { + enabled: true, + }, + }, + }, + include_build_directory: false, +}`, + expectedBazelTargets: []string{makeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + })`, + }), makeBazelTarget("cc_library_shared", "foo", attrNameToString{ + "srcs": `["foo.cpp"]`, + "target_compatible_with": `select({ + "//build/bazel/platforms/os_arch:darwin_arm64": [], + "//build/bazel/platforms/os_arch:darwin_x86_64": [], + "//build/bazel/platforms/os_arch:linux_glibc_x86": [], + "//conditions:default": ["@platforms//:incompatible"], + })`, + }), + }}) +} diff --git a/bp2build/configurability.go b/bp2build/configurability.go index c953259f9..dfbb265d2 100644 --- a/bp2build/configurability.go +++ b/bp2build/configurability.go @@ -1,10 +1,11 @@ package bp2build import ( - "android/soong/android" - "android/soong/bazel" "fmt" "reflect" + + "android/soong/android" + "android/soong/bazel" ) // Configurability support for bp2build. @@ -89,13 +90,15 @@ func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects } archSelects := map[string]reflect.Value{} defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey] + // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default. + emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0 for config, labels := range configToLabels { // Omit any entries in the map which match the default value, for brevity. if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) { continue } selectKey := axis.SelectKey(config) - if use, value := labelListSelectValue(selectKey, labels, list.EmitEmptyList); use { + if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use { archSelects[selectKey] = value } } @@ -144,9 +147,15 @@ func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) { shouldPrintDefault = true } case bazel.LabelAttribute: + if err := list.Collapse(); err != nil { + return "", err + } value, configurableAttrs = getLabelValue(list) defaultSelectValue = &bazelNone case bazel.BoolAttribute: + if err := list.Collapse(); err != nil { + return "", err + } value, configurableAttrs = getBoolValue(list) defaultSelectValue = &bazelNone default: @@ -204,11 +213,12 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *stri continue } value := selectMap[selectKey] - if isZero(value) && !emitZeroValues { - // Ignore zero values to not generate empty lists. + if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) { + // Ignore zero values to not generate empty lists. However, always note zero values if + // the default value is non-zero. continue } - s, err := prettyPrintSelectEntry(value, selectKey, indent, emitZeroValues) + s, err := prettyPrintSelectEntry(value, selectKey, indent, true) if err != nil { return "", err } diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go index 506589389..3a5d5bb2a 100644 --- a/bp2build/prebuilt_etc_conversion_test.go +++ b/bp2build/prebuilt_etc_conversion_test.go @@ -86,3 +86,45 @@ prebuilt_etc { "sub_dir": `"tz"`, })}}) } + +func TestPrebuiltEtcArchAndTargetVariant(t *testing.T) { + runPrebuiltEtcTestCase(t, bp2buildTestCase{ + description: "prebuilt_etc - arch variant", + filesystem: map[string]string{}, + blueprint: ` +prebuilt_etc { + name: "apex_tz_version", + src: "version/tz_version", + filename: "tz_version", + sub_dir: "tz", + installable: false, + arch: { + arm: { + src: "arm", + }, + arm64: { + src: "darwin_or_arm64", + }, + }, + target: { + darwin: { + src: "darwin_or_arm64", + } + }, +} +`, + expectedBazelTargets: []string{ + makeBazelTarget("prebuilt_etc", "apex_tz_version", attrNameToString{ + "filename": `"tz_version"`, + "installable": `False`, + "src": `select({ + "//build/bazel/platforms/os_arch:android_arm": "arm", + "//build/bazel/platforms/os_arch:android_arm64": "darwin_or_arm64", + "//build/bazel/platforms/os_arch:darwin_arm64": "darwin_or_arm64", + "//build/bazel/platforms/os_arch:darwin_x86_64": "darwin_or_arm64", + "//build/bazel/platforms/os_arch:linux_bionic_arm64": "darwin_or_arm64", + "//conditions:default": "version/tz_version", + })`, + "sub_dir": `"tz"`, + })}}) +} diff --git a/cc/binary.go b/cc/binary.go index 50175d92f..b59e762aa 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -558,13 +558,6 @@ func (binary *binaryDecorator) verifyHostBionicLinker(ctx ModuleContext, in, lin } func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) { - var compatibleWith bazel.StringListAttribute - if typ == "cc_binary_host" { - //incompatible with android OS - compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, []string{"@platforms//:incompatible"}) - compatibleWith.SetSelectValue(bazel.OsConfigurationAxis, bazel.ConditionsDefaultConfigKey, []string{}) - } - baseAttrs := bp2BuildParseBaseProps(ctx, m) binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m) @@ -610,16 +603,22 @@ func binaryBp2build(ctx android.TopDownMutatorContext, m *Module, typ string) { None: baseAttrs.stripNone, }, - Target_compatible_with: compatibleWith, - Features: baseAttrs.features, + Features: baseAttrs.features, } - ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{ + var enabledProperty bazel.BoolAttribute + if typ == "cc_binary_host" { + falseVal := false + enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, android.Android.Name, &falseVal) + } + + ctx.CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties{ Rule_class: "cc_binary", Bzl_load_location: "//build/bazel/rules:cc_binary.bzl", }, android.CommonAttributes{Name: m.Name()}, - attrs) + attrs, + enabledProperty) } // binaryAttributes contains Bazel attributes corresponding to a cc binary @@ -655,6 +654,4 @@ type binaryAttributes struct { Strip stripAttributes Features bazel.StringListAttribute - - Target_compatible_with bazel.StringListAttribute } diff --git a/cc/bp2build.go b/cc/bp2build.go index 2119ee43f..e4762a064 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -57,6 +57,8 @@ type staticOrSharedAttributes struct { Implementation_whole_archive_deps bazel.LabelListAttribute System_dynamic_deps bazel.LabelListAttribute + + Enabled bazel.BoolAttribute } func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute { @@ -175,6 +177,7 @@ func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, mo attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation) attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs)) + attrs.Enabled.SetSelectValue(axis, config, props.Enabled) } // system_dynamic_deps distinguishes between nil/empty list behavior: // nil -> use default values diff --git a/cc/cc.go b/cc/cc.go index 22baf30e1..281ebc12a 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -3461,8 +3461,15 @@ func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) { objectBp2Build(ctx, c) } } else if c.CcLibrary() { - static := c.BuildStaticVariant() - shared := c.BuildSharedVariant() + static := false + shared := false + if library, ok := c.linker.(*libraryDecorator); ok { + static = library.MutatedProperties.BuildStatic + shared = library.MutatedProperties.BuildShared + } else if library, ok := c.linker.(*prebuiltLibraryLinker); ok { + static = library.MutatedProperties.BuildStatic + shared = library.MutatedProperties.BuildShared + } if static && shared { if !prebuilt { diff --git a/cc/library.go b/cc/library.go index 216c12409..5720944ab 100644 --- a/cc/library.go +++ b/cc/library.go @@ -392,8 +392,12 @@ func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) { Bzl_load_location: "//build/bazel/rules:cc_library_shared.bzl", } - ctx.CreateBazelTargetModule(staticProps, android.CommonAttributes{Name: m.Name() + "_bp2build_cc_library_static"}, staticTargetAttrs) - ctx.CreateBazelTargetModule(sharedProps, android.CommonAttributes{Name: m.Name()}, sharedTargetAttrs) + ctx.CreateBazelTargetModuleWithRestrictions(staticProps, + android.CommonAttributes{Name: m.Name() + "_bp2build_cc_library_static"}, + staticTargetAttrs, staticAttrs.Enabled) + ctx.CreateBazelTargetModuleWithRestrictions(sharedProps, + android.CommonAttributes{Name: m.Name()}, + sharedTargetAttrs, sharedAttrs.Enabled) } // cc_library creates both static and/or shared libraries for a device and/or diff --git a/cc/object.go b/cc/object.go index bd43e3670..24f6ed455 100644 --- a/cc/object.go +++ b/cc/object.go @@ -155,7 +155,8 @@ func objectBp2Build(ctx android.TopDownMutatorContext, m *Module) { for config, props := range configToProps { if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok { if objectLinkerProps.Linker_script != nil { - linkerScript.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script)) + label := android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script) + linkerScript.SetSelectValue(axis, config, label) } deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs)) systemSharedLibs := objectLinkerProps.System_shared_libs diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index c2866abfa..83de65fe0 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -681,7 +681,8 @@ func prebuiltEtcBp2BuildInternal(ctx android.TopDownMutatorContext, module *Preb continue } if props.Src != nil { - srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, *props.Src)) + label := android.BazelLabelForModuleSrcSingle(ctx, *props.Src) + srcLabelAttribute.SetSelectValue(axis, config, label) } } }