Add clippy-driver build rule
Depending on the location of the repository (e.g. external/, vendor/), a different set of lints will be enabled. Add the clippy property to the rust_* modules. This property can be used to overwrite the default behaviour. Test: m checkbuild Bug: 157238651 Change-Id: Ife0f723ef4a74abb102597f8486a7b9f30e7d351
This commit is contained in:
parent
a5d1fab176
commit
92f703b084
|
@ -9,24 +9,26 @@ bootstrap_go_package {
|
|||
],
|
||||
srcs: [
|
||||
"androidmk.go",
|
||||
"compiler.go",
|
||||
"coverage.go",
|
||||
"binary.go",
|
||||
"builder.go",
|
||||
"clippy.go",
|
||||
"compiler.go",
|
||||
"coverage.go",
|
||||
"library.go",
|
||||
"prebuilt.go",
|
||||
"proc_macro.go",
|
||||
"project_json.go",
|
||||
"project_json.go",
|
||||
"rust.go",
|
||||
"test.go",
|
||||
"testing.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"binary_test.go",
|
||||
"clippy_test.go",
|
||||
"compiler_test.go",
|
||||
"coverage_test.go",
|
||||
"library_test.go",
|
||||
"project_json_test.go",
|
||||
"project_json_test.go",
|
||||
"rust_test.go",
|
||||
"test_test.go",
|
||||
],
|
||||
|
|
|
@ -39,6 +39,18 @@ var (
|
|||
},
|
||||
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
|
||||
|
||||
_ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
|
||||
clippyDriver = pctx.AndroidStaticRule("clippy",
|
||||
blueprint.RuleParams{
|
||||
Command: "$clippyCmd " +
|
||||
// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
|
||||
// Use the metadata output as it has the smallest footprint.
|
||||
"--emit metadata -o $out $in ${libFlags} " +
|
||||
"$clippyFlags $rustcFlags",
|
||||
CommandDeps: []string{"$clippyCmd"},
|
||||
},
|
||||
"rustcFlags", "libFlags", "clippyFlags")
|
||||
|
||||
zip = pctx.AndroidStaticRule("zip",
|
||||
blueprint.RuleParams{
|
||||
Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
|
||||
|
@ -125,10 +137,14 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path
|
|||
rustcFlags = append(rustcFlags, "--target="+targetTriple)
|
||||
linkFlags = append(linkFlags, "-target "+targetTriple)
|
||||
}
|
||||
// TODO once we have static libraries in the host prebuilt .bp, this
|
||||
// should be unconditionally added.
|
||||
if !(ctx.Host() && ctx.TargetPrimary()) {
|
||||
// If we're not targeting the host primary arch, do not use an implicit sysroot
|
||||
// TODO(b/159718669): Once we have defined static libraries in the host
|
||||
// prebuilts Blueprint file, sysroot should be unconditionally sourced
|
||||
// from /dev/null. Explicitly set sysroot to avoid clippy-driver to
|
||||
// internally call rustc.
|
||||
if ctx.Host() && ctx.TargetPrimary() {
|
||||
rustcFlags = append(rustcFlags, "--sysroot=${config.RustPath}")
|
||||
} else {
|
||||
// If we're not targeting the host primary arch, do not use a sysroot.
|
||||
rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
|
||||
}
|
||||
// Collect linker flags
|
||||
|
@ -179,6 +195,25 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path
|
|||
output.coverageFile = gcnoFile
|
||||
}
|
||||
|
||||
if flags.Clippy {
|
||||
clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: clippyDriver,
|
||||
Description: "clippy " + main.Rel(),
|
||||
Output: clippyFile,
|
||||
ImplicitOutputs: nil,
|
||||
Inputs: inputs,
|
||||
Implicits: implicits,
|
||||
Args: map[string]string{
|
||||
"rustcFlags": strings.Join(rustcFlags, " "),
|
||||
"libFlags": strings.Join(libFlags, " "),
|
||||
"clippyFlags": strings.Join(flags.ClippyFlags, " "),
|
||||
},
|
||||
})
|
||||
// Declare the clippy build as an implicit dependency of the original crate.
|
||||
implicits = append(implicits, clippyFile)
|
||||
}
|
||||
|
||||
ctx.Build(pctx, android.BuildParams{
|
||||
Rule: rustc,
|
||||
Description: "rustc " + main.Rel(),
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2020 The Android Open Source Project
|
||||
//
|
||||
// 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 rust
|
||||
|
||||
import (
|
||||
"android/soong/rust/config"
|
||||
)
|
||||
|
||||
type ClippyProperties struct {
|
||||
// whether to run clippy.
|
||||
Clippy *bool
|
||||
}
|
||||
|
||||
type clippy struct {
|
||||
Properties ClippyProperties
|
||||
}
|
||||
|
||||
func (c *clippy) props() []interface{} {
|
||||
return []interface{}{&c.Properties}
|
||||
}
|
||||
|
||||
func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
|
||||
if c.Properties.Clippy != nil && !*c.Properties.Clippy {
|
||||
return flags, deps
|
||||
}
|
||||
enabled, lints := config.ClippyLintsForDir(ctx.ModuleDir())
|
||||
flags.Clippy = enabled
|
||||
flags.ClippyFlags = append(flags.ClippyFlags, lints)
|
||||
return flags, deps
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2020 The Android Open Source Project
|
||||
//
|
||||
// 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 rust
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClippy(t *testing.T) {
|
||||
ctx := testRust(t, `
|
||||
rust_library {
|
||||
name: "libfoo",
|
||||
srcs: ["foo.rs"],
|
||||
crate_name: "foo",
|
||||
}
|
||||
rust_library {
|
||||
name: "libfoobar",
|
||||
srcs: ["foo.rs"],
|
||||
crate_name: "foobar",
|
||||
clippy: false,
|
||||
}`)
|
||||
|
||||
ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Output("libfoo.so")
|
||||
fooClippy := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").MaybeRule("clippy")
|
||||
if fooClippy.Rule.String() != "android/soong/rust.clippy" {
|
||||
t.Errorf("Clippy output (default) for libfoo was not generated: %+v", fooClippy)
|
||||
}
|
||||
|
||||
ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_shared").Output("libfoobar.so")
|
||||
foobarClippy := ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_shared").MaybeRule("clippy")
|
||||
if foobarClippy.Rule != nil {
|
||||
t.Errorf("Clippy output for libfoobar is not empty")
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ bootstrap_go_package {
|
|||
"arm_device.go",
|
||||
"arm64_device.go",
|
||||
"global.go",
|
||||
"clippy.go",
|
||||
"toolchain.go",
|
||||
"allowed_list.go",
|
||||
"x86_darwin_host.go",
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2020 The Android Open Source Project
|
||||
//
|
||||
// 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"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLints = []string{
|
||||
"-D missing-docs",
|
||||
"-D clippy::missing-safety-doc",
|
||||
}
|
||||
defaultVendorLints = []string{
|
||||
"",
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Default Rust lints. These apply to all Google-authored modules.
|
||||
pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string {
|
||||
if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" {
|
||||
return override
|
||||
}
|
||||
return strings.Join(defaultLints, " ")
|
||||
})
|
||||
|
||||
// Rust lints that only applies to external code.
|
||||
pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string {
|
||||
if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" {
|
||||
return override
|
||||
}
|
||||
return strings.Join(defaultVendorLints, " ")
|
||||
})
|
||||
}
|
||||
|
||||
type PathBasedClippyConfig struct {
|
||||
PathPrefix string
|
||||
Enabled bool
|
||||
ClippyConfig string
|
||||
}
|
||||
|
||||
const clippyNone = ""
|
||||
const clippyDefault = "${config.ClippyDefaultLints}"
|
||||
const clippyVendor = "${config.ClippyVendorLints}"
|
||||
|
||||
// This is a map of local path prefixes to a boolean indicating if the lint
|
||||
// rule should be generated and if so, the set of lints to use. The first entry
|
||||
// matching will be used. If no entry is matching, clippyDefault will be used.
|
||||
var DefaultLocalTidyChecks = []PathBasedClippyConfig{
|
||||
{"external/", false, clippyNone},
|
||||
{"hardware/", true, clippyVendor},
|
||||
{"prebuilts/", false, clippyNone},
|
||||
{"vendor/google", true, clippyDefault},
|
||||
{"vendor/", true, clippyVendor},
|
||||
}
|
||||
|
||||
// ClippyLintsForDir returns the Clippy lints to be used for a repository.
|
||||
func ClippyLintsForDir(dir string) (bool, string) {
|
||||
for _, pathCheck := range DefaultLocalTidyChecks {
|
||||
if strings.HasPrefix(dir, pathCheck.PathPrefix) {
|
||||
return pathCheck.Enabled, pathCheck.ClippyConfig
|
||||
}
|
||||
}
|
||||
return true, clippyDefault
|
||||
}
|
11
rust/rust.go
11
rust/rust.go
|
@ -49,8 +49,10 @@ type Flags struct {
|
|||
GlobalLinkFlags []string // Flags that apply globally to linker
|
||||
RustFlags []string // Flags that apply to rust
|
||||
LinkFlags []string // Flags that apply to linker
|
||||
ClippyFlags []string // Flags that apply to clippy-driver, during the linting
|
||||
Toolchain config.Toolchain
|
||||
Coverage bool
|
||||
Clippy bool
|
||||
}
|
||||
|
||||
type BaseProperties struct {
|
||||
|
@ -75,6 +77,7 @@ type Module struct {
|
|||
|
||||
compiler compiler
|
||||
coverage *coverage
|
||||
clippy *clippy
|
||||
cachedToolchain config.Toolchain
|
||||
subAndroidMkOnce map[subAndroidMkProvider]bool
|
||||
outputFile android.OptionalPath
|
||||
|
@ -306,6 +309,7 @@ func DefaultsFactory(props ...interface{}) android.Module {
|
|||
&PrebuiltProperties{},
|
||||
&TestProperties{},
|
||||
&cc.CoverageProperties{},
|
||||
&ClippyProperties{},
|
||||
)
|
||||
|
||||
android.InitDefaultsModule(module)
|
||||
|
@ -456,6 +460,9 @@ func (mod *Module) Init() android.Module {
|
|||
if mod.coverage != nil {
|
||||
mod.AddProperties(mod.coverage.props()...)
|
||||
}
|
||||
if mod.clippy != nil {
|
||||
mod.AddProperties(mod.clippy.props()...)
|
||||
}
|
||||
|
||||
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
|
||||
|
||||
|
@ -487,6 +494,7 @@ func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib)
|
|||
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
|
||||
module := newBaseModule(hod, multilib)
|
||||
module.coverage = &coverage{}
|
||||
module.clippy = &clippy{}
|
||||
return module
|
||||
}
|
||||
|
||||
|
@ -576,6 +584,9 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
|
|||
if mod.coverage != nil {
|
||||
flags, deps = mod.coverage.flags(ctx, flags, deps)
|
||||
}
|
||||
if mod.clippy != nil {
|
||||
flags, deps = mod.clippy.flags(ctx, flags, deps)
|
||||
}
|
||||
|
||||
if mod.compiler != nil {
|
||||
outputFile := mod.compiler.compile(ctx, flags, deps)
|
||||
|
|
Loading…
Reference in New Issue