Add gcov coverage support to Rust modules.
This adds gcov coverage support for Rust device library and binary modules (including test modules). Support is provided to pass Rust static library gcno files to CC modules and visa versa. Additional changes: * Begin mutator added for Rust modules. * SuffixInList added to android package. * CoverageEnabled added to Coverage interface. * CoverageFiles added to LinkableLibrary interface. * Fix in coverage mutator for non-CC modules which marked the wrong variant as the coverage variant. * Added coverage libraries to the cc.GatherRequiredDepsForTest. Bug: 146448203 Test: NATIVE_COVERAGE=true COVERAGE_PATHS='*' m -j <rust_module> Change-Id: If20728bdde42a1dd544a35a40f0d981b80a5835f
This commit is contained in:
parent
b8bb5d05ce
commit
a0cd8f9acb
21 changed files with 628 additions and 91 deletions
|
@ -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 {
|
||||||
|
|
|
@ -1611,6 +1611,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())
|
||||||
}
|
}
|
||||||
|
@ -1627,6 +1629,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"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -741,6 +740,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 {
|
||||||
|
@ -2489,13 +2497,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,
|
||||||
|
|
|
@ -728,6 +728,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())
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,10 @@ type BinaryCompilerProperties struct {
|
||||||
type binaryDecorator struct {
|
type binaryDecorator struct {
|
||||||
*baseCompiler
|
*baseCompiler
|
||||||
|
|
||||||
Properties BinaryCompilerProperties
|
Properties BinaryCompilerProperties
|
||||||
distFile android.OptionalPath
|
distFile android.OptionalPath
|
||||||
unstrippedOutputFile android.Path
|
coverageOutputZipFile android.OptionalPath
|
||||||
|
unstrippedOutputFile android.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ compiler = (*binaryDecorator)(nil)
|
var _ compiler = (*binaryDecorator)(nil)
|
||||||
|
@ -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,12 +159,26 @@ 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,
|
||||||
Inputs: inputs,
|
ImplicitOutputs: implicitOutputs,
|
||||||
Implicits: implicits,
|
Inputs: inputs,
|
||||||
|
Implicits: implicits,
|
||||||
Args: map[string]string{
|
Args: map[string]string{
|
||||||
"rustcFlags": strings.Join(rustcFlags, " "),
|
"rustcFlags": strings.Join(rustcFlags, " "),
|
||||||
"linkFlags": strings.Join(linkFlags, " "),
|
"linkFlags": strings.Join(linkFlags, " "),
|
||||||
|
@ -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"])
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,11 +75,12 @@ type LibraryMutatedProperties struct {
|
||||||
type libraryDecorator struct {
|
type libraryDecorator struct {
|
||||||
*baseCompiler
|
*baseCompiler
|
||||||
|
|
||||||
Properties LibraryCompilerProperties
|
Properties LibraryCompilerProperties
|
||||||
MutatedProperties LibraryMutatedProperties
|
MutatedProperties LibraryMutatedProperties
|
||||||
distFile android.OptionalPath
|
distFile android.OptionalPath
|
||||||
unstrippedOutputFile android.Path
|
coverageOutputZipFile android.OptionalPath
|
||||||
includeDirs android.Paths
|
unstrippedOutputFile android.Path
|
||||||
|
includeDirs android.Paths
|
||||||
}
|
}
|
||||||
|
|
||||||
type libraryInterface interface {
|
type libraryInterface interface {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
|
107
rust/rust.go
107
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,9 +570,17 @@ 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)
|
||||||
mod.compiler.install(ctx, mod.outputFile.Path())
|
if !mod.Properties.PreventInstall {
|
||||||
|
mod.compiler.install(ctx, mod.outputFile.Path())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue