Merge "Add gcov coverage support to Rust modules." am: 6c4e5c05c3
Change-Id: I9f998821818e30e427696cdbcb3121722a2c8f56
This commit is contained in:
@@ -391,6 +391,7 @@ bootstrap_go_package {
|
|||||||
srcs: [
|
srcs: [
|
||||||
"rust/androidmk.go",
|
"rust/androidmk.go",
|
||||||
"rust/compiler.go",
|
"rust/compiler.go",
|
||||||
|
"rust/coverage.go",
|
||||||
"rust/binary.go",
|
"rust/binary.go",
|
||||||
"rust/builder.go",
|
"rust/builder.go",
|
||||||
"rust/library.go",
|
"rust/library.go",
|
||||||
@@ -403,6 +404,7 @@ bootstrap_go_package {
|
|||||||
testSrcs: [
|
testSrcs: [
|
||||||
"rust/binary_test.go",
|
"rust/binary_test.go",
|
||||||
"rust/compiler_test.go",
|
"rust/compiler_test.go",
|
||||||
|
"rust/coverage_test.go",
|
||||||
"rust/library_test.go",
|
"rust/library_test.go",
|
||||||
"rust/rust_test.go",
|
"rust/rust_test.go",
|
||||||
"rust/test_test.go",
|
"rust/test_test.go",
|
||||||
|
@@ -141,6 +141,16 @@ func PrefixInList(list []string, prefix string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if any string in the given list has the given suffix.
|
||||||
|
func SuffixInList(list []string, suffix string) bool {
|
||||||
|
for _, s := range list {
|
||||||
|
if strings.HasSuffix(s, suffix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
|
// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
|
||||||
func IndexListPred(pred func(s string) bool, list []string) int {
|
func IndexListPred(pred func(s string) bool, list []string) int {
|
||||||
for i, l := range list {
|
for i, l := range list {
|
||||||
|
@@ -1603,6 +1603,8 @@ func (a *apexBundle) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizer
|
|||||||
return android.InList(sanitizerName, globalSanitizerNames)
|
return android.InList(sanitizerName, globalSanitizerNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ cc.Coverage = (*apexBundle)(nil)
|
||||||
|
|
||||||
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
|
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
|
||||||
return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
|
return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
|
||||||
}
|
}
|
||||||
@@ -1619,6 +1621,8 @@ func (a *apexBundle) MarkAsCoverageVariant(coverage bool) {
|
|||||||
a.properties.IsCoverageVariant = coverage
|
a.properties.IsCoverageVariant = coverage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *apexBundle) EnableCoverageIfNeeded() {}
|
||||||
|
|
||||||
// TODO(jiyong) move apexFileFor* close to the apexFile type definition
|
// TODO(jiyong) move apexFileFor* close to the apexFile type definition
|
||||||
func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
|
func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
|
||||||
// Decide the APEX-local directory by the multilib of the library
|
// Decide the APEX-local directory by the multilib of the library
|
||||||
|
@@ -117,44 +117,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
|
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
|
||||||
ctx, _ := testApex(t, bp+`
|
ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
|
||||||
cc_library {
|
|
||||||
name: "libprofile-extras",
|
|
||||||
vendor_available: true,
|
|
||||||
recovery_available: true,
|
|
||||||
native_coverage: false,
|
|
||||||
system_shared_libs: [],
|
|
||||||
stl: "none",
|
|
||||||
notice: "custom_notice",
|
|
||||||
}
|
|
||||||
cc_library {
|
|
||||||
name: "libprofile-clang-extras",
|
|
||||||
vendor_available: true,
|
|
||||||
recovery_available: true,
|
|
||||||
native_coverage: false,
|
|
||||||
system_shared_libs: [],
|
|
||||||
stl: "none",
|
|
||||||
notice: "custom_notice",
|
|
||||||
}
|
|
||||||
cc_library {
|
|
||||||
name: "libprofile-extras_ndk",
|
|
||||||
vendor_available: true,
|
|
||||||
native_coverage: false,
|
|
||||||
system_shared_libs: [],
|
|
||||||
stl: "none",
|
|
||||||
notice: "custom_notice",
|
|
||||||
sdk_version: "current",
|
|
||||||
}
|
|
||||||
cc_library {
|
|
||||||
name: "libprofile-clang-extras_ndk",
|
|
||||||
vendor_available: true,
|
|
||||||
native_coverage: false,
|
|
||||||
system_shared_libs: [],
|
|
||||||
stl: "none",
|
|
||||||
notice: "custom_notice",
|
|
||||||
sdk_version: "current",
|
|
||||||
}
|
|
||||||
`, func(fs map[string][]byte, config android.Config) {
|
|
||||||
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
|
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
15
cc/cc.go
15
cc/cc.go
@@ -437,7 +437,6 @@ var (
|
|||||||
ndkLateStubDepTag = DependencyTag{Name: "ndk late stub", Library: true}
|
ndkLateStubDepTag = DependencyTag{Name: "ndk late stub", Library: true}
|
||||||
vndkExtDepTag = DependencyTag{Name: "vndk extends", Library: true}
|
vndkExtDepTag = DependencyTag{Name: "vndk extends", Library: true}
|
||||||
runtimeDepTag = DependencyTag{Name: "runtime lib"}
|
runtimeDepTag = DependencyTag{Name: "runtime lib"}
|
||||||
coverageDepTag = DependencyTag{Name: "coverage"}
|
|
||||||
testPerSrcDepTag = DependencyTag{Name: "test_per_src"}
|
testPerSrcDepTag = DependencyTag{Name: "test_per_src"}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -745,6 +744,15 @@ func (c *Module) OutputFile() android.OptionalPath {
|
|||||||
return c.outputFile
|
return c.outputFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Module) CoverageFiles() android.Paths {
|
||||||
|
if c.linker != nil {
|
||||||
|
if library, ok := c.linker.(libraryInterface); ok {
|
||||||
|
return library.objs().coverageFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Errorf("CoverageFiles called on non-library module: %q", c.BaseModuleName()))
|
||||||
|
}
|
||||||
|
|
||||||
var _ LinkableInterface = (*Module)(nil)
|
var _ LinkableInterface = (*Module)(nil)
|
||||||
|
|
||||||
func (c *Module) UnstrippedOutputFile() android.Path {
|
func (c *Module) UnstrippedOutputFile() android.Path {
|
||||||
@@ -2493,13 +2501,16 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
|||||||
// When combining coverage files for shared libraries and executables, coverage files
|
// When combining coverage files for shared libraries and executables, coverage files
|
||||||
// in static libraries act as if they were whole static libraries. The same goes for
|
// in static libraries act as if they were whole static libraries. The same goes for
|
||||||
// source based Abi dump files.
|
// source based Abi dump files.
|
||||||
// This should only be done for cc.Modules
|
|
||||||
if c, ok := ccDep.(*Module); ok {
|
if c, ok := ccDep.(*Module); ok {
|
||||||
staticLib := c.linker.(libraryInterface)
|
staticLib := c.linker.(libraryInterface)
|
||||||
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
|
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
|
||||||
staticLib.objs().coverageFiles...)
|
staticLib.objs().coverageFiles...)
|
||||||
depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
|
depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
|
||||||
staticLib.objs().sAbiDumpFiles...)
|
staticLib.objs().sAbiDumpFiles...)
|
||||||
|
} else if c, ok := ccDep.(LinkableInterface); ok {
|
||||||
|
// Handle non-CC modules here
|
||||||
|
depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
|
||||||
|
c.CoverageFiles()...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,10 +65,10 @@ func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
|
|||||||
if cov.Properties.NeedCoverageVariant {
|
if cov.Properties.NeedCoverageVariant {
|
||||||
ctx.AddVariationDependencies([]blueprint.Variation{
|
ctx.AddVariationDependencies([]blueprint.Variation{
|
||||||
{Mutator: "link", Variation: "static"},
|
{Mutator: "link", Variation: "static"},
|
||||||
}, coverageDepTag, getGcovProfileLibraryName(ctx))
|
}, CoverageDepTag, getGcovProfileLibraryName(ctx))
|
||||||
ctx.AddVariationDependencies([]blueprint.Variation{
|
ctx.AddVariationDependencies([]blueprint.Variation{
|
||||||
{Mutator: "link", Variation: "static"},
|
{Mutator: "link", Variation: "static"},
|
||||||
}, coverageDepTag, getClangProfileLibraryName(ctx))
|
}, CoverageDepTag, getClangProfileLibraryName(ctx))
|
||||||
}
|
}
|
||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
@@ -134,14 +134,14 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags
|
|||||||
if gcovCoverage {
|
if gcovCoverage {
|
||||||
flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
|
flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
|
||||||
|
|
||||||
coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), coverageDepTag).(*Module)
|
coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
|
||||||
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
|
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
|
||||||
|
|
||||||
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
|
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
|
||||||
} else if clangCoverage {
|
} else if clangCoverage {
|
||||||
flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate")
|
flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate")
|
||||||
|
|
||||||
coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), coverageDepTag).(*Module)
|
coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
|
||||||
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
|
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,25 +150,30 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cov *coverage) begin(ctx BaseModuleContext) {
|
func (cov *coverage) begin(ctx BaseModuleContext) {
|
||||||
|
if ctx.Host() {
|
||||||
|
// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
|
||||||
|
// Just turn off for now.
|
||||||
|
} else {
|
||||||
|
cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
|
||||||
|
useSdk bool, sdkVersion string) CoverageProperties {
|
||||||
// Coverage is disabled globally
|
// Coverage is disabled globally
|
||||||
if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
|
if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
|
||||||
return
|
return properties
|
||||||
}
|
}
|
||||||
|
|
||||||
var needCoverageVariant bool
|
var needCoverageVariant bool
|
||||||
var needCoverageBuild bool
|
var needCoverageBuild bool
|
||||||
|
|
||||||
if ctx.Host() {
|
if moduleTypeHasCoverage {
|
||||||
// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
|
|
||||||
// Just turn off for now.
|
|
||||||
} else if !ctx.nativeCoverage() {
|
|
||||||
// Native coverage is not supported for this module type.
|
|
||||||
} else {
|
|
||||||
// Check if Native_coverage is set to false. This property defaults to true.
|
// Check if Native_coverage is set to false. This property defaults to true.
|
||||||
needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true)
|
needCoverageVariant = BoolDefault(properties.Native_coverage, true)
|
||||||
if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" {
|
if useSdk && sdkVersion != "current" {
|
||||||
// Native coverage is not supported for SDK versions < 23
|
// Native coverage is not supported for SDK versions < 23
|
||||||
if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
|
if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 {
|
||||||
needCoverageVariant = false
|
needCoverageVariant = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,8 +184,10 @@ func (cov *coverage) begin(ctx BaseModuleContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cov.Properties.NeedCoverageBuild = needCoverageBuild
|
properties.NeedCoverageBuild = needCoverageBuild
|
||||||
cov.Properties.NeedCoverageVariant = needCoverageVariant
|
properties.NeedCoverageVariant = needCoverageVariant
|
||||||
|
|
||||||
|
return properties
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coverage is an interface for non-CC modules to implement to be mutated for coverage
|
// Coverage is an interface for non-CC modules to implement to be mutated for coverage
|
||||||
@@ -190,6 +197,7 @@ type Coverage interface {
|
|||||||
PreventInstall()
|
PreventInstall()
|
||||||
HideFromMake()
|
HideFromMake()
|
||||||
MarkAsCoverageVariant(bool)
|
MarkAsCoverageVariant(bool)
|
||||||
|
EnableCoverageIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
func coverageMutator(mctx android.BottomUpMutatorContext) {
|
func coverageMutator(mctx android.BottomUpMutatorContext) {
|
||||||
@@ -212,14 +220,17 @@ func coverageMutator(mctx android.BottomUpMutatorContext) {
|
|||||||
m[1].(*Module).coverage.Properties.IsCoverageVariant = true
|
m[1].(*Module).coverage.Properties.IsCoverageVariant = true
|
||||||
}
|
}
|
||||||
} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
|
} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
|
||||||
// APEX modules fall here
|
// APEX and Rust modules fall here
|
||||||
|
|
||||||
// Note: variant "" is also created because an APEX can be depended on by another
|
// Note: variant "" is also created because an APEX can be depended on by another
|
||||||
// module which are split into "" and "cov" variants. e.g. when cc_test refers
|
// module which are split into "" and "cov" variants. e.g. when cc_test refers
|
||||||
// to an APEX via 'data' property.
|
// to an APEX via 'data' property.
|
||||||
m := mctx.CreateVariations("", "cov")
|
m := mctx.CreateVariations("", "cov")
|
||||||
m[0].(Coverage).MarkAsCoverageVariant(true)
|
m[0].(Coverage).MarkAsCoverageVariant(false)
|
||||||
m[0].(Coverage).PreventInstall()
|
m[0].(Coverage).PreventInstall()
|
||||||
m[0].(Coverage).HideFromMake()
|
m[0].(Coverage).HideFromMake()
|
||||||
|
|
||||||
|
m[1].(Coverage).MarkAsCoverageVariant(true)
|
||||||
|
m[1].(Coverage).EnableCoverageIfNeeded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ type LinkableInterface interface {
|
|||||||
CcLibraryInterface() bool
|
CcLibraryInterface() bool
|
||||||
|
|
||||||
OutputFile() android.OptionalPath
|
OutputFile() android.OptionalPath
|
||||||
|
CoverageFiles() android.Paths
|
||||||
|
|
||||||
IncludeDirs() android.Paths
|
IncludeDirs() android.Paths
|
||||||
SetDepsInLinkOrder([]android.Path)
|
SetDepsInLinkOrder([]android.Path)
|
||||||
@@ -83,4 +84,5 @@ var (
|
|||||||
|
|
||||||
CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
|
CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
|
||||||
CrtEndDepTag = DependencyTag{Name: "crtend"}
|
CrtEndDepTag = DependencyTag{Name: "crtend"}
|
||||||
|
CoverageDepTag = DependencyTag{Name: "coverage"}
|
||||||
)
|
)
|
||||||
|
@@ -192,6 +192,45 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
|||||||
symbol_file: "",
|
symbol_file: "",
|
||||||
sdk_version: "current",
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Coverage libraries
|
||||||
|
cc_library {
|
||||||
|
name: "libprofile-extras",
|
||||||
|
vendor_available: true,
|
||||||
|
recovery_available: true,
|
||||||
|
native_coverage: false,
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
notice: "custom_notice",
|
||||||
|
}
|
||||||
|
cc_library {
|
||||||
|
name: "libprofile-clang-extras",
|
||||||
|
vendor_available: true,
|
||||||
|
recovery_available: true,
|
||||||
|
native_coverage: false,
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
notice: "custom_notice",
|
||||||
|
}
|
||||||
|
cc_library {
|
||||||
|
name: "libprofile-extras_ndk",
|
||||||
|
vendor_available: true,
|
||||||
|
native_coverage: false,
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
notice: "custom_notice",
|
||||||
|
sdk_version: "current",
|
||||||
|
}
|
||||||
|
cc_library {
|
||||||
|
name: "libprofile-clang-extras_ndk",
|
||||||
|
vendor_available: true,
|
||||||
|
native_coverage: false,
|
||||||
|
system_shared_libs: [],
|
||||||
|
stl: "none",
|
||||||
|
notice: "custom_notice",
|
||||||
|
sdk_version: "current",
|
||||||
|
}
|
||||||
|
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libdl",
|
name: "libdl",
|
||||||
no_libcrt: true,
|
no_libcrt: true,
|
||||||
|
@@ -714,6 +714,8 @@ func (a *AndroidApp) MarkAsCoverageVariant(coverage bool) {
|
|||||||
a.appProperties.IsCoverageVariant = coverage
|
a.appProperties.IsCoverageVariant = coverage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AndroidApp) EnableCoverageIfNeeded() {}
|
||||||
|
|
||||||
var _ cc.Coverage = (*AndroidApp)(nil)
|
var _ cc.Coverage = (*AndroidApp)(nil)
|
||||||
|
|
||||||
// android_app compiles sources and Android resources into an Android application package `.apk` file.
|
// android_app compiles sources and Android resources into an Android application package `.apk` file.
|
||||||
|
@@ -46,6 +46,12 @@ func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mod *Module) AndroidMk() android.AndroidMkData {
|
func (mod *Module) AndroidMk() android.AndroidMkData {
|
||||||
|
if mod.Properties.HideFromMake {
|
||||||
|
return android.AndroidMkData{
|
||||||
|
Disabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret := android.AndroidMkData{
|
ret := android.AndroidMkData{
|
||||||
OutputFile: mod.outputFile,
|
OutputFile: mod.outputFile,
|
||||||
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
|
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
|
||||||
@@ -84,6 +90,9 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr
|
|||||||
ret.DistFile = binary.distFile
|
ret.DistFile = binary.distFile
|
||||||
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
|
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
|
||||||
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
|
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
|
||||||
|
if binary.coverageOutputZipFile.Valid() {
|
||||||
|
fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+binary.coverageOutputZipFile.String())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +133,10 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An
|
|||||||
if !library.rlib() {
|
if !library.rlib() {
|
||||||
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
|
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
|
||||||
}
|
}
|
||||||
|
if library.coverageOutputZipFile.Valid() {
|
||||||
|
fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+library.coverageOutputZipFile.String())
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@ type binaryDecorator struct {
|
|||||||
|
|
||||||
Properties BinaryCompilerProperties
|
Properties BinaryCompilerProperties
|
||||||
distFile android.OptionalPath
|
distFile android.OptionalPath
|
||||||
|
coverageOutputZipFile android.OptionalPath
|
||||||
unstrippedOutputFile android.Path
|
unstrippedOutputFile android.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +105,10 @@ func (binary *binaryDecorator) compilerProps() []interface{} {
|
|||||||
&binary.Properties)
|
&binary.Properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (binary *binaryDecorator) nativeCoverage() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
|
func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
|
||||||
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
|
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
|
||||||
|
|
||||||
@@ -114,7 +119,21 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path
|
|||||||
|
|
||||||
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
|
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
|
||||||
|
|
||||||
TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
||||||
|
binary.coverageFile = outputs.coverageFile
|
||||||
|
|
||||||
|
var coverageFiles android.Paths
|
||||||
|
if outputs.coverageFile != nil {
|
||||||
|
coverageFiles = append(coverageFiles, binary.coverageFile)
|
||||||
|
}
|
||||||
|
if len(deps.coverageFiles) > 0 {
|
||||||
|
coverageFiles = append(coverageFiles, deps.coverageFiles...)
|
||||||
|
}
|
||||||
|
binary.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, binary.getStem(ctx))
|
||||||
|
|
||||||
return outputFile
|
return outputFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath {
|
||||||
|
return binary.coverageOutputZipFile
|
||||||
|
}
|
||||||
|
@@ -18,6 +18,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
|
"github.com/google/blueprint/pathtools"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
)
|
)
|
||||||
@@ -36,44 +37,57 @@ var (
|
|||||||
Depfile: "$out.d",
|
Depfile: "$out.d",
|
||||||
},
|
},
|
||||||
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
|
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
|
||||||
|
|
||||||
|
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",
|
||||||
|
CommandDeps: []string{"${SoongZipCmd}"},
|
||||||
|
Rspfile: "$out.rsp",
|
||||||
|
RspfileContent: "$in",
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
type buildOutput struct {
|
||||||
|
outputFile android.Path
|
||||||
|
coverageFile android.Path
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, includeDirs []string) {
|
outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
||||||
|
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, includeDirs []string) {
|
outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, includeDirs []string) {
|
outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, includeDirs []string) {
|
outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, includeDirs []string) {
|
outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
flags.RustFlags = append(flags.RustFlags, "-C lto")
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
|
func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
|
||||||
flags Flags, outputFile android.WritablePath, includeDirs []string) {
|
flags Flags, outputFile android.WritablePath, includeDirs []string) buildOutput {
|
||||||
transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
|
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func rustLibsToPaths(libs RustLibraries) android.Paths {
|
func rustLibsToPaths(libs RustLibraries) android.Paths {
|
||||||
@@ -85,11 +99,15 @@ func rustLibsToPaths(libs RustLibraries) android.Paths {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
|
func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
|
||||||
outputFile android.WritablePath, crate_type string, includeDirs []string) {
|
outputFile android.WritablePath, crate_type string, includeDirs []string) buildOutput {
|
||||||
|
|
||||||
var inputs android.Paths
|
var inputs android.Paths
|
||||||
var implicits android.Paths
|
var implicits android.Paths
|
||||||
|
var output buildOutput
|
||||||
var libFlags, rustcFlags, linkFlags []string
|
var libFlags, rustcFlags, linkFlags []string
|
||||||
|
var implicitOutputs android.WritablePaths
|
||||||
|
|
||||||
|
output.outputFile = outputFile
|
||||||
crate_name := ctx.(ModuleContext).CrateName()
|
crate_name := ctx.(ModuleContext).CrateName()
|
||||||
targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
|
targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
|
||||||
|
|
||||||
@@ -141,10 +159,24 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path
|
|||||||
implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
|
implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if flags.Coverage {
|
||||||
|
var gcnoFile android.WritablePath
|
||||||
|
|
||||||
|
if outputFile.Ext() != "" {
|
||||||
|
gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno"))
|
||||||
|
} else {
|
||||||
|
gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno")
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitOutputs = append(implicitOutputs, gcnoFile)
|
||||||
|
output.coverageFile = gcnoFile
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Build(pctx, android.BuildParams{
|
ctx.Build(pctx, android.BuildParams{
|
||||||
Rule: rustc,
|
Rule: rustc,
|
||||||
Description: "rustc " + main.Rel(),
|
Description: "rustc " + main.Rel(),
|
||||||
Output: outputFile,
|
Output: outputFile,
|
||||||
|
ImplicitOutputs: implicitOutputs,
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
Implicits: implicits,
|
Implicits: implicits,
|
||||||
Args: map[string]string{
|
Args: map[string]string{
|
||||||
@@ -156,4 +188,23 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func TransformCoverageFilesToZip(ctx android.ModuleContext,
|
||||||
|
covFiles android.Paths, baseName string) android.OptionalPath {
|
||||||
|
if len(covFiles) > 0 {
|
||||||
|
|
||||||
|
outputFile := android.PathForModuleOut(ctx, baseName+".zip")
|
||||||
|
|
||||||
|
ctx.Build(pctx, android.BuildParams{
|
||||||
|
Rule: zip,
|
||||||
|
Description: "zip " + outputFile.Base(),
|
||||||
|
Inputs: covFiles,
|
||||||
|
Output: outputFile,
|
||||||
|
})
|
||||||
|
|
||||||
|
return android.OptionalPathForPath(outputFile)
|
||||||
|
}
|
||||||
|
return android.OptionalPath{}
|
||||||
}
|
}
|
||||||
|
@@ -110,6 +110,7 @@ type baseCompiler struct {
|
|||||||
linkDirs []string
|
linkDirs []string
|
||||||
edition string
|
edition string
|
||||||
src android.Path //rustc takes a single src file
|
src android.Path //rustc takes a single src file
|
||||||
|
coverageFile android.Path //rustc generates a single gcno file
|
||||||
|
|
||||||
// Install related
|
// Install related
|
||||||
dir string
|
dir string
|
||||||
@@ -120,6 +121,10 @@ type baseCompiler struct {
|
|||||||
location installLocation
|
location installLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
|
||||||
|
panic("baseCompiler does not implement coverageOutputZipPath()")
|
||||||
|
}
|
||||||
|
|
||||||
var _ compiler = (*baseCompiler)(nil)
|
var _ compiler = (*baseCompiler)(nil)
|
||||||
|
|
||||||
func (compiler *baseCompiler) inData() bool {
|
func (compiler *baseCompiler) inData() bool {
|
||||||
@@ -235,6 +240,10 @@ func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath
|
|||||||
compiler.relativeInstallPath(), compiler.relative)
|
compiler.relativeInstallPath(), compiler.relative)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (compiler *baseCompiler) nativeCoverage() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
|
func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
|
||||||
compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
|
compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
|
||||||
}
|
}
|
||||||
|
72
rust/coverage.go
Normal file
72
rust/coverage.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
// 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 (
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong/cc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CovLibraryName = "libprofile-extras"
|
||||||
|
|
||||||
|
type coverage struct {
|
||||||
|
Properties cc.CoverageProperties
|
||||||
|
|
||||||
|
// Whether binaries containing this module need --coverage added to their ldflags
|
||||||
|
linkCoverage bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov *coverage) props() []interface{} {
|
||||||
|
return []interface{}{&cov.Properties}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
|
||||||
|
if cov.Properties.NeedCoverageVariant {
|
||||||
|
ctx.AddVariationDependencies([]blueprint.Variation{
|
||||||
|
{Mutator: "link", Variation: "static"},
|
||||||
|
}, cc.CoverageDepTag, CovLibraryName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
|
||||||
|
|
||||||
|
if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
|
||||||
|
return flags, deps
|
||||||
|
}
|
||||||
|
|
||||||
|
if cov.Properties.CoverageEnabled {
|
||||||
|
flags.Coverage = true
|
||||||
|
coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
|
||||||
|
flags.RustFlags = append(flags.RustFlags,
|
||||||
|
"-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads")
|
||||||
|
flags.LinkFlags = append(flags.LinkFlags,
|
||||||
|
"--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
|
||||||
|
deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags, deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cov *coverage) begin(ctx BaseModuleContext) {
|
||||||
|
if ctx.Host() {
|
||||||
|
// Host coverage not yet supported.
|
||||||
|
} else {
|
||||||
|
// Update useSdk and sdkVersion args if Rust modules become SDK aware.
|
||||||
|
cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), false, "")
|
||||||
|
}
|
||||||
|
}
|
181
rust/coverage_test.go
Normal file
181
rust/coverage_test.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// 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 (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test that coverage flags are being correctly generated.
|
||||||
|
func TestCoverageFlags(t *testing.T) {
|
||||||
|
ctx := testRustCov(t, `
|
||||||
|
rust_library {
|
||||||
|
name: "libfoo_cov",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
crate_name: "foo",
|
||||||
|
}
|
||||||
|
rust_binary {
|
||||||
|
name: "fizz_cov",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
}
|
||||||
|
rust_binary {
|
||||||
|
name: "buzzNoCov",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
native_coverage: false,
|
||||||
|
}
|
||||||
|
rust_library {
|
||||||
|
name: "libbar_nocov",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
crate_name: "bar",
|
||||||
|
native_coverage: false,
|
||||||
|
}`)
|
||||||
|
|
||||||
|
// Make sure native_coverage: false isn't creating a coverage variant.
|
||||||
|
if android.InList("android_arm64_armv8-a_dylib_cov", ctx.ModuleVariantsForTests("libbar_nocov")) {
|
||||||
|
t.Fatalf("coverage variant created for module 'libbar_nocov' with native coverage disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just test the dylib variants unless the library coverage logic changes to distinguish between the types.
|
||||||
|
libfooCov := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc")
|
||||||
|
libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
|
||||||
|
fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
|
||||||
|
buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
|
||||||
|
|
||||||
|
rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"}
|
||||||
|
for _, flag := range rustcCoverageFlags {
|
||||||
|
missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
|
||||||
|
containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
|
||||||
|
|
||||||
|
if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
|
||||||
|
t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
|
||||||
|
}
|
||||||
|
if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
|
||||||
|
t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
|
||||||
|
}
|
||||||
|
if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
|
||||||
|
t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
|
||||||
|
}
|
||||||
|
if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
|
||||||
|
t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
linkCoverageFlags := []string{"--coverage", " -g "}
|
||||||
|
for _, flag := range linkCoverageFlags {
|
||||||
|
missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
|
||||||
|
containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
|
||||||
|
|
||||||
|
if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
|
||||||
|
t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
|
||||||
|
}
|
||||||
|
if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
|
||||||
|
t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
|
||||||
|
}
|
||||||
|
if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
|
||||||
|
t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
|
||||||
|
}
|
||||||
|
if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
|
||||||
|
t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test coverage files are included correctly
|
||||||
|
func TestCoverageZip(t *testing.T) {
|
||||||
|
ctx := testRustCov(t, `
|
||||||
|
rust_library {
|
||||||
|
name: "libfoo",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
rlibs: ["librlib"],
|
||||||
|
crate_name: "foo",
|
||||||
|
}
|
||||||
|
rust_library_rlib {
|
||||||
|
name: "librlib",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
crate_name: "rlib",
|
||||||
|
}
|
||||||
|
rust_binary {
|
||||||
|
name: "fizz",
|
||||||
|
rlibs: ["librlib"],
|
||||||
|
static_libs: ["libfoo"],
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
}
|
||||||
|
cc_binary {
|
||||||
|
name: "buzz",
|
||||||
|
static_libs: ["libfoo"],
|
||||||
|
srcs: ["foo.c"],
|
||||||
|
}
|
||||||
|
cc_library {
|
||||||
|
name: "libbar",
|
||||||
|
static_libs: ["libfoo"],
|
||||||
|
compile_multilib: "64",
|
||||||
|
srcs: ["foo.c"],
|
||||||
|
}`)
|
||||||
|
|
||||||
|
fizzZipInputs := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
|
||||||
|
libfooZipInputs := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib_cov").Rule("zip").Inputs.Strings()
|
||||||
|
buzzZipInputs := ctx.ModuleForTests("buzz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
|
||||||
|
libbarZipInputs := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared_cov").Rule("zip").Inputs.Strings()
|
||||||
|
|
||||||
|
// Make sure the expected number of input files are included.
|
||||||
|
if len(fizzZipInputs) != 3 {
|
||||||
|
t.Fatalf("expected only 3 coverage inputs for rust 'fizz' binary, got %#v: %#v", len(fizzZipInputs), fizzZipInputs)
|
||||||
|
}
|
||||||
|
if len(libfooZipInputs) != 2 {
|
||||||
|
t.Fatalf("expected only 2 coverage inputs for rust 'libfoo' library, got %#v: %#v", len(libfooZipInputs), libfooZipInputs)
|
||||||
|
}
|
||||||
|
if len(buzzZipInputs) != 2 {
|
||||||
|
t.Fatalf("expected only 2 coverage inputs for cc 'buzz' binary, got %#v: %#v", len(buzzZipInputs), buzzZipInputs)
|
||||||
|
}
|
||||||
|
if len(libbarZipInputs) != 2 {
|
||||||
|
t.Fatalf("expected only 2 coverage inputs for cc 'libbar' library, got %#v: %#v", len(libbarZipInputs), libbarZipInputs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the expected inputs are provided to the zip rule.
|
||||||
|
if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
|
||||||
|
!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") ||
|
||||||
|
!android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
|
||||||
|
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
|
||||||
|
}
|
||||||
|
if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
|
||||||
|
!android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.dylib.gcno") {
|
||||||
|
t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
|
||||||
|
}
|
||||||
|
if !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_cov/obj/foo.gcno") ||
|
||||||
|
!android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
|
||||||
|
t.Fatalf("missing expected coverage files for cc 'buzz' binary: %#v", buzzZipInputs)
|
||||||
|
}
|
||||||
|
if !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/obj/foo.gcno") ||
|
||||||
|
!android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libfoo.gcno") {
|
||||||
|
t.Fatalf("missing expected coverage files for cc 'libbar' library: %#v", libbarZipInputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCoverageDeps(t *testing.T) {
|
||||||
|
ctx := testRustCov(t, `
|
||||||
|
rust_binary {
|
||||||
|
name: "fizz",
|
||||||
|
srcs: ["foo.rs"],
|
||||||
|
}`)
|
||||||
|
|
||||||
|
fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
|
||||||
|
if !strings.Contains(fizz.Args["linkFlags"], "libprofile-extras.a") {
|
||||||
|
t.Fatalf("missing expected coverage 'libprofile-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
|
||||||
|
}
|
||||||
|
}
|
@@ -78,6 +78,7 @@ type libraryDecorator struct {
|
|||||||
Properties LibraryCompilerProperties
|
Properties LibraryCompilerProperties
|
||||||
MutatedProperties LibraryMutatedProperties
|
MutatedProperties LibraryMutatedProperties
|
||||||
distFile android.OptionalPath
|
distFile android.OptionalPath
|
||||||
|
coverageOutputZipFile android.OptionalPath
|
||||||
unstrippedOutputFile android.Path
|
unstrippedOutputFile android.Path
|
||||||
includeDirs android.Paths
|
includeDirs android.Paths
|
||||||
}
|
}
|
||||||
@@ -107,6 +108,10 @@ type libraryInterface interface {
|
|||||||
BuildOnlyShared()
|
BuildOnlyShared()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (library *libraryDecorator) nativeCoverage() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (library *libraryDecorator) exportedDirs() []string {
|
func (library *libraryDecorator) exportedDirs() []string {
|
||||||
return library.linkDirs
|
return library.linkDirs
|
||||||
}
|
}
|
||||||
@@ -351,24 +356,37 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
|
|||||||
fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
|
fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
|
||||||
outputFile = android.PathForModuleOut(ctx, fileName)
|
outputFile = android.PathForModuleOut(ctx, fileName)
|
||||||
|
|
||||||
TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
||||||
|
library.coverageFile = outputs.coverageFile
|
||||||
} else if library.dylib() {
|
} else if library.dylib() {
|
||||||
fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
|
fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
|
||||||
outputFile = android.PathForModuleOut(ctx, fileName)
|
outputFile = android.PathForModuleOut(ctx, fileName)
|
||||||
|
|
||||||
TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
||||||
|
library.coverageFile = outputs.coverageFile
|
||||||
} else if library.static() {
|
} else if library.static() {
|
||||||
fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
|
fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
|
||||||
outputFile = android.PathForModuleOut(ctx, fileName)
|
outputFile = android.PathForModuleOut(ctx, fileName)
|
||||||
|
|
||||||
TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
||||||
|
library.coverageFile = outputs.coverageFile
|
||||||
} else if library.shared() {
|
} else if library.shared() {
|
||||||
fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
|
fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
|
||||||
outputFile = android.PathForModuleOut(ctx, fileName)
|
outputFile = android.PathForModuleOut(ctx, fileName)
|
||||||
|
|
||||||
TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
|
||||||
|
library.coverageFile = outputs.coverageFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var coverageFiles android.Paths
|
||||||
|
if library.coverageFile != nil {
|
||||||
|
coverageFiles = append(coverageFiles, library.coverageFile)
|
||||||
|
}
|
||||||
|
if len(deps.coverageFiles) > 0 {
|
||||||
|
coverageFiles = append(coverageFiles, deps.coverageFiles...)
|
||||||
|
}
|
||||||
|
library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
|
||||||
|
|
||||||
if library.rlib() || library.dylib() {
|
if library.rlib() || library.dylib() {
|
||||||
library.reexportDirs(deps.linkDirs...)
|
library.reexportDirs(deps.linkDirs...)
|
||||||
library.reexportDepFlags(deps.depFlags...)
|
library.reexportDepFlags(deps.depFlags...)
|
||||||
|
@@ -69,3 +69,7 @@ func (prebuilt *prebuiltLibraryDecorator) compilerDeps(ctx DepsContext, deps Dep
|
|||||||
deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
|
deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
|
||||||
return deps
|
return deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (prebuilt *prebuiltLibraryDecorator) nativeCoverage() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
105
rust/rust.go
105
rust/rust.go
@@ -40,6 +40,7 @@ func init() {
|
|||||||
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
|
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
|
||||||
ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
|
ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
|
||||||
|
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
|
||||||
})
|
})
|
||||||
pctx.Import("android/soong/rust/config")
|
pctx.Import("android/soong/rust/config")
|
||||||
}
|
}
|
||||||
@@ -51,6 +52,7 @@ type Flags struct {
|
|||||||
LinkFlags []string // Flags that apply to linker
|
LinkFlags []string // Flags that apply to linker
|
||||||
RustFlagsDeps android.Paths // Files depended on by compiler flags
|
RustFlagsDeps android.Paths // Files depended on by compiler flags
|
||||||
Toolchain config.Toolchain
|
Toolchain config.Toolchain
|
||||||
|
Coverage bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseProperties struct {
|
type BaseProperties struct {
|
||||||
@@ -60,6 +62,8 @@ type BaseProperties struct {
|
|||||||
AndroidMkSharedLibs []string
|
AndroidMkSharedLibs []string
|
||||||
AndroidMkStaticLibs []string
|
AndroidMkStaticLibs []string
|
||||||
SubName string `blueprint:"mutated"`
|
SubName string `blueprint:"mutated"`
|
||||||
|
PreventInstall bool
|
||||||
|
HideFromMake bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Module struct {
|
type Module struct {
|
||||||
@@ -72,6 +76,7 @@ type Module struct {
|
|||||||
multilib android.Multilib
|
multilib android.Multilib
|
||||||
|
|
||||||
compiler compiler
|
compiler compiler
|
||||||
|
coverage *coverage
|
||||||
cachedToolchain config.Toolchain
|
cachedToolchain config.Toolchain
|
||||||
subAndroidMkOnce map[subAndroidMkProvider]bool
|
subAndroidMkOnce map[subAndroidMkProvider]bool
|
||||||
outputFile android.OptionalPath
|
outputFile android.OptionalPath
|
||||||
@@ -224,6 +229,8 @@ type PathDeps struct {
|
|||||||
depFlags []string
|
depFlags []string
|
||||||
//ReexportedDeps android.Paths
|
//ReexportedDeps android.Paths
|
||||||
|
|
||||||
|
coverageFiles android.Paths
|
||||||
|
|
||||||
CrtBegin android.OptionalPath
|
CrtBegin android.OptionalPath
|
||||||
CrtEnd android.OptionalPath
|
CrtEnd android.OptionalPath
|
||||||
}
|
}
|
||||||
@@ -245,6 +252,34 @@ type compiler interface {
|
|||||||
inData() bool
|
inData() bool
|
||||||
install(ctx ModuleContext, path android.Path)
|
install(ctx ModuleContext, path android.Path)
|
||||||
relativeInstallPath() string
|
relativeInstallPath() string
|
||||||
|
|
||||||
|
nativeCoverage() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) isCoverageVariant() bool {
|
||||||
|
return mod.coverage.Properties.IsCoverageVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ cc.Coverage = (*Module)(nil)
|
||||||
|
|
||||||
|
func (mod *Module) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
|
||||||
|
return mod.coverage != nil && mod.coverage.Properties.NeedCoverageVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) PreventInstall() {
|
||||||
|
mod.Properties.PreventInstall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) HideFromMake() {
|
||||||
|
mod.Properties.HideFromMake = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) MarkAsCoverageVariant(coverage bool) {
|
||||||
|
mod.coverage.Properties.IsCoverageVariant = coverage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) EnableCoverageIfNeeded() {
|
||||||
|
mod.coverage.Properties.CoverageEnabled = mod.coverage.Properties.NeedCoverageBuild
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultsFactory() android.Module {
|
func defaultsFactory() android.Module {
|
||||||
@@ -268,6 +303,7 @@ func DefaultsFactory(props ...interface{}) android.Module {
|
|||||||
&ProcMacroCompilerProperties{},
|
&ProcMacroCompilerProperties{},
|
||||||
&PrebuiltProperties{},
|
&PrebuiltProperties{},
|
||||||
&TestProperties{},
|
&TestProperties{},
|
||||||
|
&cc.CoverageProperties{},
|
||||||
)
|
)
|
||||||
|
|
||||||
android.InitDefaultsModule(module)
|
android.InitDefaultsModule(module)
|
||||||
@@ -395,6 +431,18 @@ func (mod *Module) HasStaticVariant() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *Module) CoverageFiles() android.Paths {
|
||||||
|
if mod.compiler != nil {
|
||||||
|
if library, ok := mod.compiler.(*libraryDecorator); ok {
|
||||||
|
if library.coverageFile != nil {
|
||||||
|
return android.Paths{library.coverageFile}
|
||||||
|
}
|
||||||
|
return android.Paths{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
|
||||||
|
}
|
||||||
|
|
||||||
var _ cc.LinkableInterface = (*Module)(nil)
|
var _ cc.LinkableInterface = (*Module)(nil)
|
||||||
|
|
||||||
func (mod *Module) Init() android.Module {
|
func (mod *Module) Init() android.Module {
|
||||||
@@ -403,6 +451,10 @@ func (mod *Module) Init() android.Module {
|
|||||||
if mod.compiler != nil {
|
if mod.compiler != nil {
|
||||||
mod.AddProperties(mod.compiler.compilerProps()...)
|
mod.AddProperties(mod.compiler.compilerProps()...)
|
||||||
}
|
}
|
||||||
|
if mod.coverage != nil {
|
||||||
|
mod.AddProperties(mod.coverage.props()...)
|
||||||
|
}
|
||||||
|
|
||||||
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
|
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
|
||||||
|
|
||||||
android.InitDefaultableModule(mod)
|
android.InitDefaultableModule(mod)
|
||||||
@@ -432,6 +484,7 @@ 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.coverage = &coverage{}
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,6 +507,7 @@ type ModuleContextIntf interface {
|
|||||||
toolchain() config.Toolchain
|
toolchain() config.Toolchain
|
||||||
baseModuleName() string
|
baseModuleName() string
|
||||||
CrateName() string
|
CrateName() string
|
||||||
|
nativeCoverage() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type depsContext struct {
|
type depsContext struct {
|
||||||
@@ -466,6 +520,14 @@ type moduleContext struct {
|
|||||||
moduleContextImpl
|
moduleContextImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *moduleContextImpl) nativeCoverage() bool {
|
||||||
|
return ctx.mod.nativeCoverage()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) nativeCoverage() bool {
|
||||||
|
return mod.compiler != nil && mod.compiler.nativeCoverage()
|
||||||
|
}
|
||||||
|
|
||||||
type moduleContextImpl struct {
|
type moduleContextImpl struct {
|
||||||
mod *Module
|
mod *Module
|
||||||
ctx BaseModuleContext
|
ctx BaseModuleContext
|
||||||
@@ -508,11 +570,19 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
|
|||||||
|
|
||||||
if mod.compiler != nil {
|
if mod.compiler != nil {
|
||||||
flags = mod.compiler.compilerFlags(ctx, flags)
|
flags = mod.compiler.compilerFlags(ctx, flags)
|
||||||
|
}
|
||||||
|
if mod.coverage != nil {
|
||||||
|
flags, deps = mod.coverage.flags(ctx, flags, deps)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mod.compiler != nil {
|
||||||
outputFile := mod.compiler.compile(ctx, flags, deps)
|
outputFile := mod.compiler.compile(ctx, flags, deps)
|
||||||
mod.outputFile = android.OptionalPathForPath(outputFile)
|
mod.outputFile = android.OptionalPathForPath(outputFile)
|
||||||
|
if !mod.Properties.PreventInstall {
|
||||||
mod.compiler.install(ctx, mod.outputFile.Path())
|
mod.compiler.install(ctx, mod.outputFile.Path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) deps(ctx DepsContext) Deps {
|
func (mod *Module) deps(ctx DepsContext) Deps {
|
||||||
deps := Deps{}
|
deps := Deps{}
|
||||||
@@ -521,6 +591,10 @@ func (mod *Module) deps(ctx DepsContext) Deps {
|
|||||||
deps = mod.compiler.compilerDeps(ctx, deps)
|
deps = mod.compiler.compilerDeps(ctx, deps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mod.coverage != nil {
|
||||||
|
deps = mod.coverage.deps(ctx, deps)
|
||||||
|
}
|
||||||
|
|
||||||
deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
|
deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
|
||||||
deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
|
deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
|
||||||
deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
|
deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
|
||||||
@@ -553,6 +627,12 @@ var (
|
|||||||
testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
|
testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (mod *Module) begin(ctx BaseModuleContext) {
|
||||||
|
if mod.coverage != nil {
|
||||||
|
mod.coverage.begin(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
||||||
var depPaths PathDeps
|
var depPaths PathDeps
|
||||||
|
|
||||||
@@ -588,6 +668,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
|||||||
ctx.ModuleErrorf("mod %q not an rlib library", depName)
|
ctx.ModuleErrorf("mod %q not an rlib library", depName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
|
||||||
directRlibDeps = append(directRlibDeps, rustDep)
|
directRlibDeps = append(directRlibDeps, rustDep)
|
||||||
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
|
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
|
||||||
case procMacroDepTag:
|
case procMacroDepTag:
|
||||||
@@ -642,6 +723,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
|
|||||||
depFlag = "-lstatic=" + libName
|
depFlag = "-lstatic=" + libName
|
||||||
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
|
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
|
||||||
depPaths.depFlags = append(depPaths.depFlags, depFlag)
|
depPaths.depFlags = append(depPaths.depFlags, depFlag)
|
||||||
|
depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
|
||||||
directStaticLibDeps = append(directStaticLibDeps, ccDep)
|
directStaticLibDeps = append(directStaticLibDeps, ccDep)
|
||||||
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
|
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
|
||||||
case cc.SharedDepTag:
|
case cc.SharedDepTag:
|
||||||
@@ -772,6 +854,29 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
|
|||||||
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
|
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BeginMutator(ctx android.BottomUpMutatorContext) {
|
||||||
|
if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
|
||||||
|
mod.beginMutator(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseModuleContext struct {
|
||||||
|
android.BaseModuleContext
|
||||||
|
moduleContextImpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mod *Module) beginMutator(actx android.BottomUpMutatorContext) {
|
||||||
|
ctx := &baseModuleContext{
|
||||||
|
BaseModuleContext: actx,
|
||||||
|
moduleContextImpl: moduleContextImpl{
|
||||||
|
mod: mod,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx.ctx = ctx
|
||||||
|
|
||||||
|
mod.begin(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) Name() string {
|
func (mod *Module) Name() string {
|
||||||
name := mod.ModuleBase.Name()
|
name := mod.ModuleBase.Name()
|
||||||
if p, ok := mod.compiler.(interface {
|
if p, ok := mod.compiler.(interface {
|
||||||
|
@@ -21,6 +21,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
"android/soong/cc"
|
"android/soong/cc"
|
||||||
)
|
)
|
||||||
@@ -57,6 +59,7 @@ func testConfig(bp string) android.Config {
|
|||||||
|
|
||||||
fs := map[string][]byte{
|
fs := map[string][]byte{
|
||||||
"foo.rs": nil,
|
"foo.rs": nil,
|
||||||
|
"foo.c": nil,
|
||||||
"src/bar.rs": nil,
|
"src/bar.rs": nil,
|
||||||
"liby.so": nil,
|
"liby.so": nil,
|
||||||
"libz.so": nil,
|
"libz.so": nil,
|
||||||
@@ -68,6 +71,14 @@ func testConfig(bp string) android.Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testRust(t *testing.T, bp string) *android.TestContext {
|
func testRust(t *testing.T, bp string) *android.TestContext {
|
||||||
|
return testRustContext(t, bp, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRustCov(t *testing.T, bp string) *android.TestContext {
|
||||||
|
return testRustContext(t, bp, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContext {
|
||||||
// TODO (b/140435149)
|
// TODO (b/140435149)
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
t.Skip("Only the Linux toolchain is supported for Rust")
|
t.Skip("Only the Linux toolchain is supported for Rust")
|
||||||
@@ -76,6 +87,11 @@ func testRust(t *testing.T, bp string) *android.TestContext {
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
config := testConfig(bp)
|
config := testConfig(bp)
|
||||||
|
|
||||||
|
if coverage {
|
||||||
|
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
|
||||||
|
config.TestProductVariables.CoveragePaths = []string{"*"}
|
||||||
|
}
|
||||||
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
ctx := CreateTestContext()
|
ctx := CreateTestContext()
|
||||||
ctx.Register(config)
|
ctx.Register(config)
|
||||||
|
@@ -50,6 +50,10 @@ type testDecorator struct {
|
|||||||
testConfig android.Path
|
testConfig android.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (test *testDecorator) nativeCoverage() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
|
func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
|
||||||
module := newModule(hod, android.MultilibFirst)
|
module := newModule(hod, android.MultilibFirst)
|
||||||
|
|
||||||
|
@@ -98,6 +98,7 @@ func CreateTestContext() *android.TestContext {
|
|||||||
// rust mutators
|
// rust mutators
|
||||||
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
|
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
|
||||||
ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
|
ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
|
||||||
|
ctx.BottomUp("rust_begin", BeginMutator).Parallel()
|
||||||
})
|
})
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
Reference in New Issue
Block a user