diff options
| -rw-r--r-- | android/apex.go | 165 | ||||
| -rw-r--r-- | apex/apex.go | 26 | ||||
| -rw-r--r-- | apex/apex_test.go | 67 | ||||
| -rw-r--r-- | cc/androidmk.go | 3 | ||||
| -rw-r--r-- | cc/cc.go | 34 | ||||
| -rw-r--r-- | cc/library.go | 4 |
6 files changed, 212 insertions, 87 deletions
diff --git a/android/apex.go b/android/apex.go index 3a191cf60..d1fb6f4ef 100644 --- a/android/apex.go +++ b/android/apex.go @@ -14,7 +14,11 @@ package android -import "sync" +import ( + "sync" + + "github.com/google/blueprint" +) // ApexModule is the interface that a module type is expected to implement if // the module has to be built differently depending on whether the module @@ -25,7 +29,7 @@ import "sync" // or C APIs from other APEXs. // // A module implementing this interface will be mutated into multiple -// variations by the apex mutator if it is directly or indirectly included +// variations by apex.apexMutator if it is directly or indirectly included // in one or more APEXs. Specifically, if a module is included in apex.foo and // apex.bar then three apex variants are created: platform, apex.foo and // apex.bar. The platform variant is for the regular partitions @@ -35,31 +39,44 @@ type ApexModule interface { Module apexModuleBase() *ApexModuleBase - // Marks that this module should be built for the APEX of the specified name + // Marks that this module should be built for the APEX of the specified name. + // Call this before apex.apexMutator is run. BuildForApex(apexName string) - // Tests whether this module will be built for the platform or not (= APEXs) - IsForPlatform() bool - // Returns the name of APEX that this module will be built for. Empty string // is returned when 'IsForPlatform() == true'. Note that a module can be - // included to multiple APEXs, in which case, the module is mutated into + // included in multiple APEXes, in which case, the module is mutated into // multiple modules each of which for an APEX. This method returns the // name of the APEX that a variant module is for. + // Call this after apex.apexMutator is run. ApexName() string - // Tests if this module can have APEX variants. APEX variants are + // Tests whether this module will be built for the platform or not. + // This is a shortcut for ApexName() == "" + IsForPlatform() bool + + // Tests if this module could have APEX variants. APEX variants are // created only for the modules that returns true here. This is useful - // for not creating APEX variants for shared libraries such as NDK stubs. + // for not creating APEX variants for certain types of shared libraries + // such as NDK stubs. CanHaveApexVariants() bool // Tests if this module can be installed to APEX as a file. For example, // this would return true for shared libs while return false for static // libs. IsInstallableToApex() bool + + // Mutate this module into one or more variants each of which is built + // for an APEX marked via BuildForApex(). + CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module + + // Sets the name of the apex variant of this module. Called inside + // CreateApexVariations. + setApexName(apexName string) } type ApexProperties struct { + // Name of the apex variant that this module is mutated into ApexName string `blueprint:"mutated"` } @@ -69,6 +86,7 @@ type ApexModuleBase struct { ApexProperties ApexProperties canHaveApexVariants bool + apexVariations []string } func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { @@ -76,15 +94,21 @@ func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase { } func (m *ApexModuleBase) BuildForApex(apexName string) { - m.ApexProperties.ApexName = apexName + if !InList(apexName, m.apexVariations) { + m.apexVariations = append(m.apexVariations, apexName) + } +} + +func (m *ApexModuleBase) ApexName() string { + return m.ApexProperties.ApexName } func (m *ApexModuleBase) IsForPlatform() bool { return m.ApexProperties.ApexName == "" } -func (m *ApexModuleBase) ApexName() string { - return m.ApexProperties.ApexName +func (m *ApexModuleBase) setApexName(apexName string) { + m.ApexProperties.ApexName = apexName } func (m *ApexModuleBase) CanHaveApexVariants() bool { @@ -96,61 +120,73 @@ func (m *ApexModuleBase) IsInstallableToApex() bool { return false } -// This structure maps a module name to the set of APEX bundle names that the module -// should be built for. Examples: +func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module { + if len(m.apexVariations) > 0 { + // The original module is mutated into "platform" variation. + variations := []string{"platform"} + for _, a := range m.apexVariations { + variations = append(variations, a) + } + modules := mctx.CreateVariations(variations...) + for i, m := range modules { + if i == 0 { + continue // platform + } + m.(ApexModule).setApexName(variations[i]) + } + return modules + } + return nil +} + +var apexData OncePer +var apexNamesMapMutex sync.Mutex + +// This structure maintains the global mapping in between modules and APEXes. +// Examples: // -// ...["foo"]["bar"] == true: module foo is directly depended on by APEX bar -// ...["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar -// ...["foo"]["bar"] doesn't exist: foo is not built for APEX bar -// ...["foo"] doesn't exist: foo is not built for any APEX -func apexBundleNamesMap(config Config) map[string]map[string]bool { - return config.Once("apexBundleNames", func() interface{} { +// apexNamesMap()["foo"]["bar"] == true: module foo is directly depended on by APEX bar +// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar +// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar +func apexNamesMap() map[string]map[string]bool { + return apexData.Once("apexNames", func() interface{} { return make(map[string]map[string]bool) }).(map[string]map[string]bool) } -var bundleNamesMapMutex sync.Mutex - -// Mark that a module named moduleName should be built for an apex named bundleName -// directDep should be set to true if the module is a direct dependency of the apex. -func BuildModuleForApexBundle(ctx BaseModuleContext, moduleName string, bundleName string, directDep bool) { - bundleNamesMapMutex.Lock() - defer bundleNamesMapMutex.Unlock() - bundleNames, ok := apexBundleNamesMap(ctx.Config())[moduleName] +// Update the map to mark that a module named moduleName is directly or indirectly +// depended on by an APEX named apexName. Directly depending means that a module +// is explicitly listed in the build definition of the APEX via properties like +// native_shared_libs, java_libs, etc. +func UpdateApexDependency(apexName string, moduleName string, directDep bool) { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + apexNames, ok := apexNamesMap()[moduleName] if !ok { - bundleNames = make(map[string]bool) - apexBundleNamesMap(ctx.Config())[moduleName] = bundleNames + apexNames = make(map[string]bool) + apexNamesMap()[moduleName] = apexNames } - bundleNames[bundleName] = bundleNames[bundleName] || directDep + apexNames[apexName] = apexNames[apexName] || directDep } -// Returns the list of apex bundle names that the module named moduleName -// should be built for. -func GetApexBundlesForModule(ctx BaseModuleContext, moduleName string) map[string]bool { - bundleNamesMapMutex.Lock() - defer bundleNamesMapMutex.Unlock() - return apexBundleNamesMap(ctx.Config())[moduleName] -} - -// Tests if moduleName is directly depended on by bundleName (i.e. referenced in -// native_shared_libs, etc.) -func DirectlyInApex(config Config, bundleName string, moduleName string) bool { - bundleNamesMapMutex.Lock() - defer bundleNamesMapMutex.Unlock() - if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { - return bundleNames[bundleName] +// Tests whether a module named moduleName is directly depended on by an APEX +// named apexName. +func DirectlyInApex(apexName string, moduleName string) bool { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + if apexNames, ok := apexNamesMap()[moduleName]; ok { + return apexNames[apexName] } return false } -// Tests if moduleName is directly depended on by any APEX. If this returns true, -// that means the module is part of the platform. -func DirectlyInAnyApex(config Config, moduleName string) bool { - bundleNamesMapMutex.Lock() - defer bundleNamesMapMutex.Unlock() - if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok { - for bn := range bundleNames { - if bundleNames[bn] { +// Tests whether a module named moduleName is directly depended on by any APEX. +func DirectlyInAnyApex(moduleName string) bool { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + if apexNames, ok := apexNamesMap()[moduleName]; ok { + for an := range apexNames { + if apexNames[an] { return true } } @@ -158,6 +194,27 @@ func DirectlyInAnyApex(config Config, moduleName string) bool { return false } +// Tests whether a module named module is depended on (including both +// direct and indirect dependencies) by any APEX. +func InAnyApex(moduleName string) bool { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + apexNames, ok := apexNamesMap()[moduleName] + return ok && len(apexNames) > 0 +} + +func GetApexesForModule(moduleName string) []string { + ret := []string{} + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + if apexNames, ok := apexNamesMap()[moduleName]; ok { + for an := range apexNames { + ret = append(ret, an) + } + } + return ret +} + func InitApexModule(m ApexModule) { base := m.apexModuleBase() base.canHaveApexVariants = true diff --git a/apex/apex.go b/apex/apex.go index f412d8603..46207b215 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -150,11 +150,13 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { if _, ok := mctx.Module().(*apexBundle); ok { apexBundleName := mctx.ModuleName() mctx.WalkDeps(func(child, parent android.Module) bool { + depName := mctx.OtherModuleName(child) + // If the parent is apexBundle, this child is directly depended. + _, directDep := parent.(*apexBundle) + android.UpdateApexDependency(apexBundleName, depName, directDep) + if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() { - moduleName := mctx.OtherModuleName(am) + "-" + am.Target().String() - // If the parent is apexBundle, this child is directly depended. - _, directDep := parent.(*apexBundle) - android.BuildModuleForApexBundle(mctx, moduleName, apexBundleName, directDep) + am.BuildForApex(apexBundleName) return true } else { return false @@ -166,21 +168,7 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { // Create apex variations if a module is included in APEX(s). func apexMutator(mctx android.BottomUpMutatorContext) { if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - moduleName := mctx.ModuleName() + "-" + am.Target().String() - bundleNames := android.GetApexBundlesForModule(mctx, moduleName) - if len(bundleNames) > 0 { - variations := []string{"platform"} - for bn := range bundleNames { - variations = append(variations, bn) - } - modules := mctx.CreateVariations(variations...) - for i, m := range modules { - if i == 0 { - continue // platform - } - m.(android.ApexModule).BuildForApex(variations[i]) - } - } + am.CreateApexVariations(mctx) } else if _, ok := mctx.Module().(*apexBundle); ok { // apex bundle itself is mutated so that it and its modules have same // apex variant. diff --git a/apex/apex_test.go b/apex/apex_test.go index c01c40a76..72f6488c7 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -318,6 +318,73 @@ func TestApexWithStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") } +func TestApexWithExplicitStubsDependency(t *testing.T) { + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + shared_libs: ["libfoo#10"], + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libfoo", + srcs: ["mylib.cpp"], + shared_libs: ["libbar"], + system_shared_libs: [], + stl: "none", + stubs: { + versions: ["10", "20", "30"], + }, + } + + cc_library { + name: "libbar", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + } + + `) + + apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + copyCmds := apexRule.Args["copy_commands"] + + // Ensure that direct non-stubs dep is always included + ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + + // Ensure that indirect stubs dep is not included + ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so") + + // Ensure that dependency of stubs is not included + ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") + + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + + // Ensure that mylib is linking with version 10 of libfoo + ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10_myapex/libfoo.so") + // ... and not linking to the non-stub (impl) variant of libfoo + ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_myapex/libfoo.so") + + libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10_myapex").Rule("ld").Args["libFlags"] + + // Ensure that libfoo stubs is not linking to libbar (since it is a stubs) + ensureNotContains(t, libFooStubsLdFlags, "libbar.so") +} + func TestApexWithSystemLibsStubs(t *testing.T) { ctx := testApex(t, ` apex { diff --git a/cc/androidmk.go b/cc/androidmk.go index f5e04bb02..1f5a8adfc 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -76,6 +76,9 @@ func (c *Module) AndroidMk() android.AndroidMkData { if len(c.Properties.AndroidMkWholeStaticLibs) > 0 { fmt.Fprintln(w, "LOCAL_WHOLE_STATIC_LIBRARIES := "+strings.Join(c.Properties.AndroidMkWholeStaticLibs, " ")) } + if len(c.Properties.ApexesProvidingSharedLibs) > 0 { + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(c.Properties.ApexesProvidingSharedLibs, " ")) + } fmt.Fprintln(w, "LOCAL_SOONG_LINK_TYPE :=", c.getMakeLinkType()) if c.useVndk() { fmt.Fprintln(w, "LOCAL_USE_VNDK := true") @@ -183,12 +183,13 @@ type BaseProperties struct { // Minimum sdk version supported when compiling against the ndk Sdk_version *string - AndroidMkSharedLibs []string `blueprint:"mutated"` - AndroidMkStaticLibs []string `blueprint:"mutated"` - AndroidMkRuntimeLibs []string `blueprint:"mutated"` - AndroidMkWholeStaticLibs []string `blueprint:"mutated"` - HideFromMake bool `blueprint:"mutated"` - PreventInstall bool `blueprint:"mutated"` + AndroidMkSharedLibs []string `blueprint:"mutated"` + AndroidMkStaticLibs []string `blueprint:"mutated"` + AndroidMkRuntimeLibs []string `blueprint:"mutated"` + AndroidMkWholeStaticLibs []string `blueprint:"mutated"` + HideFromMake bool `blueprint:"mutated"` + PreventInstall bool `blueprint:"mutated"` + ApexesProvidingSharedLibs []string `blueprint:"mutated"` UseVndk bool `blueprint:"mutated"` @@ -1106,7 +1107,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { 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() + versionVariantAvail := !ctx.useVndk() && !c.inRecovery() if version != "" && versionVariantAvail { // Version is explicitly specified. i.e. libFoo#30 variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) @@ -1421,9 +1422,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { 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) + depInSameApex := android.DirectlyInApex(c.ApexName(), depName) + depInPlatform := !android.DirectlyInAnyApex(depName) var useThisDep bool if depIsStubs && explicitlyVersioned { @@ -1579,6 +1579,20 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Export the shared libs to Make. switch depTag { case sharedDepTag, sharedExportDepTag, lateSharedDepTag: + // Dependency to the stubs lib which is already included in an APEX + // is not added to the androidmk dependency + if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok { + if dependentLibrary.buildStubs() && android.InAnyApex(depName) { + // Also add the dependency to the APEX(es) providing the library so that + // m <module> can trigger building the APEXes as well. + for _, an := range android.GetApexesForModule(depName) { + c.Properties.ApexesProvidingSharedLibs = append( + c.Properties.ApexesProvidingSharedLibs, an) + } + break + } + } + // Note: the order of libs in this list is not important because // they merely serve as Make dependencies and do not affect this lib itself. c.Properties.AndroidMkSharedLibs = append( diff --git a/cc/library.go b/cc/library.go index bd4304359..36f3a865a 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1016,10 +1016,6 @@ func latestStubsVersionFor(config android.Config, name string) string { // Version mutator splits a module into the mandatory non-stubs variant // (which is unnamed) and zero or more stubs variants. func VersionMutator(mctx android.BottomUpMutatorContext) { - if mctx.Os() != android.Android { - return - } - if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil { if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() && len(library.Properties.Stubs.Versions) > 0 { |