Merge changes Iaa6411b5,I2118b8a2,Ibbdd3cbd,I2d1bbda2 am: 38e9f0b82f am: 99f29d244a am: c5c5d80d30

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1652620

Change-Id: I09a93351bcae2c27531fd258ddacdd8bc5ddd474
This commit is contained in:
Martin Stjernholm 2021-03-30 12:42:38 +00:00 committed by Automerger Merge Worker
commit 2f1e93ef36
6 changed files with 132 additions and 28 deletions

View File

@ -453,6 +453,23 @@ func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
} }
} }
// AvailableToSameApexes returns true if the two modules are apex_available to
// exactly the same set of APEXes (and platform), i.e. if their apex_available
// properties have the same elements.
func AvailableToSameApexes(mod1, mod2 ApexModule) bool {
mod1ApexAvail := SortedUniqueStrings(mod1.apexModuleBase().ApexProperties.Apex_available)
mod2ApexAvail := SortedUniqueStrings(mod2.apexModuleBase().ApexProperties.Apex_available)
if len(mod1ApexAvail) != len(mod2ApexAvail) {
return false
}
for i, v := range mod1ApexAvail {
if v != mod2ApexAvail[i] {
return false
}
}
return true
}
type byApexName []ApexInfo type byApexName []ApexInfo
func (a byApexName) Len() int { return len(a) } func (a byApexName) Len() int { return len(a) }

View File

@ -1642,16 +1642,10 @@ type InstallPath struct {
// Will panic if called from outside a test environment. // Will panic if called from outside a test environment.
func ensureTestOnly() { func ensureTestOnly() {
// Normal soong test environment if PrefixInList(os.Args, "-test.") {
if InList("-test.short", os.Args) {
return return
} }
// IntelliJ test environment panic(fmt.Errorf("Not in test. Command line:\n %s", strings.Join(os.Args, "\n ")))
if InList("-test.v", os.Args) {
return
}
panic(fmt.Errorf("Not in test\n%s", strings.Join(os.Args, "\n")))
} }
func (p InstallPath) RelativeToTop() Path { func (p InstallPath) RelativeToTop() Path {

View File

@ -193,6 +193,17 @@ func FilterList(list []string, filter []string) (remainder []string, filtered []
return return
} }
// FilterListPred returns the elements of the given list for which the predicate
// returns true. Order is kept.
func FilterListPred(list []string, pred func(s string) bool) (filtered []string) {
for _, l := range list {
if pred(l) {
filtered = append(filtered, l)
}
}
return
}
// RemoveListFromList removes the strings belonging to the filter list from the // RemoveListFromList removes the strings belonging to the filter list from the
// given list and returns the result // given list and returns the result
func RemoveListFromList(list []string, filter_out []string) (result []string) { func RemoveListFromList(list []string, filter_out []string) (result []string) {

View File

@ -18,6 +18,7 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
"strings"
"testing" "testing"
) )
@ -299,6 +300,14 @@ func TestFilterList(t *testing.T) {
} }
} }
func TestFilterListPred(t *testing.T) {
pred := func(s string) bool { return strings.HasPrefix(s, "a/") }
AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "b/a", "a/b"}, pred), []string{"a/c", "a/b"})
AssertArrayString(t, "filter", FilterListPred([]string{"b/c", "a/a", "b/b"}, pred), []string{"a/a"})
AssertArrayString(t, "filter", FilterListPred([]string{"c/c", "b/a", "c/b"}, pred), []string{})
AssertArrayString(t, "filter", FilterListPred([]string{"a/c", "a/a", "a/b"}, pred), []string{"a/c", "a/a", "a/b"})
}
func TestRemoveListFromList(t *testing.T) { func TestRemoveListFromList(t *testing.T) {
input := []string{"a", "b", "c", "d", "a", "c", "d"} input := []string{"a", "b", "c", "d", "a", "c", "d"}
filter := []string{"a", "c"} filter := []string{"a", "c"}

View File

@ -6863,21 +6863,77 @@ func TestTestFor(t *testing.T) {
} }
`) `)
// the test 'mytest' is a test for the apex, therefore is linked to the ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ")
mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
}
// These modules are tests for the apex, therefore are linked to the
// actual implementation of mylib instead of its stub. // actual implementation of mylib instead of its stub.
ldFlags := ctx.ModuleForTests("mytest", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] ensureLinkedLibIs("mytest", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so") ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") ensureLinkedLibIs("mybench", "android_arm64_armv8-a", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
}
// The same should be true for cc_library func TestIndirectTestFor(t *testing.T) {
ldFlags = ctx.ModuleForTests("mytestlib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] ctx := testApex(t, `
ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so") apex {
ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") name: "myapex",
key: "myapex.key",
native_shared_libs: ["mylib", "myprivlib"],
updatable: false,
}
// ... and for cc_benchmark apex_key {
ldFlags = ctx.ModuleForTests("mybench", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] name: "myapex.key",
ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared/mylib.so") public_key: "testkey.avbpubkey",
ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so") private_key: "testkey.pem",
}
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
stubs: {
versions: ["1"],
},
apex_available: ["myapex"],
}
cc_library {
name: "myprivlib",
srcs: ["mylib.cpp"],
system_shared_libs: [],
stl: "none",
shared_libs: ["mylib"],
apex_available: ["myapex"],
}
cc_library {
name: "mytestlib",
srcs: ["mylib.cpp"],
system_shared_libs: [],
shared_libs: ["myprivlib"],
stl: "none",
test_for: ["myapex"],
}
`)
ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) {
ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ")
mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) })
android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags)
}
// The platform variant of mytestlib links to the platform variant of the
// internal myprivlib.
ensureLinkedLibIs("mytestlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/myprivlib/", "android_arm64_armv8-a_shared/myprivlib.so")
// The platform variant of myprivlib links to the platform variant of mylib
// and bypasses its stubs.
ensureLinkedLibIs("myprivlib", "android_arm64_armv8-a_shared", "out/soong/.intermediates/mylib/", "android_arm64_armv8-a_shared/mylib.so")
} }
// TODO(jungjw): Move this to proptools // TODO(jungjw): Move this to proptools

View File

@ -363,7 +363,7 @@ type BaseProperties struct {
// List of APEXes that this module has private access to for testing purpose. The module // List of APEXes that this module has private access to for testing purpose. The module
// can depend on libraries that are not exported by the APEXes and use private symbols // can depend on libraries that are not exported by the APEXes and use private symbols
// from the exported libraries. // from the exported libraries.
Test_for []string Test_for []string `android:"arch_variant"`
} }
type VendorProperties struct { type VendorProperties struct {
@ -2631,7 +2631,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
// However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules, // However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules,
// always link to non-stub variant // always link to non-stub variant
useStubs = dep.(android.ApexModule).NotInPlatform() && !c.bootstrap() useStubs = dep.(android.ApexModule).NotInPlatform() && !c.bootstrap()
// Another exception: if this module is bundled with an APEX, then if useStubs {
// Another exception: if this module is a test for an APEX, then
// it is linked with the non-stub variant of a module in the APEX // it is linked with the non-stub variant of a module in the APEX
// as if this is part of the APEX. // as if this is part of the APEX.
testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo) testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
@ -2641,6 +2642,22 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
break break
} }
} }
}
if useStubs {
// Yet another exception: If this module and the dependency are
// available to the same APEXes then skip stubs between their
// platform variants. This complements the test_for case above,
// which avoids the stubs on a direct APEX library dependency, by
// avoiding stubs for indirect test dependencies as well.
//
// TODO(b/183882457): This doesn't work if the two libraries have
// only partially overlapping apex_available. For that test_for
// modules would need to be split into APEX variants and resolved
// separately for each APEX they have access to.
if android.AvailableToSameApexes(c, dep.(android.ApexModule)) {
useStubs = false
}
}
} else { } else {
// If building for APEX, use stubs when the parent is in any APEX that // If building for APEX, use stubs when the parent is in any APEX that
// the child is not in. // the child is not in.