Add support for versioned stubs.
A cc_library or cc_library_shared can be configured to have stubs
variants of the lib.
cc_library_shared {
name: "libfoo",
srcs: ["foo.cpp"],
stubs: {
symbol_file: "foo.map.txt",
versions: ["1", "2", "3"],
},
}
then, stubs variants of libfoo for version 1, 2, and 3 are created
from foo.map.txt. Each version has the symbols from the map file where
each symbol is annotated with the version that the symbol was introduced
via the 'introduced=<ver>' syntax. The versions don't need to be in sync
with the platform versions (e.g., P for 28). The versions are local to
the library.
For another library or executable to use the versioned stubs lib, use
the new 'name#ver' syntax to specify the version:
cc_binary {
name: "test",
....
shared_libs: ["libFoo#2"],
}
Internally, a new mutator 'version' is applied to all cc.Module objects.
By default, a variant named 'impl' is created for the non-stub version.
If the versions property is set, additional variations are created per a
version with the mutable property BuildStubs set as true, which lets the
compiler and the linker to build a stubs lib from the symbol file
instead from the source files.
This feature will be used to enforce stable interfaces among APEXs. When
a lib foo in an APEX is depending on a lib bar in another APEX, then bar
should have stable interface (in C lang) and foo should be depending on
one of the stubs libs of bar. Only libraries in the same APEX as foo can
link against non-stub version of it.
Bug: 112672359
Test: m (cc_test added)
Change-Id: I2488be0b9d7b7b8d7761234dc1c9c0e3add8601c
diff --git a/cc/cc.go b/cc/cc.go
index 8b68489..0569563 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -39,6 +39,7 @@
ctx.BottomUp("vndk", vndkMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
+ ctx.BottomUp("version", versionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
})
@@ -945,6 +946,16 @@
c.begin(ctx)
}
+// Split name#version into name and version
+func stubsLibNameAndVersion(name string) (string, string) {
+ if sharp := strings.LastIndex(name, "#"); sharp != -1 && sharp != len(name)-1 {
+ version := name[sharp+1:]
+ libname := name[:sharp]
+ return libname, version
+ }
+ return name, ""
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
@@ -979,25 +990,28 @@
variantLibs = []string{}
nonvariantLibs = []string{}
for _, entry := range list {
- if ctx.useSdk() && inList(entry, ndkPrebuiltSharedLibraries) {
- if !inList(entry, ndkMigratedLibs) {
- nonvariantLibs = append(nonvariantLibs, entry+".ndk."+version)
+ // strip #version suffix out
+ name, _ := stubsLibNameAndVersion(entry)
+ if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
+ if !inList(name, ndkMigratedLibs) {
+ nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
} else {
- variantLibs = append(variantLibs, entry+ndkLibrarySuffix)
+ variantLibs = append(variantLibs, name+ndkLibrarySuffix)
}
- } else if ctx.useVndk() && inList(entry, llndkLibraries) {
- nonvariantLibs = append(nonvariantLibs, entry+llndkLibrarySuffix)
- } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(entry, vendorPublicLibraries) {
- vendorPublicLib := entry + vendorPublicLibrarySuffix
+ } else if ctx.useVndk() && inList(name, llndkLibraries) {
+ nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix)
+ } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, vendorPublicLibraries) {
+ vendorPublicLib := name + vendorPublicLibrarySuffix
if actx.OtherModuleExists(vendorPublicLib) {
nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
} else {
// This can happen if vendor_public_library module is defined in a
// namespace that isn't visible to the current module. In that case,
// link to the original library.
- nonvariantLibs = append(nonvariantLibs, entry)
+ nonvariantLibs = append(nonvariantLibs, name)
}
} else {
+ // put name#version back
nonvariantLibs = append(nonvariantLibs, entry)
}
}
@@ -1009,6 +1023,15 @@
deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders)
}
+ if c.linker != nil {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ if library.buildStubs() {
+ // Stubs lib does not have dependency to other libraries. Don't proceed.
+ return
+ }
+ }
+ }
+
for _, lib := range deps.HeaderLibs {
depTag := headerDepTag
if inList(lib, deps.ReexportHeaderLibHeaders) {
@@ -1035,19 +1058,40 @@
{Mutator: "link", Variation: "static"},
}, lateStaticDepTag, deps.LateStaticLibs...)
+ // shared lib names without the #version suffix
+ var sharedLibNames []string
+
for _, lib := range deps.SharedLibs {
+ name, version := stubsLibNameAndVersion(lib)
+ sharedLibNames = append(sharedLibNames, name)
depTag := sharedDepTag
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- }, depTag, lib)
+ var variations []blueprint.Variation
+ variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
+ if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
+ variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
+ }
+ actx.AddVariationDependencies(variations, depTag, name)
}
- actx.AddVariationDependencies([]blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- }, lateSharedDepTag, deps.LateSharedLibs...)
+ for _, lib := range deps.LateSharedLibs {
+ name, version := stubsLibNameAndVersion(lib)
+ if inList(name, sharedLibNames) {
+ // This is to handle the case that some of the late shared libs (libc, libdl, libm, ...)
+ // are added also to SharedLibs with version (e.g., libc#10). If not skipped, we will be
+ // linking against both the stubs lib and the non-stubs lib at the same time.
+ continue
+ }
+ depTag := lateSharedDepTag
+ var variations []blueprint.Variation
+ variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
+ if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
+ variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
+ }
+ actx.AddVariationDependencies(variations, depTag, name)
+ }
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "shared"},
@@ -1629,8 +1673,8 @@
return
}
- if genrule, ok := mctx.Module().(*genrule.Module); ok {
- if props, ok := genrule.Extra.(*GenruleExtraProperties); ok {
+ if g, ok := mctx.Module().(*genrule.Module); ok {
+ if props, ok := g.Extra.(*GenruleExtraProperties); ok {
var coreVariantNeeded bool = false
var vendorVariantNeeded bool = false
var recoveryVariantNeeded bool = false
@@ -1650,7 +1694,7 @@
if recoveryVariantNeeded {
primaryArch := mctx.Config().DevicePrimaryArchType()
- moduleArch := genrule.Target().Arch.ArchType
+ moduleArch := g.Target().Arch.ArchType
if moduleArch != primaryArch {
recoveryVariantNeeded = false
}
@@ -1666,7 +1710,13 @@
if recoveryVariantNeeded {
variants = append(variants, recoveryMode)
}
- mctx.CreateVariations(variants...)
+ mod := mctx.CreateVariations(variants...)
+ for i, v := range variants {
+ if v == recoveryMode {
+ m := mod[i].(*genrule.Module)
+ m.Extra.(*GenruleExtraProperties).InRecovery = true
+ }
+ }
}
}