diff options
author | 2024-10-01 14:03:40 -0700 | |
---|---|---|
committer | 2024-10-07 04:26:19 +0000 | |
commit | 91ae5ecbd64ea79b0cadddcd13fe6b1746fb7f04 (patch) | |
tree | 9ce9873f540c4ea1bf172be29d66a12fd88cd394 | |
parent | 7297f05ee8cda422ccb32c4af4d9d715d6bac10e (diff) |
Convert sabi to TransitionMutator
The sabi mutator walks static dependencies of native libraries with ABI
stability guarantees (LLNDK, APEX, or cross-partition) and sets a flag
that causes the modules to generate additional rules to extract the ABI
from each source/object pair, combine them, and add a rule that diffs
them against the checked in version. In order to remove top down
mutators that mutate dependencies, convert it to a transition mutator.
This may cause the same static library code to be compiled identically
twice with and without the configuration, but there are relatively
few static libraries that are dependencies of stable ABI libraries.
If the cost of compiling these static libraries becomes too high this
can be replaced with something like Bazel aspects, where the stable
ABI library visits its static dependencies and adds extra rules to
generate the sabi dumps.
Bug: 367784740
Test: TestSabi
Flag: EXEMPT refactor
Change-Id: Ie6bd44680afdca15b09ba0b64ed0df9964a936a6
-rw-r--r-- | cc/cc.go | 4 | ||||
-rw-r--r-- | cc/library.go | 15 | ||||
-rw-r--r-- | cc/sabi.go | 103 | ||||
-rw-r--r-- | cc/sabi_test.go | 6 |
4 files changed, 86 insertions, 42 deletions
@@ -76,9 +76,9 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries).Parallel() }) - ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.PostApexMutators(func(ctx android.RegisterMutatorsContext) { // sabi mutator needs to be run after apex mutator finishes. - ctx.TopDown("sabi_deps", sabiDepsMutator) + ctx.Transition("sabi", &sabiTransitionMutator{}) }) ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory) diff --git a/cc/library.go b/cc/library.go index 988d55a84..988a7fa0b 100644 --- a/cc/library.go +++ b/cc/library.go @@ -548,8 +548,7 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d return flags } -func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseModuleContext) headerAbiCheckerProperties { - m := ctx.Module().(*Module) +func (library *libraryDecorator) getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties { variantProps := &library.Properties.Target.Platform.Header_abi_checker if m.InVendor() { variantProps = &library.Properties.Target.Vendor.Header_abi_checker @@ -559,7 +558,7 @@ func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseM props := library.Properties.Header_abi_checker err := proptools.AppendProperties(&props, variantProps, nil) if err != nil { - ctx.ModuleErrorf("Cannot merge headerAbiCheckerProperties: %s", err.Error()) + panic(fmt.Errorf("Cannot merge headerAbiCheckerProperties: %s", err.Error())) } return props } @@ -718,7 +717,7 @@ type libraryInterface interface { setShared() // Gets the ABI properties for vendor, product, or platform variant - getHeaderAbiCheckerProperties(ctx android.BaseModuleContext) headerAbiCheckerProperties + getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties // Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) @@ -1365,7 +1364,7 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, sourceVersion, errorMessage string) { extraFlags := []string{"-target-version", sourceVersion} - headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx) + headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)) if Bool(headerAbiChecker.Check_all_apis) { extraFlags = append(extraFlags, "-check-all-apis") } else { @@ -1437,7 +1436,7 @@ func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) { if library.sabi.shouldCreateSourceAbiDump() { exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx) - headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx) + headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)) currSdkVersion := currRefAbiDumpSdkVersion(ctx) currVendorVersion := ctx.Config().VendorApiLevel() @@ -1451,7 +1450,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD []string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */) var llndkDump, apexVariantDump android.Path - tags := classifySourceAbiDump(ctx) + tags := classifySourceAbiDump(ctx.Module().(*Module)) optInTags := []lsdumpTag{} for _, tag := range tags { if tag == llndkLsdumpTag && currVendorVersion != "" { @@ -1868,7 +1867,7 @@ func (library *libraryDecorator) buildStubs() bool { } func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *string { - if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil { + if props := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)); props.Symbol_file != nil { return props.Symbol_file } if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { diff --git a/cc/sabi.go b/cc/sabi.go index 64eab4160..2caf0d470 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -84,8 +84,8 @@ func (props *headerAbiCheckerProperties) explicitlyDisabled() bool { type SAbiProperties struct { // Whether ABI dump should be created for this module. - // Set by `sabiDepsMutator` if this module is a shared library that needs ABI check, or a static - // library that is depended on by an ABI checked library. + // Set by `sabiTransitionMutator` if this module is a shared library that needs ABI check, + // or a static library that is depended on by an ABI checked library. ShouldCreateSourceAbiDump bool `blueprint:"mutated"` // Include directories that may contain ABI information exported by a library. @@ -121,10 +121,9 @@ func (sabi *sabi) shouldCreateSourceAbiDump() bool { } // Returns a slice of strings that represent the ABI dumps generated for this module. -func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag { +func classifySourceAbiDump(m *Module) []lsdumpTag { result := []lsdumpTag{} - m := ctx.Module().(*Module) - headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx) + headerAbiChecker := m.library.getHeaderAbiCheckerProperties(m) if headerAbiChecker.explicitlyDisabled() { return result } @@ -149,24 +148,37 @@ func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag { return result } -// Called from sabiDepsMutator to check whether ABI dumps should be created for this module. +type shouldCreateAbiDumpContext interface { + android.ModuleProviderContext + Module() android.Module + Config() android.Config +} + +var _ shouldCreateAbiDumpContext = android.ModuleContext(nil) +var _ shouldCreateAbiDumpContext = android.OutgoingTransitionContext(nil) + +// Called from sabiTransitionMutator to check whether ABI dumps should be created for this module. // ctx should be wrapping a native library type module. -func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { - // Only generate ABI dump for device modules. - if !ctx.Device() { +func shouldCreateSourceAbiDumpForLibrary(ctx shouldCreateAbiDumpContext) bool { + m, ok := ctx.Module().(*Module) + if !ok { return false } - m := ctx.Module().(*Module) + // Only generate ABI dump for device modules. + if !m.Device() { + return false + } // Only create ABI dump for native library module types. if m.library == nil { return false } - // Create ABI dump for static libraries only if they are dependencies of ABI checked libraries. + // Don't create ABI dump for static libraries + // The sabi variant will be propagated to dependencies of ABI checked libraries. if m.library.static() { - return m.sabi.shouldCreateSourceAbiDump() + return false } // Module is shared library type. @@ -215,31 +227,64 @@ func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { return false } } - return len(classifySourceAbiDump(ctx)) > 0 + return len(classifySourceAbiDump(m)) > 0 } // Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps // of their dependencies would be generated. -func sabiDepsMutator(mctx android.TopDownMutatorContext) { +type sabiTransitionMutator struct{} + +func (s *sabiTransitionMutator) Split(ctx android.BaseModuleContext) []string { + return []string{""} +} + +func (s *sabiTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { // Escape hatch to not check any ABI dump. - if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { - return + if ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { + return "" } + // Only create ABI dump for native shared libraries and their static library dependencies. - if m, ok := mctx.Module().(*Module); ok && m.sabi != nil { - if shouldCreateSourceAbiDumpForLibrary(mctx) { - // Mark this module so that .sdump / .lsdump for this library can be generated. + if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { + if shouldCreateSourceAbiDumpForLibrary(ctx) { + if IsStaticDepTag(ctx.DepTag()) || ctx.DepTag() == reuseObjTag { + return "sabi" + } + } else if sourceVariation == "sabi" { + if IsWholeStaticLib(ctx.DepTag()) || ctx.DepTag() == reuseObjTag { + return "sabi" + } + } + } + + return "" +} + +func (s *sabiTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + if incomingVariation == "" { + return "" + } + + if incomingVariation == "sabi" { + if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { + return "sabi" + } + } + + return "" +} + +func (s *sabiTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + if m, ok := ctx.Module().(*Module); ok && m.sabi != nil { + if variation == "sabi" { m.sabi.Properties.ShouldCreateSourceAbiDump = true - // Mark all of its static library dependencies. - mctx.VisitDirectDeps(func(child android.Module) { - depTag := mctx.OtherModuleDependencyTag(child) - if IsStaticDepTag(depTag) || depTag == reuseObjTag { - if c, ok := child.(*Module); ok && c.sabi != nil { - // Mark this module so that .sdump for this static library can be generated. - c.sabi.Properties.ShouldCreateSourceAbiDump = true - } - } - }) + m.HideFromMake() + m.Properties.PreventInstall = true + } else if shouldCreateSourceAbiDumpForLibrary(ctx) { + // Escape hatch to not check any ABI dump. + if !ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { + m.sabi.Properties.ShouldCreateSourceAbiDump = true + } } } } diff --git a/cc/sabi_test.go b/cc/sabi_test.go index 849fc36e8..6b8cc1759 100644 --- a/cc/sabi_test.go +++ b/cc/sabi_test.go @@ -48,13 +48,13 @@ func TestSabi(t *testing.T) { PrepareForTestWithCcDefaultModules, ).RunTestWithBp(t, bp) - libsabiStatic := result.ModuleForTests("libsabi", "android_arm64_armv8-a_static") + libsabiStatic := result.ModuleForTests("libsabi", "android_arm64_armv8-a_static_sabi") sabiObjSDump := libsabiStatic.Output("obj/sabi.sdump") - libDirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static") + libDirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static_sabi") directObjSDump := libDirect.Output("obj/direct.sdump") - libTransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static") + libTransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static_sabi") transitiveObjSDump := libTransitive.Output("obj/transitive.sdump") libsabiShared := result.ModuleForTests("libsabi", "android_arm64_armv8-a_shared") |