diff options
34 files changed, 1568 insertions, 538 deletions
diff --git a/android/arch.go b/android/arch.go index 10c827ba2..9ff439ccc 100644 --- a/android/arch.go +++ b/android/arch.go @@ -897,7 +897,7 @@ func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc { // Add the OS/Arch combinations, e.g. "android_arm64". for _, archType := range osArchTypeMap[os] { - targets = append(targets, os.Field+"_"+archType.Name) + targets = append(targets, GetCompoundTargetName(os, archType)) // Also add the special "linux_<arch>" and "bionic_<arch>" property structs. if os.Linux() { @@ -1217,6 +1217,10 @@ func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archT return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib) } +func GetCompoundTargetName(os OsType, arch ArchType) string { + return os.Field + "_" + arch.Name +} + // Returns the structs corresponding to the properties specific to the given // architecture and OS in archProperties. func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value { @@ -1323,7 +1327,7 @@ func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch // key: value, // }, // }, - field := os.Field + "_" + archType.Name + field := GetCompoundTargetName(os, archType) userFriendlyField := "target." + os.Name + "_" + archType.Name if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok { result = append(result, osArchProperties) @@ -1950,19 +1954,47 @@ func (m *ModuleBase) GetArchProperties(ctx ArchVariantContext, propertySet inter return archToProp } -// Returns the struct containing the properties specific to the given -// architecture type. These look like this in Blueprint files: -// target: { -// android: { -// key: value, -// }, -// }, -// This struct will also contain sub-structs containing to the architecture/CPU -// variants and features that themselves contain properties specific to those. -func getTargetStruct(ctx ArchVariantContext, archProperties interface{}, os OsType) (reflect.Value, bool) { - archPropValues := reflect.ValueOf(archProperties).Elem() - targetProp := archPropValues.FieldByName("Target").Elem() - return getChildPropertyStruct(ctx, targetProp, os.Field, os.Field) +// Returns a struct matching the propertySet interface, containing properties specific to the targetName +// For example, given these arguments: +// propertySet = BaseCompilerProperties +// targetName = "android_arm" +// And given this Android.bp fragment: +// target: +// android_arm: { +// srcs: ["foo.c"], +// } +// android_arm64: { +// srcs: ["bar.c"], +// } +// } +// This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"] +func getTargetStruct(ctx ArchVariantContext, propertySet interface{}, archProperties []interface{}, targetName string) interface{} { + propertyStructs := make([]reflect.Value, 0) + for _, archProperty := range archProperties { + archPropValues := reflect.ValueOf(archProperty).Elem() + targetProp := archPropValues.FieldByName("Target").Elem() + targetStruct, ok := getChildPropertyStruct(ctx, targetProp, targetName, targetName) + if ok { + propertyStructs = append(propertyStructs, targetStruct) + } + } + + // Create a new instance of the requested property set + value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() + + // Merge all the structs together + for _, propertyStruct := range propertyStructs { + mergePropertyStruct(ctx, value, propertyStruct) + } + + return value +} + +// Properties corresponds to e.g. Target: android: {...} +// ArchProperties corresponds to e.g. Target: android_arm: {...}, android_arm64: {...}, ... +type TargetProperties struct { + Properties interface{} + ArchProperties map[ArchType]interface{} } // GetTargetProperties returns a map of OS target (e.g. android, windows) to the @@ -1974,13 +2006,15 @@ func getTargetStruct(ctx ArchVariantContext, archProperties interface{}, os OsTy // the os-specific property value specified by the module if defined. // // Implemented in a way very similar to GetArchProperties(). -func (m *ModuleBase) GetTargetProperties(ctx ArchVariantContext, propertySet interface{}) map[OsType]interface{} { - // Return value of the arch types to the prop values for that arch. - osToProp := map[OsType]interface{}{} +// +// NOTE: "Target" == OS +func (m *ModuleBase) GetTargetProperties(ctx ArchVariantContext, propertySet interface{}) map[OsType]TargetProperties { + // Return value of the target types to the prop values for that target. + targetToProp := map[OsType]TargetProperties{} - // Nothing to do for non-OS/arch-specific modules. + // Nothing to do for non-target-specific modules. if !m.ArchSpecific() { - return osToProp + return targetToProp } dstType := reflect.ValueOf(propertySet).Type() @@ -1998,33 +2032,26 @@ func (m *ModuleBase) GetTargetProperties(ctx ArchVariantContext, propertySet int if archProperties == nil { // This module does not have the property set requested - return osToProp + return targetToProp } + // For android, linux, ... for _, os := range osTypeList { if os == CommonOS { // It looks like this OS value is not used in Blueprint files continue } - - propertyStructs := make([]reflect.Value, 0) - for _, archProperty := range archProperties { - targetStruct, ok := getTargetStruct(ctx, archProperty, os) - if ok { - propertyStructs = append(propertyStructs, targetStruct) - } + targetProperties := TargetProperties{ + Properties: getTargetStruct(ctx, propertySet, archProperties, os.Field), + ArchProperties: make(map[ArchType]interface{}), } - - // Create a new instance of the requested property set - value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface() - - // Merge all the structs together - for _, propertyStruct := range propertyStructs { - mergePropertyStruct(ctx, value, propertyStruct) + // For arm, x86, ... + for _, arch := range osArchTypeMap[os] { + targetName := GetCompoundTargetName(os, arch) + targetProperties.ArchProperties[arch] = getTargetStruct(ctx, propertySet, archProperties, targetName) } - - osToProp[os] = value + targetToProp[os] = targetProperties } - return osToProp + return targetToProp } diff --git a/android/bazel.go b/android/bazel.go index f56c24e04..ef770bf9c 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -138,7 +138,6 @@ var ( // e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed "external/bazelbuild-rules_android":/* recursive = */ true, - "prebuilts/clang/host/linux-x86":/* recursive = */ false, "prebuilts/sdk":/* recursive = */ false, "prebuilts/sdk/tools":/* recursive = */ false, } @@ -155,6 +154,7 @@ var ( "external/fmtlib": Bp2BuildDefaultTrueRecursively, "external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively, "external/scudo": Bp2BuildDefaultTrueRecursively, + "prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively, } // Per-module denylist to always opt modules out of both bp2build and mixed builds. diff --git a/android/variable.go b/android/variable.go index 672576a9f..7658cdd4a 100644 --- a/android/variable.go +++ b/android/variable.go @@ -467,7 +467,7 @@ type ProductConfigProperties map[string][]ProductConfigProperty // ProductVariableProperties returns a ProductConfigProperties containing only the properties which // have been set for the module in the given context. -func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties { +func ProductVariableProperties(ctx BaseMutatorContext) ProductConfigProperties { module := ctx.Module() moduleBase := module.base() @@ -477,7 +477,31 @@ func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties return productConfigProperties } - variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName("Product_variables") + productVariableValues(moduleBase.variableProperties, "", &productConfigProperties) + + for arch, targetProps := range moduleBase.GetArchProperties(ctx, moduleBase.variableProperties) { + // GetArchProperties is creating an instance of the requested type + // and productVariablesValues expects an interface, so no need to cast + productVariableValues(targetProps, arch.Name, &productConfigProperties) + } + + for os, targetProps := range moduleBase.GetTargetProperties(ctx, moduleBase.variableProperties) { + // GetTargetProperties is creating an instance of the requested type + // and productVariablesValues expects an interface, so no need to cast + productVariableValues(targetProps.Properties, os.Name, &productConfigProperties) + for arch, archProperties := range targetProps.ArchProperties { + productVariableValues(archProperties, os.Name+"_"+arch.Name, &productConfigProperties) + } + } + + return productConfigProperties +} + +func productVariableValues(variableProps interface{}, suffix string, productConfigProperties *ProductConfigProperties) { + if suffix != "" { + suffix = "-" + suffix + } + variableValues := reflect.ValueOf(variableProps).Elem().FieldByName("Product_variables") for i := 0; i < variableValues.NumField(); i++ { variableValue := variableValues.Field(i) // Check if any properties were set for the module @@ -495,15 +519,13 @@ func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties // e.g. Asflags, Cflags, Enabled, etc. propertyName := variableValue.Type().Field(j).Name - productConfigProperties[propertyName] = append(productConfigProperties[propertyName], + (*productConfigProperties)[propertyName] = append((*productConfigProperties)[propertyName], ProductConfigProperty{ - ProductConfigVariable: productVariableName, + ProductConfigVariable: productVariableName + suffix, Property: property.Interface(), }) } } - - return productConfigProperties } func VariableMutator(mctx BottomUpMutatorContext) { diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 9965f83bd..7aecff62d 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -62,6 +62,7 @@ func TestBootclasspathFragments(t *testing.T) { apex { name: "com.android.art", key: "com.android.art.key", + bootclasspath_fragments: ["art-bootclasspath-fragment"], java_libs: [ "baz", "quuz", @@ -100,32 +101,12 @@ func TestBootclasspathFragments(t *testing.T) { "com.android.art", ], } - - bootclasspath_fragment { - name: "framework-bootclasspath-fragment", - image_name: "boot", - } `, ) - // Make sure that the framework-bootclasspath-fragment is using the correct configuration. - checkBootclasspathFragment(t, result, "framework-bootclasspath-fragment", "platform:foo,platform:bar", ` -test_device/dex_bootjars/android/system/framework/arm/boot-foo.art -test_device/dex_bootjars/android/system/framework/arm/boot-foo.oat -test_device/dex_bootjars/android/system/framework/arm/boot-foo.vdex -test_device/dex_bootjars/android/system/framework/arm/boot-bar.art -test_device/dex_bootjars/android/system/framework/arm/boot-bar.oat -test_device/dex_bootjars/android/system/framework/arm/boot-bar.vdex -test_device/dex_bootjars/android/system/framework/arm64/boot-foo.art -test_device/dex_bootjars/android/system/framework/arm64/boot-foo.oat -test_device/dex_bootjars/android/system/framework/arm64/boot-foo.vdex -test_device/dex_bootjars/android/system/framework/arm64/boot-bar.art -test_device/dex_bootjars/android/system/framework/arm64/boot-bar.oat -test_device/dex_bootjars/android/system/framework/arm64/boot-bar.vdex -`) - // Make sure that the art-bootclasspath-fragment is using the correct configuration. - checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "com.android.art:baz,com.android.art:quuz", ` + checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000", + "com.android.art:baz,com.android.art:quuz", ` test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex @@ -263,10 +244,10 @@ func TestBootclasspathFragments_FragmentDependency(t *testing.T) { checkSdkKindStubs("other", otherInfo, android.SdkCorePlatform) } -func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) { +func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) { t.Helper() - bootclasspathFragment := result.ModuleForTests(moduleName, "android_common").Module().(*java.BootclasspathFragmentModule) + bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule) bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo) modules := bootclasspathFragmentInfo.Modules() @@ -401,7 +382,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { ).RunTest(t) ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ - "etc/classpaths/mybootclasspathfragment.pb", + "etc/classpaths/bootclasspath.pb", "javalib/arm/boot.art", "javalib/arm/boot.oat", "javalib/arm/boot.vdex", @@ -613,7 +594,7 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ // This does not include art, oat or vdex files as they are only included for the art boot // image. - "etc/classpaths/mybootclasspathfragment.pb", + "etc/classpaths/bootclasspath.pb", "javalib/bar.jar", "javalib/foo.jar", }) diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index e1a101ad9..95b6e230d 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -67,7 +67,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) { `) ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ - "etc/classpaths/mysystemserverclasspathfragment.pb", + "etc/classpaths/systemserverclasspath.pb", "javalib/foo.jar", }) diff --git a/bazel/properties.go b/bazel/properties.go index 3e778bb69..8adc9d07f 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -19,6 +19,7 @@ import ( "path/filepath" "regexp" "sort" + "strings" ) // BazelTargetModuleProperties contain properties and metadata used for @@ -136,6 +137,63 @@ func SubtractStrings(haystack []string, needle []string) []string { return strings } +// Return all needles in a given haystack, where needleFn is true for needles. +func FilterLabelList(haystack LabelList, needleFn func(string) bool) LabelList { + var includes []Label + + for _, inc := range haystack.Includes { + if needleFn(inc.Label) { + includes = append(includes, inc) + } + } + return LabelList{Includes: includes, Excludes: haystack.Excludes} +} + +// Return all needles in a given haystack, where needleFn is true for needles. +func FilterLabelListAttribute(haystack LabelListAttribute, needleFn func(string) bool) LabelListAttribute { + var result LabelListAttribute + + result.Value = FilterLabelList(haystack.Value, needleFn) + + for arch := range PlatformArchMap { + result.SetValueForArch(arch, FilterLabelList(haystack.GetValueForArch(arch), needleFn)) + } + + for os := range PlatformOsMap { + result.SetOsValueForTarget(os, FilterLabelList(haystack.GetOsValueForTarget(os), needleFn)) + + // TODO(b/187530594): Should we handle arch=CONDITIONS_DEFAULT here? (not in ArchValues) + for _, arch := range AllArches { + result.SetOsArchValueForTarget(os, arch, FilterLabelList(haystack.GetOsArchValueForTarget(os, arch), needleFn)) + } + } + + return result +} + +// Subtract needle from haystack +func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute { + var result LabelListAttribute + + for arch := range PlatformArchMap { + result.SetValueForArch(arch, + SubtractBazelLabelList(haystack.GetValueForArch(arch), needle.GetValueForArch(arch))) + } + + for os := range PlatformOsMap { + result.SetOsValueForTarget(os, SubtractBazelLabelList(haystack.GetOsValueForTarget(os), needle.GetOsValueForTarget(os))) + + // TODO(b/187530594): Should we handle arch=CONDITIONS_DEFAULT here? (not in ArchValues) + for _, arch := range AllArches { + result.SetOsArchValueForTarget(os, arch, SubtractBazelLabelList(haystack.GetOsArchValueForTarget(os, arch), needle.GetOsArchValueForTarget(os, arch))) + } + } + + result.Value = SubtractBazelLabelList(haystack.Value, needle.Value) + + return result +} + // Subtract needle from haystack func SubtractBazelLabels(haystack []Label, needle []Label) []Label { // This is really a set @@ -192,6 +250,21 @@ const ( OS_LINUX_BIONIC = "linux_bionic" OS_WINDOWS = "windows" + // Targets in arch.go + TARGET_ANDROID_ARM = "android_arm" + TARGET_ANDROID_ARM64 = "android_arm64" + TARGET_ANDROID_X86 = "android_x86" + TARGET_ANDROID_X86_64 = "android_x86_64" + TARGET_DARWIN_X86_64 = "darwin_x86_64" + TARGET_FUCHSIA_ARM64 = "fuchsia_arm64" + TARGET_FUCHSIA_X86_64 = "fuchsia_x86_64" + TARGET_LINUX_X86 = "linux_glibc_x86" + TARGET_LINUX_x86_64 = "linux_glibc_x86_64" + TARGET_LINUX_BIONIC_ARM64 = "linux_bionic_arm64" + TARGET_LINUX_BIONIC_X86_64 = "linux_bionic_x86_64" + TARGET_WINDOWS_X86 = "windows_x86" + TARGET_WINDOWS_X86_64 = "windows_x86_64" + // This is the string representation of the default condition wherever a // configurable attribute is used in a select statement, i.e. // //conditions:default for Bazel. @@ -200,6 +273,10 @@ const ( // config variable default key in an Android.bp file, although there's no // integration with Soong config variables (yet). CONDITIONS_DEFAULT = "conditions_default" + + ConditionsDefaultSelectKey = "//conditions:default" + + productVariableBazelPackage = "//build/bazel/product_variables" ) var ( @@ -215,7 +292,7 @@ var ( ARCH_ARM64: "//build/bazel/platforms/arch:arm64", ARCH_X86: "//build/bazel/platforms/arch:x86", ARCH_X86_64: "//build/bazel/platforms/arch:x86_64", - CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map. + CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of as arch select map. } // A map of target operating systems to the Bazel label of the @@ -227,8 +304,28 @@ var ( OS_LINUX: "//build/bazel/platforms/os:linux", OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic", OS_WINDOWS: "//build/bazel/platforms/os:windows", - CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map. - } + CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map. + } + + PlatformTargetMap = map[string]string{ + TARGET_ANDROID_ARM: "//build/bazel/platforms:android_arm", + TARGET_ANDROID_ARM64: "//build/bazel/platforms:android_arm64", + TARGET_ANDROID_X86: "//build/bazel/platforms:android_x86", + TARGET_ANDROID_X86_64: "//build/bazel/platforms:android_x86_64", + TARGET_DARWIN_X86_64: "//build/bazel/platforms:darwin_x86_64", + TARGET_FUCHSIA_ARM64: "//build/bazel/platforms:fuchsia_arm64", + TARGET_FUCHSIA_X86_64: "//build/bazel/platforms:fuchsia_x86_64", + TARGET_LINUX_X86: "//build/bazel/platforms:linux_glibc_x86", + TARGET_LINUX_x86_64: "//build/bazel/platforms:linux_glibc_x86_64", + TARGET_LINUX_BIONIC_ARM64: "//build/bazel/platforms:linux_bionic_arm64", + TARGET_LINUX_BIONIC_X86_64: "//build/bazel/platforms:linux_bionic_x86_64", + TARGET_WINDOWS_X86: "//build/bazel/platforms:windows_x86", + TARGET_WINDOWS_X86_64: "//build/bazel/platforms:windows_x86_64", + CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map. + } + + // TODO(b/187530594): Should we add CONDITIONS_DEFAULT here? + AllArches = []string{ARCH_ARM, ARCH_ARM64, ARCH_X86, ARCH_X86_64} ) type Attribute interface { @@ -292,15 +389,32 @@ type labelListArchValues struct { ConditionsDefault LabelList } -type labelListOsValues struct { - Android LabelList - Darwin LabelList - Fuchsia LabelList - Linux LabelList - LinuxBionic LabelList - Windows LabelList +type labelListTargetValue struct { + // E.g. for android + OsValue LabelList - ConditionsDefault LabelList + // E.g. for android_arm, android_arm64, ... + ArchValues labelListArchValues +} + +func (target *labelListTargetValue) Append(other labelListTargetValue) { + target.OsValue.Append(other.OsValue) + target.ArchValues.X86.Append(other.ArchValues.X86) + target.ArchValues.X86_64.Append(other.ArchValues.X86_64) + target.ArchValues.Arm.Append(other.ArchValues.Arm) + target.ArchValues.Arm64.Append(other.ArchValues.Arm64) + target.ArchValues.ConditionsDefault.Append(other.ArchValues.ConditionsDefault) +} + +type labelListTargetValues struct { + Android labelListTargetValue + Darwin labelListTargetValue + Fuchsia labelListTargetValue + Linux labelListTargetValue + LinuxBionic labelListTargetValue + Windows labelListTargetValue + + ConditionsDefault labelListTargetValue } // LabelListAttribute is used to represent a list of Bazel labels as an @@ -317,7 +431,7 @@ type LabelListAttribute struct { // The os-specific attribute label list values. Optional. If used, these // are generated in a select statement and appended to the non-os specific // label list Value. - OsValues labelListOsValues + TargetValues labelListTargetValues } // MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value. @@ -336,10 +450,10 @@ func (attrs *LabelListAttribute) Append(other LabelListAttribute) { } for os := range PlatformOsMap { - this := attrs.GetValueForOS(os) - that := other.GetValueForOS(os) + this := attrs.getValueForTarget(os) + that := other.getValueForTarget(os) this.Append(that) - attrs.SetValueForOS(os, this) + attrs.setValueForTarget(os, this) } attrs.Value.Append(other.Value) @@ -355,9 +469,15 @@ func (attrs LabelListAttribute) HasConfigurableValues() bool { } for os := range PlatformOsMap { - if len(attrs.GetValueForOS(os).Includes) > 0 { + if len(attrs.GetOsValueForTarget(os).Includes) > 0 { return true } + // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT (not in AllArches) + for _, arch := range AllArches { + if len(attrs.GetOsArchValueForTarget(os, arch).Includes) > 0 { + return true + } + } } return false } @@ -390,36 +510,92 @@ func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) { *v = value } -func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList { - return map[string]*LabelList{ - OS_ANDROID: &attrs.OsValues.Android, - OS_DARWIN: &attrs.OsValues.Darwin, - OS_FUCHSIA: &attrs.OsValues.Fuchsia, - OS_LINUX: &attrs.OsValues.Linux, - OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic, - OS_WINDOWS: &attrs.OsValues.Windows, - CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault, +func (attrs *LabelListAttribute) targetValuePtrs() map[string]*labelListTargetValue { + return map[string]*labelListTargetValue{ + OS_ANDROID: &attrs.TargetValues.Android, + OS_DARWIN: &attrs.TargetValues.Darwin, + OS_FUCHSIA: &attrs.TargetValues.Fuchsia, + OS_LINUX: &attrs.TargetValues.Linux, + OS_LINUX_BIONIC: &attrs.TargetValues.LinuxBionic, + OS_WINDOWS: &attrs.TargetValues.Windows, + CONDITIONS_DEFAULT: &attrs.TargetValues.ConditionsDefault, } } -// GetValueForOS returns the label_list attribute value for an OS target. -func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList { - var v *LabelList - if v = attrs.osValuePtrs()[os]; v == nil { +func (attrs *LabelListAttribute) getValueForTarget(os string) labelListTargetValue { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { panic(fmt.Errorf("Unknown os: %s", os)) } return *v } -// SetValueForArch sets the label_list attribute value for an OS target. -func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) { - var v *LabelList - if v = attrs.osValuePtrs()[os]; v == nil { +func (attrs *LabelListAttribute) GetOsValueForTarget(os string) LabelList { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + return v.OsValue +} + +func (attrs *LabelListAttribute) GetOsArchValueForTarget(os string, arch string) LabelList { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + switch arch { + case ARCH_X86: + return v.ArchValues.X86 + case ARCH_X86_64: + return v.ArchValues.X86_64 + case ARCH_ARM: + return v.ArchValues.Arm + case ARCH_ARM64: + return v.ArchValues.Arm64 + case CONDITIONS_DEFAULT: + return v.ArchValues.ConditionsDefault + default: + panic(fmt.Errorf("Unknown arch: %s\n", arch)) + } +} + +func (attrs *LabelListAttribute) setValueForTarget(os string, value labelListTargetValue) { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { panic(fmt.Errorf("Unknown os: %s", os)) } *v = value } +func (attrs *LabelListAttribute) SetOsValueForTarget(os string, value LabelList) { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + v.OsValue = value +} + +func (attrs *LabelListAttribute) SetOsArchValueForTarget(os string, arch string, value LabelList) { + var v *labelListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + switch arch { + case ARCH_X86: + v.ArchValues.X86 = value + case ARCH_X86_64: + v.ArchValues.X86_64 = value + case ARCH_ARM: + v.ArchValues.Arm = value + case ARCH_ARM64: + v.ArchValues.Arm64 = value + case CONDITIONS_DEFAULT: + v.ArchValues.ConditionsDefault = value + default: + panic(fmt.Errorf("Unknown arch: %s\n", arch)) + } +} + // StringListAttribute corresponds to the string_list Bazel attribute type with // support for additional metadata, like configurations. type StringListAttribute struct { @@ -434,7 +610,11 @@ type StringListAttribute struct { // The os-specific attribute string list values. Optional. If used, these // are generated in a select statement and appended to the non-os specific // label list Value. - OsValues stringListOsValues + TargetValues stringListTargetValues + + // list of product-variable string list values. Optional. if used, each will generate a select + // statement appended to the label list Value. + ProductValues []ProductVariableValues } // MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value. @@ -455,15 +635,44 @@ type stringListArchValues struct { ConditionsDefault []string } -type stringListOsValues struct { - Android []string - Darwin []string - Fuchsia []string - Linux []string - LinuxBionic []string - Windows []string +type stringListTargetValue struct { + // E.g. for android + OsValue []string - ConditionsDefault []string + // E.g. for android_arm, android_arm64, ... + ArchValues stringListArchValues +} + +func (target *stringListTargetValue) Append(other stringListTargetValue) { + target.OsValue = append(target.OsValue, other.OsValue...) + target.ArchValues.X86 = append(target.ArchValues.X86, other.ArchValues.X86...) + target.ArchValues.X86_64 = append(target.ArchValues.X86_64, other.ArchValues.X86_64...) + target.ArchValues.Arm = append(target.ArchValues.Arm, other.ArchValues.Arm...) + target.ArchValues.Arm64 = append(target.ArchValues.Arm64, other.ArchValues.Arm64...) + target.ArchValues.ConditionsDefault = append(target.ArchValues.ConditionsDefault, other.ArchValues.ConditionsDefault...) +} + +type stringListTargetValues struct { + Android stringListTargetValue + Darwin stringListTargetValue + Fuchsia stringListTargetValue + Linux stringListTargetValue + LinuxBionic stringListTargetValue + Windows stringListTargetValue + + ConditionsDefault stringListTargetValue +} + +// Product Variable values for StringListAttribute +type ProductVariableValues struct { + ProductVariable string + + Values []string +} + +// SelectKey returns the appropriate select key for the receiving ProductVariableValues. +func (p ProductVariableValues) SelectKey() string { + return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(p.ProductVariable)) } // HasConfigurableValues returns true if the attribute contains @@ -476,11 +685,19 @@ func (attrs StringListAttribute) HasConfigurableValues() bool { } for os := range PlatformOsMap { - if len(attrs.GetValueForOS(os)) > 0 { + if len(attrs.GetOsValueForTarget(os)) > 0 { return true } + // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (Not in AllArches) + for _, arch := range AllArches { + if len(attrs.GetOsArchValueForTarget(os, arch)) > 0 { + return true + } + + } } - return false + + return len(attrs.ProductValues) > 0 } func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string { @@ -511,36 +728,98 @@ func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { *v = value } -func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string { - return map[string]*[]string{ - OS_ANDROID: &attrs.OsValues.Android, - OS_DARWIN: &attrs.OsValues.Darwin, - OS_FUCHSIA: &attrs.OsValues.Fuchsia, - OS_LINUX: &attrs.OsValues.Linux, - OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic, - OS_WINDOWS: &attrs.OsValues.Windows, - CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault, +func (attrs *StringListAttribute) targetValuePtrs() map[string]*stringListTargetValue { + return map[string]*stringListTargetValue{ + OS_ANDROID: &attrs.TargetValues.Android, + OS_DARWIN: &attrs.TargetValues.Darwin, + OS_FUCHSIA: &attrs.TargetValues.Fuchsia, + OS_LINUX: &attrs.TargetValues.Linux, + OS_LINUX_BIONIC: &attrs.TargetValues.LinuxBionic, + OS_WINDOWS: &attrs.TargetValues.Windows, + CONDITIONS_DEFAULT: &attrs.TargetValues.ConditionsDefault, } } -// GetValueForOS returns the string_list attribute value for an OS target. -func (attrs *StringListAttribute) GetValueForOS(os string) []string { - var v *[]string - if v = attrs.osValuePtrs()[os]; v == nil { +func (attrs *StringListAttribute) getValueForTarget(os string) stringListTargetValue { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { panic(fmt.Errorf("Unknown os: %s", os)) } return *v } -// SetValueForArch sets the string_list attribute value for an OS target. -func (attrs *StringListAttribute) SetValueForOS(os string, value []string) { - var v *[]string - if v = attrs.osValuePtrs()[os]; v == nil { +func (attrs *StringListAttribute) GetOsValueForTarget(os string) []string { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + return v.OsValue +} + +func (attrs *StringListAttribute) GetOsArchValueForTarget(os string, arch string) []string { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + switch arch { + case ARCH_X86: + return v.ArchValues.X86 + case ARCH_X86_64: + return v.ArchValues.X86_64 + case ARCH_ARM: + return v.ArchValues.Arm + case ARCH_ARM64: + return v.ArchValues.Arm64 + case CONDITIONS_DEFAULT: + return v.ArchValues.ConditionsDefault + default: + panic(fmt.Errorf("Unknown arch: %s\n", arch)) + } +} + +func (attrs *StringListAttribute) setValueForTarget(os string, value stringListTargetValue) { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { panic(fmt.Errorf("Unknown os: %s", os)) } *v = value } +func (attrs *StringListAttribute) SortedProductVariables() []ProductVariableValues { + vals := attrs.ProductValues[:] + sort.Slice(vals, func(i, j int) bool { return vals[i].ProductVariable < vals[j].ProductVariable }) + return vals +} + +func (attrs *StringListAttribute) SetOsValueForTarget(os string, value []string) { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + v.OsValue = value +} + +func (attrs *StringListAttribute) SetOsArchValueForTarget(os string, arch string, value []string) { + var v *stringListTargetValue + if v = attrs.targetValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + switch arch { + case ARCH_X86: + v.ArchValues.X86 = value + case ARCH_X86_64: + v.ArchValues.X86_64 = value + case ARCH_ARM: + v.ArchValues.Arm = value + case ARCH_ARM64: + v.ArchValues.Arm64 = value + case CONDITIONS_DEFAULT: + v.ArchValues.ConditionsDefault = value + default: + panic(fmt.Errorf("Unknown arch: %s\n", arch)) + } +} + // Append appends all values, including os and arch specific ones, from another // StringListAttribute to this StringListAttribute func (attrs *StringListAttribute) Append(other StringListAttribute) { @@ -552,10 +831,25 @@ func (attrs *StringListAttribute) Append(other StringListAttribute) { } for os := range PlatformOsMap { - this := attrs.GetValueForOS(os) - that := other.GetValueForOS(os) - this = append(this, that...) - attrs.SetValueForOS(os, this) + this := attrs.getValueForTarget(os) + that := other.getValueForTarget(os) + this.Append(that) + attrs.setValueForTarget(os, this) + } + + productValues := make(map[string][]string, 0) + for _, pv := range attrs.ProductValues { + productValues[pv.ProductVariable] = pv.Values + } + for _, pv := range other.ProductValues { + productValues[pv.ProductVariable] = append(productValues[pv.ProductVariable], pv.Values...) + } + attrs.ProductValues = make([]ProductVariableValues, 0, len(productValues)) + for pv, vals := range productValues { + attrs.ProductValues = append(attrs.ProductValues, ProductVariableValues{ + ProductVariable: pv, + Values: vals, + }) } attrs.Value = append(attrs.Value, other.Value...) diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index bddc524cd..388c8cf66 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -19,6 +19,7 @@ import ( "android/soong/bazel" "fmt" "reflect" + "sort" "strings" "github.com/google/blueprint" @@ -34,6 +35,7 @@ type BazelTarget struct { content string ruleClass string bzlLoadLocation string + handcrafted bool } // IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file, @@ -45,12 +47,47 @@ func (t BazelTarget) IsLoadedFromStarlark() bool { // BazelTargets is a typedef for a slice of BazelTarget objects. type BazelTargets []BazelTarget +// HasHandcraftedTargetsreturns true if a set of bazel targets contain +// handcrafted ones. +func (targets BazelTargets) hasHandcraftedTargets() bool { + for _, target := range targets { + if target.handcrafted { + return true + } + } + return false +} + +// sort a list of BazelTargets in-place, by name, and by generated/handcrafted types. +func (targets BazelTargets) sort() { + sort.Slice(targets, func(i, j int) bool { + if targets[i].handcrafted != targets[j].handcrafted { + // Handcrafted targets will be generated after the bp2build generated targets. + return targets[j].handcrafted + } + // This will cover all bp2build generated targets. + return targets[i].name < targets[j].name + }) +} + // String returns the string representation of BazelTargets, without load // statements (use LoadStatements for that), since the targets are usually not // adjacent to the load statements at the top of the BUILD file. func (targets BazelTargets) String() string { var res string for i, target := range targets { + // There is only at most 1 handcrafted "target", because its contents + // represent the entire BUILD file content from the tree. See + // build_conversion.go#getHandcraftedBuildContent for more information. + // + // Add a header to make it easy to debug where the handcrafted targets + // are in a generated BUILD file. + if target.handcrafted { + res += "# -----------------------------\n" + res += "# Section: Handcrafted targets. \n" + res += "# -----------------------------\n\n" + } + res += target.content if i != len(targets)-1 { res += "\n\n" @@ -267,7 +304,8 @@ func getHandcraftedBuildContent(ctx *CodegenContext, b android.Bazelable, pathTo } // TODO(b/181575318): once this is more targeted, we need to include name, rule class, etc return BazelTarget{ - content: c, + content: c, + handcrafted: true, }, nil } @@ -294,6 +332,7 @@ func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module, btm android.B targetName, attributes, ), + handcrafted: false, } } @@ -529,6 +568,9 @@ func isZero(value reflect.Value) bool { return true } default: + if !value.IsValid() { + return true + } zeroValue := reflect.Zero(value.Type()) result := value.Interface() == zeroValue.Interface() return result diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index 71660a8e1..b1c342c69 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -1452,53 +1452,61 @@ filegroup { dir := "." for _, testCase := range testCases { - fs := make(map[string][]byte) - toParse := []string{ - "Android.bp", - } - for f, content := range testCase.fs { - if strings.HasSuffix(f, "Android.bp") { - toParse = append(toParse, f) + t.Run(testCase.description, func(t *testing.T) { + fs := make(map[string][]byte) + toParse := []string{ + "Android.bp", } - fs[f] = []byte(content) - } - config := android.TestConfig(buildDir, nil, testCase.bp, fs) - ctx := android.NewTestContext(config) - ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) - for _, m := range testCase.depsMutators { - ctx.DepsBp2BuildMutators(m) - } - ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) - ctx.RegisterForBazelConversion() + for f, content := range testCase.fs { + if strings.HasSuffix(f, "Android.bp") { + toParse = append(toParse, f) + } + fs[f] = []byte(content) + } + config := android.TestConfig(buildDir, nil, testCase.bp, fs) + ctx := android.NewTestContext(config) + ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) + for _, m := range testCase.depsMutators { + ctx.DepsBp2BuildMutators(m) + } + 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 - } + _, errs := ctx.ParseFileList(dir, toParse) + if errored(t, testCase.description, errs) { + return + } + _, errs = ctx.ResolveDependencies(config) + if errored(t, testCase.description, errs) { + return + } - checkDir := dir - if testCase.dir != "" { - checkDir = testCase.dir - } - bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir) - if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { - t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets) - } else { + checkDir := dir + if testCase.dir != "" { + checkDir = testCase.dir + } + bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir) + bazelTargets.sort() + actualCount := len(bazelTargets) + expectedCount := len(testCase.expectedBazelTargets) + if actualCount != expectedCount { + t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets) + } + if !strings.Contains(bazelTargets.String(), "Section: Handcrafted targets. ") { + t.Errorf("Expected string representation of bazelTargets to contain handcrafted section header.") + } for i, target := range bazelTargets { - if w, g := testCase.expectedBazelTargets[i], target.content; w != g { + actualContent := target.content + expectedContent := testCase.expectedBazelTargets[i] + if expectedContent != actualContent { t.Errorf( - "%s: Expected generated Bazel target to be '%s', got '%s'", - testCase.description, - w, - g, + "Expected generated Bazel target to be '%s', got '%s'", + expectedContent, + actualContent, ) } } - } + }) } } diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go index 0a729374e..6aa148ec2 100644 --- a/bp2build/cc_library_conversion_test.go +++ b/bp2build/cc_library_conversion_test.go @@ -41,6 +41,7 @@ toolchain_library { ) func runCcLibraryTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc) } @@ -52,6 +53,7 @@ func registerCcLibraryModuleTypes(ctx android.RegistrationContext) { } func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) { + t.Helper() dir := "." filesystem := make(map[string][]byte) toParse := []string{ @@ -311,7 +313,7 @@ cc_library { "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"], "//conditions:default": [], }), - srcs = ["math/cosf.c"], + srcs_c = ["math/cosf.c"], )`}, }) } @@ -398,6 +400,141 @@ cc_library { name: "shared_dep_for_both" } }) } +func TestCcLibrarySharedStaticPropsInArch(t *testing.T) { + runCcLibraryTestCase(t, bp2buildTestCase{ + description: "cc_library shared/static props in arch", + moduleTypeUnderTest: "cc_library", + moduleTypeUnderTestFactory: cc.LibraryFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + dir: "foo/bar", + filesystem: map[string]string{ + "foo/bar/arm.cpp": "", + "foo/bar/x86.cpp": "", + "foo/bar/sharedonly.cpp": "", + "foo/bar/staticonly.cpp": "", + "foo/bar/Android.bp": ` +cc_library { + name: "a", + arch: { + arm: { + shared: { + srcs: ["arm_shared.cpp"], + cflags: ["-DARM_SHARED"], + static_libs: ["arm_static_dep_for_shared"], + whole_static_libs: ["arm_whole_static_dep_for_shared"], + shared_libs: ["arm_shared_dep_for_shared"], + }, + }, + x86: { + static: { + srcs: ["x86_static.cpp"], + cflags: ["-DX86_STATIC"], + static_libs: ["x86_dep_for_static"], + }, + }, + }, + target: { + android: { + shared: { + srcs: ["android_shared.cpp"], + cflags: ["-DANDROID_SHARED"], + static_libs: ["android_dep_for_shared"], + }, + }, + android_arm: { + shared: { + cflags: ["-DANDROID_ARM_SHARED"], + }, + }, + }, + srcs: ["both.cpp"], + cflags: ["bothflag"], + static_libs: ["static_dep_for_both"], + static: { + srcs: ["staticonly.cpp"], + cflags: ["staticflag"], + static_libs: ["static_dep_for_static"], + }, + shared: { + srcs: ["sharedonly.cpp"], + cflags: ["sharedflag"], + static_libs: ["static_dep_for_shared"], + }, + bazel_module: { bp2build_available: true }, +} + +cc_library_static { name: "static_dep_for_shared" } +cc_library_static { name: "static_dep_for_static" } +cc_library_static { name: "static_dep_for_both" } + +cc_library_static { name: "arm_static_dep_for_shared" } +cc_library_static { name: "arm_whole_static_dep_for_shared" } +cc_library_static { name: "arm_shared_dep_for_shared" } + +cc_library_static { name: "x86_dep_for_static" } + +cc_library_static { name: "android_dep_for_shared" } +`, + }, + blueprint: soongCcLibraryPreamble, + expectedBazelTargets: []string{`cc_library( + name = "a", + copts = [ + "bothflag", + "-Ifoo/bar", + "-I$(BINDIR)/foo/bar", + ], + dynamic_deps_for_shared = select({ + "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"], + "//conditions:default": [], + }), + implementation_deps = [":static_dep_for_both"], + shared_copts = ["sharedflag"] + select({ + "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms:android_arm": ["-DANDROID_ARM_SHARED"], + "//conditions:default": [], + }), + shared_srcs = ["sharedonly.cpp"] + select({ + "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": ["android_shared.cpp"], + "//conditions:default": [], + }), + srcs = ["both.cpp"], + static_copts = ["staticflag"] + select({ + "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"], + "//conditions:default": [], + }), + static_deps_for_shared = [":static_dep_for_shared"] + select({ + "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms/os:android": [":android_dep_for_shared"], + "//conditions:default": [], + }), + static_deps_for_static = [":static_dep_for_static"] + select({ + "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"], + "//conditions:default": [], + }), + static_srcs = ["staticonly.cpp"] + select({ + "//build/bazel/platforms/arch:x86": ["x86_static.cpp"], + "//conditions:default": [], + }), + whole_archive_deps_for_shared = select({ + "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"], + "//conditions:default": [], + }), +)`}, + }) +} + func TestCcLibraryNonConfiguredVersionScript(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ description: "cc_library non-configured version script", @@ -618,7 +755,7 @@ cc_library { func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) { runCcLibraryTestCase(t, bp2buildTestCase{ - description: "cc_library cppflags goes into copts", + description: "cc_library cppflags usage", moduleTypeUnderTest: "cc_library", moduleTypeUnderTestFactory: cc.LibraryFactory, moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build, @@ -654,10 +791,12 @@ func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) { name = "a", copts = [ "-Wall", - "-fsigned-char", - "-pedantic", "-Ifoo/bar", "-I$(BINDIR)/foo/bar", + ], + cppflags = [ + "-fsigned-char", + "-pedantic", ] + select({ "//build/bazel/platforms/arch:arm64": ["-DARM64=1"], "//conditions:default": [], diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 2859bab70..264ba6bb8 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -84,6 +84,7 @@ func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) { } func runCcLibraryHeadersTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc) } diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 62084a544..833ceba09 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -76,6 +76,7 @@ func registerCcLibraryStaticModuleTypes(ctx android.RegistrationContext) { } func runCcLibraryStaticTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc) } @@ -650,7 +651,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = [ + srcs_c = [ "common.c", "foo-a.c", ], @@ -682,7 +683,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": ["foo-arm.c"], "//conditions:default": [], }), @@ -719,7 +720,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": ["for-arm.c"], "//conditions:default": ["not-for-arm.c"], }), @@ -758,7 +759,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": [ "for-arm.c", "not-for-x86.c", @@ -813,7 +814,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": [ "for-arm.c", "not-for-arm64.c", @@ -909,7 +910,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": ["for-lib32.c"], "//build/bazel/platforms/arch:x86": ["for-lib32.c"], "//conditions:default": ["not-for-lib32.c"], @@ -948,7 +949,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": [ "for-lib32.c", "not-for-lib64.c", @@ -1020,7 +1021,7 @@ cc_library_static { "-I$(BINDIR)/.", ], linkstatic = True, - srcs = ["common.c"] + select({ + srcs_c = ["common.c"] + select({ "//build/bazel/platforms/arch:arm": [ "for-arm.c", "for-lib32.c", @@ -1074,10 +1075,10 @@ func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) { moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, filesystem: map[string]string{ - "common.c": "", - "for-x86.c": "", - "not-for-x86.c": "", - "not-for-everything.c": "", + "common.cpp": "", + "for-x86.cpp": "", + "not-for-x86.cpp": "", + "not-for-everything.cpp": "", "dep/Android.bp": ` genrule { name: "generated_src_other_pkg", @@ -1118,14 +1119,14 @@ genrule { cc_library_static { name: "foo_static3", - srcs: ["common.c", "not-for-*.c"], - exclude_srcs: ["not-for-everything.c"], + srcs: ["common.cpp", "not-for-*.cpp"], + exclude_srcs: ["not-for-everything.cpp"], generated_sources: ["generated_src", "generated_src_other_pkg"], generated_headers: ["generated_hdr", "generated_hdr_other_pkg"], arch: { x86: { - srcs: ["for-x86.c"], - exclude_srcs: ["not-for-x86.c"], + srcs: ["for-x86.cpp"], + exclude_srcs: ["not-for-x86.cpp"], generated_sources: ["generated_src_x86"], generated_headers: ["generated_hdr_other_pkg_x86"], }, @@ -1144,15 +1145,192 @@ cc_library_static { "//dep:generated_src_other_pkg", ":generated_hdr", ":generated_src", - "common.c", + "common.cpp", ] + select({ "//build/bazel/platforms/arch:x86": [ "//dep:generated_hdr_other_pkg_x86", ":generated_src_x86", - "for-x86.c", + "for-x86.cpp", ], - "//conditions:default": ["not-for-x86.c"], + "//conditions:default": ["not-for-x86.cpp"], + }), +)`}, + }) +} + +func TestCcLibraryStaticGetTargetProperties(t *testing.T) { + runCcLibraryStaticTestCase(t, bp2buildTestCase{ + + description: "cc_library_static complex GetTargetProperties", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + blueprint: soongCcLibraryStaticPreamble + ` +cc_library_static { + name: "foo_static", + target: { + android: { + srcs: ["android_src.c"], + }, + android_arm: { + srcs: ["android_arm_src.c"], + }, + android_arm64: { + srcs: ["android_arm64_src.c"], + }, + android_x86: { + srcs: ["android_x86_src.c"], + }, + android_x86_64: { + srcs: ["android_x86_64_src.c"], + }, + linux_bionic_arm64: { + srcs: ["linux_bionic_arm64_src.c"], + }, + linux_bionic_x86_64: { + srcs: ["linux_bionic_x86_64_src.c"], + }, + }, +}`, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + copts = [ + "-I.", + "-I$(BINDIR)/.", + ], + linkstatic = True, + srcs_c = select({ + "//build/bazel/platforms/os:android": ["android_src.c"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms:android_arm": ["android_arm_src.c"], + "//build/bazel/platforms:android_arm64": ["android_arm64_src.c"], + "//build/bazel/platforms:android_x86": ["android_x86_src.c"], + "//build/bazel/platforms:android_x86_64": ["android_x86_64_src.c"], + "//conditions:default": [], + }) + select({ + "//build/bazel/platforms:linux_bionic_arm64": ["linux_bionic_arm64_src.c"], + "//build/bazel/platforms:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"], + "//conditions:default": [], + }), +)`}, + }) +} + +func TestCcLibraryStaticProductVariableSelects(t *testing.T) { + runCcLibraryStaticTestCase(t, bp2buildTestCase{ + description: "cc_library_static product variable selects", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + filesystem: map[string]string{}, + blueprint: soongCcLibraryStaticPreamble + ` +cc_library_static { + name: "foo_static", + srcs: ["common.c"], + product_variables: { + malloc_not_svelte: { + cflags: ["-Wmalloc_not_svelte"], + }, + malloc_zero_contents: { + cflags: ["-Wmalloc_zero_contents"], + }, + binder32bit: { + cflags: ["-Wbinder32bit"], + }, + }, +} `, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + copts = [ + "-I.", + "-I$(BINDIR)/.", + ] + select({ + "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"], + "//conditions:default": [], + }), + linkstatic = True, + srcs_c = ["common.c"], +)`}, + }) +} + +func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) { + runCcLibraryStaticTestCase(t, bp2buildTestCase{ + description: "cc_library_static arch-specific product variable selects", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + filesystem: map[string]string{}, + blueprint: soongCcLibraryStaticPreamble + ` +cc_library_static { + name: "foo_static", + srcs: ["common.c"], + product_variables: { + malloc_not_svelte: { + cflags: ["-Wmalloc_not_svelte"], + }, + }, + arch: { + arm64: { + product_variables: { + malloc_not_svelte: { + cflags: ["-Warm64_malloc_not_svelte"], + }, + }, + }, + }, + multilib: { + lib32: { + product_variables: { + malloc_not_svelte: { + cflags: ["-Wlib32_malloc_not_svelte"], + }, + }, + }, + }, + target: { + android: { + product_variables: { + malloc_not_svelte: { + cflags: ["-Wandroid_malloc_not_svelte"], + }, + }, + } + }, +} `, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + copts = [ + "-I.", + "-I$(BINDIR)/.", + ] + select({ + "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"], + "//conditions:default": [], + }) + select({ + "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"], + "//conditions:default": [], }), + linkstatic = True, + srcs_c = ["common.c"], )`}, }) } diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index b69135b6e..f7e94c28c 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -27,6 +27,7 @@ func registerCcObjectModuleTypes(ctx android.RegistrationContext) { } func runCcObjectTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, registerCcObjectModuleTypes, tc) } @@ -208,7 +209,10 @@ func TestCcObjectProductVariable(t *testing.T) { `, expectedBazelTargets: []string{`cc_object( name = "foo", - asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"], + asflags = select({ + "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"], + "//conditions:default": [], + }), copts = ["-fno-addrsig"], )`, }, diff --git a/bp2build/configurability.go b/bp2build/configurability.go index 2b8f6cc2e..b5070b9c9 100644 --- a/bp2build/configurability.go +++ b/bp2build/configurability.go @@ -11,26 +11,55 @@ import ( type selects map[string]reflect.Value -func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) { +func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) { value := reflect.ValueOf(list.Value) if !list.HasConfigurableValues() { - return value, nil, nil + return value, []selects{} } + selectValues := make([]selects, 0) archSelects := map[string]reflect.Value{} for arch, selectKey := range bazel.PlatformArchMap { archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch)) } + if len(archSelects) > 0 { + selectValues = append(selectValues, archSelects) + } osSelects := map[string]reflect.Value{} - for os, selectKey := range bazel.PlatformOsMap { - osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os)) + osArchSelects := make([]selects, 0) + for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) { + selectKey := bazel.PlatformOsMap[os] + osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os)) + archSelects := make(map[string]reflect.Value) + // TODO(b/187530594): Should we also check arch=CONDITIONS_DEFAULT? (not in AllArches) + for _, arch := range bazel.AllArches { + target := os + "_" + arch + selectKey := bazel.PlatformTargetMap[target] + archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch)) + } + osArchSelects = append(osArchSelects, archSelects) + } + if len(osSelects) > 0 { + selectValues = append(selectValues, osSelects) + } + if len(osArchSelects) > 0 { + selectValues = append(selectValues, osArchSelects...) + } + + for _, pv := range list.SortedProductVariables() { + s := make(selects) + if len(pv.Values) > 0 { + s[pv.SelectKey()] = reflect.ValueOf(pv.Values) + s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{}) + selectValues = append(selectValues, s) + } } - return value, archSelects, osSelects + return value, selectValues } -func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) { +func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) { var value reflect.Value var archSelects selects @@ -43,13 +72,13 @@ func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) value = reflect.ValueOf(label.Value) } - return value, archSelects, nil + return value, []selects{archSelects} } -func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) { +func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) { value := reflect.ValueOf(list.Value.Includes) if !list.HasConfigurableValues() { - return value, nil, nil + return value, []selects{} } archSelects := map[string]reflect.Value{} @@ -58,33 +87,48 @@ func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, } osSelects := map[string]reflect.Value{} - for os, selectKey := range bazel.PlatformOsMap { - osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes) + osArchSelects := make([]selects, 0) + for _, os := range android.SortedStringKeys(bazel.PlatformOsMap) { + selectKey := bazel.PlatformOsMap[os] + osSelects[selectKey] = reflect.ValueOf(list.GetOsValueForTarget(os).Includes) + archSelects := make(map[string]reflect.Value) + // TODO(b/187530594): Should we also check arch=CONDITIOSN_DEFAULT? (not in AllArches) + for _, arch := range bazel.AllArches { + target := os + "_" + arch + selectKey := bazel.PlatformTargetMap[target] + archSelects[selectKey] = reflect.ValueOf(list.GetOsArchValueForTarget(os, arch).Includes) + } + osArchSelects = append(osArchSelects, archSelects) } - return value, archSelects, osSelects + var selects []selects + selects = append(selects, archSelects) + selects = append(selects, osSelects) + selects = append(selects, osArchSelects...) + return value, selects } // prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain // select statements. func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) { var value reflect.Value - var archSelects, osSelects selects + var configurableAttrs []selects var defaultSelectValue string switch list := v.(type) { case bazel.StringListAttribute: - value, archSelects, osSelects = getStringListValues(list) + value, configurableAttrs = getStringListValues(list) defaultSelectValue = "[]" case bazel.LabelListAttribute: - value, archSelects, osSelects = getLabelListValues(list) + value, configurableAttrs = getLabelListValues(list) defaultSelectValue = "[]" case bazel.LabelAttribute: - value, archSelects, osSelects = getLabelValue(list) + value, configurableAttrs = getLabelValue(list) defaultSelectValue = "None" default: return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v) } + var err error ret := "" if value.Kind() != reflect.Invalid { s, err := prettyPrint(value, indent) @@ -108,13 +152,14 @@ func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) { return s, nil } - ret, err := appendSelects(archSelects, defaultSelectValue, ret) - if err != nil { - return "", err + for _, configurableAttr := range configurableAttrs { + ret, err = appendSelects(configurableAttr, defaultSelectValue, ret) + if err != nil { + return "", err + } } - ret, err = appendSelects(osSelects, defaultSelectValue, ret) - return ret, err + return ret, nil } // prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way @@ -125,11 +170,10 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue strin } // addConditionsDefault := false - conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT] var selects string for _, selectKey := range android.SortedStringKeys(selectMap) { - if selectKey == conditionsDefaultKey { + if selectKey == bazel.ConditionsDefaultSelectKey { // Handle default condition later. continue } @@ -159,14 +203,14 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue strin ret += selects // Handle the default condition - s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent) + s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent) if err != nil { return "", err } if s == "" { // Print an explicit empty list (the default value) even if the value is // empty, to avoid errors about not finding a configuration that matches. - ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue) + ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue) } else { // Print the custom default value. ret += s diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 101ad3d04..bced4c19f 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -5,7 +5,6 @@ import ( "android/soong/cc/config" "fmt" "reflect" - "sort" "strings" "github.com/google/blueprint/proptools" @@ -64,22 +63,28 @@ func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) continue } targets := buildToTargets[dir] - sort.Slice(targets, func(i, j int) bool { - // this will cover all bp2build generated targets - if targets[i].name < targets[j].name { - return true - } - // give a strict ordering to content from hand-crafted targets - return targets[i].content < targets[j].content - }) - content := soongModuleLoad + targets.sort() + + var content string if mode == Bp2Build { - content = `# This file was automatically generated by bp2build for the Bazel migration project. -# Feel free to edit or test it, but do *not* check it into your version control system.` - content += "\n\n" - content += "package(default_visibility = [\"//visibility:public\"])" - content += "\n\n" + content = `# READ THIS FIRST: +# This file was automatically generated by bp2build for the Bazel migration project. +# Feel free to edit or test it, but do *not* check it into your version control system. +` + if targets.hasHandcraftedTargets() { + // For BUILD files with both handcrafted and generated targets, + // don't hardcode actual content, like package() declarations. + // Leave that responsibility to the checked-in BUILD file + // instead. + content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.` + } else { + // For fully-generated BUILD files, hardcode the default visibility. + content += "package(default_visibility = [\"//visibility:public\"])" + } + content += "\n" content += targets.LoadStatements() + } else if mode == QueryView { + content = soongModuleLoad } if content != "" { // If there are load statements, add a couple of newlines. diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go index 95bce3c18..7bedf7120 100644 --- a/bp2build/python_binary_conversion_test.go +++ b/bp2build/python_binary_conversion_test.go @@ -8,6 +8,7 @@ import ( ) func runPythonTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) } diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go index 91bba541d..82e0a14ca 100644 --- a/bp2build/sh_conversion_test.go +++ b/bp2build/sh_conversion_test.go @@ -49,6 +49,7 @@ func TestShBinaryLoadStatement(t *testing.T) { } func runShBinaryTestCase(t *testing.T, tc bp2buildTestCase) { + t.Helper() runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc) } diff --git a/cc/bp2build.go b/cc/bp2build.go index 95a3fe157..339a489d0 100644 --- a/cc/bp2build.go +++ b/cc/bp2build.go @@ -50,35 +50,51 @@ func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) { var allDeps []string - for _, p := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) { - // base compiler props - if baseCompilerProps, ok := p.(*BaseCompilerProperties); ok { + for _, osProps := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) { + // os base compiler props + if baseCompilerProps, ok := osProps.Properties.(*BaseCompilerProperties); ok { allDeps = append(allDeps, baseCompilerProps.Generated_headers...) allDeps = append(allDeps, baseCompilerProps.Generated_sources...) } + // os + arch base compiler props + for _, archProps := range osProps.ArchProperties { + if baseCompilerProps, ok := archProps.(*BaseCompilerProperties); ok { + allDeps = append(allDeps, baseCompilerProps.Generated_headers...) + allDeps = append(allDeps, baseCompilerProps.Generated_sources...) + } + } } - for _, p := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) { + for _, props := range module.GetArchProperties(ctx, &BaseCompilerProperties{}) { // arch specific compiler props - if baseCompilerProps, ok := p.(*BaseCompilerProperties); ok { + if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { allDeps = append(allDeps, baseCompilerProps.Generated_headers...) allDeps = append(allDeps, baseCompilerProps.Generated_sources...) } } - for _, p := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) { - // arch specific linker props - if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { + for _, osProps := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) { + // os specific linker props + if baseLinkerProps, ok := osProps.Properties.(*BaseLinkerProperties); ok { allDeps = append(allDeps, baseLinkerProps.Header_libs...) allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) allDeps = append(allDeps, baseLinkerProps.Static_libs...) allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...) } + // os + arch base compiler props + for _, archProps := range osProps.ArchProperties { + if baseLinkerProps, ok := archProps.(*BaseLinkerProperties); ok { + allDeps = append(allDeps, baseLinkerProps.Header_libs...) + allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) + allDeps = append(allDeps, baseLinkerProps.Static_libs...) + allDeps = append(allDeps, baseLinkerProps.Whole_static_libs...) + } + } } - for _, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { + for _, props := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { // arch specific linker props - if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { + if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok { allDeps = append(allDeps, baseLinkerProps.Header_libs...) allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) allDeps = append(allDeps, baseLinkerProps.Static_libs...) @@ -88,24 +104,64 @@ func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) { // Deps in the static: { .. } and shared: { .. } props of a cc_library. if lib, ok := module.compiler.(*libraryDecorator); ok { - allDeps = append(allDeps, lib.SharedProperties.Shared.Static_libs...) - allDeps = append(allDeps, lib.SharedProperties.Shared.Whole_static_libs...) - allDeps = append(allDeps, lib.SharedProperties.Shared.Shared_libs...) + appendDeps := func(deps []string, p StaticOrSharedProperties) []string { + deps = append(deps, p.Static_libs...) + deps = append(deps, p.Whole_static_libs...) + deps = append(deps, p.Shared_libs...) + return deps + } - allDeps = append(allDeps, lib.StaticProperties.Static.Static_libs...) - allDeps = append(allDeps, lib.StaticProperties.Static.Whole_static_libs...) - allDeps = append(allDeps, lib.StaticProperties.Static.Shared_libs...) + allDeps = appendDeps(allDeps, lib.SharedProperties.Shared) + allDeps = appendDeps(allDeps, lib.StaticProperties.Static) // TODO(b/186024507, b/186489250): Temporarily exclude adding // system_shared_libs deps until libc and libm builds. // allDeps = append(allDeps, lib.SharedProperties.Shared.System_shared_libs...) // allDeps = append(allDeps, lib.StaticProperties.Static.System_shared_libs...) + + // Deps in the target/arch nested static: { .. } and shared: { .. } props of a cc_library. + // target: { <target>: shared: { ... } } + for _, targetProps := range module.GetTargetProperties(ctx, &SharedProperties{}) { + if p, ok := targetProps.Properties.(*SharedProperties); ok { + allDeps = appendDeps(allDeps, p.Shared) + } + for _, archProperties := range targetProps.ArchProperties { + if p, ok := archProperties.(*SharedProperties); ok { + allDeps = appendDeps(allDeps, p.Shared) + } + } + } + // target: { <target>: static: { ... } } + for _, targetProps := range module.GetTargetProperties(ctx, &StaticProperties{}) { + if p, ok := targetProps.Properties.(*StaticProperties); ok { + allDeps = appendDeps(allDeps, p.Static) + } + for _, archProperties := range targetProps.ArchProperties { + if p, ok := archProperties.(*StaticProperties); ok { + allDeps = appendDeps(allDeps, p.Static) + } + } + } + // arch: { <arch>: shared: { ... } } + for _, properties := range module.GetArchProperties(ctx, &SharedProperties{}) { + if p, ok := properties.(*SharedProperties); ok { + allDeps = appendDeps(allDeps, p.Shared) + } + } + // arch: { <arch>: static: { ... } } + for _, properties := range module.GetArchProperties(ctx, &StaticProperties{}) { + if p, ok := properties.(*StaticProperties); ok { + allDeps = appendDeps(allDeps, p.Static) + } + } } ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...) } -type sharedAttributes struct { +// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties -- +// properties which apply to either the shared or static version of a cc_library module. +type staticOrSharedAttributes struct { copts bazel.StringListAttribute srcs bazel.LabelListAttribute staticDeps bazel.LabelListAttribute @@ -114,84 +170,124 @@ type sharedAttributes struct { } // bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library. -func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) sharedAttributes { +func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes { lib, ok := module.compiler.(*libraryDecorator) if !ok { - return sharedAttributes{} + return staticOrSharedAttributes{} } - copts := bazel.StringListAttribute{Value: lib.SharedProperties.Shared.Cflags} - - srcs := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleSrc(ctx, lib.SharedProperties.Shared.Srcs)} - - staticDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Static_libs)} - - dynamicDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Shared_libs)} - - wholeArchiveDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)} - - return sharedAttributes{ - copts: copts, - srcs: srcs, - staticDeps: staticDeps, - dynamicDeps: dynamicDeps, - wholeArchiveDeps: wholeArchiveDeps, - } -} - -type staticAttributes struct { - copts bazel.StringListAttribute - srcs bazel.LabelListAttribute - staticDeps bazel.LabelListAttribute - dynamicDeps bazel.LabelListAttribute - wholeArchiveDeps bazel.LabelListAttribute + return bp2buildParseStaticOrSharedProps(ctx, module, lib, false) } // bp2buildParseStaticProps returns the attributes for the static variant of a cc_library. -func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticAttributes { +func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes { lib, ok := module.compiler.(*libraryDecorator) if !ok { - return staticAttributes{} + return staticOrSharedAttributes{} } - copts := bazel.StringListAttribute{Value: lib.StaticProperties.Static.Cflags} + return bp2buildParseStaticOrSharedProps(ctx, module, lib, true) +} - srcs := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)} +func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes { + var props StaticOrSharedProperties + if isStatic { + props = lib.StaticProperties.Static + } else { + props = lib.SharedProperties.Shared + } - staticDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Static_libs)} + attrs := staticOrSharedAttributes{ + copts: bazel.StringListAttribute{Value: props.Cflags}, + srcs: bazel.LabelListAttribute{Value: android.BazelLabelForModuleSrc(ctx, props.Srcs)}, + staticDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Static_libs)}, + dynamicDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Shared_libs)}, + wholeArchiveDeps: bazel.LabelListAttribute{Value: android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)}, + } - dynamicDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Shared_libs)} + setArchAttrs := func(arch string, props StaticOrSharedProperties) { + attrs.copts.SetValueForArch(arch, props.Cflags) + attrs.srcs.SetValueForArch(arch, android.BazelLabelForModuleSrc(ctx, props.Srcs)) + attrs.staticDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Static_libs)) + attrs.dynamicDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Shared_libs)) + attrs.wholeArchiveDeps.SetValueForArch(arch, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)) + } - wholeArchiveDeps := bazel.LabelListAttribute{ - Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Whole_static_libs)} + setTargetAttrs := func(target string, props StaticOrSharedProperties) { + attrs.copts.SetOsValueForTarget(target, props.Cflags) + attrs.srcs.SetOsValueForTarget(target, android.BazelLabelForModuleSrc(ctx, props.Srcs)) + attrs.staticDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Static_libs)) + attrs.dynamicDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Shared_libs)) + attrs.wholeArchiveDeps.SetOsValueForTarget(target, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)) + } - return staticAttributes{ - copts: copts, - srcs: srcs, - staticDeps: staticDeps, - dynamicDeps: dynamicDeps, - wholeArchiveDeps: wholeArchiveDeps, + setTargetArchAttrs := func(target, arch string, props StaticOrSharedProperties) { + attrs.copts.SetOsArchValueForTarget(target, arch, props.Cflags) + attrs.srcs.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleSrc(ctx, props.Srcs)) + attrs.staticDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Static_libs)) + attrs.dynamicDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Shared_libs)) + attrs.wholeArchiveDeps.SetOsArchValueForTarget(target, arch, android.BazelLabelForModuleDeps(ctx, props.Whole_static_libs)) } + + if isStatic { + for arch, properties := range module.GetArchProperties(ctx, &StaticProperties{}) { + if staticOrSharedProps, ok := properties.(*StaticProperties); ok { + setArchAttrs(arch.Name, staticOrSharedProps.Static) + } + } + for target, p := range module.GetTargetProperties(ctx, &StaticProperties{}) { + if staticOrSharedProps, ok := p.Properties.(*StaticProperties); ok { + setTargetAttrs(target.Name, staticOrSharedProps.Static) + } + for arch, archProperties := range p.ArchProperties { + if staticOrSharedProps, ok := archProperties.(*StaticProperties); ok { + setTargetArchAttrs(target.Name, arch.Name, staticOrSharedProps.Static) + } + } + } + } else { + for arch, p := range module.GetArchProperties(ctx, &SharedProperties{}) { + if staticOrSharedProps, ok := p.(*SharedProperties); ok { + setArchAttrs(arch.Name, staticOrSharedProps.Shared) + } + } + for target, p := range module.GetTargetProperties(ctx, &SharedProperties{}) { + if staticOrSharedProps, ok := p.Properties.(*SharedProperties); ok { + setTargetAttrs(target.Name, staticOrSharedProps.Shared) + } + for arch, archProperties := range p.ArchProperties { + if staticOrSharedProps, ok := archProperties.(*SharedProperties); ok { + setTargetArchAttrs(target.Name, arch.Name, staticOrSharedProps.Shared) + } + } + } + } + + return attrs } // Convenience struct to hold all attributes parsed from compiler properties. type compilerAttributes struct { - copts bazel.StringListAttribute + // Options for all languages + copts bazel.StringListAttribute + // Assembly options and sources + asFlags bazel.StringListAttribute + asSrcs bazel.LabelListAttribute + // C options and sources + conlyFlags bazel.StringListAttribute + cSrcs bazel.LabelListAttribute + // C++ options and sources + cppFlags bazel.StringListAttribute srcs bazel.LabelListAttribute - includes bazel.StringListAttribute } // bp2BuildParseCompilerProps returns copts, srcs and hdrs and other attributes. func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Module) compilerAttributes { var srcs bazel.LabelListAttribute var copts bazel.StringListAttribute + var asFlags bazel.StringListAttribute + var conlyFlags bazel.StringListAttribute + var cppFlags bazel.StringListAttribute // Creates the -I flags for a directory, while making the directory relative // to the exec root for Bazel to work. @@ -215,15 +311,21 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul return append(includeDirs, baseCompilerProps.Local_include_dirs...) } - // Parse the list of copts. - parseCopts := func(baseCompilerProps *BaseCompilerProperties) []string { - var copts []string - for _, flag := range append(baseCompilerProps.Cflags, baseCompilerProps.Cppflags...) { + parseCommandLineFlags := func(soongFlags []string) []string { + var result []string + for _, flag := range soongFlags { // Soong's cflags can contain spaces, like `-include header.h`. For // Bazel's copts, split them up to be compatible with the // no_copts_tokenization feature. - copts = append(copts, strings.Split(flag, " ")...) + result = append(result, strings.Split(flag, " ")...) } + return result + } + + // Parse the list of copts. + parseCopts := func(baseCompilerProps *BaseCompilerProperties) []string { + var copts []string + copts = append(copts, parseCommandLineFlags(baseCompilerProps.Cflags)...) for _, dir := range parseLocalIncludeDirs(baseCompilerProps) { copts = append(copts, includeFlags(dir)...) } @@ -260,6 +362,9 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { srcs.Value = parseSrcs(baseCompilerProps) copts.Value = parseCopts(baseCompilerProps) + asFlags.Value = parseCommandLineFlags(baseCompilerProps.Asflags) + conlyFlags.Value = parseCommandLineFlags(baseCompilerProps.Conlyflags) + cppFlags.Value = parseCommandLineFlags(baseCompilerProps.Cppflags) // Used for arch-specific srcs later. baseSrcs = baseCompilerProps.Srcs @@ -290,6 +395,9 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul } copts.SetValueForArch(arch.Name, parseCopts(baseCompilerProps)) + asFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Asflags)) + conlyFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags)) + cppFlags.SetValueForArch(arch.Name, parseCommandLineFlags(baseCompilerProps.Cppflags)) } } @@ -308,19 +416,67 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul // TODO(b/186153868): handle the case with multiple variant types, e.g. when arch and os are both used. srcs.SetValueForArch(bazel.CONDITIONS_DEFAULT, defaultsSrcs) - // Handle OS specific props. - for os, props := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) { - if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { + // Handle target specific properties. + for os, osProps := range module.GetTargetProperties(ctx, &BaseCompilerProperties{}) { + if baseCompilerProps, ok := osProps.Properties.(*BaseCompilerProperties); ok { srcsList := parseSrcs(baseCompilerProps) // TODO(b/186153868): add support for os-specific srcs and exclude_srcs - srcs.SetValueForOS(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList)) - copts.SetValueForOS(os.Name, parseCopts(baseCompilerProps)) + srcs.SetOsValueForTarget(os.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList)) + copts.SetOsValueForTarget(os.Name, parseCopts(baseCompilerProps)) + asFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Asflags)) + conlyFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags)) + cppFlags.SetOsValueForTarget(os.Name, parseCommandLineFlags(baseCompilerProps.Cppflags)) + } + for arch, archProps := range osProps.ArchProperties { + if baseCompilerProps, ok := archProps.(*BaseCompilerProperties); ok { + srcsList := parseSrcs(baseCompilerProps) + // TODO(b/186153868): add support for os-specific srcs and exclude_srcs + srcs.SetOsArchValueForTarget(os.Name, arch.Name, bazel.SubtractBazelLabelList(srcsList, baseSrcsLabelList)) + copts.SetOsArchValueForTarget(os.Name, arch.Name, parseCopts(baseCompilerProps)) + asFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Asflags)) + conlyFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Conlyflags)) + cppFlags.SetOsArchValueForTarget(os.Name, arch.Name, parseCommandLineFlags(baseCompilerProps.Cppflags)) + } + } + } + + productVariableProps := android.ProductVariableProperties(ctx) + if props, exists := productVariableProps["Cflags"]; exists { + for _, prop := range props { + flags, ok := prop.Property.([]string) + if !ok { + ctx.ModuleErrorf("Could not convert product variable cflag property") + } + newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable) + copts.ProductValues = append(copts.ProductValues, bazel.ProductVariableValues{ + ProductVariable: prop.ProductConfigVariable, + Values: newFlags, + }) } } + // Branch srcs into three language-specific groups. + // C++ is the "catch-all" group, and comprises generated sources because we don't + // know the language of these sources until the genrule is executed. + // TODO(b/): Handle language detection of sources in a Bazel rule. + isCSrc := func(s string) bool { + return strings.HasSuffix(s, ".c") + } + isAsmSrc := func(s string) bool { + return strings.HasSuffix(s, ".S") || strings.HasSuffix(s, ".s") + } + cSrcs := bazel.FilterLabelListAttribute(srcs, isCSrc) + asSrcs := bazel.FilterLabelListAttribute(srcs, isAsmSrc) + srcs = bazel.SubtractBazelLabelListAttribute(srcs, cSrcs) + srcs = bazel.SubtractBazelLabelListAttribute(srcs, asSrcs) return compilerAttributes{ - srcs: srcs, - copts: copts, + copts: copts, + srcs: srcs, + asFlags: asFlags, + asSrcs: asSrcs, + cSrcs: cSrcs, + conlyFlags: conlyFlags, + cppFlags: cppFlags, } } @@ -353,13 +509,18 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) var linkopts bazel.StringListAttribute var versionScript bazel.LabelAttribute + getLibs := func(baseLinkerProps *BaseLinkerProperties) []string { + libs := baseLinkerProps.Header_libs + libs = append(libs, baseLinkerProps.Static_libs...) + libs = android.SortedUniqueStrings(libs) + return libs + } + for _, linkerProps := range module.linker.linkerProps() { if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { - libs := baseLinkerProps.Header_libs - libs = append(libs, baseLinkerProps.Static_libs...) + libs := getLibs(baseLinkerProps) exportedLibs := baseLinkerProps.Export_header_lib_headers wholeArchiveLibs := baseLinkerProps.Whole_static_libs - libs = android.SortedUniqueStrings(libs) deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs)) exportedDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, exportedLibs)) linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps) @@ -376,13 +537,11 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) } } - for arch, p := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { - if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { - libs := baseLinkerProps.Header_libs - libs = append(libs, baseLinkerProps.Static_libs...) + for arch, props := range module.GetArchProperties(ctx, &BaseLinkerProperties{}) { + if baseLinkerProps, ok := props.(*BaseLinkerProperties); ok { + libs := getLibs(baseLinkerProps) exportedLibs := baseLinkerProps.Export_header_lib_headers wholeArchiveLibs := baseLinkerProps.Whole_static_libs - libs = android.SortedUniqueStrings(libs) deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs)) exportedDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs)) linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps)) @@ -398,21 +557,34 @@ func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) } } - for os, p := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) { - if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { - libs := baseLinkerProps.Header_libs - libs = append(libs, baseLinkerProps.Static_libs...) + for os, targetProperties := range module.GetTargetProperties(ctx, &BaseLinkerProperties{}) { + if baseLinkerProps, ok := targetProperties.Properties.(*BaseLinkerProperties); ok { + libs := getLibs(baseLinkerProps) exportedLibs := baseLinkerProps.Export_header_lib_headers wholeArchiveLibs := baseLinkerProps.Whole_static_libs - libs = android.SortedUniqueStrings(libs) - wholeArchiveDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) - deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs)) - exportedDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs)) + wholeArchiveDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) + deps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, libs)) + exportedDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs)) - linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps)) + linkopts.SetOsValueForTarget(os.Name, getBp2BuildLinkerFlags(baseLinkerProps)) sharedLibs := baseLinkerProps.Shared_libs - dynamicDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs)) + dynamicDeps.SetOsValueForTarget(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs)) + } + for arch, archProperties := range targetProperties.ArchProperties { + if baseLinkerProps, ok := archProperties.(*BaseLinkerProperties); ok { + libs := getLibs(baseLinkerProps) + exportedLibs := baseLinkerProps.Export_header_lib_headers + wholeArchiveLibs := baseLinkerProps.Whole_static_libs + wholeArchiveDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs)) + deps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, libs)) + exportedDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, exportedLibs)) + + linkopts.SetOsArchValueForTarget(os.Name, arch.Name, getBp2BuildLinkerFlags(baseLinkerProps)) + + sharedLibs := baseLinkerProps.Shared_libs + dynamicDeps.SetOsArchValueForTarget(os.Name, arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs)) + } } } @@ -461,32 +633,38 @@ func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Mo includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...) includeDirsAttribute := bazel.MakeStringListAttribute(includeDirs) - for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) { - if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { - archIncludeDirs := flagExporterProperties.Export_system_include_dirs - archIncludeDirs = append(archIncludeDirs, flagExporterProperties.Export_include_dirs...) + getVariantIncludeDirs := func(includeDirs []string, flagExporterProperties *FlagExporterProperties) []string { + variantIncludeDirs := flagExporterProperties.Export_system_include_dirs + variantIncludeDirs = append(variantIncludeDirs, flagExporterProperties.Export_include_dirs...) - // To avoid duplicate includes when base includes + arch includes are combined - // FIXME: This doesn't take conflicts between arch and os includes into account - archIncludeDirs = bazel.SubtractStrings(archIncludeDirs, includeDirs) + // To avoid duplicate includes when base includes + arch includes are combined + // TODO: This doesn't take conflicts between arch and os includes into account + variantIncludeDirs = bazel.SubtractStrings(variantIncludeDirs, includeDirs) + return variantIncludeDirs + } + for arch, props := range module.GetArchProperties(ctx, &FlagExporterProperties{}) { + if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { + archIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties) if len(archIncludeDirs) > 0 { includeDirsAttribute.SetValueForArch(arch.Name, archIncludeDirs) } } } - for os, props := range module.GetTargetProperties(ctx, &FlagExporterProperties{}) { - if flagExporterProperties, ok := props.(*FlagExporterProperties); ok { - osIncludeDirs := flagExporterProperties.Export_system_include_dirs - osIncludeDirs = append(osIncludeDirs, flagExporterProperties.Export_include_dirs...) - - // To avoid duplicate includes when base includes + os includes are combined - // FIXME: This doesn't take conflicts between arch and os includes into account - osIncludeDirs = bazel.SubtractStrings(osIncludeDirs, includeDirs) - - if len(osIncludeDirs) > 0 { - includeDirsAttribute.SetValueForOS(os.Name, osIncludeDirs) + for os, targetProperties := range module.GetTargetProperties(ctx, &FlagExporterProperties{}) { + if flagExporterProperties, ok := targetProperties.Properties.(*FlagExporterProperties); ok { + targetIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties) + if len(targetIncludeDirs) > 0 { + includeDirsAttribute.SetOsValueForTarget(os.Name, targetIncludeDirs) + } + } + for arch, archProperties := range targetProperties.ArchProperties { + if flagExporterProperties, ok := archProperties.(*FlagExporterProperties); ok { + targetIncludeDirs := getVariantIncludeDirs(includeDirs, flagExporterProperties) + if len(targetIncludeDirs) > 0 { + includeDirsAttribute.SetOsArchValueForTarget(os.Name, arch.Name, targetIncludeDirs) + } } } } diff --git a/cc/cc_test.go b/cc/cc_test.go index d82619a04..5acafbe2a 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -554,6 +554,13 @@ func TestVndk(t *testing.T) { } } + cc_library { + name: "libclang_rt.hwasan-llndk", + llndk: { + symbol_file: "libclang_rt.hwasan.map.txt", + } + } + cc_library_headers { name: "libllndk_headers", llndk: { @@ -661,7 +668,7 @@ func TestVndk(t *testing.T) { "VNDK-product: libvndk_product.so", "VNDK-product: libvndk_sp_product_private-x.so", }) - checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"}) + checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libclang_rt.hwasan-llndk.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"}) checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"}) checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"}) checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"}) diff --git a/cc/library.go b/cc/library.go index c918b96ba..9fb7a2451 100644 --- a/cc/library.go +++ b/cc/library.go @@ -230,6 +230,13 @@ type bazelCcLibraryAttributes struct { Copts bazel.StringListAttribute Includes bazel.StringListAttribute Linkopts bazel.StringListAttribute + + Cppflags bazel.StringListAttribute + Srcs_c bazel.LabelListAttribute + Conlyflags bazel.StringListAttribute + Srcs_as bazel.LabelListAttribute + Asflags bazel.StringListAttribute + // Attributes pertaining to shared variant. Shared_copts bazel.StringListAttribute Shared_srcs bazel.LabelListAttribute @@ -239,6 +246,7 @@ type bazelCcLibraryAttributes struct { Whole_archive_deps_for_shared bazel.LabelListAttribute User_link_flags bazel.StringListAttribute Version_script bazel.LabelAttribute + // Attributes pertaining to static variant. Static_copts bazel.StringListAttribute Static_srcs bazel.LabelListAttribute @@ -294,20 +302,27 @@ func CcLibraryBp2Build(ctx android.TopDownMutatorContext) { srcs.Append(compilerAttrs.srcs) attrs := &bazelCcLibraryAttributes{ - Srcs: srcs, - Implementation_deps: linkerAttrs.deps, - Deps: linkerAttrs.exportedDeps, - Dynamic_deps: linkerAttrs.dynamicDeps, - Whole_archive_deps: linkerAttrs.wholeArchiveDeps, - Copts: compilerAttrs.copts, - Includes: exportedIncludes, - Linkopts: linkerAttrs.linkopts, + Srcs: srcs, + Implementation_deps: linkerAttrs.deps, + Deps: linkerAttrs.exportedDeps, + Dynamic_deps: linkerAttrs.dynamicDeps, + Whole_archive_deps: linkerAttrs.wholeArchiveDeps, + Copts: compilerAttrs.copts, + Includes: exportedIncludes, + Linkopts: linkerAttrs.linkopts, + Cppflags: compilerAttrs.cppFlags, + Srcs_c: compilerAttrs.cSrcs, + Conlyflags: compilerAttrs.conlyFlags, + Srcs_as: compilerAttrs.asSrcs, + Asflags: compilerAttrs.asFlags, + Shared_copts: sharedAttrs.copts, Shared_srcs: sharedAttrs.srcs, Static_deps_for_shared: sharedAttrs.staticDeps, Whole_archive_deps_for_shared: sharedAttrs.wholeArchiveDeps, Dynamic_deps_for_shared: sharedAttrs.dynamicDeps, Version_script: linkerAttrs.versionScript, + Static_copts: staticAttrs.copts, Static_srcs: staticAttrs.srcs, Static_deps_for_static: staticAttrs.staticDeps, @@ -2230,6 +2245,12 @@ type bazelCcLibraryStaticAttributes struct { Linkstatic bool Includes bazel.StringListAttribute Hdrs bazel.LabelListAttribute + + Cppflags bazel.StringListAttribute + Srcs_c bazel.LabelListAttribute + Conlyflags bazel.StringListAttribute + Srcs_as bazel.LabelListAttribute + Asflags bazel.StringListAttribute } type bazelCcLibraryStatic struct { @@ -2259,6 +2280,12 @@ func ccLibraryStaticBp2BuildInternal(ctx android.TopDownMutatorContext, module * Linkopts: linkerAttrs.linkopts, Linkstatic: true, Includes: exportedIncludes, + + Cppflags: compilerAttrs.cppFlags, + Srcs_c: compilerAttrs.cSrcs, + Conlyflags: compilerAttrs.conlyFlags, + Srcs_as: compilerAttrs.asSrcs, + Asflags: compilerAttrs.asFlags, } props := bazel.BazelTargetModuleProperties{ diff --git a/cc/object.go b/cc/object.go index d8f1ababa..cd711617b 100644 --- a/cc/object.go +++ b/cc/object.go @@ -116,7 +116,7 @@ type bazelObjectAttributes struct { Hdrs bazel.LabelListAttribute Deps bazel.LabelListAttribute Copts bazel.StringListAttribute - Asflags []string + Asflags bazel.StringListAttribute } type bazelObject struct { @@ -157,7 +157,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { // Set arch-specific configurable attributes compilerAttrs := bp2BuildParseCompilerProps(ctx, m) - var asFlags []string + var asFlags bazel.StringListAttribute var deps bazel.LabelListAttribute for _, props := range m.linker.linkerProps() { @@ -176,16 +176,23 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { ctx.ModuleErrorf("Could not convert product variable asflag property") return } - // TODO(b/183595873) handle other product variable usages -- as selects? - if newFlags, subbed := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable); subbed { - asFlags = append(asFlags, newFlags...) - } + newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable) + asFlags.ProductValues = append(asFlags.ProductValues, bazel.ProductVariableValues{ + ProductVariable: prop.ProductConfigVariable, + Values: newFlags, + }) } } // TODO(b/183595872) warn/error if we're not handling product variables + // Don't split cc_object srcs across languages. Doing so would add complexity, + // and this isn't typically done for cc_object. + srcs := compilerAttrs.srcs + srcs.Append(compilerAttrs.cSrcs) + srcs.Append(compilerAttrs.asSrcs) + attrs := &bazelObjectAttributes{ - Srcs: compilerAttrs.srcs, + Srcs: srcs, Deps: deps, Copts: compilerAttrs.copts, Asflags: asFlags, diff --git a/cc/vndk.go b/cc/vndk.go index 0254edc66..6a56c34db 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -234,7 +234,6 @@ type moduleListerFunc func(ctx android.SingletonContext) (moduleNames, fileNames var ( llndkLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() }) - llndkLibrariesWithoutHWASAN = vndkModuleListRemover(llndkLibraries, "libclang_rt.hwasan-") vndkSPLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP }) vndkCoreLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore }) vndkPrivateLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate }) @@ -419,10 +418,6 @@ func init() { } func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) { - // Make uses LLNDK_LIBRARIES to determine which libraries to install. - // HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. - // Therefore, by removing the library here, we cause it to only be installed if libc - // depends on it. ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory) ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory) ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory) @@ -434,8 +429,9 @@ func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) { type vndkLibrariesTxt struct { android.SingletonModuleBase - lister moduleListerFunc - makeVarName string + lister moduleListerFunc + makeVarName string + filterOutFromMakeVar string properties VndkLibrariesTxtProperties @@ -454,8 +450,12 @@ var _ android.OutputFileProducer = &vndkLibrariesTxt{} // llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries // generated by Soong but can be referenced by other modules. // For example, apex_vndk can depend on these files as prebuilt. +// Make uses LLNDK_LIBRARIES to determine which libraries to install. +// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN. +// Therefore, by removing the library here, we cause it to only be installed if libc +// depends on it. func llndkLibrariesTxtFactory() android.SingletonModule { - return newVndkLibrariesTxt(llndkLibrariesWithoutHWASAN, "LLNDK_LIBRARIES") + return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan-") } // vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries @@ -493,16 +493,21 @@ func vndkUsingCoreVariantLibrariesTxtFactory() android.SingletonModule { return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES") } -func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule { +func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule { m := &vndkLibrariesTxt{ - lister: lister, - makeVarName: makeVarName, + lister: lister, + makeVarName: makeVarName, + filterOutFromMakeVar: filter, } m.AddProperties(&m.properties) android.InitAndroidModule(m) return m } +func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule { + return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "") +} + func insertVndkVersion(filename string, vndkVersion string) string { if index := strings.LastIndex(filename, "."); index != -1 { return filename[:index] + "." + vndkVersion + filename[index:] @@ -542,8 +547,21 @@ func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries { } func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) { - ctx.Strict(txt.makeVarName, strings.Join(txt.moduleNames, " ")) - + filter := func(modules []string, prefix string) []string { + if prefix == "" { + return modules + } + var result []string + for _, module := range modules { + if strings.HasPrefix(module, prefix) { + continue + } else { + result = append(result, module) + } + } + return result + } + ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " ")) } // PrebuiltEtcModule interface diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 70c88563f..7abb67f29 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -175,6 +175,9 @@ func writeJsonModuleGraph(configuration android.Config, ctx *android.Context, pa writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir()) } +// doChosenActivity runs Soong for a specific activity, like bp2build, queryview +// or the actual Soong build for the build.ninja file. Returns the top level +// output file of the specific activity. func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string { bazelConversionRequested := bp2buildMarker != "" mixedModeBuild := configuration.BazelContext.BazelEnabled() @@ -187,11 +190,7 @@ func doChosenActivity(configuration android.Config, extraNinjaDeps []string) str // Run the alternate pipeline of bp2build mutators and singleton to convert // Blueprint to BUILD files before everything else. runBp2Build(configuration, extraNinjaDeps) - if bp2buildMarker != "" { - return bp2buildMarker - } else { - return bootstrap.CmdlineArgs.OutFile - } + return bp2buildMarker } ctx := newContext(configuration, prepareBuildActions) @@ -327,13 +326,13 @@ func writeFakeNinjaFile(extraNinjaDeps []string, buildDir string) { ninjaFileName := "build.ninja" ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName) - ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName) + ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName+".d") // A workaround to create the 'nothing' ninja target so `m nothing` works, // since bp2build runs without Kati, and the 'nothing' target is declared in // a Makefile. ioutil.WriteFile(ninjaFile, []byte("build nothing: phony\n phony_output = true\n"), 0666) ioutil.WriteFile(ninjaFileD, - []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)), + []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFile, extraNinjaDepsString)), 0666) } @@ -520,9 +519,14 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { os.Exit(1) } - if bp2buildMarker != "" { - touch(shared.JoinPath(topDir, bp2buildMarker)) - } else { - writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir()) - } + // Create an empty bp2build marker file. + touch(shared.JoinPath(topDir, bp2buildMarker)) + + // bp2build *always* writes a fake Ninja file containing just the nothing + // phony target if it ever re-runs. This allows bp2build to exit early with + // GENERATE_BAZEL_FILES=1 m nothing. + // + // If bp2build is invoked as part of an integrated mixed build, the fake + // build.ninja file will be rewritten later into the real file anyway. + writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir()) } diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index db49df8df..188d36225 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -168,61 +168,70 @@ func bootclasspathFragmentFactory() android.Module { // necessary. func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) { contents := m.properties.Contents - if m.properties.Image_name == nil && len(contents) == 0 { - ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`) + if len(contents) == 0 { + ctx.PropertyErrorf("contents", "required property is missing") + return + } + + if m.properties.Image_name == nil { + // Nothing to do. + return } imageName := proptools.String(m.properties.Image_name) - if imageName == "art" { - // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property. - if android.IsModuleInVersionedSdk(m) { - // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons: - // 1. There is no way to use this at the moment so ignoring it is safe. - // 2. Attempting to initialize the contents property from the configuration will end up having - // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems - // as the unversioned prebuilt could end up with an APEX variant created for the source - // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in - // turn will prevent it from accessing the dex implementation jar from that which will - // break hidden API processing, amongst others. - return - } + if imageName != "art" { + ctx.PropertyErrorf("image_name", `unknown image name %q, expected "art"`, imageName) + return + } - // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is - // too early in the Soong processing for that to work. - global := dexpreopt.GetGlobalConfig(ctx) - modules := global.ArtApexJars - - // Make sure that the apex specified in the configuration is consistent and is one for which - // this boot image is available. - commonApex := "" - for i := 0; i < modules.Len(); i++ { - apex := modules.Apex(i) - jar := modules.Jar(i) - if apex == "platform" { - ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar) - continue - } - if !m.AvailableFor(apex) { - ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q", - apex, m.ApexAvailable()) - continue - } - if commonApex == "" { - commonApex = apex - } else if commonApex != apex { - ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q", - commonApex, apex) - } - } + // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property. + if android.IsModuleInVersionedSdk(m) { + // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons: + // 1. There is no way to use this at the moment so ignoring it is safe. + // 2. Attempting to initialize the contents property from the configuration will end up having + // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems + // as the unversioned prebuilt could end up with an APEX variant created for the source + // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in + // turn will prevent it from accessing the dex implementation jar from that which will + // break hidden API processing, amongst others. + return + } - if len(contents) != 0 { - // Nothing to do. - return + // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is + // too early in the Soong processing for that to work. + global := dexpreopt.GetGlobalConfig(ctx) + modules := global.ArtApexJars + + // Make sure that the apex specified in the configuration is consistent and is one for which + // this boot image is available. + commonApex := "" + for i := 0; i < modules.Len(); i++ { + apex := modules.Apex(i) + jar := modules.Jar(i) + if apex == "platform" { + ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar) + continue + } + if !m.AvailableFor(apex) { + ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q", + apex, m.ApexAvailable()) + continue + } + if commonApex == "" { + commonApex = apex + } else if commonApex != apex { + ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q", + commonApex, apex) } + } - // Store the jars in the Contents property so that they can be used to add dependencies. - m.properties.Contents = modules.CopyOfJars() + if len(contents) != 0 { + // Nothing to do. + return } + + // Store the jars in the Contents property so that they can be used to add dependencies. + m.properties.Contents = modules.CopyOfJars() } // bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this @@ -270,11 +279,12 @@ var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(Bootcla // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the // apex contents. type BootclasspathFragmentApexContentInfo struct { - // The image config, internal to this module (and the dex_bootjars singleton). - // - // Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur - // when SkipDexpreoptBootJars(ctx) returns true. - imageConfig *bootImageConfig + // The configured modules, will be empty if this is from a bootclasspath_fragment that does not + // set image_name: "art". + modules android.ConfiguredJarList + + // Map from arch type to the boot image files. + bootImageFilesByArch map[android.ArchType]android.OutputPaths // Map from the name of the context module (as returned by Name()) to the hidden API encoded dex // jar path. @@ -282,24 +292,14 @@ type BootclasspathFragmentApexContentInfo struct { } func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList { - return i.imageConfig.modules + return i.modules } // Get a map from ArchType to the associated boot image's contents for Android. // // Extension boot images only return their own files, not the files of the boot images they extend. func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() map[android.ArchType]android.OutputPaths { - files := map[android.ArchType]android.OutputPaths{} - if i.imageConfig != nil { - for _, variant := range i.imageConfig.variants { - // We also generate boot images for host (for testing), but we don't need those in the apex. - // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device - if variant.target.Os == android.Android { - files[variant.target.Arch.ArchType] = variant.imagesDeps - } - } - } - return files + return i.bootImageFilesByArch } // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module. @@ -412,20 +412,33 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // modules. func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module, hiddenAPIFlagOutput *HiddenAPIFlagOutput) { // Construct the apex content info from the config. - info := BootclasspathFragmentApexContentInfo{ - imageConfig: imageConfig, - } + info := BootclasspathFragmentApexContentInfo{} // Populate the apex content info with paths to the dex jars. b.populateApexContentInfoDexJars(ctx, &info, contents, hiddenAPIFlagOutput) - if !SkipDexpreoptBootJars(ctx) { - // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars - // GenerateSingletonBuildActions method as it cannot create it for itself. - dexpreopt.GetGlobalSoongConfig(ctx) - - // Only generate the boot image if the configuration does not skip it. - b.generateBootImageBuildActions(ctx, contents) + if imageConfig != nil { + info.modules = imageConfig.modules + + if !SkipDexpreoptBootJars(ctx) { + // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars + // GenerateSingletonBuildActions method as it cannot create it for itself. + dexpreopt.GetGlobalSoongConfig(ctx) + + // Only generate the boot image if the configuration does not skip it. + if b.generateBootImageBuildActions(ctx, contents, imageConfig) { + // Allow the apex to access the boot image files. + files := map[android.ArchType]android.OutputPaths{} + for _, variant := range imageConfig.variants { + // We also generate boot images for host (for testing), but we don't need those in the apex. + // TODO(b/177892522) - consider changing this to check Os.OsClass = android.Device + if variant.target.Os == android.Android { + files[variant.target.Arch.ArchType] = variant.imagesDeps + } + } + info.bootImageFilesByArch = files + } + } } // Make the apex content info available for other modules. @@ -589,32 +602,23 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIAllFlagsFile(ctx android.M // generateBootImageBuildActions generates ninja rules to create the boot image if required for this // module. -func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, contents []android.Module) { +// +// Returns true if the boot image is created, false otherwise. +func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, contents []android.Module, imageConfig *bootImageConfig) bool { global := dexpreopt.GetGlobalConfig(ctx) if !shouldBuildBootImages(ctx.Config(), global) { - return - } - - // Bootclasspath fragment modules that are not preferred do not produce a boot image. - if !isActiveModule(ctx.Module()) { - return - } - - // Bootclasspath fragment modules that have no image_name property do not produce a boot image. - imageConfig := b.getImageConfig(ctx) - if imageConfig == nil { - return + return false } // Bootclasspath fragment modules that are for the platform do not produce a boot image. apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if apexInfo.IsForPlatform() { - return + return false } // Bootclasspath fragment modules that are versioned do not produce a boot image. if android.IsModuleInVersionedSdk(ctx.Module()) { - return + return false } // Copy the dex jars of this fragment's content modules to their predefined locations. @@ -623,6 +627,8 @@ func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android. // Build a profile for the image config and then use that to build the boot image. profile := bootImageProfileRule(ctx, imageConfig) buildBootImage(ctx, imageConfig, profile) + + return true } type bootclasspathFragmentMemberType struct { diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 581625d8c..fba7d1a71 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -29,38 +29,28 @@ var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers( dexpreopt.PrepareForTestByEnablingDexpreopt, ) -func TestUnknownBootclasspathFragment(t *testing.T) { +func TestBootclasspathFragment_UnknownImageName(t *testing.T) { prepareForTestWithBootclasspathFragment. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)). + `\Qimage_name: unknown image name "unknown", expected "art"\E`)). RunTestWithBp(t, ` bootclasspath_fragment { name: "unknown-bootclasspath-fragment", image_name: "unknown", + contents: ["foo"], } `) } -func TestUnknownBootclasspathFragmentImageName(t *testing.T) { +func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) { prepareForTestWithBootclasspathFragment. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)). - RunTestWithBp(t, ` - bootclasspath_fragment { - name: "unknown-bootclasspath-fragment", - image_name: "unknown", - } - `) -} - -func TestUnknownPrebuiltBootclasspathFragment(t *testing.T) { - prepareForTestWithBootclasspathFragment. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qimage_name: Unknown image name "unknown", expected one of art, boot\E`)). + `\Qimage_name: unknown image name "unknown", expected "art"\E`)). RunTestWithBp(t, ` prebuilt_bootclasspath_fragment { name: "unknown-bootclasspath-fragment", image_name: "unknown", + contents: ["foo"], } `) } @@ -76,6 +66,7 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T bootclasspath_fragment { name: "bootclasspath-fragment", image_name: "art", + contents: ["foo", "bar"], apex_available: [ "apex", ], @@ -94,6 +85,7 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin bootclasspath_fragment { name: "bootclasspath-fragment", image_name: "art", + contents: ["foo", "bar"], apex_available: [ "apex1", "apex2", @@ -102,17 +94,6 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin `) } -func TestBootclasspathFragmentWithoutImageNameOrContents(t *testing.T) { - prepareForTestWithBootclasspathFragment. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `\Qneither of the "image_name" and "contents" properties\E`)). - RunTestWithBp(t, ` - bootclasspath_fragment { - name: "bootclasspath-fragment", - } - `) -} - func TestBootclasspathFragment_Coverage(t *testing.T) { prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{ "EMMA_INSTRUMENT": "true", diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index bc0416a47..0e14d24f2 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -105,7 +105,7 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars } func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.ModuleContext, jars []classpathJar) { - outputFilename := ctx.ModuleName() + ".pb" + outputFilename := strings.ToLower(c.classpathType.String()) + ".pb" c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") diff --git a/java/droidstubs.go b/java/droidstubs.go index 566f7e30d..953105603 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -546,7 +546,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { `\n` + `If it is not possible to do so, there are workarounds:\n` + `\n` + - `1. You can suppress the errors with @SuppressLint("<id>")\n` + `1. You can suppress the errors with @SuppressLint("<id>")\n` + + ` where the <id> is given in brackets in the error message above.\n` if baselineFile.Valid() { cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path()) diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index d332f63df..ed5549d35 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -287,7 +287,7 @@ func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) { ).RunTest(t) p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) - android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base()) + android.AssertStringEquals(t, "output filepath", "bootclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base()) android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) } @@ -327,7 +327,7 @@ func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { want := map[string][]string{ "LOCAL_MODULE": {"platform-bootclasspath"}, "LOCAL_MODULE_CLASS": {"ETC"}, - "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"}, + "LOCAL_INSTALLED_MODULE_STEM": {"bootclasspath.pb"}, // Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths } diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index a72b3f60c..9111c309f 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -53,13 +53,7 @@ func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx an func (p *platformSystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { global := dexpreopt.GetGlobalConfig(ctx) - - jars := global.SystemServerJars - // TODO(satayev): split apex jars into separate configs. - for i := 0; i < global.UpdatableSystemServerJars.Len(); i++ { - jars = jars.Append(global.UpdatableSystemServerJars.Apex(i), global.UpdatableSystemServerJars.Jar(i)) - } - return jars + return global.SystemServerJars } type SystemServerClasspathModule struct { @@ -101,8 +95,12 @@ func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.Mo } func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { - // TODO(satayev): populate with actual content - return android.EmptyConfiguredJarList() + global := dexpreopt.GetGlobalConfig(ctx) + + // Only create configs for updatable boot jars. Non-updatable system server jars must be part of the + // platform_systemserverclasspath's classpath proto config to guarantee that they come before any + // updatable jars at runtime. + return global.UpdatableSystemServerJars.Filter(s.properties.Contents) } type systemServerClasspathFragmentContentDependencyTag struct { diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go index 5272f271d..9ad50dd4a 100644 --- a/java/systemserver_classpath_fragment_test.go +++ b/java/systemserver_classpath_fragment_test.go @@ -24,7 +24,7 @@ var prepareForTestWithSystemServerClasspath = android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ) -func TestPlatformSystemserverClasspathVariant(t *testing.T) { +func TestPlatformSystemServerClasspathVariant(t *testing.T) { result := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -38,7 +38,7 @@ func TestPlatformSystemserverClasspathVariant(t *testing.T) { android.AssertIntEquals(t, "expect 1 variant", 1, len(variants)) } -func TestPlatformSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) { +func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) { result := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -49,11 +49,11 @@ func TestPlatformSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) { ).RunTest(t) p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule) - android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base()) + android.AssertStringEquals(t, "output filepath", "systemserverclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base()) android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) } -func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { +func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) { preparer := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -78,8 +78,8 @@ func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { want := map[string][]string{ "LOCAL_MODULE": {"platform-systemserverclasspath"}, "LOCAL_MODULE_CLASS": {"ETC"}, - "LOCAL_INSTALLED_MODULE_STEM": {"platform-systemserverclasspath.pb"}, - // Output and Install paths are tested separately in TestSystemserverClasspath_ClasspathFragmentPaths + "LOCAL_INSTALLED_MODULE_STEM": {"systemserverclasspath.pb"}, + // Output and Install paths are tested separately in TestPlatformSystemServerClasspath_ClasspathFragmentPaths } p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule) @@ -96,7 +96,7 @@ func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) { }) } -func TestSystemserverclasspathFragmentWithoutContents(t *testing.T) { +func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) { prepareForTestWithSystemServerClasspath. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( `\Qempty contents are not allowed\E`)). diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index bd69f06f2..d9fe2816f 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -424,6 +424,7 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { android.GroupFixturePreparers( prepareForSdkTestWithApex, prepareForSdkTestWithJava, + android.FixtureAddFile("java/mybootlib.jar", nil), android.FixtureWithRootAndroidBp(` sdk { name: "mysdk", @@ -433,16 +434,27 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { bootclasspath_fragment { name: "mybootclasspathfragment", image_name: "art", + contents: ["mybootlib"], apex_available: ["myapex"], } + java_library { + name: "mybootlib", + apex_available: ["myapex"], + srcs: ["Test.java"], + system_modules: "none", + sdk_version: "none", + min_sdk_version: "1", + compile_dex: true, + } + sdk_snapshot { name: "mysdk@1", - bootclasspath_fragments: ["mybootclasspathfragment_mysdk_1"], + bootclasspath_fragments: ["mysdk_mybootclasspathfragment@1"], } prebuilt_bootclasspath_fragment { - name: "mybootclasspathfragment_mysdk_1", + name: "mysdk_mybootclasspathfragment@1", sdk_member_name: "mybootclasspathfragment", prefer: false, visibility: ["//visibility:public"], @@ -450,6 +462,15 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { "myapex", ], image_name: "art", + contents: ["mysdk_mybootlib@1"], + } + + java_import { + name: "mysdk_mybootlib@1", + sdk_member_name: "mybootlib", + visibility: ["//visibility:public"], + apex_available: ["com.android.art"], + jars: ["java/mybootlib.jar"], } `), ).RunTest(t) diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 42d5680f1..4805846b7 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -104,6 +104,12 @@ type shBinaryProperties struct { Recovery_available *bool } +// Test option struct. +type TestOptions struct { + // If the test is a hostside(no device required) unittest that shall be run during presubmit check. + Unit_test *bool +} + type TestProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. @@ -143,6 +149,9 @@ type TestProperties struct { // list of device library modules that should be installed alongside the test. // Only available for host sh_test modules. Data_device_libs []string `android:"path,arch_variant"` + + // Test options. + Test_options TestOptions } type ShBinary struct { @@ -440,6 +449,9 @@ func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries { dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath) entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath) } + if Bool(s.testProperties.Test_options.Unit_test) { + entries.SetBool("LOCAL_IS_UNIT_TEST", true) + } }, }, }} diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 9e7e59462..20317d88c 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -3,6 +3,7 @@ package sh import ( "os" "path/filepath" + "strconv" "testing" "android/soong/android" @@ -148,6 +149,9 @@ func TestShTestHost(t *testing.T) { "testdata/data1", "testdata/sub/data2", ], + test_options: { + unit_test: true, + }, } `) @@ -156,6 +160,9 @@ func TestShTestHost(t *testing.T) { if !mod.Host() { t.Errorf("host bit is not set for a sh_test_host module.") } + entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] + actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0]) + android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData) } func TestShTestHost_dataDeviceModules(t *testing.T) { diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh index 42363e9c0..8c8dc8208 100755 --- a/tests/bootstrap_test.sh +++ b/tests/bootstrap_test.sh @@ -493,6 +493,21 @@ function test_bp2build_smoke { [[ -e out/soong/workspace ]] || fail "Bazel workspace not created" } +function test_bp2build_generates_fake_ninja_file { + setup + create_mock_bazel + + run_bp2build + + if [[ ! -f "./out/soong/build.ninja" ]]; then + fail "./out/soong/build.ninja was not generated" + fi + + if ! grep "build nothing: phony" "./out/soong/build.ninja"; then + fail "missing phony nothing target in out/soong/build.ninja" + fi +} + function test_bp2build_add_android_bp { setup @@ -678,6 +693,7 @@ test_glob_during_bootstrapping test_soong_build_rerun_iff_environment_changes test_dump_json_module_graph test_bp2build_smoke +test_bp2build_generates_fake_ninja_file test_bp2build_null_build test_bp2build_add_android_bp test_bp2build_add_to_glob diff --git a/ui/build/soong.go b/ui/build/soong.go index a41dbe1b5..cd645eb41 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -155,9 +155,9 @@ func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) { Outputs: []string{bp2BuildMarkerFile}, Args: bp2buildArgs, } - args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{ - bp2buildInvocation, - mainSoongBuildInvocation, + args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{bp2buildInvocation} + if config.bazelBuildMode() == mixedBuild { + args.PrimaryBuilderInvocations = append(args.PrimaryBuilderInvocations, mainSoongBuildInvocation) } } else { args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation} |