Merge changes from topic 'soong-clang-tidy'

* changes:
  Add clang-tidy support
  Start using "struct Objects" to store object Paths
This commit is contained in:
Treehugger Robot
2016-11-01 01:18:59 +00:00
committed by Gerrit Code Review
21 changed files with 447 additions and 77 deletions

View File

@@ -95,6 +95,7 @@ bootstrap_go_package {
srcs: [ srcs: [
"cc/config/clang.go", "cc/config/clang.go",
"cc/config/global.go", "cc/config/global.go",
"cc/config/tidy.go",
"cc/config/toolchain.go", "cc/config/toolchain.go",
"cc/config/arm_device.go", "cc/config/arm_device.go",
@@ -108,6 +109,9 @@ bootstrap_go_package {
"cc/config/x86_linux_host.go", "cc/config/x86_linux_host.go",
"cc/config/x86_windows_host.go", "cc/config/x86_windows_host.go",
], ],
testSrcs: [
"cc/config/tidy_test.go",
],
} }
bootstrap_go_package { bootstrap_go_package {
@@ -134,6 +138,7 @@ bootstrap_go_package {
"cc/sanitize.go", "cc/sanitize.go",
"cc/stl.go", "cc/stl.go",
"cc/strip.go", "cc/strip.go",
"cc/tidy.go",
"cc/util.go", "cc/util.go",
"cc/compiler.go", "cc/compiler.go",

View File

@@ -384,6 +384,17 @@ func (c *config) UseGoma() bool {
return Bool(c.ProductVariables.UseGoma) return Bool(c.ProductVariables.UseGoma)
} }
func (c *config) ClangTidy() bool {
return Bool(c.ProductVariables.ClangTidy)
}
func (c *config) TidyChecks() string {
if c.ProductVariables.TidyChecks == nil {
return ""
}
return *c.ProductVariables.TidyChecks
}
func (c *config) LibartImgHostBaseAddress() string { func (c *config) LibartImgHostBaseAddress() string {
return "0x60000000" return "0x60000000"
} }

View File

@@ -112,6 +112,9 @@ type productVariables struct {
UseGoma *bool `json:",omitempty"` UseGoma *bool `json:",omitempty"`
Debuggable *bool `json:",omitempty"` Debuggable *bool `json:",omitempty"`
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
DevicePrefer32BitExecutables *bool `json:",omitempty"` DevicePrefer32BitExecutables *bool `json:",omitempty"`
HostPrefer32BitExecutables *bool `json:",omitempty"` HostPrefer32BitExecutables *bool `json:",omitempty"`

View File

@@ -53,6 +53,9 @@ var standardProperties = map[string]struct {
"LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": {"export_shared_lib_headers", bpparser.ListType}, "LOCAL_EXPORT_SHARED_LIBRARY_HEADERS": {"export_shared_lib_headers", bpparser.ListType},
"LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": {"export_static_lib_headers", bpparser.ListType}, "LOCAL_EXPORT_STATIC_LIBRARY_HEADERS": {"export_static_lib_headers", bpparser.ListType},
"LOCAL_INIT_RC": {"init_rc", bpparser.ListType}, "LOCAL_INIT_RC": {"init_rc", bpparser.ListType},
"LOCAL_TIDY_FLAGS": {"tidy_flags", bpparser.ListType},
// TODO: This is comma-seperated, not space-separated
"LOCAL_TIDY_CHECKS": {"tidy_checks", bpparser.ListType},
"LOCAL_JAVA_RESOURCE_DIRS": {"java_resource_dirs", bpparser.ListType}, "LOCAL_JAVA_RESOURCE_DIRS": {"java_resource_dirs", bpparser.ListType},
"LOCAL_JAVACFLAGS": {"javacflags", bpparser.ListType}, "LOCAL_JAVACFLAGS": {"javacflags", bpparser.ListType},
@@ -73,6 +76,7 @@ var standardProperties = map[string]struct {
"LOCAL_RTTI_FLAG": {"rtti", bpparser.BoolType}, "LOCAL_RTTI_FLAG": {"rtti", bpparser.BoolType},
"LOCAL_NO_STANDARD_LIBRARIES": {"no_standard_libraries", bpparser.BoolType}, "LOCAL_NO_STANDARD_LIBRARIES": {"no_standard_libraries", bpparser.BoolType},
"LOCAL_PACK_MODULE_RELOCATIONS": {"pack_relocations", bpparser.BoolType}, "LOCAL_PACK_MODULE_RELOCATIONS": {"pack_relocations", bpparser.BoolType},
"LOCAL_TIDY": {"tidy", bpparser.BoolType},
"LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.BoolType}, "LOCAL_EXPORT_PACKAGE_RESOURCES": {"export_package_resources", bpparser.BoolType},
} }

View File

@@ -250,7 +250,7 @@ func (binary *binaryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags
} }
func (binary *binaryDecorator) link(ctx ModuleContext, func (binary *binaryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix() fileName := binary.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
outputFile := android.PathForModuleOut(ctx, fileName) outputFile := android.PathForModuleOut(ctx, fileName)
@@ -282,8 +282,9 @@ func (binary *binaryDecorator) link(ctx ModuleContext,
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
linkerDeps = append(linkerDeps, objs.tidyFiles...)
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs, TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
builderFlags, outputFile) builderFlags, outputFile)

View File

@@ -150,6 +150,14 @@ var (
Restat: true, Restat: true,
}, },
"crossCompile") "crossCompile")
clangTidy = pctx.AndroidStaticRule("clangTidy",
blueprint.RuleParams{
Command: "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
Description: "tidy $out",
},
"cFlags", "tidyFlags")
) )
func init() { func init() {
@@ -174,19 +182,44 @@ type builderFlags struct {
libFlags string libFlags string
yaccFlags string yaccFlags string
protoFlags string protoFlags string
tidyFlags string
toolchain config.Toolchain toolchain config.Toolchain
clang bool clang bool
tidy bool
stripKeepSymbols bool stripKeepSymbols bool
stripKeepMiniDebugInfo bool stripKeepMiniDebugInfo bool
stripAddGnuDebuglink bool stripAddGnuDebuglink bool
} }
type Objects struct {
objFiles android.Paths
tidyFiles android.Paths
}
func (a Objects) Copy() Objects {
return Objects{
objFiles: append(android.Paths{}, a.objFiles...),
tidyFiles: append(android.Paths{}, a.tidyFiles...),
}
}
func (a Objects) Append(b Objects) Objects {
return Objects{
objFiles: append(a.objFiles, b.objFiles...),
tidyFiles: append(a.tidyFiles, b.tidyFiles...),
}
}
// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths, func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths,
flags builderFlags, deps android.Paths) (objFiles android.Paths) { flags builderFlags, deps android.Paths) Objects {
objFiles = make(android.Paths, len(srcFiles)) objFiles := make(android.Paths, len(srcFiles))
var tidyFiles android.Paths
if flags.tidy && flags.clang {
tidyFiles = make(android.Paths, 0, len(srcFiles))
}
cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags cflags := flags.globalFlags + " " + flags.cFlags + " " + flags.conlyFlags
cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags cppflags := flags.globalFlags + " " + flags.cFlags + " " + flags.cppFlags
@@ -207,11 +240,13 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
var moduleCflags string var moduleCflags string
var ccCmd string var ccCmd string
tidy := flags.tidy && flags.clang
switch srcFile.Ext() { switch srcFile.Ext() {
case ".S", ".s": case ".S", ".s":
ccCmd = "gcc" ccCmd = "gcc"
moduleCflags = asflags moduleCflags = asflags
tidy = false
case ".c": case ".c":
ccCmd = "gcc" ccCmd = "gcc"
moduleCflags = cflags moduleCflags = cflags
@@ -248,22 +283,45 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and
"ccCmd": ccCmd, "ccCmd": ccCmd,
}, },
}) })
if tidy {
tidyFile := android.ObjPathWithExt(ctx, srcFile, subdir, "tidy")
tidyFiles = append(tidyFiles, tidyFile)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: clangTidy,
Output: tidyFile,
Input: srcFile,
// We must depend on objFile, since clang-tidy doesn't
// support exporting dependencies.
Implicit: objFile,
Args: map[string]string{
"cFlags": moduleCflags,
"tidyFlags": flags.tidyFlags,
},
})
}
} }
return objFiles return Objects{
objFiles: objFiles,
tidyFiles: tidyFiles,
}
} }
// Generate a rule for compiling multiple .o files to a static library (.a) // Generate a rule for compiling multiple .o files to a static library (.a)
func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
flags builderFlags, outputFile android.ModuleOutPath) { flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
arCmd := gccCmd(flags.toolchain, "ar") arCmd := gccCmd(flags.toolchain, "ar")
arFlags := "crsPD" arFlags := "crsPD"
ctx.ModuleBuild(pctx, android.ModuleBuildParams{ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: ar, Rule: ar,
Output: outputFile, Output: outputFile,
Inputs: objFiles, Inputs: objFiles,
Implicits: deps,
Args: map[string]string{ Args: map[string]string{
"arFlags": arFlags, "arFlags": arFlags,
"arCmd": arCmd, "arCmd": arCmd,
@@ -276,7 +334,7 @@ func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
// very small command line length limit, so we have to split the ar into multiple // very small command line length limit, so we have to split the ar into multiple
// steps, each appending to the previous one. // steps, each appending to the previous one.
func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths, func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
flags builderFlags, outputPath android.ModuleOutPath) { flags builderFlags, outputPath android.ModuleOutPath, deps android.Paths) {
arFlags := "cqs" arFlags := "cqs"
@@ -285,8 +343,9 @@ func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.P
dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension) dummyAr := android.PathForModuleOut(ctx, "dummy"+staticLibraryExtension)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: emptyFile, Rule: emptyFile,
Output: dummy, Output: dummy,
Implicits: deps,
}) })
ctx.ModuleBuild(pctx, android.ModuleBuildParams{ ctx.ModuleBuild(pctx, android.ModuleBuildParams{
@@ -329,9 +388,10 @@ func TransformDarwinObjToStaticLib(ctx android.ModuleContext, objFiles android.P
if in == "" { if in == "" {
ctx.Build(pctx, blueprint.BuildParams{ ctx.Build(pctx, blueprint.BuildParams{
Rule: darwinAr, Rule: darwinAr,
Outputs: []string{out}, Outputs: []string{out},
Inputs: l, Inputs: l,
Implicits: deps.Strings(),
Args: map[string]string{ Args: map[string]string{
"arFlags": arFlags, "arFlags": arFlags,
}, },

View File

@@ -76,8 +76,8 @@ type PathDeps struct {
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
// Paths to .o files // Paths to .o files
ObjFiles android.Paths Objs Objects
WholeStaticLibObjFiles android.Paths WholeStaticLibObjs Objects
// Paths to generated source files // Paths to generated source files
GeneratedSources android.Paths GeneratedSources android.Paths
@@ -100,9 +100,11 @@ type Flags struct {
protoFlags []string // Flags that apply to proto source files protoFlags []string // Flags that apply to proto source files
LdFlags []string // Flags that apply to linker command lines LdFlags []string // Flags that apply to linker command lines
libFlags []string // Flags to add libraries early to the link order libFlags []string // Flags to add libraries early to the link order
TidyFlags []string // Flags that apply to clang-tidy
Toolchain config.Toolchain Toolchain config.Toolchain
Clang bool Clang bool
Tidy bool
RequiredInstructionSet string RequiredInstructionSet string
DynamicLinker string DynamicLinker string
@@ -174,7 +176,7 @@ type compiler interface {
appendCflags([]string) appendCflags([]string)
appendAsflags([]string) appendAsflags([]string)
compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects
} }
type linker interface { type linker interface {
@@ -183,7 +185,7 @@ type linker interface {
linkerFlags(ctx ModuleContext, flags Flags) Flags linkerFlags(ctx ModuleContext, flags Flags) Flags
linkerProps() []interface{} linkerProps() []interface{}
link(ctx ModuleContext, flags Flags, deps PathDeps, objFiles android.Paths) android.Path link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
appendLdflags([]string) appendLdflags([]string)
} }
@@ -368,6 +370,9 @@ func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib)
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
module := newBaseModule(hod, multilib) module := newBaseModule(hod, multilib)
module.features = []feature{
&tidyFeature{},
}
module.stl = &stl{} module.stl = &stl{}
module.sanitize = &sanitize{} module.sanitize = &sanitize{}
return module return module
@@ -440,16 +445,16 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...) flags.GlobalFlags = append(flags.GlobalFlags, deps.Flags...)
var objFiles android.Paths var objs Objects
if c.compiler != nil { if c.compiler != nil {
objFiles = c.compiler.compile(ctx, flags, deps) objs = c.compiler.compile(ctx, flags, deps)
if ctx.Failed() { if ctx.Failed() {
return return
} }
} }
if c.linker != nil { if c.linker != nil {
outputFile := c.linker.link(ctx, flags, deps, objFiles) outputFile := c.linker.link(ctx, flags, deps, objs)
if ctx.Failed() { if ctx.Failed() {
return return
} }
@@ -813,8 +818,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
} }
if tag == reuseObjTag { if tag == reuseObjTag {
depPaths.ObjFiles = append(depPaths.ObjFiles, depPaths.Objs = depPaths.Objs.Append(cc.compiler.(libraryInterface).reuseObjs())
cc.compiler.(libraryInterface).reuseObjs()...)
return return
} }
@@ -868,10 +872,9 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
} }
ctx.AddMissingDependencies(missingDeps) ctx.AddMissingDependencies(missingDeps)
} }
depPaths.WholeStaticLibObjFiles = depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
append(depPaths.WholeStaticLibObjFiles, staticLib.objs()...)
case objDepTag: case objDepTag:
ptr = &depPaths.ObjFiles depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
case crtBeginDepTag: case crtBeginDepTag:
depPaths.CrtBegin = linkFile depPaths.CrtBegin = linkFile
case crtEndDepTag: case crtEndDepTag:
@@ -950,6 +953,7 @@ func DefaultsFactory(props ...interface{}) (blueprint.Module, []interface{}) {
&SanitizeProperties{}, &SanitizeProperties{},
&StripProperties{}, &StripProperties{},
&InstallerProperties{}, &InstallerProperties{},
&TidyProperties{},
) )
return android.InitDefaultsModule(module, module, props...) return android.InitDefaultsModule(module, module, props...)

View File

@@ -105,3 +105,31 @@ func CheckBadHostLdlibs(ctx ModuleContext, prop string, flags []string) {
} }
} }
} }
// Check for bad clang tidy flags
func CheckBadTidyFlags(ctx ModuleContext, prop string, flags []string) {
for _, flag := range flags {
flag = strings.TrimSpace(flag)
if !strings.HasPrefix(flag, "-") {
ctx.PropertyErrorf(prop, "Flag `%s` must start with `-`", flag)
} else if strings.HasPrefix(flag, "-fix") {
ctx.PropertyErrorf(prop, "Flag `%s` is not allowed, since it could cause multiple writes to the same source file", flag)
} else if strings.HasPrefix(flag, "-checks=") {
ctx.PropertyErrorf(prop, "Flag `%s` is not allowed, use `tidy_checks` property instead", flag)
} else if strings.Contains(flag, " ") {
ctx.PropertyErrorf(prop, "Bad flag: `%s` is not an allowed multi-word flag. Should it be split into multiple flags?", flag)
}
}
}
// Check for bad clang tidy checks
func CheckBadTidyChecks(ctx ModuleContext, prop string, checks []string) {
for _, check := range checks {
if strings.Contains(check, " ") {
ctx.PropertyErrorf("tidy_checks", "Check `%s` invalid, cannot contain spaces", check)
} else if strings.Contains(check, ",") {
ctx.PropertyErrorf("tidy_checks", "Check `%s` invalid, cannot contain commas. Split each entry into it's own string instead", check)
}
}
}

View File

@@ -350,7 +350,7 @@ func ndkPathDeps(ctx ModuleContext) android.Paths {
return nil return nil
} }
func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
pathDeps := deps.GeneratedHeaders pathDeps := deps.GeneratedHeaders
pathDeps = append(pathDeps, ndkPathDeps(ctx)...) pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
@@ -367,18 +367,18 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD
compiler.deps = pathDeps compiler.deps = pathDeps
// Compile files listed in c.Properties.Srcs into objects // Compile files listed in c.Properties.Srcs into objects
objFiles := compileObjs(ctx, buildFlags, "", srcs, compiler.deps) objs := compileObjs(ctx, buildFlags, "", srcs, compiler.deps)
if ctx.Failed() { if ctx.Failed() {
return nil return Objects{}
} }
return objFiles return objs
} }
// Compile a list of source files into objects a specified subdirectory // Compile a list of source files into objects a specified subdirectory
func compileObjs(ctx android.ModuleContext, flags builderFlags, func compileObjs(ctx android.ModuleContext, flags builderFlags,
subdir string, srcFiles, deps android.Paths) android.Paths { subdir string, srcFiles, deps android.Paths) Objects {
return TransformSourceToObj(ctx, subdir, srcFiles, flags, deps) return TransformSourceToObj(ctx, subdir, srcFiles, flags, deps)
} }

106
cc/config/tidy.go Normal file
View File

@@ -0,0 +1,106 @@
// Copyright 2016 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 config
import (
"strings"
)
func init() {
// Most Android source files are not clang-tidy clean yet.
// Global tidy checks include only google*, performance*,
// and misc-macro-parentheses, but not google-readability*
// or google-runtime-references.
pctx.StaticVariable("TidyDefaultGlobalChecks", strings.Join([]string{
"-*",
"google*",
"misc-macro-parentheses",
"performance*",
"-google-readability*",
"-google-runtime-references",
}, ","))
// There are too many clang-tidy warnings in external and vendor projects.
// Enable only some google checks for these projects.
pctx.StaticVariable("TidyExternalVendorChecks", strings.Join([]string{
"-*",
"google*",
"-google-build-using-namespace",
"-google-default-arguments",
"-google-explicit-constructor",
"-google-readability*",
"-google-runtime-int",
"-google-runtime-references",
}, ","))
// Give warnings to header files only in selected directories.
// Do not give warnings to external or vendor header files, which contain too
// many warnings.
pctx.StaticVariable("TidyDefaultHeaderDirs", strings.Join([]string{
"art/",
"bionic/",
"bootable/",
"build/",
"cts/",
"dalvik/",
"developers/",
"development/",
"frameworks/",
"libcore/",
"libnativehelper/",
"system/",
}, "|"))
}
type PathBasedTidyCheck struct {
PathPrefix string
Checks string
}
const tidyDefault = "${config.TidyDefaultGlobalChecks}"
const tidyExternalVendor = "${config.TidyExternalVendorChecks}"
// This is a map of local path prefixes to the set of default clang-tidy checks
// to be used.
// The last matched local_path_prefix should be the most specific to be used.
var DefaultLocalTidyChecks = []PathBasedTidyCheck{
{"external/", tidyExternalVendor},
{"external/google", tidyDefault},
{"external/webrtc", tidyDefault},
{"frameworks/compile/mclinker/", tidyExternalVendor},
{"hardware/qcom", tidyExternalVendor},
{"vendor/", tidyExternalVendor},
{"vendor/google", tidyDefault},
{"vendor/google_devices", tidyExternalVendor},
}
var reversedDefaultLocalTidyChecks = reverseTidyChecks(DefaultLocalTidyChecks)
func reverseTidyChecks(in []PathBasedTidyCheck) []PathBasedTidyCheck {
ret := make([]PathBasedTidyCheck, len(in))
for i, check := range in {
ret[len(in)-i-1] = check
}
return ret
}
func TidyChecksForDir(dir string) string {
for _, pathCheck := range reversedDefaultLocalTidyChecks {
if strings.HasPrefix(dir, pathCheck.PathPrefix) {
return pathCheck.Checks
}
}
return tidyDefault
}

41
cc/config/tidy_test.go Normal file
View File

@@ -0,0 +1,41 @@
// Copyright 2016 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 config
import (
"testing"
)
func TestTidyChecksForDir(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{"foo/bar", tidyDefault},
{"vendor/foo/bar", tidyExternalVendor},
{"vendor/google", tidyDefault},
{"vendor/google/foo", tidyDefault},
{"vendor/google_devices/foo", tidyExternalVendor},
}
for _, testCase := range testCases {
t.Run(testCase.input, func(t *testing.T) {
output := TidyChecksForDir(testCase.input)
if output != testCase.expected {
t.Error("Output doesn't match expected", output, testCase.expected)
}
})
}
}

View File

@@ -160,7 +160,7 @@ type libraryDecorator struct {
Properties LibraryProperties Properties LibraryProperties
// For reusing static library objects for shared library // For reusing static library objects for shared library
reuseObjFiles android.Paths reuseObjects Objects
// table-of-contents file to optimize out relinking when possible // table-of-contents file to optimize out relinking when possible
tocFile android.OptionalPath tocFile android.OptionalPath
@@ -173,7 +173,7 @@ type libraryDecorator struct {
wholeStaticMissingDeps []string wholeStaticMissingDeps []string
// For whole_static_libs // For whole_static_libs
objFiles android.Paths objects Objects
// Uses the module's name if empty, but can be overridden. Does not include // Uses the module's name if empty, but can be overridden. Does not include
// shlib suffix. // shlib suffix.
@@ -251,31 +251,29 @@ func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Fla
return flags return flags
} }
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
var objFiles android.Paths objs := library.baseCompiler.compile(ctx, flags, deps)
library.reuseObjects = objs
objFiles = library.baseCompiler.compile(ctx, flags, deps)
library.reuseObjFiles = objFiles
buildFlags := flagsToBuilderFlags(flags) buildFlags := flagsToBuilderFlags(flags)
if library.static() { if library.static() {
srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs) srcs := android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
objFiles = append(objFiles, compileObjs(ctx, buildFlags, android.DeviceStaticLibrary, objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary,
srcs, library.baseCompiler.deps)...) srcs, library.baseCompiler.deps))
} else { } else {
srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs) srcs := android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
objFiles = append(objFiles, compileObjs(ctx, buildFlags, android.DeviceSharedLibrary, objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary,
srcs, library.baseCompiler.deps)...) srcs, library.baseCompiler.deps))
} }
return objFiles return objs
} }
type libraryInterface interface { type libraryInterface interface {
getWholeStaticMissingDeps() []string getWholeStaticMissingDeps() []string
static() bool static() bool
objs() android.Paths objs() Objects
reuseObjs() android.Paths reuseObjs() Objects
toc() android.OptionalPath toc() android.OptionalPath
// Returns true if the build options for the module have selected a static or shared build // Returns true if the build options for the module have selected a static or shared build
@@ -340,18 +338,18 @@ func (library *libraryDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) De
} }
func (library *libraryDecorator) linkStatic(ctx ModuleContext, func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
library.objFiles = append(android.Paths{}, deps.WholeStaticLibObjFiles...) library.objects = deps.WholeStaticLibObjs.Copy()
library.objFiles = append(library.objFiles, objFiles...) library.objects = library.objects.Append(objs)
outputFile := android.PathForModuleOut(ctx, outputFile := android.PathForModuleOut(ctx,
ctx.ModuleName()+library.Properties.VariantName+staticLibraryExtension) ctx.ModuleName()+library.Properties.VariantName+staticLibraryExtension)
if ctx.Darwin() { if ctx.Darwin() {
TransformDarwinObjToStaticLib(ctx, library.objFiles, flagsToBuilderFlags(flags), outputFile) TransformDarwinObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
} else { } else {
TransformObjToStaticLib(ctx, library.objFiles, flagsToBuilderFlags(flags), outputFile) TransformObjToStaticLib(ctx, library.objects.objFiles, flagsToBuilderFlags(flags), outputFile, objs.tidyFiles)
} }
library.wholeStaticMissingDeps = ctx.GetMissingDependencies() library.wholeStaticMissingDeps = ctx.GetMissingDependencies()
@@ -362,7 +360,7 @@ func (library *libraryDecorator) linkStatic(ctx ModuleContext,
} }
func (library *libraryDecorator) linkShared(ctx ModuleContext, func (library *libraryDecorator) linkShared(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
var linkerDeps android.Paths var linkerDeps android.Paths
@@ -454,8 +452,9 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
linkerDeps = append(linkerDeps, objs.tidyFiles...)
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, TransformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile) linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile)
@@ -463,15 +462,15 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
} }
func (library *libraryDecorator) link(ctx ModuleContext, func (library *libraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
objFiles = append(objFiles, deps.ObjFiles...) objs = objs.Append(deps.Objs)
var out android.Path var out android.Path
if library.static() { if library.static() {
out = library.linkStatic(ctx, flags, deps, objFiles) out = library.linkStatic(ctx, flags, deps, objs)
} else { } else {
out = library.linkShared(ctx, flags, deps, objFiles) out = library.linkShared(ctx, flags, deps, objs)
} }
library.exportIncludes(ctx, "-I") library.exportIncludes(ctx, "-I")
@@ -505,12 +504,12 @@ func (library *libraryDecorator) getWholeStaticMissingDeps() []string {
return library.wholeStaticMissingDeps return library.wholeStaticMissingDeps
} }
func (library *libraryDecorator) objs() android.Paths { func (library *libraryDecorator) objs() Objects {
return library.objFiles return library.objects
} }
func (library *libraryDecorator) reuseObjs() android.Paths { func (library *libraryDecorator) reuseObjs() Objects {
return library.reuseObjFiles return library.reuseObjects
} }
func (library *libraryDecorator) toc() android.OptionalPath { func (library *libraryDecorator) toc() android.OptionalPath {

View File

@@ -197,6 +197,6 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
} }
func (linker *baseLinker) link(ctx ModuleContext, func (linker *baseLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
panic(fmt.Errorf("baseLinker doesn't know how to link")) panic(fmt.Errorf("baseLinker doesn't know how to link"))
} }

View File

@@ -36,6 +36,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) {
ctx.Strict("CLANG_CXX", "${config.ClangBin}/clang++") ctx.Strict("CLANG_CXX", "${config.ClangBin}/clang++")
ctx.Strict("LLVM_AS", "${config.ClangBin}/llvm-as") ctx.Strict("LLVM_AS", "${config.ClangBin}/llvm-as")
ctx.Strict("LLVM_LINK", "${config.ClangBin}/llvm-link") ctx.Strict("LLVM_LINK", "${config.ClangBin}/llvm-link")
ctx.Strict("PATH_TO_CLANG_TIDY", "${config.ClangBin}/clang-tidy")
ctx.StrictSorted("CLANG_CONFIG_UNKNOWN_CFLAGS", strings.Join(config.ClangUnknownCflags, " ")) ctx.StrictSorted("CLANG_CONFIG_UNKNOWN_CFLAGS", strings.Join(config.ClangUnknownCflags, " "))
ctx.Strict("GLOBAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}") ctx.Strict("GLOBAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideGlobalCflags}")
@@ -52,6 +53,10 @@ func makeVarsProvider(ctx android.MakeVarsContext) {
ctx.Strict("DEFAULT_CPP_STD_VERSION", config.CppStdVersion) ctx.Strict("DEFAULT_CPP_STD_VERSION", config.CppStdVersion)
ctx.Strict("DEFAULT_GCC_CPP_STD_VERSION", config.GccCppStdVersion) ctx.Strict("DEFAULT_GCC_CPP_STD_VERSION", config.GccCppStdVersion)
ctx.Strict("DEFAULT_GLOBAL_TIDY_CHECKS", "${config.TidyDefaultGlobalChecks}")
ctx.Strict("DEFAULT_LOCAL_TIDY_CHECKS", joinLocalTidyChecks(config.DefaultLocalTidyChecks))
ctx.Strict("DEFAULT_TIDY_HEADER_DIRS", "${config.TidyDefaultHeaderDirs}")
includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes} ${config.CommonGlobalSystemIncludes}") includeFlags, err := ctx.Eval("${config.CommonGlobalIncludes} ${config.CommonGlobalSystemIncludes}")
if err != nil { if err != nil {
panic(err) panic(err)
@@ -257,3 +262,11 @@ func splitSystemIncludes(ctx android.MakeVarsContext, val string) (includes, sys
return includes, systemIncludes return includes, systemIncludes
} }
func joinLocalTidyChecks(checks []config.PathBasedTidyCheck) string {
rets := make([]string, len(checks))
for i, check := range config.DefaultLocalTidyChecks {
rets[i] = check.PathPrefix + ":" + check.Checks
}
return strings.Join(rets, " ")
}

View File

@@ -189,7 +189,7 @@ func (c *stubDecorator) compilerInit(ctx BaseModuleContext) {
ndkMigratedLibs = append(ndkMigratedLibs, name) ndkMigratedLibs = append(ndkMigratedLibs, name)
} }
func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Paths { func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
arch := ctx.Arch().ArchType.String() arch := ctx.Arch().ArchType.String()
if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) { if !strings.HasSuffix(ctx.ModuleName(), ndkLibrarySuffix) {
@@ -242,11 +242,11 @@ func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
} }
func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
objFiles android.Paths) android.Path { objs Objects) android.Path {
linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String() linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
flags.LdFlags = append(flags.LdFlags, linkerScriptFlag) flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
return stub.libraryDecorator.link(ctx, flags, deps, objFiles) return stub.libraryDecorator.link(ctx, flags, deps, objs)
} }
func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) { func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {

View File

@@ -79,7 +79,7 @@ func ndkPrebuiltObjectFactory() (blueprint.Module, []interface{}) {
} }
func (c *ndkPrebuiltObjectLinker) link(ctx ModuleContext, flags Flags, func (c *ndkPrebuiltObjectLinker) link(ctx ModuleContext, flags Flags,
deps PathDeps, objFiles android.Paths) android.Path { deps PathDeps, objs Objects) android.Path {
// A null build step, but it sets up the output path. // A null build step, but it sets up the output path.
if !strings.HasPrefix(ctx.ModuleName(), "ndk_crt") { if !strings.HasPrefix(ctx.ModuleName(), "ndk_crt") {
ctx.ModuleErrorf("NDK prebuilts must have an ndk_crt prefixed name") ctx.ModuleErrorf("NDK prebuilts must have an ndk_crt prefixed name")
@@ -115,7 +115,7 @@ func ndkPrebuiltLibraryFactory() (blueprint.Module, []interface{}) {
} }
func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags, func (ndk *ndkPrebuiltLibraryLinker) link(ctx ModuleContext, flags Flags,
deps PathDeps, objFiles android.Paths) android.Path { deps PathDeps, objs Objects) android.Path {
// A null build step, but it sets up the output path. // A null build step, but it sets up the output path.
ndk.exportIncludes(ctx, "-isystem") ndk.exportIncludes(ctx, "-isystem")
@@ -181,7 +181,7 @@ func getNdkStlLibDir(ctx android.ModuleContext, toolchain config.Toolchain, stl
} }
func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags, func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags,
deps PathDeps, objFiles android.Paths) android.Path { deps PathDeps, objs Objects) android.Path {
// A null build step, but it sets up the output path. // A null build step, but it sets up the output path.
if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") { if !strings.HasPrefix(ctx.ModuleName(), "ndk_lib") {
ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name") ctx.ModuleErrorf("NDK prebuilts must have an ndk_lib prefixed name")

View File

@@ -70,16 +70,16 @@ func (*objectLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
} }
func (object *objectLinker) link(ctx ModuleContext, func (object *objectLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
objFiles = append(objFiles, deps.ObjFiles...) objs = objs.Append(deps.Objs)
var outputFile android.Path var outputFile android.Path
if len(objFiles) == 1 { if len(objs.objFiles) == 1 {
outputFile = objFiles[0] outputFile = objs.objFiles[0]
} else { } else {
output := android.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension) output := android.PathForModuleOut(ctx, ctx.ModuleName()+objectExtension)
TransformObjsToObj(ctx, objFiles, flagsToBuilderFlags(flags), output) TransformObjsToObj(ctx, objs.objFiles, flagsToBuilderFlags(flags), output)
outputFile = output outputFile = output
} }

View File

@@ -46,7 +46,7 @@ func (p *prebuiltLibraryLinker) linkerProps() []interface{} {
} }
func (p *prebuiltLibraryLinker) link(ctx ModuleContext, func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
// TODO(ccross): verify shared library dependencies // TODO(ccross): verify shared library dependencies
if len(p.Prebuilt.Properties.Srcs) > 0 { if len(p.Prebuilt.Properties.Srcs) > 0 {
p.libraryDecorator.exportIncludes(ctx, "-I") p.libraryDecorator.exportIncludes(ctx, "-I")

93
cc/tidy.go Normal file
View File

@@ -0,0 +1,93 @@
// Copyright 2016 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 (
"strings"
"github.com/google/blueprint/proptools"
"android/soong/cc/config"
)
type TidyProperties struct {
// whether to run clang-tidy over C-like sources.
Tidy *bool
// Extra flags to pass to clang-tidy
Tidy_flags []string
// Extra checks to enable or disable in clang-tidy
Tidy_checks []string
}
type tidyFeature struct {
Properties TidyProperties
}
func (tidy *tidyFeature) props() []interface{} {
return []interface{}{&tidy.Properties}
}
func (tidy *tidyFeature) begin(ctx BaseModuleContext) {
}
func (tidy *tidyFeature) deps(ctx BaseModuleContext, deps Deps) Deps {
return deps
}
func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
// Check if tidy is explicitly disabled for this module
if tidy.Properties.Tidy != nil && !*tidy.Properties.Tidy {
return flags
}
// If not explicitly set, check the global tidy flag
if tidy.Properties.Tidy == nil && !ctx.AConfig().ClangTidy() {
return flags
}
// Clang-tidy requires clang
if !flags.Clang {
return flags
}
flags.Tidy = true
CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
esc := proptools.NinjaAndShellEscape
flags.TidyFlags = append(flags.TidyFlags, esc(tidy.Properties.Tidy_flags)...)
if len(flags.TidyFlags) == 0 {
headerFilter := "-header-filter=\"(" + ctx.ModuleDir() + "|${config.TidyDefaultHeaderDirs})\""
flags.TidyFlags = append(flags.TidyFlags, headerFilter)
}
tidyChecks := "-checks="
if checks := ctx.AConfig().TidyChecks(); len(checks) > 0 {
tidyChecks += checks
} else {
tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
}
if len(tidy.Properties.Tidy_checks) > 0 {
CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",")
}
flags.TidyFlags = append(flags.TidyFlags, tidyChecks)
return flags
}

View File

@@ -53,12 +53,12 @@ func toolchainLibraryFactory() (blueprint.Module, []interface{}) {
} }
func (library *toolchainLibraryDecorator) compile(ctx ModuleContext, flags Flags, func (library *toolchainLibraryDecorator) compile(ctx ModuleContext, flags Flags,
deps PathDeps) android.Paths { deps PathDeps) Objects {
return nil return Objects{}
} }
func (library *toolchainLibraryDecorator) link(ctx ModuleContext, func (library *toolchainLibraryDecorator) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path { flags Flags, deps PathDeps, objs Objects) android.Path {
libName := ctx.ModuleName() + staticLibraryExtension libName := ctx.ModuleName() + staticLibraryExtension
outputFile := android.PathForModuleOut(ctx, libName) outputFile := android.PathForModuleOut(ctx, libName)

View File

@@ -96,8 +96,10 @@ func flagsToBuilderFlags(in Flags) builderFlags {
protoFlags: strings.Join(in.protoFlags, " "), protoFlags: strings.Join(in.protoFlags, " "),
ldFlags: strings.Join(in.LdFlags, " "), ldFlags: strings.Join(in.LdFlags, " "),
libFlags: strings.Join(in.libFlags, " "), libFlags: strings.Join(in.libFlags, " "),
tidyFlags: strings.Join(in.TidyFlags, " "),
toolchain: in.Toolchain, toolchain: in.Toolchain,
clang: in.Clang, clang: in.Clang,
tidy: in.Tidy,
} }
} }