Stubs variant is used when building for APEX

When a native module is built for an APEX and is depending on a native
library having stubs (i.e. stubs.versions property is set), the stubs
variant is used unless the dependent lib is directly included in the
same APEX with the depending module.

Example:

apex {
    name: "myapex",
    native_shared_libs: ["libX", "libY"],
}

cc_library {
    name: "libX",
    shared_libs: ["libY", "libZ"],
}

cc_library {
    name: "libY",
    stubs: { versions: ["1", "2"], },
}

cc_library {
    name: "libZ",
    stubs: { versions: ["1", "2"], },
}

In this case, libX is linking to the impl variant of libY (that provides
private APIs) while libY is linking to the version 2 stubs of libZ. This is
because libY is directly included in the same apex via
native_shared_libs property, but libZ isn't.

Bug: 112672359
Test: apex_test added
Change-Id: If9871b70dc74a06bd828dd4cd1aeebd2e68b837c
This commit is contained in:
Jiyong Park
2018-11-18 18:02:45 +09:00
parent 2098eb8c2a
commit 25fc6a9cc9
7 changed files with 589 additions and 42 deletions

112
cc/cc.go
View File

@@ -39,7 +39,7 @@ func init() {
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("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
})
@@ -248,6 +248,7 @@ type ModuleContextIntf interface {
getVndkExtendsModuleName() string
isPgoCompile() bool
useClangLld(actx ModuleContext) bool
isApex() bool
}
type ModuleContext interface {
@@ -308,6 +309,8 @@ type dependencyTag struct {
library bool
reexportFlags bool
explicitlyVersioned bool
}
var (
@@ -511,6 +514,20 @@ func (c *Module) onlyInRecovery() bool {
return c.ModuleBase.InstallInRecovery()
}
func (c *Module) IsStubs() bool {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.buildStubs()
}
return false
}
func (c *Module) HasStubsVariants() bool {
if library, ok := c.linker.(*libraryDecorator); ok {
return len(library.Properties.Stubs.Versions) > 0
}
return false
}
type baseModuleContext struct {
android.BaseContext
moduleContextImpl
@@ -649,6 +666,11 @@ func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
return ctx.mod.getVndkExtendsModuleName()
}
// Tests if this module is built for APEX
func (ctx *moduleContextImpl) isApex() bool {
return ctx.mod.ApexName() != ""
}
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -1081,6 +1103,30 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
{Mutator: "link", Variation: "static"},
}, lateStaticDepTag, deps.LateStaticLibs...)
addSharedLibDependencies := func(depTag dependencyTag, name string, version string) {
var variations []blueprint.Variation
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
versionVariantAvail := ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery()
if version != "" && versionVariantAvail {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
depTag.explicitlyVersioned = true
}
actx.AddVariationDependencies(variations, depTag, name)
// If the version is not specified, add dependency to the latest stubs library.
// The stubs library will be used when the depending module is built for APEX and
// the dependent module is not in the same APEX.
latestVersion := latestStubsVersionFor(actx.Config(), name)
if version == "" && latestVersion != "" && versionVariantAvail {
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "shared"},
{Mutator: "version", Variation: latestVersion},
}, depTag, name)
// Note that depTag.explicitlyVersioned is false in this case.
}
}
// shared lib names without the #version suffix
var sharedLibNames []string
@@ -1091,29 +1137,17 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
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)
addSharedLibDependencies(depTag, name, version)
}
for _, lib := range deps.LateSharedLibs {
name, version := stubsLibNameAndVersion(lib)
if inList(name, sharedLibNames) {
if inList(lib, 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)
addSharedLibDependencies(lateSharedDepTag, lib, "")
}
actx.AddVariationDependencies([]blueprint.Variation{
@@ -1372,7 +1406,53 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return
}
}
// Extract explicitlyVersioned field from the depTag and reset it inside the struct.
// Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true
// won't be matched to sharedDepTag and lateSharedDepTag.
explicitlyVersioned := false
if t, ok := depTag.(dependencyTag); ok {
explicitlyVersioned = t.explicitlyVersioned
t.explicitlyVersioned = false
depTag = t
}
if t, ok := depTag.(dependencyTag); ok && t.library {
if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
depIsStubs := dependentLibrary.buildStubs()
depHasStubs := ccDep.HasStubsVariants()
depNameWithTarget := depName + "-" + ccDep.Target().String()
depInSameApex := android.DirectlyInApex(ctx.Config(), c.ApexName(), depNameWithTarget)
depInPlatform := !android.DirectlyInAnyApex(ctx.Config(), depNameWithTarget)
var useThisDep bool
if depIsStubs && explicitlyVersioned {
// Always respect dependency to the versioned stubs (i.e. libX#10)
useThisDep = true
} else if !depHasStubs {
// Use non-stub variant if that is the only choice
// (i.e. depending on a lib without stubs.version property)
useThisDep = true
} else if c.IsForPlatform() {
// If not building for APEX, use stubs only when it is from
// an APEX (and not from platform)
useThisDep = (depInPlatform != depIsStubs)
if c.inRecovery() {
// However, for recovery modules, since there is no APEX there,
// always link to non-stub variant
useThisDep = !depIsStubs
}
} else {
// If building for APEX, use stubs only when it is not from
// the same APEX
useThisDep = (depInSameApex != depIsStubs)
}
if !useThisDep {
return // stop processing this dep
}
}
if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
flags := i.exportedFlags()
deps := i.exportedFlagsDeps()