Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91ae5ecb authored by Colin Cross's avatar Colin Cross
Browse files

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
parent 7297f05e
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -76,9 +76,9 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
		ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries).Parallel()
		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.
		// 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)
	ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory)
+7 −8
Original line number Original line Diff line number Diff line
@@ -548,8 +548,7 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d
	return flags
	return flags
}
}


func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseModuleContext) headerAbiCheckerProperties {
func (library *libraryDecorator) getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties {
	m := ctx.Module().(*Module)
	variantProps := &library.Properties.Target.Platform.Header_abi_checker
	variantProps := &library.Properties.Target.Platform.Header_abi_checker
	if m.InVendor() {
	if m.InVendor() {
		variantProps = &library.Properties.Target.Vendor.Header_abi_checker
		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
	props := library.Properties.Header_abi_checker
	err := proptools.AppendProperties(&props, variantProps, nil)
	err := proptools.AppendProperties(&props, variantProps, nil)
	if err != nil {
	if err != nil {
		ctx.ModuleErrorf("Cannot merge headerAbiCheckerProperties: %s", err.Error())
		panic(fmt.Errorf("Cannot merge headerAbiCheckerProperties: %s", err.Error()))
	}
	}
	return props
	return props
}
}
@@ -718,7 +717,7 @@ type libraryInterface interface {
	setShared()
	setShared()


	// Gets the ABI properties for vendor, product, or platform variant
	// 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
	// Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff
	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
	androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer)
@@ -1365,7 +1364,7 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext,
	sourceVersion, errorMessage string) {
	sourceVersion, errorMessage string) {


	extraFlags := []string{"-target-version", sourceVersion}
	extraFlags := []string{"-target-version", sourceVersion}
	headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
	headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module))
	if Bool(headerAbiChecker.Check_all_apis) {
	if Bool(headerAbiChecker.Check_all_apis) {
		extraFlags = append(extraFlags, "-check-all-apis")
		extraFlags = append(extraFlags, "-check-all-apis")
	} else {
	} 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) {
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) {
	if library.sabi.shouldCreateSourceAbiDump() {
	if library.sabi.shouldCreateSourceAbiDump() {
		exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx)
		exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx)
		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module))
		currSdkVersion := currRefAbiDumpSdkVersion(ctx)
		currSdkVersion := currRefAbiDumpSdkVersion(ctx)
		currVendorVersion := ctx.Config().VendorApiLevel()
		currVendorVersion := ctx.Config().VendorApiLevel()


@@ -1451,7 +1450,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD
			[]string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */)
			[]string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */)


		var llndkDump, apexVariantDump android.Path
		var llndkDump, apexVariantDump android.Path
		tags := classifySourceAbiDump(ctx)
		tags := classifySourceAbiDump(ctx.Module().(*Module))
		optInTags := []lsdumpTag{}
		optInTags := []lsdumpTag{}
		for _, tag := range tags {
		for _, tag := range tags {
			if tag == llndkLsdumpTag && currVendorVersion != "" {
			if tag == llndkLsdumpTag && currVendorVersion != "" {
@@ -1868,7 +1867,7 @@ func (library *libraryDecorator) buildStubs() bool {
}
}


func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *string {
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
		return props.Symbol_file
	}
	}
	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
+74 −29
Original line number Original line Diff line number Diff line
@@ -84,8 +84,8 @@ func (props *headerAbiCheckerProperties) explicitlyDisabled() bool {


type SAbiProperties struct {
type SAbiProperties struct {
	// Whether ABI dump should be created for this module.
	// 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
	// Set by `sabiTransitionMutator` if this module is a shared library that needs ABI check,
	// library that is depended on by an ABI checked library.
	// or a static library that is depended on by an ABI checked library.
	ShouldCreateSourceAbiDump bool `blueprint:"mutated"`
	ShouldCreateSourceAbiDump bool `blueprint:"mutated"`


	// Include directories that may contain ABI information exported by a library.
	// 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.
// 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{}
	result := []lsdumpTag{}
	m := ctx.Module().(*Module)
	headerAbiChecker := m.library.getHeaderAbiCheckerProperties(m)
	headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx)
	if headerAbiChecker.explicitlyDisabled() {
	if headerAbiChecker.explicitlyDisabled() {
		return result
		return result
	}
	}
@@ -149,24 +148,37 @@ func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag {
	return result
	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.
// ctx should be wrapping a native library type module.
func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
func shouldCreateSourceAbiDumpForLibrary(ctx shouldCreateAbiDumpContext) bool {
	// Only generate ABI dump for device modules.
	m, ok := ctx.Module().(*Module)
	if !ctx.Device() {
	if !ok {
		return false
		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.
	// Only create ABI dump for native library module types.
	if m.library == nil {
	if m.library == nil {
		return false
		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() {
	if m.library.static() {
		return m.sabi.shouldCreateSourceAbiDump()
		return false
	}
	}


	// Module is shared library type.
	// Module is shared library type.
@@ -215,31 +227,64 @@ func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool {
			return false
			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
// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
// of their dependencies would be generated.
// 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.
	// Escape hatch to not check any ABI dump.
	if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
	if ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
		return
		return ""
	}
	}

	// Only create ABI dump for native shared libraries and their static library dependencies.
	// Only create ABI dump for native shared libraries and their static library dependencies.
	if m, ok := mctx.Module().(*Module); ok && m.sabi != nil {
	if m, ok := ctx.Module().(*Module); ok && m.sabi != nil {
		if shouldCreateSourceAbiDumpForLibrary(mctx) {
		if shouldCreateSourceAbiDumpForLibrary(ctx) {
			// Mark this module so that .sdump / .lsdump for this library can be generated.
			if IsStaticDepTag(ctx.DepTag()) || ctx.DepTag() == reuseObjTag {
			m.sabi.Properties.ShouldCreateSourceAbiDump = true
				return "sabi"
			// Mark all of its static library dependencies.
			}
			mctx.VisitDirectDeps(func(child android.Module) {
		} else if sourceVariation == "sabi" {
				depTag := mctx.OtherModuleDependencyTag(child)
			if IsWholeStaticLib(ctx.DepTag()) || ctx.DepTag() == reuseObjTag {
				if IsStaticDepTag(depTag) || depTag == reuseObjTag {
				return "sabi"
					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
	}
	}

	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
			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
			}
			}
			})
		}
		}
	}
	}
}
}
+3 −3
Original line number Original line Diff line number Diff line
@@ -48,13 +48,13 @@ func TestSabi(t *testing.T) {
		PrepareForTestWithCcDefaultModules,
		PrepareForTestWithCcDefaultModules,
	).RunTestWithBp(t, bp)
	).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")
	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")
	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")
	transitiveObjSDump := libTransitive.Output("obj/transitive.sdump")


	libsabiShared := result.ModuleForTests("libsabi", "android_arm64_armv8-a_shared")
	libsabiShared := result.ModuleForTests("libsabi", "android_arm64_armv8-a_shared")