1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package cc 16 17import ( 18 "sync" 19 20 "android/soong/android" 21 "android/soong/cc/config" 22) 23 24var ( 25 lsdumpPaths []string 26 lsdumpPathsLock sync.Mutex 27) 28 29// Properties for ABI compatibility checker in Android.bp. 30type headerAbiCheckerProperties struct { 31 // Enable ABI checks (even if this is not an LLNDK/VNDK lib) 32 Enabled *bool 33 34 // Path to a symbol file that specifies the symbols to be included in the generated 35 // ABI dump file 36 Symbol_file *string `android:"path"` 37 38 // Symbol versions that should be ignored from the symbol file 39 Exclude_symbol_versions []string 40 41 // Symbol tags that should be ignored from the symbol file 42 Exclude_symbol_tags []string 43 44 // Run checks on all APIs (in addition to the ones referred by 45 // one of exported ELF symbols.) 46 Check_all_apis *bool 47 48 // Extra flags passed to header-abi-diff 49 Diff_flags []string 50 51 // Opt-in reference dump directories 52 Ref_dump_dirs []string 53} 54 55func (props *headerAbiCheckerProperties) enabled() bool { 56 return Bool(props.Enabled) 57} 58 59func (props *headerAbiCheckerProperties) explicitlyDisabled() bool { 60 return !BoolDefault(props.Enabled, true) 61} 62 63type SAbiProperties struct { 64 // Whether ABI dump should be created for this module. 65 // Set by `sabiDepsMutator` if this module is a shared library that needs ABI check, or a static 66 // library that is depended on by an ABI checked library. 67 ShouldCreateSourceAbiDump bool `blueprint:"mutated"` 68 69 // Include directories that may contain ABI information exported by a library. 70 // These directories are passed to the header-abi-dumper. 71 ReexportedIncludes []string `blueprint:"mutated"` 72} 73 74type sabi struct { 75 Properties SAbiProperties 76} 77 78func (sabi *sabi) props() []interface{} { 79 return []interface{}{&sabi.Properties} 80} 81 82func (sabi *sabi) flags(ctx ModuleContext, flags Flags) Flags { 83 // Filter out flags which libTooling don't understand. 84 // This is here for legacy reasons and future-proof, in case the version of libTooling and clang 85 // diverge. 86 flags.Local.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CFlags) 87 flags.Global.ToolingCFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CFlags) 88 flags.Local.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Local.CppFlags) 89 flags.Global.ToolingCppFlags = config.ClangLibToolingFilterUnknownCflags(flags.Global.CppFlags) 90 return flags 91} 92 93// Returns true if ABI dump should be created for this library, either because library is ABI 94// checked or is depended on by an ABI checked library. 95// Could be called as a nil receiver. 96func (sabi *sabi) shouldCreateSourceAbiDump() bool { 97 return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump 98} 99 100// Returns a string that represents the class of the ABI dump. 101// Returns an empty string if ABI check is disabled for this library. 102func classifySourceAbiDump(ctx android.BaseModuleContext) string { 103 m := ctx.Module().(*Module) 104 headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx) 105 if headerAbiChecker.explicitlyDisabled() { 106 return "" 107 } 108 // Return NDK if the library is both NDK and LLNDK. 109 if m.IsNdk(ctx.Config()) { 110 return "NDK" 111 } 112 if m.isImplementationForLLNDKPublic() { 113 return "LLNDK" 114 } 115 if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() { 116 if m.IsVndkSp() { 117 if m.IsVndkExt() { 118 return "VNDK-SP-ext" 119 } else { 120 return "VNDK-SP" 121 } 122 } else { 123 if m.IsVndkExt() { 124 return "VNDK-ext" 125 } else { 126 return "VNDK-core" 127 } 128 } 129 } 130 if m.library.hasStubsVariants() && !m.InProduct() && !m.InVendor() { 131 return "PLATFORM" 132 } 133 if headerAbiChecker.enabled() { 134 if m.InProduct() { 135 return "PRODUCT" 136 } 137 if m.InVendor() { 138 return "VENDOR" 139 } 140 return "PLATFORM" 141 } 142 return "" 143} 144 145// Called from sabiDepsMutator to check whether ABI dumps should be created for this module. 146// ctx should be wrapping a native library type module. 147func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { 148 // Only generate ABI dump for device modules. 149 if !ctx.Device() { 150 return false 151 } 152 153 m := ctx.Module().(*Module) 154 155 // Only create ABI dump for native library module types. 156 if m.library == nil { 157 return false 158 } 159 160 // Create ABI dump for static libraries only if they are dependencies of ABI checked libraries. 161 if m.library.static() { 162 return m.sabi.shouldCreateSourceAbiDump() 163 } 164 165 // Module is shared library type. 166 167 // Don't check uninstallable modules. 168 if m.IsHideFromMake() { 169 return false 170 } 171 172 // Don't check ramdisk or recovery variants. Only check core, vendor or product variants. 173 if m.InRamdisk() || m.InVendorRamdisk() || m.InRecovery() { 174 return false 175 } 176 177 // Don't create ABI dump for prebuilts. 178 if m.Prebuilt() != nil || m.IsSnapshotPrebuilt() { 179 return false 180 } 181 182 // Coverage builds have extra symbols. 183 if m.isCoverageVariant() { 184 return false 185 } 186 187 // Some sanitizer variants may have different ABI. 188 if m.sanitize != nil && !m.sanitize.isVariantOnProductionDevice() { 189 return false 190 } 191 192 // Don't create ABI dump for stubs. 193 if m.isNDKStubLibrary() || m.IsLlndk() || m.IsStubs() { 194 return false 195 } 196 197 isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() 198 if isPlatformVariant { 199 // Bionic libraries that are installed to the bootstrap directory are not ABI checked. 200 // Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs, 201 // are checked. 202 if InstallToBootstrap(m.BaseModuleName(), ctx.Config()) { 203 return false 204 } 205 } else { 206 // Don't create ABI dump if this library is for APEX but isn't exported. 207 if !m.HasStubsVariants() { 208 return false 209 } 210 } 211 return classifySourceAbiDump(ctx) != "" 212} 213 214// Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps 215// of their dependencies would be generated. 216func sabiDepsMutator(mctx android.TopDownMutatorContext) { 217 // Escape hatch to not check any ABI dump. 218 if mctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") { 219 return 220 } 221 // Only create ABI dump for native shared libraries and their static library dependencies. 222 if m, ok := mctx.Module().(*Module); ok && m.sabi != nil { 223 if shouldCreateSourceAbiDumpForLibrary(mctx) { 224 // Mark this module so that .sdump / .lsdump for this library can be generated. 225 m.sabi.Properties.ShouldCreateSourceAbiDump = true 226 // Mark all of its static library dependencies. 227 mctx.VisitDirectDeps(func(child android.Module) { 228 depTag := mctx.OtherModuleDependencyTag(child) 229 if IsStaticDepTag(depTag) || depTag == reuseObjTag { 230 if c, ok := child.(*Module); ok && c.sabi != nil { 231 // Mark this module so that .sdump for this static library can be generated. 232 c.sabi.Properties.ShouldCreateSourceAbiDump = true 233 } 234 } 235 }) 236 } 237 } 238} 239 240// Add an entry to the global list of lsdump. The list is exported to a Make variable by 241// `cc.makeVarsProvider`. 242func addLsdumpPath(lsdumpPath string) { 243 lsdumpPathsLock.Lock() 244 defer lsdumpPathsLock.Unlock() 245 lsdumpPaths = append(lsdumpPaths, lsdumpPath) 246} 247