diff --git a/cc/cc.go b/cc/cc.go index afdf85b12..7a94f89ce 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -79,7 +79,6 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel() ctx.BottomUp("coverage", coverageMutator).Parallel() - ctx.TopDown("vndk_deps", sabiDepsMutator) ctx.TopDown("lto_deps", ltoDepsMutator) ctx.BottomUp("lto", ltoMutator).Parallel() @@ -88,6 +87,11 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel() }) + ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { + // sabi mutator needs to be run after apex mutator finishes. + ctx.TopDown("sabi_deps", sabiDepsMutator) + }) + ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory) } @@ -415,7 +419,6 @@ type ModuleContextIntf interface { inRamdisk() bool inVendorRamdisk() bool inRecovery() bool - shouldCreateSourceAbiDump() bool selectedStl() string baseModuleName() string getVndkExtendsModuleName() string @@ -1279,42 +1282,6 @@ func (ctx *moduleContextImpl) mustUseVendorVariant() bool { return ctx.mod.MustUseVendorVariant() } -// Check whether ABI dumps should be created for this module. -func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool { - if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { - return false - } - - // Coverage builds have extra symbols. - if ctx.mod.isCoverageVariant() { - return false - } - - if ctx.ctx.Fuchsia() { - return false - } - - if sanitize := ctx.mod.sanitize; sanitize != nil { - if !sanitize.isVariantOnProductionDevice() { - return false - } - } - if !ctx.ctx.Device() { - // Host modules do not need ABI dumps. - return false - } - if ctx.isNDKStubLibrary() { - // Stubs do not need ABI dumps. - return false - } - if lib := ctx.mod.library; lib != nil && lib.buildStubs() { - // Stubs do not need ABI dumps. - return false - } - - return true -} - func (ctx *moduleContextImpl) selectedStl() string { if stl := ctx.mod.stl; stl != nil { return stl.Properties.SelectedStl diff --git a/cc/config/clang.go b/cc/config/clang.go index 441bff2a5..519a9e2d2 100644 --- a/cc/config/clang.go +++ b/cc/config/clang.go @@ -249,6 +249,10 @@ func ClangFilterUnknownLldflags(lldflags []string) []string { return result } +func ClangLibToolingFilterUnknownCflags(libToolingFlags []string) []string { + return android.RemoveListFromList(libToolingFlags, ClangLibToolingUnknownCflags) +} + func inListSorted(s string, list []string) bool { for _, l := range list { if s == l { diff --git a/cc/library.go b/cc/library.go index 06b99054f..ed6755f3c 100644 --- a/cc/library.go +++ b/cc/library.go @@ -594,59 +594,12 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d return flags } -// Returns a string that represents the class of the ABI dump. -// Returns an empty string if ABI check is disabled for this library. -func (library *libraryDecorator) classifySourceAbiDump(ctx ModuleContext) string { - enabled := library.Properties.Header_abi_checker.Enabled - if enabled != nil && !Bool(enabled) { - return "" - } - // Return NDK if the library is both NDK and LLNDK. - if ctx.isNdk(ctx.Config()) { - return "NDK" - } - if ctx.isLlndkPublic(ctx.Config()) { - return "LLNDK" - } - if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) { - if ctx.isVndkSp() { - if ctx.IsVndkExt() { - return "VNDK-SP-ext" - } else { - return "VNDK-SP" - } - } else { - if ctx.IsVndkExt() { - return "VNDK-ext" - } else { - return "VNDK-core" - } - } - } - if Bool(enabled) || library.hasStubsVariants() { - return "PLATFORM" - } - return "" +func (library *libraryDecorator) headerAbiCheckerEnabled() bool { + return Bool(library.Properties.Header_abi_checker.Enabled) } -func (library *libraryDecorator) shouldCreateSourceAbiDump(ctx ModuleContext) bool { - if !ctx.shouldCreateSourceAbiDump() { - return false - } - if !ctx.isForPlatform() { - if !library.hasStubsVariants() { - // Skip ABI checks if this library is for APEX but isn't exported. - return false - } - if !Bool(library.Properties.Header_abi_checker.Enabled) { - // Skip ABI checks if this library is for APEX and did not explicitly enable - // ABI checks. - // TODO(b/145608479): ABI checks should be enabled by default. Remove this - // after evaluating the extra build time. - return false - } - } - return library.classifySourceAbiDump(ctx) != "" +func (library *libraryDecorator) headerAbiCheckerExplicitlyDisabled() bool { + return !BoolDefault(library.Properties.Header_abi_checker.Enabled, true) } func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { @@ -668,7 +621,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } return Objects{} } - if library.shouldCreateSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps { + if library.sabi.shouldCreateSourceAbiDump() { exportIncludeDirs := library.flagExporter.exportedIncludes(ctx) var SourceAbiFlags []string for _, dir := range exportIncludeDirs.Strings() { @@ -718,6 +671,10 @@ type libraryInterface interface { setStatic() setShared() + // Check whether header_abi_checker is enabled or explicitly disabled. + headerAbiCheckerEnabled() bool + headerAbiCheckerExplicitlyDisabled() bool + // Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) @@ -1158,7 +1115,7 @@ func getRefAbiDumpFile(ctx ModuleContext, vndkVersion, fileName string) android. } func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) { - if library.shouldCreateSourceAbiDump(ctx) { + if library.sabi.shouldCreateSourceAbiDump() { var vndkVersion string if ctx.useVndk() { @@ -1183,7 +1140,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec library.Properties.Header_abi_checker.Exclude_symbol_versions, library.Properties.Header_abi_checker.Exclude_symbol_tags) - addLsdumpPath(library.classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String()) + addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String()) refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName) if refAbiDumpFile != nil { diff --git a/cc/sabi.go b/cc/sabi.go index ef6beada6..99e718e60 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -15,7 +15,6 @@ package cc import ( - "strings" "sync" "android/soong/android" @@ -23,12 +22,18 @@ import ( ) var ( - lsdumpPaths []string - sabiLock sync.Mutex + lsdumpPaths []string + lsdumpPathsLock sync.Mutex ) type SAbiProperties struct { - CreateSAbiDumps bool `blueprint:"mutated"` + // 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. + ShouldCreateSourceAbiDump bool `blueprint:"mutated"` + + // Include directories that may contain ABI information exported by a library. + // These directories are passed to the header-abi-dumper. ReexportedIncludes []string `blueprint:"mutated"` } @@ -36,66 +41,172 @@ type sabi struct { Properties SAbiProperties } -func (sabimod *sabi) props() []interface{} { - return []interface{}{&sabimod.Properties} +func (sabi *sabi) props() []interface{} { + return []interface{}{&sabi.Properties} } -func (sabimod *sabi) begin(ctx BaseModuleContext) {} +func (sabi *sabi) begin(ctx BaseModuleContext) {} -func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps { +func (sabi *sabi) deps(ctx BaseModuleContext, deps Deps) Deps { return deps } -func inListWithPrefixSearch(flag string, filter []string) bool { - // Assuming the filter is small enough. - // If the suffix of a filter element is *, try matching prefixes as well. - for _, f := range filter { - if (f == flag) || (strings.HasSuffix(f, "*") && strings.HasPrefix(flag, strings.TrimSuffix(f, "*"))) { - return true - } - } - return false -} - -func filterOutWithPrefix(list []string, filter []string) (remainder []string) { - // Go through the filter, matching and optionally doing a prefix search for list elements. - for _, l := range list { - if !inListWithPrefixSearch(l, filter) { - remainder = append(remainder, l) - } - } - return -} - -func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags { - // Assuming that the cflags which clang LibTooling tools cannot - // understand have not been converted to ninja variables yet. - flags.Local.ToolingCFlags = filterOutWithPrefix(flags.Local.CFlags, config.ClangLibToolingUnknownCflags) - flags.Global.ToolingCFlags = filterOutWithPrefix(flags.Global.CFlags, config.ClangLibToolingUnknownCflags) - flags.Local.ToolingCppFlags = filterOutWithPrefix(flags.Local.CppFlags, config.ClangLibToolingUnknownCflags) - flags.Global.ToolingCppFlags = filterOutWithPrefix(flags.Global.CppFlags, config.ClangLibToolingUnknownCflags) - +func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags { + // Filter out flags which libTooling don't understand. + // This is here for legacy reasons and future-proof, in case the version of libTooling and clang + // diverge. + flags.Local.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CFlags) + flags.Global.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CFlags) + flags.Local.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CppFlags) + flags.Global.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CppFlags) return flags } -func sabiDepsMutator(mctx android.TopDownMutatorContext) { - if c, ok := mctx.Module().(*Module); ok && - ((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) || - (c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) { - mctx.VisitDirectDeps(func(m android.Module) { - if tag, ok := mctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok && tag.static() { - cc, _ := m.(*Module) - if cc == nil { - return - } - cc.sabi.Properties.CreateSAbiDumps = true +// Returns true if ABI dump should be created for this library, either because library is ABI +// checked or is depended on by an ABI checked library. +// Could be called as a nil receiver. +func (sabi *sabi) shouldCreateSourceAbiDump() bool { + return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump +} + +// Returns a string that represents the class of the ABI dump. +// Returns an empty string if ABI check is disabled for this library. +func classifySourceAbiDump(ctx android.BaseModuleContext) string { + m := ctx.Module().(*Module) + if m.library.headerAbiCheckerExplicitlyDisabled() { + return "" + } + // Return NDK if the library is both NDK and LLNDK. + if m.IsNdk(ctx.Config()) { + return "NDK" + } + if m.isLlndkPublic(ctx.Config()) { + return "LLNDK" + } + if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate(ctx.Config()) { + if m.isVndkSp() { + if m.IsVndkExt() { + return "VNDK-SP-ext" + } else { + return "VNDK-SP" } - }) + } else { + if m.IsVndkExt() { + return "VNDK-ext" + } else { + return "VNDK-core" + } + } + } + if m.library.headerAbiCheckerEnabled() || m.library.hasStubsVariants() { + return "PLATFORM" + } + return "" +} + +// Called from sabiDepsMutator 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 { + if ctx.Fuchsia() { + return false + } + + // Only generate ABI dump for device modules. + if !ctx.Device() { + return false + } + + m := ctx.Module().(*Module) + + // 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. + if m.library.static() { + return m.sabi.shouldCreateSourceAbiDump() + } + + // Module is shared library type. + + // Don't check uninstallable modules. + if m.IsSkipInstall() { + return false + } + + // Don't check ramdisk or recovery variants. Only check core, vendor or product variants. + if m.InRamdisk() || m.InVendorRamdisk() || m.InRecovery() { + return false + } + + // Don't create ABI dump for prebuilts. + if m.Prebuilt() != nil || m.isSnapshotPrebuilt() { + return false + } + + // Coverage builds have extra symbols. + if m.isCoverageVariant() { + return false + } + + // Some sanitizer variants may have different ABI. + if m.sanitize != nil && !m.sanitize.isVariantOnProductionDevice() { + return false + } + + // Don't create ABI dump for stubs. + if m.isNDKStubLibrary() || m.IsStubs() { + return false + } + + isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() + if isPlatformVariant { + // Bionic libraries that are installed to the bootstrap directory are not ABI checked. + // Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs, + // are checked. + if InstallToBootstrap(m.BaseModuleName(), ctx.Config()) { + return false + } + } else { + // Don't create ABI dump if this library is for APEX but isn't exported. + if !m.HasStubsVariants() { + return false + } + } + return classifySourceAbiDump(ctx) != "" +} + +// 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) { + // Escape hatch to not check any ABI dump. + if mctx.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. + m.sabi.Properties.ShouldCreateSourceAbiDump = true + // Mark all of its static library dependencies. + mctx.VisitDirectDeps(func(child android.Module) { + depTag := mctx.OtherModuleDependencyTag(child) + if libDepTag, ok := depTag.(libraryDependencyTag); ok && libDepTag.static() { + 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 + } + } + }) + } } } +// Add an entry to the global list of lsdump. The list is exported to a Make variable by +// `cc.makeVarsProvider`. func addLsdumpPath(lsdumpPath string) { - sabiLock.Lock() + lsdumpPathsLock.Lock() + defer lsdumpPathsLock.Unlock() lsdumpPaths = append(lsdumpPaths, lsdumpPath) - sabiLock.Unlock() }