Handle multiple linkages in sdk snapshots

Currently, if the same library is specified for multiple of native_libs,
native_shared_libs, and native_static_libs for different arch/oses,
there can be a few errors:

1. specifying a .so file as `srcs` within a cc_prebuilt_library rather
than being specified only for shared
2. the final type of prebuilt library is dependent on the arch/os

This change introduces:
* an ability for a member type to override the type for specified
  properties
  * checks for a library being used with incompatible member types
  * basing linkage nesting on the member type in addition to variants

  This will ensure that the correct library type is used, regardless of
  the order of iteration over oses/arches, and support nesting linkages
  where necessary but only one linkage variant exists.

Test: soong tests
Test: CI
Change-Id: I81dee013b09b99c34ca6c18f9cfcc12ee56d33d1
This commit is contained in:
Liz Kammer 2022-05-12 20:40:00 -04:00
parent 4dd76eb26c
commit 96320dfff8
5 changed files with 285 additions and 22 deletions

View file

@ -670,6 +670,9 @@ type SdkMemberType interface {
// host OS variant explicitly and disable all other host OS'es.
IsHostOsDependent() bool
// SupportedLinkages returns the names of the linkage variants supported by this module.
SupportedLinkages() []string
// AddDependencies adds dependencies from the SDK module to all the module variants the member
// type contributes to the SDK. `names` is the list of module names given in the member type
// property (as returned by SdkPropertyName()) in the SDK module. The exact set of variants
@ -733,6 +736,9 @@ type SdkMemberType interface {
// SupportedTraits returns the set of traits supported by this member type.
SupportedTraits() SdkMemberTraitSet
// Overrides returns whether type overrides other SdkMemberType
Overrides(SdkMemberType) bool
}
var _ sdkRegisterable = (SdkMemberType)(nil)
@ -756,6 +762,13 @@ type SdkDependencyContext interface {
type SdkMemberTypeBase struct {
PropertyName string
// Property names that this SdkMemberTypeBase can override, this is useful when a module type is a
// superset of another module type.
OverridesPropertyNames map[string]bool
// The names of linkage variants supported by this module.
SupportedLinkageNames []string
// When set to true BpPropertyNotRequired indicates that the member type does not require the
// property to be specifiable in an Android.bp file.
BpPropertyNotRequired bool
@ -796,6 +809,14 @@ func (b *SdkMemberTypeBase) SupportedTraits() SdkMemberTraitSet {
return NewSdkMemberTraitSet(b.Traits)
}
func (b *SdkMemberTypeBase) Overrides(other SdkMemberType) bool {
return b.OverridesPropertyNames[other.SdkPropertyName()]
}
func (b *SdkMemberTypeBase) SupportedLinkages() []string {
return b.SupportedLinkageNames
}
// registeredModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports
// modules.
var registeredModuleExportsMemberTypes = &sdkRegistry{}

View file

@ -27,32 +27,33 @@ import (
var sharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_shared_libs",
SupportsSdk: true,
HostOsDependent: true,
PropertyName: "native_shared_libs",
SupportsSdk: true,
HostOsDependent: true,
SupportedLinkageNames: []string{"shared"},
},
prebuiltModuleType: "cc_prebuilt_library_shared",
linkTypes: []string{"shared"},
}
var staticLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_static_libs",
SupportsSdk: true,
HostOsDependent: true,
PropertyName: "native_static_libs",
SupportsSdk: true,
HostOsDependent: true,
SupportedLinkageNames: []string{"static"},
},
prebuiltModuleType: "cc_prebuilt_library_static",
linkTypes: []string{"static"},
}
var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_libs",
SupportsSdk: true,
HostOsDependent: true,
PropertyName: "native_libs",
OverridesPropertyNames: map[string]bool{"native_shared_libs": true, "native_static_libs": true},
SupportsSdk: true,
HostOsDependent: true,
SupportedLinkageNames: []string{"static", "shared"},
},
prebuiltModuleType: "cc_prebuilt_library",
linkTypes: []string{"static", "shared"},
}
func init() {
@ -69,9 +70,6 @@ type librarySdkMemberType struct {
noOutputFiles bool // True if there are no srcs files.
// The set of link types supported. A set of "static", "shared", or nil to
// skip link type variations.
linkTypes []string
}
func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
@ -165,12 +163,12 @@ func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext
// Add any additional dependencies needed.
variations = append(variations, dependency.imageVariations...)
if mt.linkTypes == nil {
if mt.SupportedLinkageNames == nil {
// No link types are supported so add a dependency directly.
ctx.AddFarVariationDependencies(variations, dependencyTag, name)
} else {
// Otherwise, add a dependency on each supported link type in turn.
for _, linkType := range mt.linkTypes {
for _, linkType := range mt.SupportedLinkageNames {
libVariations := append(variations,
blueprint.Variation{Mutator: "link", Variation: linkType})
// If this is for the device and a shared link type then add a dependency onto the

View file

@ -37,7 +37,6 @@ var ccObjectSdkMemberType = &librarySdkMemberType{
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_object",
linkTypes: nil,
}
type objectLinker struct {

View file

@ -1740,6 +1740,229 @@ myinclude/Test.h -> include/myinclude/Test.h
)
}
func TestSnapshotSameLibraryWithNativeLibsAndNativeSharedLib(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {
host_supported: true,
name: "myexports",
target: {
android: {
native_shared_libs: [
"mynativelib",
],
},
not_windows: {
native_libs: [
"mynativelib",
],
},
},
}
cc_library {
name: "mynativelib",
host_supported: true,
srcs: [
"Test.cpp",
],
stl: "none",
recovery_available: true,
vendor_available: true,
}
`)
CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library {
name: "mynativelib",
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
host_supported: true,
vendor_available: true,
stl: "none",
compile_multilib: "both",
target: {
host: {
enabled: false,
},
android_arm64: {
shared: {
srcs: ["android/arm64/lib/mynativelib.so"],
},
static: {
enabled: false,
},
},
android_arm: {
shared: {
srcs: ["android/arm/lib/mynativelib.so"],
},
static: {
enabled: false,
},
},
linux_glibc_x86_64: {
enabled: true,
static: {
srcs: ["linux_glibc/x86_64/lib/mynativelib.a"],
},
shared: {
srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
},
},
linux_glibc_x86: {
enabled: true,
static: {
srcs: ["linux_glibc/x86/lib/mynativelib.a"],
},
shared: {
srcs: ["linux_glibc/x86/lib/mynativelib.so"],
},
},
},
}
`),
checkAllCopyRules(`
.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> android/arm64/lib/mynativelib.so
.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> android/arm/lib/mynativelib.so
.intermediates/mynativelib/linux_glibc_x86_64_static/mynativelib.a -> linux_glibc/x86_64/lib/mynativelib.a
.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
.intermediates/mynativelib/linux_glibc_x86_static/mynativelib.a -> linux_glibc/x86/lib/mynativelib.a
.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
`),
)
}
func TestSnapshotSameLibraryWithAndroidNativeLibsAndHostNativeSharedLib(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {
host_supported: true,
name: "myexports",
target: {
android: {
native_libs: [
"mynativelib",
],
},
not_windows: {
native_shared_libs: [
"mynativelib",
],
},
},
}
cc_library {
name: "mynativelib",
host_supported: true,
srcs: [
"Test.cpp",
],
stl: "none",
recovery_available: true,
vendor_available: true,
}
`)
CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
cc_prebuilt_library {
name: "mynativelib",
prefer: false,
visibility: ["//visibility:public"],
apex_available: ["//apex_available:platform"],
host_supported: true,
vendor_available: true,
stl: "none",
compile_multilib: "both",
target: {
host: {
enabled: false,
},
android_arm64: {
static: {
srcs: ["android/arm64/lib/mynativelib.a"],
},
shared: {
srcs: ["android/arm64/lib/mynativelib.so"],
},
},
android_arm: {
static: {
srcs: ["android/arm/lib/mynativelib.a"],
},
shared: {
srcs: ["android/arm/lib/mynativelib.so"],
},
},
linux_glibc_x86_64: {
enabled: true,
shared: {
srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
},
static: {
enabled: false,
},
},
linux_glibc_x86: {
enabled: true,
shared: {
srcs: ["linux_glibc/x86/lib/mynativelib.so"],
},
static: {
enabled: false,
},
},
},
}
`),
checkAllCopyRules(`
.intermediates/mynativelib/android_arm64_armv8-a_static/mynativelib.a -> android/arm64/lib/mynativelib.a
.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> android/arm64/lib/mynativelib.so
.intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> android/arm/lib/mynativelib.a
.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> android/arm/lib/mynativelib.so
.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> linux_glibc/x86_64/lib/mynativelib.so
.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> linux_glibc/x86/lib/mynativelib.so
`),
)
}
func TestSnapshotSameLibraryWithNativeStaticLibsAndNativeSharedLib(t *testing.T) {
testSdkError(t, "Incompatible member types", `
module_exports {
host_supported: true,
name: "myexports",
target: {
android: {
native_shared_libs: [
"mynativelib",
],
},
not_windows: {
native_static_libs: [
"mynativelib",
],
},
},
}
cc_library {
name: "mynativelib",
host_supported: true,
srcs: [
],
stl: "none",
recovery_available: true,
vendor_available: true,
}
`)
}
func TestHostSnapshotWithMultiLib64(t *testing.T) {
result := testSdkWithCc(t, `
module_exports {

View file

@ -268,13 +268,19 @@ func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, mem
member = &sdkMember{memberType: memberType, name: name}
byName[name] = member
byType[memberType] = append(byType[memberType], member)
} else if member.memberType != memberType {
// validate whether this is the same member type or and overriding member type
if memberType.Overrides(member.memberType) {
member.memberType = memberType
} else if !member.memberType.Overrides(memberType) {
ctx.ModuleErrorf("Incompatible member types %q %q", member.memberType, memberType)
}
}
// Only append new variants to the list. This is needed because a member can be both
// exported by the sdk and also be a transitive sdk member.
member.variants = appendUniqueVariants(member.variants, variant)
}
var members []*sdkMember
for _, memberListProperty := range s.memberTypeListProperties() {
membersOfType := byType[memberListProperty.memberType]
@ -1777,7 +1783,9 @@ func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType and
// added.
archInfo.Properties = variantPropertiesFactory()
if len(archVariants) == 1 {
// if there are multiple supported link variants, we want to nest based on linkage even if there
// is only one variant, otherwise, if there is only one variant we can populate based on the arch
if len(archVariants) == 1 && len(ctx.MemberType().SupportedLinkages()) <= 1 {
archInfo.Properties.PopulateFromVariant(ctx, archVariants[0])
} else {
// Group the variants by image type.
@ -1904,11 +1912,13 @@ func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant stri
// Create the properties into which the image variant specific properties will be added.
imageInfo.Properties = variantPropertiesFactory()
if len(imageVariants) == 1 {
// if there are multiple supported link variants, we want to nest even if there is only one
// variant, otherwise, if there is only one variant we can populate based on the image
if len(imageVariants) == 1 && len(ctx.MemberType().SupportedLinkages()) <= 1 {
imageInfo.Properties.PopulateFromVariant(ctx, imageVariants[0])
} else {
// There is more than one variant for this image variant which must be differentiated by link
// type.
// type. Or there are multiple supported linkages and we need to nest based on link type.
for _, linkVariant := range imageVariants {
linkType := getLinkType(linkVariant)
if linkType == "" {
@ -1952,10 +1962,22 @@ func (imageInfo *imageVariantSpecificInfo) addToPropertySet(ctx *memberContext,
addSdkMemberPropertiesToSet(ctx, imageInfo.Properties, propertySet)
usedLinkages := make(map[string]bool, len(imageInfo.linkInfos))
for _, linkInfo := range imageInfo.linkInfos {
usedLinkages[linkInfo.linkType] = true
linkInfo.addToPropertySet(ctx, propertySet)
}
// If not all supported linkages had existing variants, we need to disable the unsupported variant
if len(imageInfo.linkInfos) < len(ctx.MemberType().SupportedLinkages()) {
for _, l := range ctx.MemberType().SupportedLinkages() {
if _, ok := usedLinkages[l]; !ok {
otherLinkagePropertySet := propertySet.AddPropertySet(l)
otherLinkagePropertySet.AddProperty("enabled", false)
}
}
}
// If this is for a non-core image variant then make sure that the property set does not contain
// any properties as providing non-core image variant specific properties for prebuilts is not
// currently supported.