Loading android/mutator.go +14 −0 Original line number Diff line number Diff line Loading @@ -132,11 +132,15 @@ type TopDownMutatorContext interface { VisitDepsDepthFirst(visit func(Module)) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) WalkDeps(visit func(Module, Module) bool) // GetWalkPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module } type androidTopDownMutatorContext struct { blueprint.TopDownMutatorContext androidBaseContextImpl walkPath []Module } type AndroidBottomUpMutator func(BottomUpMutatorContext) Loading Loading @@ -287,10 +291,16 @@ func (a *androidTopDownMutatorContext) VisitDepsDepthFirstIf(pred func(Module) b } func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) { a.walkPath = []Module{a.Module()} a.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool { childAndroidModule, _ := child.(Module) parentAndroidModule, _ := parent.(Module) if childAndroidModule != nil && parentAndroidModule != nil { // record walkPath before visit for a.walkPath[len(a.walkPath)-1] != parentAndroidModule { a.walkPath = a.walkPath[0 : len(a.walkPath)-1] } a.walkPath = append(a.walkPath, childAndroidModule) return visit(childAndroidModule, parentAndroidModule) } else { return false Loading @@ -298,6 +308,10 @@ func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) }) } func (a *androidTopDownMutatorContext) GetWalkPath() []Module { return a.walkPath } func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) { for _, p := range props { err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties, Loading cc/cc.go +36 −21 Original line number Diff line number Diff line Loading @@ -68,6 +68,8 @@ func init() { ctx.TopDown("lto_deps", ltoDepsMutator) ctx.BottomUp("lto", ltoMutator).Parallel() ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) pctx.Import("android/soong/cc/config") Loading Loading @@ -1469,30 +1471,44 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag depe } // Tests whether the dependent library is okay to be double loaded inside a single process. // If a library is a member of VNDK and at the same time dependencies of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loaded: true // If a library has a vendor variant and is a (transitive) dependency of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). func checkDoubleLoadableLibries(ctx android.ModuleContext, from *Module, to *Module) { if _, ok := from.linker.(*libraryDecorator); !ok { return func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { check := func(child, parent android.Module) bool { to, ok := child.(*Module) if !ok { // follow thru cc.Defaults, etc. return true } if inList(ctx.ModuleName(), llndkLibraries) || (from.useVndk() && Bool(from.VendorProperties.Double_loadable)) { _, depIsLlndk := to.linker.(*llndkStubDecorator) depIsVndkSp := false if to.vndkdep != nil && to.vndkdep.isVndkSp() { depIsVndkSp = true if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() { return false } depIsVndk := false if to.vndkdep != nil && to.vndkdep.isVndk() { depIsVndk = true // if target lib has no vendor variant, keep checking dependency graph if !to.hasVendorVariant() { return true } if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) { return false } var stringPath []string for _, m := range ctx.GetWalkPath() { stringPath = append(stringPath, m.Name()) } ctx.ModuleErrorf("links a library %q which is not LL-NDK, "+ "VNDK-SP, or explicitly marked as 'double_loadable:true'. "+ "(dependency: %s)", ctx.OtherModuleName(to), strings.Join(stringPath, " -> ")) return false } if module, ok := ctx.Module().(*Module); ok { if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() { if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) { ctx.WalkDeps(check) } depIsDoubleLoadable := Bool(to.VendorProperties.Double_loadable) if !depIsLlndk && !depIsVndkSp && !depIsDoubleLoadable && depIsVndk { ctx.ModuleErrorf("links VNDK library %q that isn't double loadable (not also LL-NDK, "+ "VNDK-SP, or explicitly marked as 'double_loadable').", ctx.OtherModuleName(to)) } } } Loading Loading @@ -1648,7 +1664,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } checkLinkType(ctx, c, ccDep, t) checkDoubleLoadableLibries(ctx, c, ccDep) } var ptr *android.Paths Loading cc/cc_test.go +306 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ func createTestContext(t *testing.T, config android.Config, bp string, os androi ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) ctx.Register() // add some modules that are required by the compiler and/or linker Loading Loading @@ -428,6 +431,309 @@ func TestVndkDepError(t *testing.T) { nocrt: true, } `) // Check whether an error is emitted when a VNDK lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-private lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndkprivate", vendor_available: false, vndk: { enabled: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-sp lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndksp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-sp-private lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndkspprivate", vendor_available: false, vndk: { enabled: true, support_system_process: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) } func TestDoubleLoadbleDep(t *testing.T) { // okay to link : LLNDK -> double_loadable VNDK testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libdoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, } `) // okay to link : LLNDK -> VNDK-SP testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libvndksp"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libvndksp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } `) // okay to link : double_loadable -> double_loadable testCc(t, ` cc_library { name: "libdoubleloadable1", shared_libs: ["libdoubleloadable2"], vendor_available: true, double_loadable: true, } cc_library { name: "libdoubleloadable2", vendor_available: true, double_loadable: true, } `) // okay to link : double_loadable VNDK -> double_loadable VNDK private testCc(t, ` cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: false, vndk: { enabled: true, }, double_loadable: true, } `) // okay to link : LLNDK -> core-only -> vendor_available & double_loadable testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libcoreonly"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libcoreonly", shared_libs: ["libvendoravailable"], } // indirect dependency of LLNDK cc_library { name: "libvendoravailable", vendor_available: true, double_loadable: true, } `) } func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", shared_libs: ["libnondoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libnondoubleloadable", vendor_available: true, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a LLNDK depends on a non-double_loadable vendor_available lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", no_libgcc: true, shared_libs: ["libnondoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libnondoubleloadable", vendor_available: true, } `) // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable vendor_available lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: true, } `) // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: true, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a double_loadable VNDK depends on a non-double_loadable VNDK private lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: false, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a LLNDK depends on a non-double_loadable indirectly. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", shared_libs: ["libcoreonly"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libcoreonly", shared_libs: ["libvendoravailable"], } // indirect dependency of LLNDK cc_library { name: "libvendoravailable", vendor_available: true, } `) } func TestVndkMustNotBeProductSpecific(t *testing.T) { Loading Loading
android/mutator.go +14 −0 Original line number Diff line number Diff line Loading @@ -132,11 +132,15 @@ type TopDownMutatorContext interface { VisitDepsDepthFirst(visit func(Module)) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) WalkDeps(visit func(Module, Module) bool) // GetWalkPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module } type androidTopDownMutatorContext struct { blueprint.TopDownMutatorContext androidBaseContextImpl walkPath []Module } type AndroidBottomUpMutator func(BottomUpMutatorContext) Loading Loading @@ -287,10 +291,16 @@ func (a *androidTopDownMutatorContext) VisitDepsDepthFirstIf(pred func(Module) b } func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) { a.walkPath = []Module{a.Module()} a.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool { childAndroidModule, _ := child.(Module) parentAndroidModule, _ := parent.(Module) if childAndroidModule != nil && parentAndroidModule != nil { // record walkPath before visit for a.walkPath[len(a.walkPath)-1] != parentAndroidModule { a.walkPath = a.walkPath[0 : len(a.walkPath)-1] } a.walkPath = append(a.walkPath, childAndroidModule) return visit(childAndroidModule, parentAndroidModule) } else { return false Loading @@ -298,6 +308,10 @@ func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) }) } func (a *androidTopDownMutatorContext) GetWalkPath() []Module { return a.walkPath } func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) { for _, p := range props { err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties, Loading
cc/cc.go +36 −21 Original line number Diff line number Diff line Loading @@ -68,6 +68,8 @@ func init() { ctx.TopDown("lto_deps", ltoDepsMutator) ctx.BottomUp("lto", ltoMutator).Parallel() ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) pctx.Import("android/soong/cc/config") Loading Loading @@ -1469,30 +1471,44 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag depe } // Tests whether the dependent library is okay to be double loaded inside a single process. // If a library is a member of VNDK and at the same time dependencies of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loaded: true // If a library has a vendor variant and is a (transitive) dependency of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). func checkDoubleLoadableLibries(ctx android.ModuleContext, from *Module, to *Module) { if _, ok := from.linker.(*libraryDecorator); !ok { return func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) { check := func(child, parent android.Module) bool { to, ok := child.(*Module) if !ok { // follow thru cc.Defaults, etc. return true } if inList(ctx.ModuleName(), llndkLibraries) || (from.useVndk() && Bool(from.VendorProperties.Double_loadable)) { _, depIsLlndk := to.linker.(*llndkStubDecorator) depIsVndkSp := false if to.vndkdep != nil && to.vndkdep.isVndkSp() { depIsVndkSp = true if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() { return false } depIsVndk := false if to.vndkdep != nil && to.vndkdep.isVndk() { depIsVndk = true // if target lib has no vendor variant, keep checking dependency graph if !to.hasVendorVariant() { return true } if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) { return false } var stringPath []string for _, m := range ctx.GetWalkPath() { stringPath = append(stringPath, m.Name()) } ctx.ModuleErrorf("links a library %q which is not LL-NDK, "+ "VNDK-SP, or explicitly marked as 'double_loadable:true'. "+ "(dependency: %s)", ctx.OtherModuleName(to), strings.Join(stringPath, " -> ")) return false } if module, ok := ctx.Module().(*Module); ok { if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() { if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) { ctx.WalkDeps(check) } depIsDoubleLoadable := Bool(to.VendorProperties.Double_loadable) if !depIsLlndk && !depIsVndkSp && !depIsDoubleLoadable && depIsVndk { ctx.ModuleErrorf("links VNDK library %q that isn't double loadable (not also LL-NDK, "+ "VNDK-SP, or explicitly marked as 'double_loadable').", ctx.OtherModuleName(to)) } } } Loading Loading @@ -1648,7 +1664,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } checkLinkType(ctx, c, ccDep, t) checkDoubleLoadableLibries(ctx, c, ccDep) } var ptr *android.Paths Loading
cc/cc_test.go +306 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ func createTestContext(t *testing.T, config android.Config, bp string, os androi ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) ctx.Register() // add some modules that are required by the compiler and/or linker Loading Loading @@ -428,6 +431,309 @@ func TestVndkDepError(t *testing.T) { nocrt: true, } `) // Check whether an error is emitted when a VNDK lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-private lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndkprivate", vendor_available: false, vndk: { enabled: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-sp lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndksp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) // Check whether an error is emitted when a VNDK-sp-private lib depends on a non-VNDK lib. testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", ` cc_library { name: "libvndkspprivate", vendor_available: false, vndk: { enabled: true, support_system_process: true, }, shared_libs: ["libnonvndk"], nocrt: true, } cc_library { name: "libnonvndk", vendor_available: true, nocrt: true, } `) } func TestDoubleLoadbleDep(t *testing.T) { // okay to link : LLNDK -> double_loadable VNDK testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libdoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, } `) // okay to link : LLNDK -> VNDK-SP testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libvndksp"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libvndksp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } `) // okay to link : double_loadable -> double_loadable testCc(t, ` cc_library { name: "libdoubleloadable1", shared_libs: ["libdoubleloadable2"], vendor_available: true, double_loadable: true, } cc_library { name: "libdoubleloadable2", vendor_available: true, double_loadable: true, } `) // okay to link : double_loadable VNDK -> double_loadable VNDK private testCc(t, ` cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: false, vndk: { enabled: true, }, double_loadable: true, } `) // okay to link : LLNDK -> core-only -> vendor_available & double_loadable testCc(t, ` cc_library { name: "libllndk", shared_libs: ["libcoreonly"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libcoreonly", shared_libs: ["libvendoravailable"], } // indirect dependency of LLNDK cc_library { name: "libvendoravailable", vendor_available: true, double_loadable: true, } `) } func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", shared_libs: ["libnondoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libnondoubleloadable", vendor_available: true, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a LLNDK depends on a non-double_loadable vendor_available lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", no_libgcc: true, shared_libs: ["libnondoubleloadable"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libnondoubleloadable", vendor_available: true, } `) // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable vendor_available lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: true, } `) // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: true, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a double_loadable VNDK depends on a non-double_loadable VNDK private lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libdoubleloadable", vendor_available: true, vndk: { enabled: true, }, double_loadable: true, shared_libs: ["libnondoubleloadable"], } cc_library { name: "libnondoubleloadable", vendor_available: false, vndk: { enabled: true, }, } `) // Check whether an error is emitted when a LLNDK depends on a non-double_loadable indirectly. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` cc_library { name: "libllndk", shared_libs: ["libcoreonly"], } llndk_library { name: "libllndk", symbol_file: "", } cc_library { name: "libcoreonly", shared_libs: ["libvendoravailable"], } // indirect dependency of LLNDK cc_library { name: "libvendoravailable", vendor_available: true, } `) } func TestVndkMustNotBeProductSpecific(t *testing.T) { Loading