diff options
| -rw-r--r-- | android/apex.go | 165 | ||||
| -rw-r--r-- | apex/apex.go | 57 | ||||
| -rw-r--r-- | apex/apex_test.go | 72 | ||||
| -rw-r--r-- | cc/androidmk.go | 3 | ||||
| -rw-r--r-- | cc/cc.go | 34 | ||||
| -rw-r--r-- | cc/library.go | 22 |
6 files changed, 257 insertions, 96 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..c14cd9eb0 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. @@ -223,6 +211,9 @@ type apexBundleProperties struct { // or an android_app_certificate module name in the form ":module". Certificate *string + // Whether this APEX is installable to one of the partitions. Default: true. + Installable *bool + Multilib struct { First struct { // List of native libraries whose compile_multilib is "first" @@ -461,6 +452,10 @@ func (a *apexBundle) Srcs() android.Paths { return android.Paths{a.outputFiles[imageApex]} } +func (a *apexBundle) installable() bool { + return a.properties.Installable == nil || proptools.Bool(a.properties.Installable) +} + func getCopyManifestForNativeLibrary(cc *cc.Module) (fileToCopy android.Path, dirInApex string) { // Decide the APEX-local directory by the multilib of the library // In the future, we may query this to the module. @@ -788,18 +783,22 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile and }) // Install to $OUT/soong/{target,host}/.../apex - ctx.InstallFile(android.PathForModuleInstall(ctx, "apex"), ctx.ModuleName()+suffix, a.outputFiles[apexType]) + if a.installable() { + ctx.InstallFile(android.PathForModuleInstall(ctx, "apex"), ctx.ModuleName()+suffix, a.outputFiles[apexType]) + } } func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { - // For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along - // with other ordinary files. - manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) - a.filesInfo = append(a.filesInfo, apexFile{manifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc}) - - for _, fi := range a.filesInfo { - dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir) - ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile) + if a.installable() { + // For flattened APEX, do nothing but make sure that apex_manifest.json file is also copied along + // with other ordinary files. + manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) + a.filesInfo = append(a.filesInfo, apexFile{manifest, ctx.ModuleName() + ".apex_manifest.json", android.Common, ".", etc}) + + for _, fi := range a.filesInfo { + dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir) + ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile) + } } } @@ -844,6 +843,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", fi.builtFile.Base()) fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String()) fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake()) + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) archStr := fi.archType.String() if archStr != "common" { fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) @@ -872,6 +872,7 @@ func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkD fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFiles[apexType].String()) fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString())) fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexType.suffix()) + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable()) fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key)) fmt.Fprintln(w, "include $(BUILD_PREBUILT)") diff --git a/apex/apex_test.go b/apex/apex_test.go index c01c40a76..88c57bc0d 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -267,6 +267,7 @@ func TestApexWithStubs(t *testing.T) { cc_library { name: "mylib2", srcs: ["mylib.cpp"], + cflags: ["-include mylib.h"], system_shared_libs: [], stl: "none", stubs: { @@ -316,6 +317,77 @@ func TestApexWithStubs(t *testing.T) { ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") + + // Ensure that stubs libs are built without -include flags + mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylib2Cflags, "-include ") +} + +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) { 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..524b88626 100644 --- a/cc/library.go +++ b/cc/library.go @@ -351,6 +351,24 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d flags = library.baseCompiler.compilerFlags(ctx, flags, deps) if library.buildStubs() { + // Remove -include <file> when compiling stubs. Otherwise, the force included + // headers might cause conflicting types error with the symbols in the + // generated stubs source code. e.g. + // double acos(double); // in header + // void acos() {} // in the generated source code + removeInclude := func(flags []string) []string { + ret := flags[:0] + for _, f := range flags { + if strings.HasPrefix(f, "-include ") { + continue + } + ret = append(ret, f) + } + return ret + } + flags.GlobalFlags = removeInclude(flags.GlobalFlags) + flags.CFlags = removeInclude(flags.CFlags) + flags = addStubLibraryCompilerFlags(flags) } return flags @@ -1016,10 +1034,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 { |