diff options
author | Jayant Chowdhary <jchowdhary@google.com> | 2017-02-08 13:45:53 -0800 |
---|---|---|
committer | Jayant Chowdhary <jchowdhary@google.com> | 2017-04-14 19:48:10 -0700 |
commit | 3e231fd8bd61f2eb77e76e06a1877e2904564358 (patch) | |
tree | 9eeb71dc0e91b1fa2d198ed8504a843f6245b5db | |
parent | c43ae770c56808c802916e6346576f3f0c047194 (diff) | |
download | build_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.tar.gz build_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.tar.bz2 build_soong-3e231fd8bd61f2eb77e76e06a1877e2904564358.zip |
Add header-abi-checker for Vndk abi checks.
header-abi-dumper: dumps abi exported by source files for Vndk.
header-abi-linker: links abi dumps produced by header-abi-dumper.
header-abi-diff: compares linked dumps.
Test: mm -j64 showcommands > make_log in bionic/libc.
This produced linked dumps in out/soong/.intermediates.
Copied these dumps to
prebuilts/abi-dumps/ndk/current/arm64/source-based/.
Changed the abi and re-ran mm -j64 showcommands > make_log
confirmed that the build reported compatibility breakge without
actually failing (advisory mode).
Change-Id: Iccad6908fe68a80f47230751671d156893b96ead
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | android/paths.go | 24 | ||||
-rw-r--r-- | cc/androidmk.go | 7 | ||||
-rw-r--r-- | cc/builder.go | 104 | ||||
-rw-r--r-- | cc/cc.go | 30 | ||||
-rw-r--r-- | cc/library.go | 57 | ||||
-rw-r--r-- | cc/sabi.go | 63 | ||||
-rw-r--r-- | cc/util.go | 2 |
8 files changed, 287 insertions, 1 deletions
@@ -127,6 +127,7 @@ bootstrap_go_package { "cc/proto.go", "cc/relocation_packer.go", "cc/sanitize.go", + "cc/sabi.go", "cc/stl.go", "cc/strip.go", "cc/tidy.go", diff --git a/android/paths.go b/android/paths.go index 969c7537..75e5980e 100644 --- a/android/paths.go +++ b/android/paths.go @@ -576,6 +576,30 @@ type ModuleOutPath struct { var _ Path = ModuleOutPath{} +// PathForVndkRefDump returns an OptionalPath representing the path of the reference +// abi dump for the given module. This is not guaranteed to be valid. +func PathForVndkRefAbiDump(ctx ModuleContext, version, fileName string, vndkOrNdk, isSourceDump bool) OptionalPath { + archName := ctx.Arch().ArchType.Name + var sourceOrBinaryDir string + var vndkOrNdkDir string + var ext string + if isSourceDump { + ext = ".lsdump" + sourceOrBinaryDir = "source-based" + } else { + ext = ".bdump" + sourceOrBinaryDir = "binary-based" + } + if vndkOrNdk { + vndkOrNdkDir = "vndk" + } else { + vndkOrNdkDir = "ndk" + } + refDumpFileStr := "prebuilts/abi-dumps/" + vndkOrNdkDir + "/" + version + "/" + + archName + "/" + sourceOrBinaryDir + "/" + fileName + ext + return OptionalPathForSource(ctx, "", refDumpFileStr) +} + // PathForModuleOut returns a Path representing the paths... under the module's // output directory. func PathForModuleOut(ctx ModuleContext, paths ...string) ModuleOutPath { diff --git a/cc/androidmk.go b/cc/androidmk.go index 59a1db89..481dbb4c 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -141,6 +141,13 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) error { library.androidMkWriteExportedFlags(w) + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := ") + if library.sAbiOutputFile.Valid() { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiOutputFile.String()) + if library.sAbiDiff.Valid() && !library.static() { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES += ", library.sAbiDiff.String()) + } + } fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext()) diff --git a/cc/builder.go b/cc/builder.go index 0694cb7d..96b41589 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -168,6 +168,41 @@ var ( Description: "yasm $out", }, "asFlags") + + _ = pctx.SourcePathVariable("sAbiDumper", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-dumper") + + sAbiDump = pctx.AndroidStaticRule("sAbiDump", + blueprint.RuleParams{ + Command: "rm -f $out && $sAbiDumper -o ${out} $in $exportDirs -- $cFlags -Wno-packed -isystem ${config.RSIncludePath}", + CommandDeps: []string{"$sAbiDumper"}, + Description: "header-abi-dumper $in -o $out $exportDirs", + }, + "cFlags", "exportDirs") + + _ = pctx.SourcePathVariable("sAbiLinker", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-linker") + + sAbiLink = pctx.AndroidStaticRule("sAbiLink", + blueprint.RuleParams{ + Command: "$sAbiLinker -o ${out} $symbolFile -arch $arch -api $api $exportedHeaderFlags @${out}.rsp ", + CommandDeps: []string{"$sAbiLinker"}, + Description: "header-abi-linker $in -o $out", + Rspfile: "${out}.rsp", + RspfileContent: "${in}", + }, + "symbolFile", "arch", "api", "exportedHeaderFlags") + + _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff") + // The output file is different from what the build system knows about. + // This is done since we have to create a report file even when builds + // fail in this case. Abidiff check turned on in advice-only mode. Builds + // will not fail on abi incompatibilties / extensions. + sAbiDiff = pctx.AndroidStaticRule("sAbiDiff", + blueprint.RuleParams{ + Command: "$sAbiDiffer -advice-only -o ${out}s -new $in -old $referenceDump", + CommandDeps: []string{"$sAbiDiffer"}, + Description: "header-abi-diff -o ${out} -new $in -old $referenceDump", + }, + "referenceDump") ) func init() { @@ -194,12 +229,14 @@ type builderFlags struct { yaccFlags string protoFlags string tidyFlags string + sAbiFlags string yasmFlags string aidlFlags string toolchain config.Toolchain clang bool tidy bool coverage bool + sAbiDump bool systemIncludeFlags string @@ -214,6 +251,7 @@ type Objects struct { objFiles android.Paths tidyFiles android.Paths coverageFiles android.Paths + sAbiDumpFiles android.Paths } func (a Objects) Copy() Objects { @@ -221,6 +259,7 @@ func (a Objects) Copy() Objects { objFiles: append(android.Paths{}, a.objFiles...), tidyFiles: append(android.Paths{}, a.tidyFiles...), coverageFiles: append(android.Paths{}, a.coverageFiles...), + sAbiDumpFiles: append(android.Paths{}, a.sAbiDumpFiles...), } } @@ -229,6 +268,7 @@ func (a Objects) Append(b Objects) Objects { objFiles: append(a.objFiles, b.objFiles...), tidyFiles: append(a.tidyFiles, b.tidyFiles...), coverageFiles: append(a.coverageFiles, b.coverageFiles...), + sAbiDumpFiles: append(a.sAbiDumpFiles, b.sAbiDumpFiles...), } } @@ -265,6 +305,10 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and flags.systemIncludeFlags, flags.asFlags, }, " ") + var sAbiDumpFiles android.Paths + if flags.sAbiDump && flags.clang { + sAbiDumpFiles = make(android.Paths, 0, len(srcFiles)) + } if flags.clang { cflags += " ${config.NoOverrideClangGlobalCflags}" @@ -296,6 +340,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and var ccCmd string tidy := flags.tidy && flags.clang coverage := flags.coverage + dump := flags.sAbiDump && flags.clang switch srcFile.Ext() { case ".S", ".s": @@ -303,6 +348,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and moduleCflags = asflags tidy = false coverage = false + dump = false case ".c": ccCmd = "gcc" moduleCflags = cflags @@ -366,12 +412,29 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and }) } + if dump { + sAbiDumpFile := android.ObjPathWithExt(ctx, subdir, srcFile, "sdump") + sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile) + + ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + Rule: sAbiDump, + Output: sAbiDumpFile, + Input: srcFile, + Implicit: objFile, + Args: map[string]string{ + "cFlags": moduleCflags, + "exportDirs": flags.sAbiFlags, + }, + }) + } + } return Objects{ objFiles: objFiles, tidyFiles: tidyFiles, coverageFiles: coverageFiles, + sAbiDumpFiles: sAbiDumpFiles, } } @@ -554,6 +617,47 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext, }) } +// Generate a rule to combine .dump sAbi dump files from multiple source files +// into a single .ldump sAbi dump file +func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, + symbolFile android.OptionalPath, apiLevel, baseName, exportedHeaderFlags string) android.OptionalPath { + outputFile := android.PathForModuleOut(ctx, baseName+".lsdump") + var symbolFileStr string + var linkedDumpDep android.Path + if symbolFile.Valid() { + symbolFileStr = "-v " + symbolFile.Path().String() + linkedDumpDep = symbolFile.Path() + } + ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + Rule: sAbiLink, + Output: outputFile, + Inputs: sAbiDumps, + Implicit: linkedDumpDep, + Args: map[string]string{ + "symbolFile": symbolFileStr, + "arch": ctx.Arch().ArchType.Name, + "api": apiLevel, + "exportedHeaderFlags": exportedHeaderFlags, + }, + }) + return android.OptionalPathForPath(outputFile) +} + +func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path, + baseName string) android.OptionalPath { + outputFile := android.PathForModuleOut(ctx, baseName+".abidiff") + ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + Rule: sAbiDiff, + Output: outputFile, + Input: inputDump, + Implicit: referenceDump, + Args: map[string]string{ + "referenceDump": referenceDump.String(), + }, + }) + return android.OptionalPathForPath(outputFile) +} + // Generate a rule for extract a table of contents from a shared library (.so) func TransformSharedObjectToToc(ctx android.ModuleContext, inputFile android.WritablePath, outputFile android.WritablePath, flags builderFlags) { @@ -49,6 +49,7 @@ func init() { ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel() ctx.BottomUp("coverage", coverageLinkingMutator).Parallel() + ctx.TopDown("vndk_deps", sabiDepsMutator) }) pctx.Import("android/soong/cc/config") @@ -108,6 +109,7 @@ type Flags struct { LdFlags []string // Flags that apply to linker command lines libFlags []string // Flags to add libraries early to the link order TidyFlags []string // Flags that apply to clang-tidy + SAbiFlags []string // Flags that apply to header-abi-dumper YasmFlags []string // Flags that apply to yasm assembly source files // Global include flags that apply to C, C++, and assembly source files @@ -118,6 +120,7 @@ type Flags struct { Clang bool Tidy bool Coverage bool + SAbiDump bool RequiredInstructionSet string DynamicLinker string @@ -177,6 +180,7 @@ type ModuleContextIntf interface { sdk() bool sdkVersion() string vndk() bool + createVndkSourceAbiDump() bool selectedStl() string baseModuleName() string } @@ -283,6 +287,7 @@ type Module struct { stl *stl sanitize *sanitize coverage *coverage + sabi *sabi androidMkSharedLibDeps []string @@ -316,6 +321,9 @@ func (c *Module) Init() (blueprint.Module, []interface{}) { if c.coverage != nil { props = append(props, c.coverage.props()...) } + if c.sabi != nil { + props = append(props, c.sabi.props()...) + } for _, feature := range c.features { props = append(props, feature.props()...) } @@ -418,6 +426,12 @@ func (ctx *moduleContextImpl) vndk() bool { return ctx.mod.vndk() } +// Create source abi dumps if the module belongs to the list of VndkLibraries. +func (ctx *moduleContextImpl) createVndkSourceAbiDump() bool { + return ctx.ctx.Device() && (inList(ctx.baseModuleName(), config.LLndkLibraries())) || + (inList(ctx.baseModuleName(), config.VndkLibraries())) +} + func (ctx *moduleContextImpl) selectedStl() string { if stl := ctx.mod.stl; stl != nil { return stl.Properties.SelectedStl @@ -444,6 +458,7 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo module.stl = &stl{} module.sanitize = &sanitize{} module.coverage = &coverage{} + module.sabi = &sabi{} return module } @@ -492,6 +507,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if c.coverage != nil { flags = c.coverage.flags(ctx, flags) } + if c.sabi != nil { + flags = c.sabi.flags(ctx, flags) + } for _, feature := range c.features { flags = feature.flags(ctx, flags) } @@ -566,6 +584,9 @@ func (c *Module) begin(ctx BaseModuleContext) { if c.coverage != nil { c.coverage.begin(ctx) } + if c.sabi != nil { + c.sabi.begin(ctx) + } for _, feature := range c.features { feature.begin(ctx) } @@ -596,6 +617,9 @@ func (c *Module) deps(ctx DepsContext) Deps { if c.coverage != nil { deps = c.coverage.deps(ctx, deps) } + if c.sabi != nil { + deps = c.sabi.deps(ctx, deps) + } for _, feature := range c.features { deps = feature.deps(ctx, deps) } @@ -999,9 +1023,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } // When combining coverage files for shared libraries and executables, coverage files - // in static libraries act as if they were whole static libraries. + // in static libraries act as if they were whole static libraries. The same goes for + // source based Abi dump files. depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, staticLib.objs().coverageFiles...) + depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles, + staticLib.objs().sAbiDumpFiles...) } if ptr != nil { @@ -1085,6 +1112,7 @@ func DefaultsFactory(props ...interface{}) (blueprint.Module, []interface{}) { &InstallerProperties{}, &TidyProperties{}, &CoverageProperties{}, + &SAbiProperties{}, ) return android.InitDefaultsModule(module, module, props...) diff --git a/cc/library.go b/cc/library.go index cb85bd3b..e2ec5849 100644 --- a/cc/library.go +++ b/cc/library.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint/pathtools" "android/soong/android" + "android/soong/cc/config" ) type LibraryProperties struct { @@ -220,9 +221,17 @@ type libraryDecorator struct { sanitize *sanitize + sabi *sabi + // Output archive of gcno coverage information files coverageOutputFile android.OptionalPath + // linked Source Abi Dump + sAbiOutputFile android.OptionalPath + + // Source Abi Diff + sAbiDiff android.OptionalPath + // Decorated interafaces *baseCompiler *baseLinker @@ -316,7 +325,20 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } return Objects{} } + if ctx.createVndkSourceAbiDump() || (library.sabi.Properties.CreateSAbiDumps && ctx.Device()) { + exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs) + var SourceAbiFlags []string + for _, dir := range exportIncludeDirs.Strings() { + SourceAbiFlags = append(SourceAbiFlags, "-I "+dir) + } + flags.SAbiFlags = SourceAbiFlags + total_length := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) + len(library.Properties.Shared.Srcs) + + len(library.Properties.Static.Srcs) + if total_length > 0 { + flags.SAbiDump = true + } + } objs := library.baseCompiler.compile(ctx, flags, deps) library.reuseObjects = objs buildFlags := flagsToBuilderFlags(flags) @@ -534,11 +556,45 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...) objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...) + + objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...) + objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...) + library.coverageOutputFile = TransformCoverageFilesToLib(ctx, objs, builderFlags, library.getLibName(ctx)) + library.linkSAbiDumpFiles(ctx, objs, fileName) return ret } +func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string) { + //Also take into account object re-use. + if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() { + refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true) + versionScript := android.OptionalPathForModuleSrc(ctx, library.Properties.Version_script) + var symbolFile android.OptionalPath + if versionScript.Valid() { + symbolFile = versionScript + } + exportIncludeDirs := android.PathsForModuleSrc(ctx, library.flagExporter.Properties.Export_include_dirs) + var SourceAbiFlags []string + for _, dir := range exportIncludeDirs.Strings() { + SourceAbiFlags = append(SourceAbiFlags, "-I "+dir) + } + exportedHeaderFlags := strings.Join(SourceAbiFlags, " ") + library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, symbolFile, "current", fileName, exportedHeaderFlags) + if refSourceDumpFile.Valid() { + library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), refSourceDumpFile.Path(), fileName) + } + } +} + +func vndkVsNdk(ctx ModuleContext) bool { + if inList(ctx.baseModuleName(), config.LLndkLibraries()) { + return false + } + return true +} + func (library *libraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { @@ -656,6 +712,7 @@ func NewLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) baseLinker: NewBaseLinker(), baseInstaller: NewBaseInstaller("lib", "lib64", InstallInSystem), sanitize: module.sanitize, + sabi: module.sabi, } module.compiler = library diff --git a/cc/sabi.go b/cc/sabi.go new file mode 100644 index 00000000..7ae31c97 --- /dev/null +++ b/cc/sabi.go @@ -0,0 +1,63 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cc + +import ( + "android/soong/android" + "github.com/google/blueprint" + + "android/soong/cc/config" +) + +type SAbiProperties struct { + CreateSAbiDumps bool `blueprint:"mutated"` +} + +type sabi struct { + Properties SAbiProperties +} + +func (sabimod *sabi) props() []interface{} { + return []interface{}{&sabimod.Properties} +} + +func (sabimod *sabi) begin(ctx BaseModuleContext) {} + +func (sabimod *sabi) deps(ctx BaseModuleContext, deps Deps) Deps { + return deps +} + +func (sabimod *sabi) flags(ctx ModuleContext, flags Flags) Flags { + return flags +} + +func sabiDepsMutator(mctx android.TopDownMutatorContext) { + if c, ok := mctx.Module().(*Module); ok && + ((inList(c.Name(), config.VndkLibraries())) || (inList(c.Name(), config.LLndkLibraries())) || + (c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) { + mctx.VisitDirectDeps(func(m blueprint.Module) { + tag := mctx.OtherModuleDependencyTag(m) + switch tag { + case staticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag: + + cc, _ := m.(*Module) + if cc == nil { + return + } + cc.sabi.Properties.CreateSAbiDumps = true + } + }) + } +} @@ -99,11 +99,13 @@ func flagsToBuilderFlags(in Flags) builderFlags { ldFlags: strings.Join(in.LdFlags, " "), libFlags: strings.Join(in.libFlags, " "), tidyFlags: strings.Join(in.TidyFlags, " "), + sAbiFlags: strings.Join(in.SAbiFlags, " "), yasmFlags: strings.Join(in.YasmFlags, " "), toolchain: in.Toolchain, clang: in.Clang, coverage: in.Coverage, tidy: in.Tidy, + sAbiDump: in.SAbiDump, systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "), |