Merge "Support cc code coverage for mixed build"
This commit is contained in:
@@ -111,7 +111,7 @@ type BazelContext interface {
|
|||||||
|
|
||||||
// Issues commands to Bazel to receive results for all cquery requests
|
// Issues commands to Bazel to receive results for all cquery requests
|
||||||
// queued in the BazelContext.
|
// queued in the BazelContext.
|
||||||
InvokeBazel() error
|
InvokeBazel(config Config) error
|
||||||
|
|
||||||
// Returns true if bazel is enabled for the given configuration.
|
// Returns true if bazel is enabled for the given configuration.
|
||||||
BazelEnabled() bool
|
BazelEnabled() bool
|
||||||
@@ -191,7 +191,7 @@ func (m MockBazelContext) GetPythonBinary(label string, cfgKey configKey) (strin
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m MockBazelContext) InvokeBazel() error {
|
func (m MockBazelContext) InvokeBazel(config Config) error {
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ func (n noopBazelContext) GetPythonBinary(label string, cfgKey configKey) (strin
|
|||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n noopBazelContext) InvokeBazel() error {
|
func (n noopBazelContext) InvokeBazel(config Config) error {
|
||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,6 +361,7 @@ type bazelCommand struct {
|
|||||||
type mockBazelRunner struct {
|
type mockBazelRunner struct {
|
||||||
bazelCommandResults map[bazelCommand]string
|
bazelCommandResults map[bazelCommand]string
|
||||||
commands []bazelCommand
|
commands []bazelCommand
|
||||||
|
extraFlags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
|
func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
|
||||||
@@ -368,6 +369,7 @@ func (r *mockBazelRunner) issueBazelCommand(paths *bazelPaths,
|
|||||||
command bazelCommand,
|
command bazelCommand,
|
||||||
extraFlags ...string) (string, string, error) {
|
extraFlags ...string) (string, string, error) {
|
||||||
r.commands = append(r.commands, command)
|
r.commands = append(r.commands, command)
|
||||||
|
r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
|
||||||
if ret, ok := r.bazelCommandResults[command]; ok {
|
if ret, ok := r.bazelCommandResults[command]; ok {
|
||||||
return ret, "", nil
|
return ret, "", nil
|
||||||
}
|
}
|
||||||
@@ -676,7 +678,7 @@ func (p *bazelPaths) outDir() string {
|
|||||||
|
|
||||||
// Issues commands to Bazel to receive results for all cquery requests
|
// Issues commands to Bazel to receive results for all cquery requests
|
||||||
// queued in the BazelContext.
|
// queued in the BazelContext.
|
||||||
func (context *bazelContext) InvokeBazel() error {
|
func (context *bazelContext) InvokeBazel(config Config) error {
|
||||||
context.results = make(map[cqueryKey]string)
|
context.results = make(map[cqueryKey]string)
|
||||||
|
|
||||||
var cqueryOutput string
|
var cqueryOutput string
|
||||||
@@ -759,15 +761,31 @@ func (context *bazelContext) InvokeBazel() error {
|
|||||||
|
|
||||||
// Issue an aquery command to retrieve action information about the bazel build tree.
|
// Issue an aquery command to retrieve action information about the bazel build tree.
|
||||||
//
|
//
|
||||||
// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
|
|
||||||
var aqueryOutput string
|
var aqueryOutput string
|
||||||
|
var coverageFlags []string
|
||||||
|
if Bool(config.productVariables.ClangCoverage) {
|
||||||
|
coverageFlags = append(coverageFlags, "--collect_code_coverage")
|
||||||
|
if len(config.productVariables.NativeCoveragePaths) > 0 ||
|
||||||
|
len(config.productVariables.NativeCoverageExcludePaths) > 0 {
|
||||||
|
includePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoveragePaths, "+", ",")
|
||||||
|
excludePaths := JoinWithPrefixAndSeparator(config.productVariables.NativeCoverageExcludePaths, "-", ",")
|
||||||
|
if len(includePaths) > 0 && len(excludePaths) > 0 {
|
||||||
|
includePaths += ","
|
||||||
|
}
|
||||||
|
coverageFlags = append(coverageFlags, fmt.Sprintf(`--instrumentation_filter=%s`,
|
||||||
|
includePaths+excludePaths))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extraFlags := append([]string{"--output=jsonproto"}, coverageFlags...)
|
||||||
|
|
||||||
aqueryOutput, _, err = context.issueBazelCommand(
|
aqueryOutput, _, err = context.issueBazelCommand(
|
||||||
context.paths,
|
context.paths,
|
||||||
bazel.AqueryBuildRootRunName,
|
bazel.AqueryBuildRootRunName,
|
||||||
bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
|
bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)},
|
||||||
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
|
// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
|
||||||
// proto sources, which would add a number of unnecessary dependencies.
|
// proto sources, which would add a number of unnecessary dependencies.
|
||||||
"--output=jsonproto")
|
extraFlags...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -4,11 +4,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"android/soong/bazel/cquery"
|
"android/soong/bazel/cquery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var testConfig = TestConfig("out", nil, "", nil)
|
||||||
|
|
||||||
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
|
func TestRequestResultsAfterInvokeBazel(t *testing.T) {
|
||||||
label := "//foo:bar"
|
label := "//foo:bar"
|
||||||
cfg := configKey{"arm64_armv8-a", Android}
|
cfg := configKey{"arm64_armv8-a", Android}
|
||||||
@@ -16,7 +19,7 @@ func TestRequestResultsAfterInvokeBazel(t *testing.T) {
|
|||||||
bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
|
bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: `//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
|
||||||
})
|
})
|
||||||
bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
|
bazelContext.QueueBazelRequest(label, cquery.GetOutputFiles, cfg)
|
||||||
err := bazelContext.InvokeBazel()
|
err := bazelContext.InvokeBazel(testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
||||||
}
|
}
|
||||||
@@ -30,7 +33,7 @@ func TestRequestResultsAfterInvokeBazel(t *testing.T) {
|
|||||||
|
|
||||||
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
|
func TestInvokeBazelWritesBazelFiles(t *testing.T) {
|
||||||
bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
|
bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
|
||||||
err := bazelContext.InvokeBazel()
|
err := bazelContext.InvokeBazel(testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
||||||
}
|
}
|
||||||
@@ -86,7 +89,7 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
|
|||||||
}]
|
}]
|
||||||
}`,
|
}`,
|
||||||
})
|
})
|
||||||
err := bazelContext.InvokeBazel()
|
err := bazelContext.InvokeBazel(testConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
||||||
}
|
}
|
||||||
@@ -97,6 +100,54 @@ func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
|
||||||
|
testConfig.productVariables.ClangCoverage = boolPtr(true)
|
||||||
|
|
||||||
|
testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
|
||||||
|
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
|
||||||
|
verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
|
||||||
|
|
||||||
|
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
|
||||||
|
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
|
||||||
|
verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
|
||||||
|
|
||||||
|
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
|
||||||
|
testConfig.productVariables.NativeCoverageExcludePaths = nil
|
||||||
|
verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
|
||||||
|
|
||||||
|
testConfig.productVariables.NativeCoveragePaths = nil
|
||||||
|
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
|
||||||
|
verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
|
||||||
|
|
||||||
|
testConfig.productVariables.ClangCoverage = boolPtr(false)
|
||||||
|
actual := verifyExtraFlags(t, testConfig, ``)
|
||||||
|
if strings.Contains(actual, "--collect_code_coverage") ||
|
||||||
|
strings.Contains(actual, "--instrumentation_filter=") {
|
||||||
|
t.Errorf("Expected code coverage disabled, but got %#v", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyExtraFlags(t *testing.T, config Config, expected string) string {
|
||||||
|
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
|
||||||
|
|
||||||
|
err := bazelContext.InvokeBazel(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
|
||||||
|
if expected := 3; len(flags) != expected {
|
||||||
|
t.Errorf("Expected %d extra flags got %#v", expected, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := flags[1]
|
||||||
|
if !strings.Contains(actual, expected) {
|
||||||
|
t.Errorf("Expected %#v got %#v", expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
return actual
|
||||||
|
}
|
||||||
|
|
||||||
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
|
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
p := bazelPaths{
|
p := bazelPaths{
|
||||||
|
@@ -32,6 +32,12 @@ func CopyOf(s []string) []string {
|
|||||||
// JoinWithPrefix prepends the prefix to each string in the list and
|
// JoinWithPrefix prepends the prefix to each string in the list and
|
||||||
// returns them joined together with " " as separator.
|
// returns them joined together with " " as separator.
|
||||||
func JoinWithPrefix(strs []string, prefix string) string {
|
func JoinWithPrefix(strs []string, prefix string) string {
|
||||||
|
return JoinWithPrefixAndSeparator(strs, prefix, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
|
||||||
|
// returns them joined together with the given separator.
|
||||||
|
func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
|
||||||
if len(strs) == 0 {
|
if len(strs) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -40,7 +46,7 @@ func JoinWithPrefix(strs []string, prefix string) string {
|
|||||||
buf.WriteString(prefix)
|
buf.WriteString(prefix)
|
||||||
buf.WriteString(strs[0])
|
buf.WriteString(strs[0])
|
||||||
for i := 1; i < len(strs); i++ {
|
for i := 1; i < len(strs); i++ {
|
||||||
buf.WriteString(" ")
|
buf.WriteString(sep)
|
||||||
buf.WriteString(prefix)
|
buf.WriteString(prefix)
|
||||||
buf.WriteString(strs[i])
|
buf.WriteString(strs[i])
|
||||||
}
|
}
|
||||||
|
@@ -664,6 +664,9 @@ func shouldSkipAction(a action) bool {
|
|||||||
if a.Mnemonic == "FileWrite" {
|
if a.Mnemonic == "FileWrite" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if a.Mnemonic == "BaselineCoverage" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -959,11 +959,12 @@ func TestCcLibraryFeatures(t *testing.T) {
|
|||||||
"features": `[
|
"features": `[
|
||||||
"disable_pack_relocations",
|
"disable_pack_relocations",
|
||||||
"-no_undefined_symbols",
|
"-no_undefined_symbols",
|
||||||
|
"-coverage",
|
||||||
]`,
|
]`,
|
||||||
"srcs": `["a.cpp"]`,
|
"srcs": `["a.cpp"]`,
|
||||||
})...)
|
})...)
|
||||||
expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
|
expected_targets = append(expected_targets, makeCcLibraryTargets("b", attrNameToString{
|
||||||
"features": `select({
|
"features": `["-coverage"] + select({
|
||||||
"//build/bazel/platforms/arch:x86_64": [
|
"//build/bazel/platforms/arch:x86_64": [
|
||||||
"disable_pack_relocations",
|
"disable_pack_relocations",
|
||||||
"-no_undefined_symbols",
|
"-no_undefined_symbols",
|
||||||
@@ -994,6 +995,7 @@ cc_library {
|
|||||||
pack_relocations: false,
|
pack_relocations: false,
|
||||||
allow_undefined_symbols: true,
|
allow_undefined_symbols: true,
|
||||||
include_build_directory: false,
|
include_build_directory: false,
|
||||||
|
native_coverage: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_library {
|
cc_library {
|
||||||
@@ -1006,6 +1008,7 @@ cc_library {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
include_build_directory: false,
|
include_build_directory: false,
|
||||||
|
native_coverage: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_library {
|
cc_library {
|
||||||
|
@@ -55,6 +55,8 @@ type staticOrSharedAttributes struct {
|
|||||||
|
|
||||||
Enabled bazel.BoolAttribute
|
Enabled bazel.BoolAttribute
|
||||||
|
|
||||||
|
Native_coverage bazel.BoolAttribute
|
||||||
|
|
||||||
sdkAttributes
|
sdkAttributes
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,10 +570,15 @@ func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compilerAttrs.convertStlProps(ctx, module)
|
compilerAttrs.convertStlProps(ctx, module)
|
||||||
(&linkerAttrs).convertStripProps(ctx, module)
|
(&linkerAttrs).convertStripProps(ctx, module)
|
||||||
|
|
||||||
|
if module.coverage != nil && module.coverage.Properties.Native_coverage != nil &&
|
||||||
|
!Bool(module.coverage.Properties.Native_coverage) {
|
||||||
|
// Native_coverage is arch neutral
|
||||||
|
(&linkerAttrs).features.Append(bazel.MakeStringListAttribute([]string{"-coverage"}))
|
||||||
|
}
|
||||||
|
|
||||||
productVariableProps := android.ProductVariableProperties(ctx)
|
productVariableProps := android.ProductVariableProperties(ctx)
|
||||||
|
|
||||||
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
|
(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
|
||||||
|
@@ -139,7 +139,7 @@ func runMixedModeBuild(configuration android.Config, ctx *android.Context, extra
|
|||||||
bazelHook := func() error {
|
bazelHook := func() error {
|
||||||
ctx.EventHandler.Begin("bazel")
|
ctx.EventHandler.Begin("bazel")
|
||||||
defer ctx.EventHandler.End("bazel")
|
defer ctx.EventHandler.End("bazel")
|
||||||
return configuration.BazelContext.InvokeBazel()
|
return configuration.BazelContext.InvokeBazel(configuration)
|
||||||
}
|
}
|
||||||
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
|
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user